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 */
105 pthread_mutex_t lock;
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,
288 "Sets user language",
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 pthread_mutex_t applock = AST_MUTEX_INITIALIZER;
339 static struct ast_context *contexts = NULL;
340 /* Lock for the ast_context list */
341 static pthread_mutex_t conlock = AST_MUTEX_INITIALIZER;
342 static struct ast_app *apps = NULL;
344 /* Lock for switches */
345 static pthread_mutex_t switchlock = AST_MUTEX_INITIALIZER;
346 struct ast_switch *switches = NULL;
348 /* Lock for extension state notifys */
349 static pthread_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_pthread_mutex_lock(&applock)) {
413 ast_log(LOG_WARNING, "Unable to obtain application lock\n");
418 if (!strcasecmp(tmp->name, app))
422 ast_pthread_mutex_unlock(&applock);
426 static struct ast_switch *pbx_findswitch(char *sw)
428 struct ast_switch *asw;
429 if (ast_pthread_mutex_lock(&switchlock)) {
430 ast_log(LOG_WARNING, "Unable to obtain application lock\n");
435 if (!strcasecmp(asw->name, sw))
439 ast_pthread_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_pthread_mutex_lock(&conlock);
596 if (!strcasecmp(name, tmp->name))
602 ast_pthread_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;
744 /* Now we have the variable name on cp3 */
745 if ((first=strchr(var,':'))) {
746 strncpy(tmpvar, var, sizeof(tmpvar) - 1);
747 first = strchr(tmpvar, ':');
749 first = tmpvar + strlen(tmpvar);
751 pbx_substitute_variables_temp(c,tmpvar,ret,workspace,workspacelen - 1);
753 offset=atoi(first+1);
754 if ((second=strchr(first+1,':'))) {
756 offset2=atoi(second+1);
758 offset2=strlen(*ret)-offset;
759 if (abs(offset)>strlen(*ret)) {
763 offset=-strlen(*ret);
765 if ((offset<0 && offset2>-offset) || (offset>=0 && offset+offset2>strlen(*ret))) {
767 offset2=strlen(*ret)-offset;
769 offset2=strlen(*ret)+offset;
774 *ret+=strlen(*ret)+offset;
775 (*ret)[offset2] = '\0';
776 } else if (!strcmp(var, "CALLERIDNUM")) {
778 strncpy(workspace, c->callerid, workspacelen - 1);
779 ast_callerid_parse(workspace, &name, &num);
781 ast_shrink_phone_number(num);
785 } else if (!strcmp(var, "CALLERIDNAME")) {
787 strncpy(workspace, c->callerid, workspacelen - 1);
788 ast_callerid_parse(workspace, &name, &num);
793 } else if (!strcmp(var, "CALLERID")) {
795 strncpy(workspace, c->callerid, workspacelen - 1);
799 } else if (!strcmp(var, "HINT")) {
800 if (!ast_get_hint(workspace, workspacelen - 1, c, c->context, c->exten))
804 } else if (!strcmp(var, "EXTEN")) {
805 strncpy(workspace, c->exten, workspacelen - 1);
807 } else if (!strncmp(var, "EXTEN-", strlen("EXTEN-")) &&
808 /* XXX Remove me eventually */
809 (sscanf(var + strlen("EXTEN-"), "%d", &offset) == 1)) {
812 if (offset > strlen(c->exten))
813 offset = strlen(c->exten);
814 strncpy(workspace, c->exten + offset, workspacelen - 1);
816 ast_log(LOG_WARNING, "The use of 'EXTEN-foo' has been derprecated in favor of 'EXTEN:foo'\n");
817 } else if (!strcmp(var, "RDNIS")) {
819 strncpy(workspace, c->rdnis, workspacelen - 1);
823 } else if (!strcmp(var, "CONTEXT")) {
824 strncpy(workspace, c->context, workspacelen - 1);
826 } else if (!strcmp(var, "PRIORITY")) {
827 snprintf(workspace, workspacelen, "%d", c->priority);
829 } else if (!strcmp(var, "CHANNEL")) {
830 strncpy(workspace, c->name, workspacelen - 1);
832 } else if (!strcmp(var, "EPOCH")) {
833 snprintf(workspace, workspacelen -1, "%u",(int)time(NULL));
835 } else if (!strcmp(var, "DATETIME")) {
837 localtime_r(&thistime, &brokentime);
838 snprintf(workspace, workspacelen -1, "%02d%02d%04d-%02d:%02d:%02d",
841 brokentime.tm_year+1900,
847 } else if (!strcmp(var, "UNIQUEID")) {
848 snprintf(workspace, workspacelen -1, "%s", c->uniqueid);
850 AST_LIST_TRAVERSE(headp,variables,entries) {
852 ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",var,ast_var_name(variables));
854 if (strcasecmp(ast_var_name(variables),var)==0) {
855 *ret=ast_var_value(variables);
857 strncpy(workspace, *ret, workspacelen - 1);
864 AST_LIST_TRAVERSE(&globals,variables,entries) {
866 ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",var,ast_var_name(variables));
868 if (strcasecmp(ast_var_name(variables),var)==0) {
869 *ret=ast_var_value(variables);
871 strncpy(workspace, *ret, workspacelen - 1);
879 int len_env=strlen("ENV(");
880 if (len > (len_env+1) && !strncasecmp(var,"ENV(",len_env) && !strcmp(var+len-1,")")) {
882 strncpy(cp3, var, sizeof(cp3) - 1);
884 *ret=getenv(cp3+len_env);
886 strncpy(workspace, *ret, workspacelen - 1);
891 if (!(*ret) && !strcasecmp(var,"LEN(",4)) {
894 if (len > (len_len+1) && !strncasecmp(var,"LEN(",len_len) && strchr(var+len_len+2,')')) {
896 strncpy(cp3, var, sizeof(cp3) - 1);
897 cp3[len-len_len-1]='\0';
898 sprintf(workspace,"%d",strlen(cp3));
900 } else ast_log(LOG_NOTICE, "Wrong use of LEN(VARIABLE)\n");
905 void pbx_substitute_variables_helper(struct ast_channel *c,const char *cp1,char *cp2,int count)
908 const char *tmp, *whereweare;
911 char ltmp[256], var[256];
912 char *nextvar, *nextexp;
914 int pos, brackets, needsub, len;
916 /* Substitutes variables into cp2, based on string cp1, and assuming cp2 to be
919 while(strlen(whereweare) && count) {
920 /* Assume we're copying the whole remaining string */
921 pos = strlen(whereweare);
923 /* Look for a variable */
924 nextvar = strstr(whereweare, "${");
926 nextexp = strstr(whereweare, "$[");
928 if (nextvar && nextexp) {
929 if (nextvar < nextexp)
935 /* If there is one, we only go that far */
937 pos = nextvar - whereweare;
939 pos = nextexp - whereweare;
941 /* Can't copy more than 'count' bytes */
945 /* Copy that many bytes */
946 memcpy(cp2, whereweare, pos);
953 /* We have a variable. Find the start and end, and determine
954 if we are going to have to recursively call ourselves on the
956 vars = vare = nextvar + 2;
960 /* Find the end of it */
961 while(brackets && *vare) {
962 if ((vare[0] == '$') && (vare[1] == '{')) {
965 } else if (vare[0] == '}') {
967 } else if ((vare[0] == '$') && (vare[1] == '['))
972 ast_log(LOG_NOTICE, "Error in extension logic (missing '}')\n");
973 len = vare - vars - 1;
975 /* Skip totally over variable name */
976 whereweare += ( len + 3);
978 /* Store variable name (and truncate) */
979 memset(var, 0, sizeof(var));
980 strncpy(var, vars, sizeof(var) - 1);
983 /* Substitute if necessary */
985 memset(ltmp, 0, sizeof(ltmp));
986 pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1);
992 /* Retrieve variable value */
993 pbx_substitute_variables_temp(c,vars,&cp4, workspace, sizeof(workspace));
995 length = strlen(cp4);
998 memcpy(cp2, cp4, length);
1003 } else if (nextexp) {
1004 /* We have an expression. Find the start and end, and determine
1005 if we are going to have to recursively call ourselves on the
1007 vars = vare = nextexp + 2;
1011 /* Find the end of it */
1012 while(brackets && *vare) {
1013 if ((vare[0] == '$') && (vare[1] == '[')) {
1016 } else if (vare[0] == ']') {
1018 } else if ((vare[0] == '$') && (vare[1] == '{'))
1023 ast_log(LOG_NOTICE, "Error in extension logic (missing ']')\n");
1024 len = vare - vars - 1;
1026 /* Skip totally over variable name */
1027 whereweare += ( len + 3);
1029 /* Store variable name (and truncate) */
1030 memset(var, 0, sizeof(var));
1031 strncpy(var, vars, sizeof(var) - 1);
1034 /* Substitute if necessary */
1036 memset(ltmp, 0, sizeof(ltmp));
1037 pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1);
1043 /* Evaluate expression */
1044 cp4 = ast_expr(vars);
1046 printf("Expression is '%s'\n", cp4);
1049 length = strlen(cp4);
1052 memcpy(cp2, cp4, length);
1063 static void pbx_substitute_variables(char *passdata, int datalen, struct ast_channel *c, struct ast_exten *e) {
1065 memset(passdata, 0, datalen);
1067 /* No variables or expressions in e->data, so why scan it? */
1068 if (!strstr(e->data,"${") && !strstr(e->data,"$[")) {
1069 strncpy(passdata, e->data, datalen - 1);
1070 passdata[datalen-1] = '\0';
1074 pbx_substitute_variables_helper(c,e->data,passdata, datalen - 1);
1077 static int pbx_extension_helper(struct ast_channel *c, char *context, char *exten, int priority, char *callerid, int action)
1079 struct ast_exten *e;
1080 struct ast_app *app;
1081 struct ast_switch *sw;
1086 char *incstack[AST_PBX_MAX_STACK];
1092 if (ast_pthread_mutex_lock(&conlock)) {
1093 ast_log(LOG_WARNING, "Unable to obtain lock\n");
1094 if ((action == HELPER_EXISTS) || (action == HELPER_CANMATCH) || (action == HELPER_MATCHMORE))
1099 e = pbx_find_extension(c, context, exten, priority, callerid, action, incstack, &stacklen, &status, &sw, &data);
1102 case HELPER_CANMATCH:
1103 pthread_mutex_unlock(&conlock);
1106 pthread_mutex_unlock(&conlock);
1108 case HELPER_MATCHMORE:
1109 pthread_mutex_unlock(&conlock);
1115 app = pbx_findapp(e->app);
1116 pthread_mutex_unlock(&conlock);
1118 strncpy(c->context, context, sizeof(c->context-1));
1119 strncpy(c->exten, exten, sizeof(c->exten)-1);
1120 c->priority = priority;
1121 pbx_substitute_variables(passdata, sizeof(passdata), c, e);
1123 ast_log(LOG_DEBUG, "Launching '%s'\n", app->name);
1124 else if (option_verbose > 2)
1125 ast_verbose( VERBOSE_PREFIX_3 "Executing %s(\"%s\", \"%s\") %s\n",
1126 term_color(tmp, app->name, COLOR_BRCYAN, 0, sizeof(tmp)),
1127 term_color(tmp2, c->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
1128 term_color(tmp3, (strlen(passdata) ? (char *)passdata : ""), COLOR_BRMAGENTA, 0, sizeof(tmp3)),
1129 (newstack ? "in new stack" : "in same stack"));
1130 res = pbx_exec(c, app, passdata, newstack);
1133 ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
1137 ast_log(LOG_WARNING, "Huh (%d)?\n", action); return -1;
1141 case HELPER_CANMATCH:
1142 pthread_mutex_unlock(&conlock);
1145 pthread_mutex_unlock(&conlock);
1147 case HELPER_MATCHMORE:
1148 pthread_mutex_unlock(&conlock);
1154 pthread_mutex_unlock(&conlock);
1156 res = sw->exec(c, context, exten, priority, callerid, newstack, data);
1158 ast_log(LOG_WARNING, "No execution engine for switch %s\n", sw->name);
1163 ast_log(LOG_WARNING, "Huh (%d)?\n", action);
1167 pthread_mutex_unlock(&conlock);
1169 case STATUS_NO_CONTEXT:
1170 if ((action != HELPER_EXISTS) && (action != HELPER_MATCHMORE))
1171 ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", context);
1173 case STATUS_NO_EXTENSION:
1174 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1175 ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, context);
1177 case STATUS_NO_PRIORITY:
1178 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1179 ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, context);
1182 ast_log(LOG_DEBUG, "Shouldn't happen!\n");
1184 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1192 static struct ast_exten *ast_hint_extension(struct ast_channel *c, char *context, char *exten)
1194 struct ast_exten *e;
1195 struct ast_switch *sw;
1198 char *incstack[AST_PBX_MAX_STACK];
1201 if (ast_pthread_mutex_lock(&conlock)) {
1202 ast_log(LOG_WARNING, "Unable to obtain lock\n");
1205 e = pbx_find_extension(c, context, exten, PRIORITY_HINT, "", HELPER_EXISTS, incstack, &stacklen, &status, &sw, &data);
1206 ast_pthread_mutex_unlock(&conlock);
1210 static int ast_extension_state2(struct ast_exten *e)
1212 char hint[AST_MAX_EXTENSION] = "";
1215 int allunavailable = 1, allbusy = 1, allfree = 1;
1218 strncpy(hint, ast_get_extension_app(e), sizeof(hint)-1);
1222 rest = strchr(cur, '&');
1228 res = ast_device_state(cur);
1230 case AST_DEVICE_NOT_INUSE:
1234 case AST_DEVICE_INUSE:
1235 return AST_EXTENSION_INUSE;
1236 case AST_DEVICE_BUSY:
1241 case AST_DEVICE_UNAVAILABLE:
1242 case AST_DEVICE_INVALID:
1255 return AST_EXTENSION_NOT_INUSE;
1257 return AST_EXTENSION_BUSY;
1259 return AST_EXTENSION_UNAVAILABLE;
1261 return AST_EXTENSION_INUSE;
1263 return AST_EXTENSION_NOT_INUSE;
1267 int ast_extension_state(struct ast_channel *c, char *context, char *exten)
1269 struct ast_exten *e;
1271 e = ast_hint_extension(c, context, exten);
1275 return ast_extension_state2(e);
1278 int ast_device_state_changed(const char *fmt, ...)
1280 struct ast_hint *list;
1281 struct ast_state_cb *cblist;
1282 char hint[AST_MAX_EXTENSION];
1283 char device[AST_MAX_EXTENSION];
1290 vsnprintf(device, sizeof(device)-1, fmt, ap);
1293 rest = strchr(device, '-');
1298 pthread_mutex_lock(&hintlock);
1304 strcpy(hint, ast_get_extension_app(list->exten));
1307 rest = strchr(cur, '&');
1313 if (!strcmp(cur, device)) {
1314 // Found extension execute callbacks
1315 state = ast_extension_state2(list->exten);
1316 if ((state != -1) && (state != list->laststate)) {
1317 // For general callbacks
1320 cblist->callback(list->exten->parent->name, list->exten->exten, state, cblist->data);
1321 cblist = cblist->next;
1324 // For extension callbacks
1325 cblist = list->callbacks;
1327 cblist->callback(list->exten->parent->name, list->exten->exten, state, cblist->data);
1328 cblist = cblist->next;
1331 list->laststate = state;
1341 pthread_mutex_unlock(&hintlock);
1345 int ast_extension_state_add(char *context, char *exten,
1346 ast_state_cb_type callback, void *data)
1348 struct ast_hint *list;
1349 struct ast_state_cb *cblist;
1350 struct ast_exten *e;
1352 /* No context and extension add callback to statecbs list */
1353 if (!context && !exten) {
1354 pthread_mutex_lock(&hintlock);
1358 if (cblist->callback == callback) {
1359 cblist->data = data;
1360 pthread_mutex_unlock(&hintlock);
1363 cblist = cblist->next;
1366 /* Now inserts the callback */
1367 cblist = malloc(sizeof(struct ast_state_cb));
1369 pthread_mutex_unlock(&hintlock);
1372 memset(cblist, 0, sizeof(struct ast_state_cb));
1374 cblist->callback = callback;
1375 cblist->data = data;
1377 cblist->next = statecbs;
1380 pthread_mutex_unlock(&hintlock);
1384 if (!context || !exten)
1387 /* This callback type is for only one hint */
1388 e = ast_hint_extension(NULL, context, exten);
1393 pthread_mutex_lock(&hintlock);
1397 if (list->exten == e)
1403 pthread_mutex_unlock(&hintlock);
1407 /* Now inserts the callback */
1408 cblist = malloc(sizeof(struct ast_state_cb));
1410 pthread_mutex_unlock(&hintlock);
1413 memset(cblist, 0, sizeof(struct ast_state_cb));
1414 cblist->id = stateid++;
1415 cblist->callback = callback;
1416 cblist->data = data;
1418 cblist->next = list->callbacks;
1419 list->callbacks = cblist;
1421 pthread_mutex_unlock(&hintlock);
1425 int ast_extension_state_del(int id, ast_state_cb_type callback)
1427 struct ast_hint *list;
1428 struct ast_state_cb *cblist, *cbprev;
1430 if (!id && !callback)
1433 pthread_mutex_lock(&hintlock);
1435 /* id is zero is a callback without extension */
1440 if (cblist->callback == callback) {
1442 statecbs = cblist->next;
1444 cbprev->next = cblist->next;
1448 pthread_mutex_unlock(&hintlock);
1452 cblist = cblist->next;
1455 pthread_mutex_lock(&hintlock);
1459 /* id greater zero is a callback with extension */
1462 cblist = list->callbacks;
1465 if (cblist->id==id) {
1467 list->callbacks = cblist->next;
1469 cbprev->next = cblist->next;
1473 pthread_mutex_unlock(&hintlock);
1477 cblist = cblist->next;
1482 pthread_mutex_unlock(&hintlock);
1486 static int ast_add_hint(struct ast_exten *e)
1488 struct ast_hint *list;
1492 pthread_mutex_lock(&hintlock);
1495 /* Search if hint exists, do nothing */
1497 if (list->exten == e) {
1498 pthread_mutex_unlock(&hintlock);
1504 list = malloc(sizeof(struct ast_hint));
1506 pthread_mutex_unlock(&hintlock);
1509 /* Initialize and insert new item */
1510 memset(list, 0, sizeof(struct ast_hint));
1512 list->laststate = ast_extension_state2(e);
1516 pthread_mutex_unlock(&hintlock);
1520 static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
1522 struct ast_hint *list;
1524 pthread_mutex_lock(&hintlock);
1529 if (list->exten == oe) {
1531 pthread_mutex_unlock(&hintlock);
1536 pthread_mutex_unlock(&hintlock);
1541 static int ast_remove_hint(struct ast_exten *e)
1543 /* Cleanup the Notifys if hint is removed */
1544 struct ast_hint *list, *prev = NULL;
1545 struct ast_state_cb *cblist, *cbprev;
1550 pthread_mutex_lock(&hintlock);
1554 if (list->exten==e) {
1556 cblist = list->callbacks;
1558 /* Notify with -1 and remove all callbacks */
1560 cblist = cblist->next;
1561 cbprev->callback(list->exten->parent->name, list->exten->exten, -1, cbprev->data);
1564 list->callbacks = NULL;
1569 prev->next = list->next;
1573 pthread_mutex_unlock(&hintlock);
1581 pthread_mutex_unlock(&hintlock);
1586 int ast_get_hint(char *hint, int maxlen, struct ast_channel *c, char *context, char *exten)
1588 struct ast_exten *e;
1589 e = ast_hint_extension(c, context, exten);
1591 strncpy(hint, ast_get_extension_app(e), maxlen);
1597 int ast_exists_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid)
1599 return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_EXISTS);
1602 int ast_canmatch_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid)
1604 return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_CANMATCH);
1607 int ast_matchmore_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid)
1609 return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_MATCHMORE);
1612 int ast_spawn_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid)
1614 return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_SPAWN);
1617 int ast_pbx_run(struct ast_channel *c)
1626 /* A little initial setup here */
1628 ast_log(LOG_WARNING, "%s already has PBX structure??\n", c->name);
1629 c->pbx = malloc(sizeof(struct ast_pbx));
1631 ast_log(LOG_WARNING, "Out of memory\n");
1636 ast_log(LOG_WARNING, "%s already has a call record??\n", c->name);
1638 c->cdr = ast_cdr_alloc();
1640 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
1644 ast_cdr_init(c->cdr, c);
1647 memset(c->pbx, 0, sizeof(struct ast_pbx));
1648 /* Set reasonable defaults */
1649 c->pbx->rtimeout = 10;
1650 c->pbx->dtimeout = 5;
1652 /* Start by trying whatever the channel is set to */
1653 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
1654 /* JK02: If not successfull fall back to 's' */
1655 strncpy(c->exten, "s", sizeof(c->exten)-1);
1656 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
1657 /* JK02: And finally back to default if everything else failed */
1658 strncpy(c->context, "default", sizeof(c->context)-1);
1663 ast_cdr_start(c->cdr);
1667 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
1668 memset(exten, 0, sizeof(exten));
1669 manager_event(EVENT_FLAG_CALL, "Newexten",
1675 c->name, c->context, c->exten, c->priority, c->uniqueid);
1676 if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->callerid))) {
1677 /* Something bad happened, or a hangup has been requested. */
1678 if (((res >= '0') && (res <= '9')) || ((res >= 'A') && (res <= 'F')) ||
1679 (res == '*') || (res == '#')) {
1680 ast_log(LOG_DEBUG, "Oooh, got something to jump out with ('%c')!\n", res);
1681 memset(exten, 0, sizeof(exten));
1683 exten[pos++] = digit = res;
1687 case AST_PBX_KEEPALIVE:
1689 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
1690 else if (option_verbose > 1)
1691 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
1696 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
1697 else if (option_verbose > 1)
1698 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
1699 if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
1704 if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
1710 if ((c->_softhangup == AST_SOFTHANGUP_TIMEOUT) && (ast_exists_extension(c,c->context,"T",1,c->callerid))) {
1711 strncpy(c->exten,"T",sizeof(c->exten) - 1);
1712 /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
1713 c->whentohangup = 0;
1715 c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
1716 } else if (c->_softhangup) {
1717 ast_log(LOG_DEBUG, "Extension %s, priority %d returned normally even though call was hung up\n",
1718 c->exten, c->priority);
1724 if (!ast_exists_extension(c, c->context, c->exten, 1, c->callerid)) {
1725 /* It's not a valid extension anymore */
1726 if (ast_exists_extension(c, c->context, "i", 1, c->callerid)) {
1727 if (option_verbose > 2)
1728 ast_verbose(VERBOSE_PREFIX_3 "Sent into invalid extension '%s' in context '%s' on %s\n", c->exten, c->context, c->name);
1729 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", c->exten);
1730 strncpy(c->exten, "i", sizeof(c->exten)-1);
1733 ast_log(LOG_WARNING, "Channel '%s' sent into invalid extension '%s' in context '%s', but no invalid handler\n",
1734 c->name, c->exten, c->context);
1737 } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
1738 /* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */
1741 /* Done, wait for an extension */
1743 waittime = c->pbx->dtimeout;
1745 waittime = c->pbx->rtimeout;
1746 while (ast_matchmore_extension(c, c->context, exten, 1, c->callerid)) {
1747 /* As long as we're willing to wait, and as long as it's not defined,
1748 keep reading digits until we can't possibly get a right answer anymore. */
1749 digit = ast_waitfordigit(c, waittime * 1000);
1750 if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
1757 /* Error, maybe a hangup */
1759 exten[pos++] = digit;
1760 waittime = c->pbx->dtimeout;
1763 if (ast_exists_extension(c, c->context, exten, 1, c->callerid)) {
1764 /* Prepare the next cycle */
1765 strncpy(c->exten, exten, sizeof(c->exten)-1);
1768 /* No such extension */
1769 if (strlen(exten)) {
1770 /* An invalid extension */
1771 if (ast_exists_extension(c, c->context, "i", 1, c->callerid)) {
1772 if (option_verbose > 2)
1773 ast_verbose( VERBOSE_PREFIX_3 "Invalid extension '%s' in context '%s' on %s\n", exten, c->context, c->name);
1774 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", exten);
1775 strncpy(c->exten, "i", sizeof(c->exten)-1);
1778 ast_log(LOG_WARNING, "Invalid extension, but no rule 'i' in context '%s'\n", c->context);
1782 /* A simple timeout */
1783 if (ast_exists_extension(c, c->context, "t", 1, c->callerid)) {
1784 if (option_verbose > 2)
1785 ast_verbose( VERBOSE_PREFIX_3 "Timeout on %s\n", c->name);
1786 strncpy(c->exten, "t", sizeof(c->exten)-1);
1789 ast_log(LOG_WARNING, "Timeout, but no rule 't' in context '%s'\n", c->context);
1797 ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", c->name);
1799 if (ast_exists_extension(c, c->context, "h", 1, c->callerid)) {
1800 strcpy(c->exten, "h");
1802 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
1803 if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->callerid))) {
1804 /* Something bad happened, or a hangup has been requested. */
1806 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
1807 else if (option_verbose > 1)
1808 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
1815 pbx_destroy(c->pbx);
1817 if (res != AST_PBX_KEEPALIVE)
1822 static void *pbx_thread(void *data)
1824 /* Oh joyeous kernel, we're a new thread, with nothing to do but
1825 answer this channel and get it going. The setjmp stuff is fairly
1826 confusing, but necessary to get smooth transitions between
1827 the execution of different applications (without the use of
1828 additional threads) */
1829 struct ast_channel *c = data;
1835 int ast_pbx_start(struct ast_channel *c)
1838 pthread_attr_t attr;
1840 ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
1844 /* Start a new thread, and get something handling this channel. */
1845 pthread_attr_init(&attr);
1846 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1847 if (pthread_create(&t, &attr, pbx_thread, c)) {
1848 ast_log(LOG_WARNING, "Failed to create new channel thread\n");
1855 * This function locks contexts list by &conlist, search for the rigt context
1856 * structure, leave context list locked and call ast_context_remove_include2
1857 * which removes include, unlock contexts list and return ...
1859 int ast_context_remove_include(char *context, char *include, char *registrar)
1861 struct ast_context *c;
1863 if (ast_lock_contexts()) return -1;
1865 /* walk contexts and search for the right one ...*/
1866 c = ast_walk_contexts(NULL);
1868 /* we found one ... */
1869 if (!strcmp(ast_get_context_name(c), context)) {
1871 /* remove include from this context ... */
1872 ret = ast_context_remove_include2(c, include, registrar);
1874 ast_unlock_contexts();
1876 /* ... return results */
1879 c = ast_walk_contexts(c);
1882 /* we can't find the right one context */
1883 ast_unlock_contexts();
1888 * When we call this function, &conlock lock must be locked, because when
1889 * we giving *con argument, some process can remove/change this context
1890 * and after that there can be segfault.
1892 * This function locks given context, removes include, unlock context and
1895 int ast_context_remove_include2(struct ast_context *con, char *include, char *registrar)
1897 struct ast_include *i, *pi = NULL;
1899 if (ast_pthread_mutex_lock(&con->lock)) return -1;
1904 /* find our include */
1905 if (!strcmp(i->name, include) &&
1906 (!strcmp(i->registrar, registrar) || !registrar)) {
1907 /* remove from list */
1911 con->includes = i->next;
1912 /* free include and return */
1914 ast_pthread_mutex_unlock(&con->lock);
1921 /* we can't find the right include */
1922 ast_pthread_mutex_unlock(&con->lock);
1927 * This function locks contexts list by &conlist, search for the rigt context
1928 * structure, leave context list locked and call ast_context_remove_switch2
1929 * which removes switch, unlock contexts list and return ...
1931 int ast_context_remove_switch(char *context, char *sw, char *data, char *registrar)
1933 struct ast_context *c;
1935 if (ast_lock_contexts()) return -1;
1937 /* walk contexts and search for the right one ...*/
1938 c = ast_walk_contexts(NULL);
1940 /* we found one ... */
1941 if (!strcmp(ast_get_context_name(c), context)) {
1943 /* remove switch from this context ... */
1944 ret = ast_context_remove_switch2(c, sw, data, registrar);
1946 ast_unlock_contexts();
1948 /* ... return results */
1951 c = ast_walk_contexts(c);
1954 /* we can't find the right one context */
1955 ast_unlock_contexts();
1960 * When we call this function, &conlock lock must be locked, because when
1961 * we giving *con argument, some process can remove/change this context
1962 * and after that there can be segfault.
1964 * This function locks given context, removes switch, unlock context and
1967 int ast_context_remove_switch2(struct ast_context *con, char *sw, char *data, char *registrar)
1969 struct ast_sw *i, *pi = NULL;
1971 if (ast_pthread_mutex_lock(&con->lock)) return -1;
1976 /* find our switch */
1977 if (!strcmp(i->name, sw) && !strcmp(i->data, data) &&
1978 (!strcmp(i->registrar, registrar) || !registrar)) {
1979 /* remove from list */
1983 con->alts = i->next;
1984 /* free switch and return */
1986 ast_pthread_mutex_unlock(&con->lock);
1993 /* we can't find the right switch */
1994 ast_pthread_mutex_unlock(&con->lock);
1999 * This functions lock contexts list, search for the right context,
2000 * call ast_context_remove_extension2, unlock contexts list and return.
2001 * In this function we are using
2003 int ast_context_remove_extension(char *context, char *extension, int priority, char *registrar)
2005 struct ast_context *c;
2007 if (ast_lock_contexts()) return -1;
2009 /* walk contexts ... */
2010 c = ast_walk_contexts(NULL);
2012 /* ... search for the right one ... */
2013 if (!strcmp(ast_get_context_name(c), context)) {
2014 /* ... remove extension ... */
2015 int ret = ast_context_remove_extension2(c, extension, priority,
2017 /* ... unlock contexts list and return */
2018 ast_unlock_contexts();
2021 c = ast_walk_contexts(c);
2024 /* we can't find the right context */
2025 ast_unlock_contexts();
2030 * When do you want to call this function, make sure that &conlock is locked,
2031 * because some process can handle with your *con context before you lock
2034 * This functionc locks given context, search for the right extension and
2035 * fires out all peer in this extensions with given priority. If priority
2036 * is set to 0, all peers are removed. After that, unlock context and
2039 int ast_context_remove_extension2(struct ast_context *con, char *extension, int priority, char *registrar)
2041 struct ast_exten *exten, *prev_exten = NULL;
2043 if (ast_pthread_mutex_lock(&con->lock)) return -1;
2045 /* go through all extensions in context and search the right one ... */
2049 /* look for right extension */
2050 if (!strcmp(exten->exten, extension) &&
2051 (!strcmp(exten->registrar, registrar) || !registrar)) {
2052 struct ast_exten *peer;
2054 /* should we free all peers in this extension? (priority == 0)? */
2055 if (priority == 0) {
2056 /* remove this extension from context list */
2058 prev_exten->next = exten->next;
2060 con->root = exten->next;
2062 /* fire out all peers */
2067 if (!peer->priority==PRIORITY_HINT)
2068 ast_remove_hint(peer);
2070 peer->datad(peer->data);
2076 ast_pthread_mutex_unlock(&con->lock);
2079 /* remove only extension with exten->priority == priority */
2080 struct ast_exten *previous_peer = NULL;
2084 /* is this our extension? */
2085 if (peer->priority == priority &&
2086 (!strcmp(peer->registrar, registrar) || !registrar)) {
2087 /* we are first priority extension? */
2088 if (!previous_peer) {
2089 /* exists previous extension here? */
2091 /* yes, so we must change next pointer in
2092 * previous connection to next peer
2095 prev_exten->next = peer->peer;
2096 peer->peer->next = exten->next;
2098 prev_exten->next = exten->next;
2100 /* no previous extension, we are first
2101 * extension, so change con->root ...
2104 con->root = peer->peer;
2106 con->root = exten->next;
2109 /* we are not first priority in extension */
2110 previous_peer->peer = peer->peer;
2113 /* now, free whole priority extension */
2114 if (peer->priority==PRIORITY_HINT)
2115 ast_remove_hint(peer);
2116 peer->datad(peer->data);
2119 ast_pthread_mutex_unlock(&con->lock);
2122 /* this is not right extension, skip to next peer */
2123 previous_peer = peer;
2128 ast_pthread_mutex_unlock(&con->lock);
2134 exten = exten->next;
2137 /* we can't find right extension */
2138 ast_pthread_mutex_unlock(&con->lock);
2143 int ast_register_application(char *app, int (*execute)(struct ast_channel *, void *), char *synopsis, char *description)
2145 struct ast_app *tmp, *prev, *cur;
2147 if (ast_pthread_mutex_lock(&applock)) {
2148 ast_log(LOG_ERROR, "Unable to lock application list\n");
2153 if (!strcasecmp(app, tmp->name)) {
2154 ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
2155 ast_pthread_mutex_unlock(&applock);
2160 tmp = malloc(sizeof(struct ast_app));
2162 memset(tmp, 0, sizeof(struct ast_app));
2163 strncpy(tmp->name, app, sizeof(tmp->name)-1);
2164 tmp->execute = execute;
2165 tmp->synopsis = synopsis;
2166 tmp->description = description;
2167 /* Store in alphabetical order */
2171 if (strcasecmp(tmp->name, cur->name) < 0)
2177 tmp->next = prev->next;
2184 ast_log(LOG_WARNING, "Out of memory\n");
2185 ast_pthread_mutex_unlock(&applock);
2188 if (option_verbose > 1)
2189 ast_verbose( VERBOSE_PREFIX_2 "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
2190 ast_pthread_mutex_unlock(&applock);
2194 int ast_register_switch(struct ast_switch *sw)
2196 struct ast_switch *tmp, *prev=NULL;
2197 if (ast_pthread_mutex_lock(&switchlock)) {
2198 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
2203 if (!strcasecmp(tmp->name, sw->name))
2209 ast_pthread_mutex_unlock(&switchlock);
2210 ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name);
2218 ast_pthread_mutex_unlock(&switchlock);
2222 void ast_unregister_switch(struct ast_switch *sw)
2224 struct ast_switch *tmp, *prev=NULL;
2225 if (ast_pthread_mutex_lock(&switchlock)) {
2226 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
2233 prev->next = tmp->next;
2235 switches = tmp->next;
2242 ast_pthread_mutex_unlock(&switchlock);
2246 * Help for CLI commands ...
2248 static char show_application_help[] =
2249 "Usage: show application <application> [<application> [<application> [...]]]\n"
2250 " Describes a particular application.\n";
2252 static char show_applications_help[] =
2253 "Usage: show applications\n"
2254 " List applications which are currently available.\n";
2256 static char show_dialplan_help[] =
2257 "Usage: show dialplan [exten@][context]\n"
2260 static char show_switches_help[] =
2261 "Usage: show switches\n"
2262 " Show registered switches\n";
2265 * IMPLEMENTATION OF CLI FUNCTIONS IS IN THE SAME ORDER AS COMMANDS HELPS
2270 * 'show application' CLI command implementation functions ...
2274 * There is a possibility to show informations about more than one
2275 * application at one time. You can type 'show application Dial Echo' and
2276 * you will see informations about these two applications ...
2278 static char *complete_show_application(char *line, char *word,
2284 /* try to lock applications list ... */
2285 if (ast_pthread_mutex_lock(&applock)) {
2286 ast_log(LOG_ERROR, "Unable to lock application list\n");
2290 /* ... walk all applications ... */
2293 /* ... check if word matches this application ... */
2294 if (!strncasecmp(word, a->name, strlen(word))) {
2295 /* ... if this is right app serve it ... */
2296 if (++which > state) {
2297 char *ret = strdup(a->name);
2298 ast_pthread_mutex_unlock(&applock);
2305 /* no application match */
2306 ast_pthread_mutex_unlock(&applock);
2310 static int handle_show_application(int fd, int argc, char *argv[])
2314 int app, no_registered_app = 1;
2316 if (argc < 3) return RESULT_SHOWUSAGE;
2318 /* try to lock applications list ... */
2319 if (ast_pthread_mutex_lock(&applock)) {
2320 ast_log(LOG_ERROR, "Unable to lock application list\n");
2324 /* ... go through all applications ... */
2327 /* ... compare this application name with all arguments given
2328 * to 'show application' command ... */
2329 for (app = 2; app < argc; app++) {
2330 if (!strcasecmp(a->name, argv[app])) {
2331 no_registered_app = 0;
2333 /* ... one of our applications, show info ...*/
2334 snprintf(buf, sizeof(buf),
2335 "\n -= Info about application '%s' =- \n\n"
2336 "[Synopsis]:\n %s\n\n"
2337 "[Description]:\n%s\n",
2339 a->synopsis ? a->synopsis : "Not available",
2340 a->description ? a-> description : "Not available");
2347 ast_pthread_mutex_unlock(&applock);
2349 /* we found at least one app? no? */
2350 if (no_registered_app) {
2351 ast_cli(fd, "Your application(s) is (are) not registered\n");
2352 return RESULT_FAILURE;
2355 return RESULT_SUCCESS;
2358 static int handle_show_switches(int fd, int argc, char *argv[])
2360 struct ast_switch *sw;
2362 ast_cli(fd, "There are no registered alternative switches\n");
2363 return RESULT_SUCCESS;
2365 /* ... we have applications ... */
2366 ast_cli(fd, "\n -= Registered Asterisk Alternative Switches =-\n");
2367 if (ast_pthread_mutex_lock(&switchlock)) {
2368 ast_log(LOG_ERROR, "Unable to lock switches\n");
2373 ast_cli(fd, "%s: %s\n", sw->name, sw->description);
2376 ast_pthread_mutex_unlock(&switchlock);
2377 return RESULT_SUCCESS;
2381 * 'show applications' CLI command implementation functions ...
2383 static int handle_show_applications(int fd, int argc, char *argv[])
2387 /* try to lock applications list ... */
2388 if (ast_pthread_mutex_lock(&applock)) {
2389 ast_log(LOG_ERROR, "Unable to lock application list\n");
2393 /* ... go to first application ... */
2396 /* ... have we got at least one application (first)? no? */
2398 ast_cli(fd, "There is no registered applications\n");
2399 ast_pthread_mutex_unlock(&applock);
2403 /* ... we have applications ... */
2404 ast_cli(fd, "\n -= Registered Asterisk Applications =-\n");
2406 /* ... go through all applications ... */
2408 /* ... show informations about applications ... */
2409 ast_cli(fd," %15s: %s\n",
2411 a->synopsis ? a->synopsis : "<Synopsis not available>");
2415 /* ... unlock and return */
2416 ast_pthread_mutex_unlock(&applock);
2418 return RESULT_SUCCESS;
2422 * 'show dialplan' CLI command implementation functions ...
2424 static char *complete_show_dialplan_context(char *line, char *word, int pos,
2427 struct ast_context *c;
2430 /* we are do completion of [exten@]context on second position only */
2431 if (pos != 2) return NULL;
2433 /* try to lock contexts list ... */
2434 if (ast_lock_contexts()) {
2435 ast_log(LOG_ERROR, "Unable to lock context list\n");
2439 /* ... walk through all contexts ... */
2440 c = ast_walk_contexts(NULL);
2442 /* ... word matches context name? yes? ... */
2443 if (!strncasecmp(word, ast_get_context_name(c), strlen(word))) {
2444 /* ... for serve? ... */
2445 if (++which > state) {
2446 /* ... yes, serve this context name ... */
2447 char *ret = strdup(ast_get_context_name(c));
2448 ast_unlock_contexts();
2452 c = ast_walk_contexts(c);
2455 /* ... unlock and return */
2456 ast_unlock_contexts();
2460 static int handle_show_dialplan(int fd, int argc, char *argv[])
2462 struct ast_context *c;
2463 char *exten = NULL, *context = NULL;
2464 int context_existence = 0, extension_existence = 0;
2466 if (argc != 3 && argc != 2) return -1;
2468 /* we obtain [exten@]context? if yes, split them ... */
2470 char *splitter = argv[2];
2471 /* is there a '@' character? */
2472 if (strchr(argv[2], '@')) {
2473 /* yes, split into exten & context ... */
2474 exten = strsep(&splitter, "@");
2477 /* check for length and change to NULL if !strlen() */
2478 if (!strlen(exten)) exten = NULL;
2479 if (!strlen(context)) context = NULL;
2482 /* no '@' char, only context given */
2484 if (!strlen(context)) context = NULL;
2488 /* try to lock contexts */
2489 if (ast_lock_contexts()) {
2490 ast_cli(LOG_WARNING, "Failed to lock contexts list\n");
2491 return RESULT_FAILURE;
2494 /* walk all contexts ... */
2495 c = ast_walk_contexts(NULL);
2497 /* show this context? */
2499 !strcmp(ast_get_context_name(c), context)) {
2500 context_existence = 1;
2502 /* try to lock context before walking in ... */
2503 if (!ast_lock_context(c)) {
2504 struct ast_exten *e;
2505 struct ast_include *i;
2506 struct ast_ignorepat *ip;
2508 char buf[256], buf2[256];
2509 int context_info_printed = 0;
2511 /* are we looking for exten too? if yes, we print context
2512 * if we our extension only
2515 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
2516 ast_get_context_name(c), ast_get_context_registrar(c));
2517 context_info_printed = 1;
2520 /* walk extensions ... */
2521 e = ast_walk_context_extensions(c, NULL);
2523 struct ast_exten *p;
2525 /* looking for extension? is this our extension? */
2527 strcmp(ast_get_extension_name(e), exten))
2529 /* we are looking for extension and it's not our
2530 * extension, so skip to next extension */
2531 e = ast_walk_context_extensions(c, e);
2535 extension_existence = 1;
2537 /* may we print context info? */
2538 if (!context_info_printed) {
2539 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
2540 ast_get_context_name(c),
2541 ast_get_context_registrar(c));
2542 context_info_printed = 1;
2545 /* write extension name and first peer */
2546 bzero(buf, sizeof(buf));
2547 snprintf(buf, sizeof(buf), "'%s' =>",
2548 ast_get_extension_name(e));
2550 snprintf(buf2, sizeof(buf2),
2552 ast_get_extension_priority(e),
2553 ast_get_extension_app(e),
2554 (char *)ast_get_extension_app_data(e));
2556 ast_cli(fd, " %-17s %-45s [%s]\n", buf, buf2,
2557 ast_get_extension_registrar(e));
2559 /* walk next extension peers */
2560 p = ast_walk_extension_priorities(e, e);
2562 bzero((void *)buf2, sizeof(buf2));
2564 snprintf(buf2, sizeof(buf2),
2566 ast_get_extension_priority(p),
2567 ast_get_extension_app(p),
2568 (char *)ast_get_extension_app_data(p));
2570 ast_cli(fd," %-17s %-45s [%s]\n",
2572 ast_get_extension_registrar(p));
2574 p = ast_walk_extension_priorities(e, p);
2576 e = ast_walk_context_extensions(c, e);
2579 /* include & ignorepat we all printing if we are not
2580 * looking for exact extension
2583 if (ast_walk_context_extensions(c, NULL))
2586 /* walk included and write info ... */
2587 i = ast_walk_context_includes(c, NULL);
2589 bzero(buf, sizeof(buf));
2590 snprintf(buf, sizeof(buf), "'%s'",
2591 ast_get_include_name(i));
2592 ast_cli(fd, " Include => %-45s [%s]\n",
2593 buf, ast_get_include_registrar(i));
2594 i = ast_walk_context_includes(c, i);
2597 /* walk ignore patterns and write info ... */
2598 ip = ast_walk_context_ignorepats(c, NULL);
2600 bzero(buf, sizeof(buf));
2601 snprintf(buf, sizeof(buf), "'%s'",
2602 ast_get_ignorepat_name(ip));
2603 ast_cli(fd, " Ignore pattern => %-45s [%s]\n",
2604 buf, ast_get_ignorepat_registrar(ip));
2605 ip = ast_walk_context_ignorepats(c, ip);
2607 sw = ast_walk_context_switches(c, NULL);
2609 bzero(buf, sizeof(buf));
2610 snprintf(buf, sizeof(buf), "'%s/%s'",
2611 ast_get_switch_name(sw),
2612 ast_get_switch_data(sw));
2613 ast_cli(fd, " Alt. Switch => %-45s [%s]\n",
2614 buf, ast_get_switch_registrar(sw));
2615 sw = ast_walk_context_switches(c, sw);
2619 ast_unlock_context(c);
2621 /* if we print something in context, make an empty line */
2622 if (context_info_printed) ast_cli(fd, "\n");
2625 c = ast_walk_contexts(c);
2627 ast_unlock_contexts();
2629 /* check for input failure and throw some error messages */
2630 if (context && !context_existence) {
2631 ast_cli(fd, "There is no existence of '%s' context\n",
2633 return RESULT_FAILURE;
2636 if (exten && !extension_existence) {
2638 ast_cli(fd, "There is no existence of %s@%s extension\n",
2642 "There is no existence of '%s' extension in all contexts\n",
2644 return RESULT_FAILURE;
2648 return RESULT_SUCCESS;
2652 * CLI entries for upper commands ...
2654 static struct ast_cli_entry show_applications_cli =
2655 { { "show", "applications", NULL },
2656 handle_show_applications, "Shows registered applications",
2657 show_applications_help };
2659 static struct ast_cli_entry show_application_cli =
2660 { { "show", "application", NULL },
2661 handle_show_application, "Describe a specific application",
2662 show_application_help, complete_show_application };
2664 static struct ast_cli_entry show_dialplan_cli =
2665 { { "show", "dialplan", NULL },
2666 handle_show_dialplan, "Show dialplan",
2667 show_dialplan_help, complete_show_dialplan_context };
2669 static struct ast_cli_entry show_switches_cli =
2670 { { "show", "switches", NULL },
2671 handle_show_switches, "Show alternative switches",
2672 show_switches_help, NULL };
2674 int ast_unregister_application(char *app) {
2675 struct ast_app *tmp, *tmpl = NULL;
2676 if (ast_pthread_mutex_lock(&applock)) {
2677 ast_log(LOG_ERROR, "Unable to lock application list\n");
2682 if (!strcasecmp(app, tmp->name)) {
2684 tmpl->next = tmp->next;
2687 if (option_verbose > 1)
2688 ast_verbose( VERBOSE_PREFIX_2 "Unregistered application '%s'\n", tmp->name);
2689 ast_pthread_mutex_unlock(&applock);
2695 ast_pthread_mutex_unlock(&applock);
2699 struct ast_context *ast_context_create(char *name, char *registrar)
2701 struct ast_context *tmp;
2703 ast_pthread_mutex_lock(&conlock);
2706 if (!strcasecmp(tmp->name, name)) {
2707 ast_pthread_mutex_unlock(&conlock);
2708 ast_log(LOG_WARNING, "Tried to register context '%s', already in use\n", name);
2713 tmp = malloc(sizeof(struct ast_context));
2715 memset(tmp, 0, sizeof(struct ast_context));
2716 ast_pthread_mutex_init(&tmp->lock);
2717 strncpy(tmp->name, name, sizeof(tmp->name)-1);
2719 tmp->registrar = registrar;
2720 tmp->next = contexts;
2721 tmp->includes = NULL;
2722 tmp->ignorepats = NULL;
2725 ast_log(LOG_DEBUG, "Registered context '%s'\n", tmp->name);
2726 else if (option_verbose > 2)
2727 ast_verbose( VERBOSE_PREFIX_3 "Registered extension context '%s'\n", tmp->name);
2729 ast_log(LOG_WARNING, "Out of memory\n");
2731 ast_pthread_mutex_unlock(&conlock);
2737 * EBUSY - can't lock
2738 * ENOENT - no existence of context
2740 int ast_context_add_include(char *context, char *include, char *registrar)
2742 struct ast_context *c;
2744 if (ast_lock_contexts()) {
2749 /* walk contexts ... */
2750 c = ast_walk_contexts(NULL);
2752 /* ... search for the right one ... */
2753 if (!strcmp(ast_get_context_name(c), context)) {
2754 int ret = ast_context_add_include2(c, include, registrar);
2755 /* ... unlock contexts list and return */
2756 ast_unlock_contexts();
2759 c = ast_walk_contexts(c);
2762 /* we can't find the right context */
2763 ast_unlock_contexts();
2771 while(*c && (*c != '|')) c++; \
2772 if (*c) { *c = '\0'; c++; } else c = NULL; \
2775 static void get_timerange(struct ast_include *i, char *times)
2783 //start disabling all times, fill the fields with 0's, as they may contain garbage
2787 /* Star is all times */
2788 if (!strlen(times) || !strcmp(times, "*")) {
2790 i->minmask[x] = (1 << 30) - 1;
2793 /* Otherwise expect a range */
2794 e = strchr(times, '-');
2796 ast_log(LOG_WARNING, "Time range is not valid. Assuming no time.\n");
2801 while(*e && !isdigit(*e)) e++;
2803 ast_log(LOG_WARNING, "Invalid time range. Assuming no time.\n");
2806 if (sscanf(times, "%d:%d", &s1, &s2) != 2) {
2807 ast_log(LOG_WARNING, "%s isn't a time. Assuming no time.\n", times);
2810 if (sscanf(e, "%d:%d", &e1, &e2) != 2) {
2811 ast_log(LOG_WARNING, "%s isn't a time. Assuming no time.\n", e);
2814 s1 = s1 * 30 + s2/2;
2815 if ((s1 < 0) || (s1 >= 24*30)) {
2816 ast_log(LOG_WARNING, "%s isn't a valid star time. Assuming no time.\n", times);
2819 e1 = e1 * 30 + e2/2;
2820 if ((e1 < 0) || (e2 >= 24*30)) {
2821 ast_log(LOG_WARNING, "%s isn't a valid start time. Assuming no time.\n", times);
2824 /* Go through the time and enable each appropriate bit */
2825 for (x=s1;x != e1;x = (x + 1) % (24 * 30)) {
2826 i->minmask[x/30] |= (1 << (x % 30));
2828 /* Do the last one */
2829 i->minmask[x/30] |= (1 << (x % 30));
2833 static char *days[] =
2844 static unsigned int get_dow(char *dow)
2847 /* The following line is coincidence, really! */
2850 /* Check for all days */
2851 if (!strlen(dow) || !strcmp(dow, "*"))
2852 return (1 << 7) - 1;
2853 /* Get start and ending days */
2854 c = strchr(dow, '-');
2860 /* Find the start */
2862 while((s < 7) && strcasecmp(dow, days[s])) s++;
2864 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", dow);
2869 while((e < 7) && strcasecmp(c, days[e])) e++;
2871 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
2877 for (x=s;x!=e;x = (x + 1) % 7) {
2885 static unsigned int get_day(char *day)
2888 /* The following line is coincidence, really! */
2891 /* Check for all days */
2892 if (!strlen(day) || !strcmp(day, "*")) {
2893 mask = (1 << 30) + ((1 << 30) - 1);
2896 /* Get start and ending days */
2897 c = strchr(day, '-');
2902 /* Find the start */
2903 if (sscanf(day, "%d", &s) != 1) {
2904 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", day);
2907 if ((s < 1) || (s > 31)) {
2908 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", day);
2913 if (sscanf(c, "%d", &e) != 1) {
2914 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
2917 if ((e < 1) || (e > 31)) {
2918 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
2925 for (x=s;x!=e;x = (x + 1) % 31) {
2932 static char *months[] =
2948 static unsigned int get_month(char *mon)
2951 /* The following line is coincidence, really! */
2954 /* Check for all days */
2955 if (!strlen(mon) || !strcmp(mon, "*"))
2956 return (1 << 12) - 1;
2957 /* Get start and ending days */
2958 c = strchr(mon, '-');
2963 /* Find the start */
2965 while((s < 12) && strcasecmp(mon, months[s])) s++;
2967 ast_log(LOG_WARNING, "Invalid month '%s', assuming none\n", mon);
2972 while((e < 12) && strcasecmp(mon, months[e])) e++;
2974 ast_log(LOG_WARNING, "Invalid month '%s', assuming none\n", c);
2980 for (x=s;x!=e;x = (x + 1) % 12) {
2988 static void build_timing(struct ast_include *i, char *info)
2991 /* Check for empty just in case */
2995 /* Assume everything except time */
2996 i->monthmask = (1 << 12) - 1;
2997 i->daymask = (1 << 30) - 1 + (1 << 30);
2998 i->dowmask = (1 << 7) - 1;
2999 /* Avoid using str tok */
3001 /* Info has the time range, start with that */
3002 get_timerange(i, info);
3007 /* Now check for day of week */
3008 i->dowmask = get_dow(info);
3014 /* Now check for the day of the month */
3015 i->daymask = get_day(info);
3020 /* And finally go for the month */
3021 i->monthmask = get_month(info);
3026 * ENOMEM - out of memory
3027 * EBUSY - can't lock
3028 * EEXIST - already included
3029 * EINVAL - there is no existence of context for inclusion
3031 int ast_context_add_include2(struct ast_context *con, char *value,
3034 struct ast_include *new_include;
3036 struct ast_include *i, *il = NULL; /* include, include_last */
3038 /* allocate new include structure ... */
3039 if (!(new_include = malloc(sizeof(struct ast_include)))) {
3040 ast_log(LOG_WARNING, "Out of memory\n");
3045 /* ... fill in this structure ... */
3046 memset(new_include, 0, sizeof(struct ast_include));
3047 strncpy(new_include->name, value, sizeof(new_include->name)-1);
3048 strncpy(new_include->rname, value, sizeof(new_include->rname)-1);
3049 c = new_include->rname;
3050 /* Strip off timing info */
3051 while(*c && (*c != '|')) c++;
3052 /* Process if it's there */
3054 build_timing(new_include, c+1);
3057 new_include->next = NULL;
3058 new_include->registrar = registrar;
3060 /* ... try to lock this context ... */
3061 if (ast_pthread_mutex_lock(&con->lock)) {
3067 /* ... go to last include and check if context is already included too... */
3070 if (!strcasecmp(i->name, new_include->name)) {
3072 ast_pthread_mutex_unlock(&con->lock);
3080 /* ... include new context into context list, unlock, return */
3082 il->next = new_include;
3084 con->includes = new_include;
3085 if (option_verbose > 2)
3086 ast_verbose(VERBOSE_PREFIX_3 "Including context '%s' in context '%s'\n", new_include->name, ast_get_context_name(con));
3087 ast_pthread_mutex_unlock(&con->lock);
3094 * EBUSY - can't lock
3095 * ENOENT - no existence of context
3097 int ast_context_add_switch(char *context, char *sw, char *data, char *registrar)
3099 struct ast_context *c;
3101 if (ast_lock_contexts()) {
3106 /* walk contexts ... */
3107 c = ast_walk_contexts(NULL);
3109 /* ... search for the right one ... */
3110 if (!strcmp(ast_get_context_name(c), context)) {
3111 int ret = ast_context_add_switch2(c, sw, data, registrar);
3112 /* ... unlock contexts list and return */
3113 ast_unlock_contexts();
3116 c = ast_walk_contexts(c);
3119 /* we can't find the right context */
3120 ast_unlock_contexts();
3127 * ENOMEM - out of memory
3128 * EBUSY - can't lock
3129 * EEXIST - already included
3130 * EINVAL - there is no existence of context for inclusion
3132 int ast_context_add_switch2(struct ast_context *con, char *value,
3133 char *data, char *registrar)
3135 struct ast_sw *new_sw;
3136 struct ast_sw *i, *il = NULL; /* sw, sw_last */
3138 /* allocate new sw structure ... */
3139 if (!(new_sw = malloc(sizeof(struct ast_sw)))) {
3140 ast_log(LOG_WARNING, "Out of memory\n");
3145 /* ... fill in this structure ... */
3146 memset(new_sw, 0, sizeof(struct ast_sw));
3147 strncpy(new_sw->name, value, sizeof(new_sw->name)-1);
3149 strncpy(new_sw->data, data, sizeof(new_sw->data)-1);
3151 strncpy(new_sw->data, "", sizeof(new_sw->data)-1);
3152 new_sw->next = NULL;
3153 new_sw->registrar = registrar;
3155 /* ... try to lock this context ... */
3156 if (ast_pthread_mutex_lock(&con->lock)) {
3162 /* ... go to last sw and check if context is already swd too... */
3165 if (!strcasecmp(i->name, new_sw->name)) {
3167 ast_pthread_mutex_unlock(&con->lock);
3175 /* ... sw new context into context list, unlock, return */
3180 if (option_verbose > 2)
3181 ast_verbose(VERBOSE_PREFIX_3 "Including switch '%s/%s' in context '%s'\n", new_sw->name, new_sw->data, ast_get_context_name(con));
3182 ast_pthread_mutex_unlock(&con->lock);
3188 * EBUSY - can't lock
3189 * ENOENT - there is not context existence
3191 int ast_context_remove_ignorepat(char *context, char *ignorepat, char *registrar)
3193 struct ast_context *c;
3195 if (ast_lock_contexts()) {
3200 c = ast_walk_contexts(NULL);
3202 if (!strcmp(ast_get_context_name(c), context)) {
3203 int ret = ast_context_remove_ignorepat2(c, ignorepat, registrar);
3204 ast_unlock_contexts();
3207 c = ast_walk_contexts(c);
3210 ast_unlock_contexts();
3215 int ast_context_remove_ignorepat2(struct ast_context *con, char *ignorepat, char *registrar)
3217 struct ast_ignorepat *ip, *ipl = NULL;
3219 if (ast_pthread_mutex_lock(&con->lock)) {
3224 ip = con->ignorepats;
3226 if (!strcmp(ip->pattern, ignorepat) &&
3227 (registrar == ip->registrar || !registrar)) {
3229 ipl->next = ip->next;
3232 con->ignorepats = ip->next;
3235 ast_pthread_mutex_unlock(&con->lock);
3238 ipl = ip; ip = ip->next;
3241 ast_pthread_mutex_unlock(&con->lock);
3247 * EBUSY - can't lock
3248 * ENOENT - there is no existence of context
3250 int ast_context_add_ignorepat(char *con, char *value, char *registrar)
3252 struct ast_context *c;
3254 if (ast_lock_contexts()) {
3259 c = ast_walk_contexts(NULL);
3261 if (!strcmp(ast_get_context_name(c), con)) {
3262 int ret = ast_context_add_ignorepat2(c, value, registrar);
3263 ast_unlock_contexts();
3266 c = ast_walk_contexts(c);
3269 ast_unlock_contexts();
3274 int ast_context_add_ignorepat2(struct ast_context *con, char *value, char *registrar)
3276 struct ast_ignorepat *ignorepat, *ignorepatc, *ignorepatl = NULL;
3277 ignorepat = malloc(sizeof(struct ast_ignorepat));
3279 ast_log(LOG_WARNING, "Out of memory\n");
3283 memset(ignorepat, 0, sizeof(struct ast_ignorepat));
3284 strncpy(ignorepat->pattern, value, sizeof(ignorepat->pattern)-1);
3285 ignorepat->next = NULL;
3286 ignorepat->registrar = registrar;
3287 ast_pthread_mutex_lock(&con->lock);
3288 ignorepatc = con->ignorepats;
3290 ignorepatl = ignorepatc;
3291 if (!strcasecmp(ignorepatc->pattern, value)) {
3293 pthread_mutex_unlock(&con->lock);
3297 ignorepatc = ignorepatc->next;
3300 ignorepatl->next = ignorepat;
3302 con->ignorepats = ignorepat;
3303 pthread_mutex_unlock(&con->lock);
3308 int ast_ignore_pattern(char *context, char *pattern)
3310 struct ast_context *con;
3311 struct ast_ignorepat *pat;
3312 con = ast_context_find(context);
3314 pat = con->ignorepats;
3316 if (ast_extension_match(pat->pattern, pattern))
3325 * EBUSY - can't lock
3326 * ENOENT - no existence of context
3329 int ast_add_extension(char *context, int replace, char *extension, int priority, char *callerid,
3330 char *application, void *data, void (*datad)(void *), char *registrar)
3332 struct ast_context *c;
3334 if (ast_lock_contexts()) {
3339 c = ast_walk_contexts(NULL);
3341 if (!strcmp(context, ast_get_context_name(c))) {
3342 int ret = ast_add_extension2(c, replace, extension, priority, callerid,
3343 application, data, datad, registrar);
3344 ast_unlock_contexts();
3347 c = ast_walk_contexts(c);
3350 ast_unlock_contexts();
3355 int ast_async_goto(struct ast_channel *chan, char *context, char *exten, int priority, int needlock)
3359 ast_pthread_mutex_lock(&chan->lock);
3361 /* This channel is currently in the PBX */
3362 if (context && strlen(context))
3363 strncpy(chan->context, context, sizeof(chan->context) - 1);
3364 if (exten && strlen(exten))
3365 strncpy(chan->exten, exten, sizeof(chan->context) - 1);
3367 chan->priority = priority - 1;
3368 ast_softhangup_nolock(chan, AST_SOFTHANGUP_ASYNCGOTO);
3370 ast_pthread_mutex_unlock(&chan->lock);
3372 /* In order to do it when the channel doesn't really exist within
3373 the PBX, we have to make a new channel, masquerade, and start the PBX
3374 at the new location */
3375 struct ast_channel *tmpchan;
3376 struct ast_frame *f;
3377 tmpchan = ast_channel_alloc(0);
3379 snprintf(tmpchan->name, sizeof(tmpchan->name), "AsyncGoto/%s", chan->name);
3380 ast_setstate(tmpchan, chan->_state);
3381 /* Make formats okay */
3382 tmpchan->readformat = chan->readformat;
3383 tmpchan->writeformat = chan->writeformat;
3384 /* Setup proper location */
3385 if (context && strlen(context))
3386 strncpy(tmpchan->context, context, sizeof(tmpchan->context) - 1);
3388 strncpy(tmpchan->context, chan->context, sizeof(tmpchan->context) - 1);
3389 if (exten && strlen(exten))
3390 strncpy(tmpchan->exten, exten, sizeof(tmpchan->exten) - 1);
3392 strncpy(tmpchan->exten, chan->exten, sizeof(tmpchan->exten) - 1);
3394 tmpchan->priority = priority;
3396 tmpchan->priority = chan->priority;
3398 ast_pthread_mutex_unlock(&chan->lock);
3400 /* Masquerade into temp channel */
3401 ast_channel_masquerade(tmpchan, chan);
3403 /* Make the masquerade happen by reading a frame from the tmp channel */
3404 f = ast_read(tmpchan);
3407 /* Start the PBX going on our stolen channel */
3408 if (ast_pbx_start(tmpchan)) {
3409 ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmpchan->name);
3410 ast_hangup(tmpchan);
3416 ast_pthread_mutex_unlock(&chan->lock);
3422 int ast_async_goto_by_name(char *channame, char *context, char *exten, int priority)
3424 struct ast_channel *chan;
3425 chan = ast_channel_walk(NULL);
3427 if (!strcasecmp(channame, chan->name))
3429 chan = ast_channel_walk(chan);
3432 return ast_async_goto(chan, context, exten, priority, 1);
3436 static void ext_strncpy(char *dst, char *src, int len)
3439 while(*src && (count < len - 1)) {
3442 //otherwise exten => [a-b],1,... doesn't work
3457 * EBUSY - can't lock
3458 * EEXIST - extension with the same priority exist and no replace is set
3461 int ast_add_extension2(struct ast_context *con,
3462 int replace, char *extension, int priority, char *callerid,
3463 char *application, void *data, void (*datad)(void *),
3467 #define LOG do { if (option_debug) {\
3468 if (tmp->matchcid) { \
3469 ast_log(LOG_DEBUG, "Added extension '%s' priority %d (CID match '%s') to %s\n", tmp->exten, tmp->priority, tmp->cidmatch, con->name); \
3471 ast_log(LOG_DEBUG, "Added extension '%s' priority %d to %s\n", tmp->exten, tmp->priority, con->name); \
3473 } else if (option_verbose > 2) { \
3474 if (tmp->matchcid) { \
3475 ast_verbose( VERBOSE_PREFIX_3 "Added extension '%s' priority %d (CID match '%s')to %s\n", tmp->exten, tmp->priority, tmp->cidmatch, con->name); \
3477 ast_verbose( VERBOSE_PREFIX_3 "Added extension '%s' priority %d to %s\n", tmp->exten, tmp->priority, con->name); \
3482 * This is a fairly complex routine. Different extensions are kept
3483 * in order by the extension number. Then, extensions of different
3484 * priorities (same extension) are kept in a list, according to the
3487 struct ast_exten *tmp, *e, *el = NULL, *ep = NULL;
3489 /* Be optimistic: Build the extension structure first */
3490 tmp = malloc(sizeof(struct ast_exten));
3492 memset(tmp, 0, sizeof(struct ast_exten));
3493 ext_strncpy(tmp->exten, extension, sizeof(tmp->exten));
3494 tmp->priority = priority;
3496 ext_strncpy(tmp->cidmatch, callerid, sizeof(tmp->cidmatch));
3499 strcpy(tmp->cidmatch, "");
3502 strncpy(tmp->app, application, sizeof(tmp->app)-1);
3506 tmp->registrar = registrar;
3510 ast_log(LOG_WARNING, "Out of memory\n");
3514 if (ast_pthread_mutex_lock(&con->lock)) {
3516 /* And properly destroy the data */
3518 ast_log(LOG_WARNING, "Failed to lock context '%s'\n", con->name);
3524 res= strcasecmp(e->exten, extension);
3526 if (!e->matchcid && !tmp->matchcid)
3528 else if (tmp->matchcid && !e->matchcid)
3530 else if (e->matchcid && !tmp->matchcid)
3533 res = strcasecmp(e->cidmatch, tmp->cidmatch);
3536 /* We have an exact match, now we find where we are
3537 and be sure there's no duplicates */
3539 if (e->priority == tmp->priority) {
3540 /* Can't have something exactly the same. Is this a
3541 replacement? If so, replace, otherwise, bonk. */
3544 /* We're in the peer list, insert ourselves */
3546 tmp->peer = e->peer;
3548 /* We're the first extension. Take over e's functions */
3550 tmp->next = e->next;
3551 tmp->peer = e->peer;
3553 /* We're the very first extension. */
3555 tmp->next = e->next;
3556 tmp->peer = e->peer;
3558 if (tmp->priority == PRIORITY_HINT)
3559 ast_change_hint(e,tmp);
3560 /* Destroy the old one */
3563 ast_pthread_mutex_unlock(&con->lock);
3564 if (tmp->priority == PRIORITY_HINT)
3565 ast_change_hint(e, tmp);
3566 /* And immediately return success. */
3570 ast_log(LOG_WARNING, "Unable to register extension '%s', priority %d in '%s', already in use\n", tmp->exten, tmp->priority, con->name);
3571 tmp->datad(tmp->data);
3573 ast_pthread_mutex_unlock(&con->lock);
3577 } else if (e->priority > tmp->priority) {
3578 /* Slip ourselves in just before e */
3580 /* Easy enough, we're just in the peer list */
3584 /* We're the first extension in this peer list */
3586 tmp->next = e->next;
3590 /* We're the very first extension altogether */
3591 tmp->next = con->root;
3592 /* Con->root must always exist or we couldn't get here */
3593 tmp->peer = con->root->peer;