2 * Asterisk -- A telephony toolkit for Linux.
6 * Copyright (C) 1999, Mark Spencer
8 * Mark Spencer <markster@linux-support.net>
10 * This program is free software, distributed under the terms of
11 * the GNU General Public License
14 #include <asterisk/lock.h>
15 #include <asterisk/cli.h>
16 #include <asterisk/pbx.h>
17 #include <asterisk/channel.h>
18 #include <asterisk/options.h>
19 #include <asterisk/logger.h>
20 #include <asterisk/file.h>
21 #include <asterisk/callerid.h>
22 #include <asterisk/cdr.h>
23 #include <asterisk/config.h>
24 #include <asterisk/term.h>
25 #include <asterisk/manager.h>
26 #include <asterisk/ast_expr.h>
27 #include <asterisk/channel_pvt.h>
28 #include <asterisk/linkedlists.h>
29 #include <asterisk/say.h>
44 * The speed of extension handling will likely be among the most important
45 * aspects of this PBX. The switching scheme as it exists right now isn't
46 * terribly bad (it's O(N+M), where N is the # of extensions and M is the avg #
47 * of priorities, but a constant search time here would be great ;-)
56 char exten[AST_MAX_EXTENSION];
58 char cidmatch[AST_MAX_EXTENSION];
61 struct ast_context *parent;
62 /* Application to execute */
63 char app[AST_MAX_EXTENSION];
67 void (*datad)(void *);
68 /* Next higher priority with our extension */
69 struct ast_exten *peer;
72 /* Extension with a greater ID */
73 struct ast_exten *next;
77 char name[AST_MAX_EXTENSION];
78 char rname[AST_MAX_EXTENSION];
81 unsigned int monthmask;
84 unsigned int minmask[24];
85 struct ast_include *next;
89 char name[AST_MAX_EXTENSION];
91 char data[AST_MAX_EXTENSION];
95 struct ast_ignorepat {
96 char pattern[AST_MAX_EXTENSION];
98 struct ast_ignorepat *next;
101 /* An extension context */
103 /* Name of the context */
104 char name[AST_MAX_EXTENSION];
105 /* A lock to prevent multiple threads from clobbering the context */
107 /* The root of the list of extensions */
108 struct ast_exten *root;
109 /* Link them together */
110 struct ast_context *next;
111 /* Include other contexts */
112 struct ast_include *includes;
113 /* Patterns for which to continue playing dialtone */
114 struct ast_ignorepat *ignorepats;
117 /* Alternative switches */
124 /* Name of the application */
125 char name[AST_MAX_APP];
126 int (*execute)(struct ast_channel *chan, void *data);
129 struct ast_app *next;
132 /* An extension state notify */
133 struct ast_state_cb {
136 ast_state_cb_type callback;
137 struct ast_state_cb *next;
141 struct ast_exten *exten;
143 struct ast_state_cb *callbacks;
144 struct ast_hint *next;
148 static int pbx_builtin_prefix(struct ast_channel *, void *);
149 static int pbx_builtin_suffix(struct ast_channel *, void *);
150 static int pbx_builtin_stripmsd(struct ast_channel *, void *);
151 static int pbx_builtin_answer(struct ast_channel *, void *);
152 static int pbx_builtin_goto(struct ast_channel *, void *);
153 static int pbx_builtin_hangup(struct ast_channel *, void *);
154 static int pbx_builtin_background(struct ast_channel *, void *);
155 static int pbx_builtin_dtimeout(struct ast_channel *, void *);
156 static int pbx_builtin_rtimeout(struct ast_channel *, void *);
157 static int pbx_builtin_atimeout(struct ast_channel *, void *);
158 static int pbx_builtin_wait(struct ast_channel *, void *);
159 static int pbx_builtin_setlanguage(struct ast_channel *, void *);
160 static int pbx_builtin_resetcdr(struct ast_channel *, void *);
161 static int pbx_builtin_setaccount(struct ast_channel *, void *);
162 static int pbx_builtin_ringing(struct ast_channel *, void *);
163 static int pbx_builtin_congestion(struct ast_channel *, void *);
164 static int pbx_builtin_busy(struct ast_channel *, void *);
165 static int pbx_builtin_setglobalvar(struct ast_channel *, void *);
166 static int pbx_builtin_noop(struct ast_channel *, void *);
167 static int pbx_builtin_gotoif(struct ast_channel *, void *);
168 static int pbx_builtin_gotoiftime(struct ast_channel *, void *);
169 static int pbx_builtin_saynumber(struct ast_channel *, void *);
170 static int pbx_builtin_saydigits(struct ast_channel *, void *);
171 int pbx_builtin_setvar(struct ast_channel *, void *);
172 void pbx_builtin_setvar_helper(struct ast_channel *chan, char *name, char *value);
173 char *pbx_builtin_getvar_helper(struct ast_channel *chan, char *name);
175 static struct varshead globals = AST_LIST_HEAD_INITIALIZER(varshead);
177 static struct pbx_builtin {
178 char name[AST_MAX_APP];
179 int (*execute)(struct ast_channel *chan, void *data);
184 /* These applications are built into the PBX core and do not
185 need separate modules
189 { "AbsoluteTimeout", pbx_builtin_atimeout,
190 "Set absolute maximum time of call",
191 " AbsoluteTimeout(seconds): Set the absolute maximum amount of time permitted\n"
192 "for a call. A setting of 0 disables the timeout. Always returns 0.\n" },
194 { "Answer", pbx_builtin_answer,
195 "Answer a channel if ringing",
196 " Answer(): If the channel is ringing, answer it, otherwise do nothing. \n"
197 "Returns 0 unless it tries to answer the channel and fails.\n" },
199 { "BackGround", pbx_builtin_background,
200 "Play a file while awaiting extension",
201 " Background(filename): Plays a given file, while simultaneously waiting for\n"
202 "the user to begin typing an extension. The timeouts do not count until the\n"
203 "last BackGround application as ended. Always returns 0.\n" },
205 { "Busy", pbx_builtin_busy,
206 "Indicate busy condition and stop",
207 " Busy(): Requests that the channel indicate busy condition and then waits\n"
208 "for the user to hang up. Always returns -1." },
210 { "Congestion", pbx_builtin_congestion,
211 "Indicate congestion and stop",
212 " Congestion(): Requests that the channel indicate congestion and then\n"
213 "waits for the user to hang up. Always returns -1." },
215 { "DigitTimeout", pbx_builtin_dtimeout,
216 "Set maximum timeout between digits",
217 " DigitTimeout(seconds): Set the maximum amount of time permitted between\n"
218 "digits when the user is typing in an extension. When this timeout expires,\n"
219 "after the user has started to type in an extension, the extension will be\n"
220 "considered complete, and will be interpreted. Note that if an extension\n"
221 "typed in is valid, it will not have to timeout to be tested, so typically\n"
222 "at the expiry of this timeout, the extension will be considered invalid\n"
223 "(and thus control would be passed to the 'i' extension, or if it doesn't\n"
224 "exist the call would be terminated). Always returns 0.\n" },
226 { "Goto", pbx_builtin_goto,
227 "Goto a particular priority, extension, or context",
228 " Goto([[context|]extension|]priority): Set the priority to the specified\n"
229 "value, optionally setting the extension and optionally the context as well.\n"
230 "The extension BYEXTENSION is special in that it uses the current extension,\n"
231 "thus permitting you to go to a different context, without specifying a\n"
232 "specific extension. Always returns 0, even if the given context, extension,\n"
233 "or priority is invalid.\n" },
235 { "GotoIf", pbx_builtin_gotoif,
237 " GotoIf(Condition?label1:label2): Go to label 1 if condition is\n"
238 "true, to label2 if condition is false. Either label1 or label2 may be\n"
239 "omitted (in that case, we just don't take the particular branch) but not\n"
240 "both. Look for the condition syntax in examples or documentation." },
242 { "GotoIfTime", pbx_builtin_gotoiftime,
243 "Conditional goto on current time",
244 " GotoIfTime(<times>|<weekdays>|<mdays>|<months>?[[context|]extension|]pri):\n"
245 "If the current time matches the specified time, then branch to the specified\n"
246 "extension. Each of the elements may be specified either as '*' (for always)\n"
247 "or as a range. See the include syntax." },
249 { "Hangup", pbx_builtin_hangup,
250 "Unconditional hangup",
251 " Hangup(): Unconditionally hangs up a given channel by returning -1 always.\n" },
253 { "NoOp", pbx_builtin_noop,
255 " NoOp(): No-operation; Does nothing." },
257 { "Prefix", pbx_builtin_prefix,
258 "Prepend leading digits",
259 " Prefix(digits): Prepends the digit string specified by digits to the\n"
260 "channel's associated extension. For example, the number 1212 when prefixed\n"
261 "with '555' will become 5551212. This app always returns 0, and the PBX will\n"
262 "continue processing at the next priority for the *new* extension.\n"
263 " So, for example, if priority 3 of 1212 is Prefix 555, the next step\n"
264 "executed will be priority 4 of 5551212. If you switch into an extension\n"
265 "which has no first step, the PBX will treat it as though the user dialed an\n"
266 "invalid extension.\n" },
268 { "ResetCDR", pbx_builtin_resetcdr,
269 "Resets the Call Data Record",
270 " ResetCDR([options]): Causes the Call Data Record to be reset, optionally\n"
271 "storing the current CDR before zeroing it out (if 'w' option is specifed).\n"
272 "record WILL be stored. Always returns 0.\n" },
274 { "ResponseTimeout", pbx_builtin_rtimeout,
275 "Set maximum timeout awaiting response",
276 " ResponseTimeout(seconds): Set the maximum amount of time permitted after\n"
277 "falling through a series of priorities for a channel in which the user may\n"
278 "begin typing an extension. If the user does not type an extension in this\n"
279 "amount of time, control will pass to the 't' extension if it exists, and\n"
280 "if not the call would be terminated. Always returns 0.\n" },
282 { "Ringing", pbx_builtin_ringing,
283 "Indicate ringing tone",
284 " Ringing(): Request that the channel indicate ringing tone to the user.\n"
285 "Always returns 0.\n" },
287 { "SayNumber", pbx_builtin_saynumber,
289 " SayNumber(digits): Says the passed number\n" },
291 { "SayDigits", pbx_builtin_saydigits,
293 " SayDigits(digits): Says the passed digits\n" },
295 { "SetAccount", pbx_builtin_setaccount,
297 " SetAccount([account]): Set the channel account code for billing\n"
298 "purposes. Always returns 0.\n" },
300 { "SetGlobalVar", pbx_builtin_setglobalvar,
301 "Set variable to value",
302 " SetGlobalVar(#n=value): Sets global variable n to value" },
304 { "SetLanguage", pbx_builtin_setlanguage,
305 "Sets user language",
306 " SetLanguage(language): Set the channel language to 'language'. This\n"
307 "information is used for the generation of numbers, and to select a natural\n"
308 "language file when available. For example, if language is set to 'fr' and\n"
309 "the file 'demo-congrats' is requested to be played, if the file 'fr/demo-\n"
310 "congrats' exists, then it will play that file, and if not will play the\n"
311 "normal 'demo-congrats'. Always returns 0.\n" },
313 { "SetVar", pbx_builtin_setvar,
314 "Set variable to value",
315 " Setvar(#n=value): Sets variable n to value" },
317 { "StripMSD", pbx_builtin_stripmsd,
318 "Strip leading digits",
319 " StripMSD(count): Strips the leading 'count' digits from the channel's\n"
320 "associated extension. For example, the number 5551212 when stripped with a\n"
321 "count of 3 would be changed to 1212. This app always returns 0, and the PBX\n"
322 "will continue processing at the next priority for the *new* extension.\n"
323 " So, for example, if priority 3 of 5551212 is StripMSD 3, the next step\n"
324 "executed will be priority 4 of 1212. If you switch into an extension which\n"
325 "has no first step, the PBX will treat it as though the user dialed an\n"
326 "invalid extension.\n" },
328 { "Suffix", pbx_builtin_suffix,
329 "Append trailing digits",
330 " Suffix(digits): Appends the digit string specified by digits to the\n"
331 "channel's associated extension. For example, the number 555 when suffixed\n"
332 "with '1212' will become 5551212. This app always returns 0, and the PBX will\n"
333 "continue processing at the next priority for the *new* extension.\n"
334 " So, for example, if priority 3 of 555 is Suffix 1212, the next step\n"
335 "executed will be priority 4 of 5551212. If you switch into an extension\n"
336 "which has no first step, the PBX will treat it as though the user dialed an\n"
337 "invalid extension.\n" },
339 { "Wait", pbx_builtin_wait,
340 "Waits for some time",
341 " Wait(seconds): Waits for a specified number of seconds, then returns 0.\n"
342 "seconds can be passed with fractions of a second. (eg: 1.5 = 1.5 seconds)\n" },
345 /* Lock for the application list */
346 static ast_mutex_t applock = AST_MUTEX_INITIALIZER;
347 static struct ast_context *contexts = NULL;
348 /* Lock for the ast_context list */
349 static ast_mutex_t conlock = AST_MUTEX_INITIALIZER;
350 static struct ast_app *apps = NULL;
352 /* Lock for switches */
353 static ast_mutex_t switchlock = AST_MUTEX_INITIALIZER;
354 struct ast_switch *switches = NULL;
356 /* Lock for extension state notifys */
357 static ast_mutex_t hintlock = AST_MUTEX_INITIALIZER;
358 static int stateid = 1;
359 struct ast_hint *hints = NULL;
360 struct ast_state_cb *statecbs = NULL;
362 int pbx_exec(struct ast_channel *c, /* Channel */
364 void *data, /* Data for execution */
365 int newstack) /* Force stack increment */
367 /* This function is special. It saves the stack so that no matter
368 how many times it is called, it returns to the same place */
370 int stack = c->stack;
371 int (*execute)(struct ast_channel *chan, void *data) = app->execute;
372 if (newstack && stack > AST_CHANNEL_MAX_STACK - 2) {
373 /* Don't allow us to go over the max number of stacks we
375 ast_log(LOG_WARNING, "Stack overflow, cannot create another stack\n");
378 if (newstack && (res = setjmp(c->jmp[++c->stack]))) {
379 /* Okay, here's where it gets weird. If newstack is non-zero,
380 then we increase the stack increment, but setjmp is not going
381 to return until longjmp is called -- when the application
382 exec'd is finished running. */
385 if (c->stack != stack + 1)
386 ast_log(LOG_WARNING, "Stack returned to an unexpected place!\n");
387 else if (c->app[c->stack])
388 ast_log(LOG_WARNING, "Application may have forgotten to free its memory\n");
393 ast_cdr_setapp(c->cdr, app->name, data);
396 res = execute(c, data);
399 /* Any application that returns, we longjmp back, just in case. */
400 if (c->stack != stack + 1)
401 ast_log(LOG_WARNING, "Stack is not at expected value\n");
402 longjmp(c->jmp[stack+1], res);
408 /* Go no deeper than this through includes (not counting loops) */
409 #define AST_PBX_MAX_STACK 64
411 #define HELPER_EXISTS 0
412 #define HELPER_SPAWN 1
413 #define HELPER_EXEC 2
414 #define HELPER_CANMATCH 3
415 #define HELPER_MATCHMORE 4
417 struct ast_app *pbx_findapp(char *app)
420 if (ast_mutex_lock(&applock)) {
421 ast_log(LOG_WARNING, "Unable to obtain application lock\n");
426 if (!strcasecmp(tmp->name, app))
430 ast_mutex_unlock(&applock);
434 static struct ast_switch *pbx_findswitch(char *sw)
436 struct ast_switch *asw;
437 if (ast_mutex_lock(&switchlock)) {
438 ast_log(LOG_WARNING, "Unable to obtain application lock\n");
443 if (!strcasecmp(asw->name, sw))
447 ast_mutex_unlock(&switchlock);
451 static inline int include_valid(struct ast_include *i)
460 /* If it's not the right month, return */
461 if (!(i->monthmask & (1 << tm.tm_mon))) {
465 /* If it's not that time of the month.... */
466 /* Warning, tm_mday has range 1..31! */
467 if (!(i->daymask & (1 << (tm.tm_mday-1))))
470 /* If it's not the right day of the week */
471 if (!(i->dowmask & (1 << tm.tm_wday)))
474 /* Sanity check the hour just to be safe */
475 if ((tm.tm_hour < 0) || (tm.tm_hour > 23)) {
476 ast_log(LOG_WARNING, "Insane time...\n");
480 /* Now the tough part, we calculate if it fits
481 in the right time based on min/hour */
482 if (!(i->minmask[tm.tm_hour] & (1 << (tm.tm_min / 2))))
485 /* If we got this far, then we're good */
489 static void pbx_destroy(struct ast_pbx *p)
494 #define EXTENSION_MATCH_CORE(data,pattern,match) {\
495 /* All patterns begin with _ */\
496 if (pattern[0] != '_') \
498 /* Start optimistic */\
501 while(match && *data && *pattern && (*pattern != '/')) {\
502 switch(toupper(*pattern)) {\
509 where=strchr(pattern,']');\
511 border=(int)(where-pattern);\
512 if (!where || border > strlen(pattern)) {\
513 ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");\
516 for (i=0; i<border; i++) {\
519 if (pattern[i+1]=='-') {\
520 if (*data >= pattern[i] && *data <= pattern[i+2]) {\
527 if (res==1 || *data==pattern[i]) {\
536 if ((*data < '2') || (*data > '9'))\
540 if ((*data < '0') || (*data > '9'))\
544 if ((*data < '1') || (*data > '9'))\
552 /* Ignore these characters */\
556 if (*data != *pattern)\
564 int ast_extension_match(char *pattern, char *data)
567 /* If they're the same return */
568 if (!strcmp(pattern, data))
570 EXTENSION_MATCH_CORE(data,pattern,match);
571 /* Must be at the end of both */
572 if (*data || (*pattern && (*pattern != '/')))
577 static int extension_close(char *pattern, char *data, int needmore)
580 /* If "data" is longer, it can'be a subset of pattern unless
581 pattern is a pattern match */
582 if ((strlen(pattern) < strlen(data)) && (pattern[0] != '_'))
585 if ((!strlen((char *)data) || !strncasecmp(pattern, data, strlen(data))) &&
586 (!needmore || (strlen(pattern) > strlen(data)))) {
589 EXTENSION_MATCH_CORE(data,pattern,match);
590 /* If there's more or we don't care about more, return non-zero, otlherwise it's a miss */
591 if (!needmore || *pattern) {
597 struct ast_context *ast_context_find(char *name)
599 struct ast_context *tmp;
600 ast_mutex_lock(&conlock);
604 if (!strcasecmp(name, tmp->name))
610 ast_mutex_unlock(&conlock);
614 #define STATUS_NO_CONTEXT 1
615 #define STATUS_NO_EXTENSION 2
616 #define STATUS_NO_PRIORITY 3
617 #define STATUS_SUCCESS 4
619 static int matchcid(char *cidpattern, char *callerid)
621 char tmp[AST_MAX_EXTENSION];
625 /* If the Caller*ID pattern is empty, then we're matching NO Caller*ID, so
626 failing to get a number should count as a match, otherwise not */
629 if (strlen(cidpattern))
637 /* Copy original Caller*ID */
638 strncpy(tmp, callerid, sizeof(tmp)-1);
640 if (ast_callerid_parse(tmp, &name, &num))
644 ast_shrink_phone_number(num);
645 return ast_extension_match(cidpattern, num);
648 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)
651 struct ast_context *tmp;
652 struct ast_exten *e, *eroot;
653 struct ast_include *i;
655 struct ast_switch *asw;
656 /* Initialize status if appropriate */
658 *status = STATUS_NO_CONTEXT;
662 /* Check for stack overflow */
663 if (*stacklen >= AST_PBX_MAX_STACK) {
664 ast_log(LOG_WARNING, "Maximum PBX stack exceeded\n");
667 /* Check first to see if we've already been checked */
668 for (x=0;x<*stacklen;x++) {
669 if (!strcasecmp(incstack[x], context))
675 if (!strcmp(tmp->name, context)) {
676 if (*status < STATUS_NO_EXTENSION)
677 *status = STATUS_NO_EXTENSION;
680 /* Match extension */
681 if ((((action != HELPER_MATCHMORE) && ast_extension_match(eroot->exten, exten)) ||
682 ((action == HELPER_CANMATCH) && (extension_close(eroot->exten, exten, 0))) ||
683 ((action == HELPER_MATCHMORE) && (extension_close(eroot->exten, exten, 1)))) &&
684 (!eroot->matchcid || matchcid(eroot->cidmatch, callerid))) {
686 if (*status < STATUS_NO_PRIORITY)
687 *status = STATUS_NO_PRIORITY;
690 if (e->priority == priority) {
691 *status = STATUS_SUCCESS;
699 /* Check alternative switches */
702 if ((asw = pbx_findswitch(sw->name))) {
703 if (action == HELPER_CANMATCH)
704 res = asw->canmatch ? asw->canmatch(chan, context, exten, priority, callerid, sw->data) : 0;
705 else if (action == HELPER_MATCHMORE)
706 res = asw->matchmore ? asw->matchmore(chan, context, exten, priority, callerid, sw->data) : 0;
708 res = asw->exists ? asw->exists(chan, context, exten, priority, callerid, sw->data) : 0;
716 ast_log(LOG_WARNING, "No such switch '%s'\n", sw->name);
720 /* Setup the stack */
721 incstack[*stacklen] = tmp->name;
723 /* Now try any includes we have in this context */
726 if (include_valid(i)) {
727 if ((e = pbx_find_extension(chan, i->rname, exten, priority, callerid, action, incstack, stacklen, status, swo, data)))
740 static void pbx_substitute_variables_temp(struct ast_channel *c,const char *var,char **ret, char *workspace, int workspacelen)
743 char tmpvar[80] = "";
745 struct tm brokentime;
747 struct ast_var_t *variables;
748 char *name, *num; /* for callerid name + num variables */
749 struct varshead *headp=NULL;
753 /* Now we have the variable name on cp3 */
754 if ((first=strchr(var,':'))) {
755 strncpy(tmpvar, var, sizeof(tmpvar) - 1);
756 first = strchr(tmpvar, ':');
758 first = tmpvar + strlen(tmpvar);
760 pbx_substitute_variables_temp(c,tmpvar,ret,workspace,workspacelen - 1);
762 offset=atoi(first+1);
763 if ((second=strchr(first+1,':'))) {
765 offset2=atoi(second+1);
767 offset2=strlen(*ret)-offset;
768 if (abs(offset)>strlen(*ret)) {
772 offset=-strlen(*ret);
774 if ((offset<0 && offset2>-offset) || (offset>=0 && offset+offset2>strlen(*ret))) {
776 offset2=strlen(*ret)-offset;
778 offset2=strlen(*ret)+offset;
783 *ret+=strlen(*ret)+offset;
784 (*ret)[offset2] = '\0';
785 } else if (c && !strcmp(var, "CALLERIDNUM")) {
787 strncpy(workspace, c->callerid, workspacelen - 1);
788 ast_callerid_parse(workspace, &name, &num);
790 ast_shrink_phone_number(num);
794 } else if (c && !strcmp(var, "CALLERIDNAME")) {
796 strncpy(workspace, c->callerid, workspacelen - 1);
797 ast_callerid_parse(workspace, &name, &num);
802 } else if (c && !strcmp(var, "CALLERID")) {
804 strncpy(workspace, c->callerid, workspacelen - 1);
808 } else if (c && !strcmp(var, "DNID")) {
810 strncpy(workspace, c->dnid, workspacelen - 1);
814 } else if (c && !strcmp(var, "HINT")) {
815 if (!ast_get_hint(workspace, workspacelen - 1, c, c->context, c->exten))
819 } else if (c && !strcmp(var, "EXTEN")) {
820 strncpy(workspace, c->exten, workspacelen - 1);
822 } else if (c && !strncmp(var, "EXTEN-", strlen("EXTEN-")) &&
823 /* XXX Remove me eventually */
824 (sscanf(var + strlen("EXTEN-"), "%d", &offset) == 1)) {
827 if (offset > strlen(c->exten))
828 offset = strlen(c->exten);
829 strncpy(workspace, c->exten + offset, workspacelen - 1);
831 ast_log(LOG_WARNING, "The use of 'EXTEN-foo' has been deprecated in favor of 'EXTEN:foo'\n");
832 } else if (c && !strcmp(var, "RDNIS")) {
834 strncpy(workspace, c->rdnis, workspacelen - 1);
838 } else if (c && !strcmp(var, "CONTEXT")) {
839 strncpy(workspace, c->context, workspacelen - 1);
841 } else if (c && !strcmp(var, "PRIORITY")) {
842 snprintf(workspace, workspacelen, "%d", c->priority);
844 } else if (c && !strcmp(var, "CHANNEL")) {
845 strncpy(workspace, c->name, workspacelen - 1);
847 } else if (c && !strcmp(var, "EPOCH")) {
848 snprintf(workspace, workspacelen -1, "%u",(int)time(NULL));
850 } else if (c && !strcmp(var, "DATETIME")) {
852 localtime_r(&thistime, &brokentime);
853 snprintf(workspace, workspacelen -1, "%02d%02d%04d-%02d:%02d:%02d",
856 brokentime.tm_year+1900,
862 } else if (c && !strcmp(var, "TIMESTAMP")) {
864 localtime_r(&thistime, &brokentime);
865 /* 20031130-150612 */
866 snprintf(workspace, workspacelen -1, "%04d%02d%02d-%02d%02d%02d",
867 brokentime.tm_year+1900,
875 } else if (c && !strcmp(var, "UNIQUEID")) {
876 snprintf(workspace, workspacelen -1, "%s", c->uniqueid);
878 } else if (c && !strcmp(var, "HANGUPCAUSE")) {
879 snprintf(workspace, workspacelen -1, "%i", c->hangupcause);
881 } else if (c && !strcmp(var, "ACCOUNTCODE")) {
882 strncpy(workspace, c->accountcode, workspacelen - 1);
884 } else if (c && !strcmp(var, "LANGUAGE")) {
885 strncpy(workspace, c->language, workspacelen - 1);
889 AST_LIST_TRAVERSE(headp,variables,entries) {
891 ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",var,ast_var_name(variables));
893 if (strcasecmp(ast_var_name(variables),var)==0) {
894 *ret=ast_var_value(variables);
896 strncpy(workspace, *ret, workspacelen - 1);
905 AST_LIST_TRAVERSE(&globals,variables,entries) {
907 ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",var,ast_var_name(variables));
909 if (strcasecmp(ast_var_name(variables),var)==0) {
910 *ret=ast_var_value(variables);
912 strncpy(workspace, *ret, workspacelen - 1);
920 int len_env=strlen("ENV(");
921 if (len > (len_env+1) && !strncasecmp(var,"ENV(",len_env) && !strcmp(var+len-1,")")) {
923 strncpy(cp3, var, sizeof(cp3) - 1);
925 *ret=getenv(cp3+len_env);
927 strncpy(workspace, *ret, workspacelen - 1);
932 if (!(*ret) && !strncasecmp(var,"LEN(",4)) {
935 if (len > (len_len+1) && !strncasecmp(var,"LEN(",len_len) && strchr(var+len_len+2,')')) {
937 strncpy(cp3, var, sizeof(cp3) - 1);
938 cp3[len-len_len-1]='\0';
939 sprintf(workspace,"%d",strlen(cp3));
941 } else ast_log(LOG_NOTICE, "Wrong use of LEN(VARIABLE)\n");
946 void pbx_substitute_variables_helper(struct ast_channel *c,const char *cp1,char *cp2,int count)
949 const char *tmp, *whereweare;
952 char ltmp[256], var[256];
953 char *nextvar, *nextexp;
955 int pos, brackets, needsub, len;
957 /* Substitutes variables into cp2, based on string cp1, and assuming cp2 to be
960 while(strlen(whereweare) && count) {
961 /* Assume we're copying the whole remaining string */
962 pos = strlen(whereweare);
964 /* Look for a variable */
965 nextvar = strstr(whereweare, "${");
967 nextexp = strstr(whereweare, "$[");
969 if (nextvar && nextexp) {
970 if (nextvar < nextexp)
976 /* If there is one, we only go that far */
978 pos = nextvar - whereweare;
980 pos = nextexp - whereweare;
982 /* Can't copy more than 'count' bytes */
986 /* Copy that many bytes */
987 memcpy(cp2, whereweare, pos);
994 /* We have a variable. Find the start and end, and determine
995 if we are going to have to recursively call ourselves on the
997 vars = vare = nextvar + 2;
1001 /* Find the end of it */
1002 while(brackets && *vare) {
1003 if ((vare[0] == '$') && (vare[1] == '{')) {
1006 } else if (vare[0] == '}') {
1008 } else if ((vare[0] == '$') && (vare[1] == '['))
1013 ast_log(LOG_NOTICE, "Error in extension logic (missing '}')\n");
1014 len = vare - vars - 1;
1016 /* Skip totally over variable name */
1017 whereweare += ( len + 3);
1019 /* Store variable name (and truncate) */
1020 memset(var, 0, sizeof(var));
1021 strncpy(var, vars, sizeof(var) - 1);
1024 /* Substitute if necessary */
1026 memset(ltmp, 0, sizeof(ltmp));
1027 pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1);
1033 /* Retrieve variable value */
1034 strcpy(workspace, "");
1035 pbx_substitute_variables_temp(c,vars,&cp4, workspace, sizeof(workspace));
1037 length = strlen(cp4);
1040 memcpy(cp2, cp4, length);
1045 } else if (nextexp) {
1046 /* We have an expression. Find the start and end, and determine
1047 if we are going to have to recursively call ourselves on the
1049 vars = vare = nextexp + 2;
1053 /* Find the end of it */
1054 while(brackets && *vare) {
1055 if ((vare[0] == '$') && (vare[1] == '[')) {
1058 } else if (vare[0] == ']') {
1060 } else if ((vare[0] == '$') && (vare[1] == '{'))
1065 ast_log(LOG_NOTICE, "Error in extension logic (missing ']')\n");
1066 len = vare - vars - 1;
1068 /* Skip totally over variable name */
1069 whereweare += ( len + 3);
1071 /* Store variable name (and truncate) */
1072 memset(var, 0, sizeof(var));
1073 strncpy(var, vars, sizeof(var) - 1);
1076 /* Substitute if necessary */
1078 memset(ltmp, 0, sizeof(ltmp));
1079 pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1);
1085 /* Evaluate expression */
1086 cp4 = ast_expr(vars);
1088 ast_log(LOG_DEBUG, "Expression is '%s'\n", cp4);
1091 length = strlen(cp4);
1094 memcpy(cp2, cp4, length);
1105 static void pbx_substitute_variables(char *passdata, int datalen, struct ast_channel *c, struct ast_exten *e) {
1107 memset(passdata, 0, datalen);
1109 /* No variables or expressions in e->data, so why scan it? */
1110 if (!strstr(e->data,"${") && !strstr(e->data,"$[")) {
1111 strncpy(passdata, e->data, datalen - 1);
1112 passdata[datalen-1] = '\0';
1116 pbx_substitute_variables_helper(c,e->data,passdata, datalen - 1);
1119 static int pbx_extension_helper(struct ast_channel *c, char *context, char *exten, int priority, char *callerid, int action)
1121 struct ast_exten *e;
1122 struct ast_app *app;
1123 struct ast_switch *sw;
1128 char *incstack[AST_PBX_MAX_STACK];
1134 if (ast_mutex_lock(&conlock)) {
1135 ast_log(LOG_WARNING, "Unable to obtain lock\n");
1136 if ((action == HELPER_EXISTS) || (action == HELPER_CANMATCH) || (action == HELPER_MATCHMORE))
1141 e = pbx_find_extension(c, context, exten, priority, callerid, action, incstack, &stacklen, &status, &sw, &data);
1144 case HELPER_CANMATCH:
1145 ast_mutex_unlock(&conlock);
1148 ast_mutex_unlock(&conlock);
1150 case HELPER_MATCHMORE:
1151 ast_mutex_unlock(&conlock);
1157 app = pbx_findapp(e->app);
1158 ast_mutex_unlock(&conlock);
1160 if (c->context != context)
1161 strncpy(c->context, context, sizeof(c->context)-1);
1162 if (c->exten != exten)
1163 strncpy(c->exten, exten, sizeof(c->exten)-1);
1164 c->priority = priority;
1165 pbx_substitute_variables(passdata, sizeof(passdata), c, e);
1167 ast_log(LOG_DEBUG, "Launching '%s'\n", app->name);
1168 else if (option_verbose > 2)
1169 ast_verbose( VERBOSE_PREFIX_3 "Executing %s(\"%s\", \"%s\") %s\n",
1170 term_color(tmp, app->name, COLOR_BRCYAN, 0, sizeof(tmp)),
1171 term_color(tmp2, c->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
1172 term_color(tmp3, (strlen(passdata) ? (char *)passdata : ""), COLOR_BRMAGENTA, 0, sizeof(tmp3)),
1173 (newstack ? "in new stack" : "in same stack"));
1174 res = pbx_exec(c, app, passdata, newstack);
1177 ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
1181 ast_log(LOG_WARNING, "Huh (%d)?\n", action); return -1;
1185 case HELPER_CANMATCH:
1186 ast_mutex_unlock(&conlock);
1189 ast_mutex_unlock(&conlock);
1191 case HELPER_MATCHMORE:
1192 ast_mutex_unlock(&conlock);
1198 ast_mutex_unlock(&conlock);
1200 res = sw->exec(c, context, exten, priority, callerid, newstack, data);
1202 ast_log(LOG_WARNING, "No execution engine for switch %s\n", sw->name);
1207 ast_log(LOG_WARNING, "Huh (%d)?\n", action);
1211 ast_mutex_unlock(&conlock);
1213 case STATUS_NO_CONTEXT:
1214 if ((action != HELPER_EXISTS) && (action != HELPER_MATCHMORE))
1215 ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", context);
1217 case STATUS_NO_EXTENSION:
1218 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1219 ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, context);
1221 case STATUS_NO_PRIORITY:
1222 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1223 ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, context);
1226 ast_log(LOG_DEBUG, "Shouldn't happen!\n");
1228 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1236 static struct ast_exten *ast_hint_extension(struct ast_channel *c, char *context, char *exten)
1238 struct ast_exten *e;
1239 struct ast_switch *sw;
1242 char *incstack[AST_PBX_MAX_STACK];
1245 if (ast_mutex_lock(&conlock)) {
1246 ast_log(LOG_WARNING, "Unable to obtain lock\n");
1249 e = pbx_find_extension(c, context, exten, PRIORITY_HINT, "", HELPER_EXISTS, incstack, &stacklen, &status, &sw, &data);
1250 ast_mutex_unlock(&conlock);
1254 static int ast_extension_state2(struct ast_exten *e)
1256 char hint[AST_MAX_EXTENSION] = "";
1259 int allunavailable = 1, allbusy = 1, allfree = 1;
1262 strncpy(hint, ast_get_extension_app(e), sizeof(hint)-1);
1266 rest = strchr(cur, '&');
1272 res = ast_device_state(cur);
1274 case AST_DEVICE_NOT_INUSE:
1278 case AST_DEVICE_INUSE:
1279 return AST_EXTENSION_INUSE;
1280 case AST_DEVICE_BUSY:
1285 case AST_DEVICE_UNAVAILABLE:
1286 case AST_DEVICE_INVALID:
1299 return AST_EXTENSION_NOT_INUSE;
1301 return AST_EXTENSION_BUSY;
1303 return AST_EXTENSION_UNAVAILABLE;
1305 return AST_EXTENSION_INUSE;
1307 return AST_EXTENSION_NOT_INUSE;
1311 int ast_extension_state(struct ast_channel *c, char *context, char *exten)
1313 struct ast_exten *e;
1315 e = ast_hint_extension(c, context, exten);
1319 return ast_extension_state2(e);
1322 int ast_device_state_changed(const char *fmt, ...)
1324 struct ast_hint *list;
1325 struct ast_state_cb *cblist;
1326 char hint[AST_MAX_EXTENSION];
1327 char device[AST_MAX_EXTENSION];
1334 vsnprintf(device, sizeof(device)-1, fmt, ap);
1337 rest = strchr(device, '-');
1342 ast_mutex_lock(&hintlock);
1348 strcpy(hint, ast_get_extension_app(list->exten));
1351 rest = strchr(cur, '&');
1357 if (!strcmp(cur, device)) {
1358 // Found extension execute callbacks
1359 state = ast_extension_state2(list->exten);
1360 if ((state != -1) && (state != list->laststate)) {
1361 // For general callbacks
1364 cblist->callback(list->exten->parent->name, list->exten->exten, state, cblist->data);
1365 cblist = cblist->next;
1368 // For extension callbacks
1369 cblist = list->callbacks;
1371 cblist->callback(list->exten->parent->name, list->exten->exten, state, cblist->data);
1372 cblist = cblist->next;
1375 list->laststate = state;
1385 ast_mutex_unlock(&hintlock);
1389 int ast_extension_state_add(char *context, char *exten,
1390 ast_state_cb_type callback, void *data)
1392 struct ast_hint *list;
1393 struct ast_state_cb *cblist;
1394 struct ast_exten *e;
1396 /* No context and extension add callback to statecbs list */
1397 if (!context && !exten) {
1398 ast_mutex_lock(&hintlock);
1402 if (cblist->callback == callback) {
1403 cblist->data = data;
1404 ast_mutex_unlock(&hintlock);
1407 cblist = cblist->next;
1410 /* Now inserts the callback */
1411 cblist = malloc(sizeof(struct ast_state_cb));
1413 ast_mutex_unlock(&hintlock);
1416 memset(cblist, 0, sizeof(struct ast_state_cb));
1418 cblist->callback = callback;
1419 cblist->data = data;
1421 cblist->next = statecbs;
1424 ast_mutex_unlock(&hintlock);
1428 if (!context || !exten)
1431 /* This callback type is for only one hint */
1432 e = ast_hint_extension(NULL, context, exten);
1437 ast_mutex_lock(&hintlock);
1441 if (list->exten == e)
1447 ast_mutex_unlock(&hintlock);
1451 /* Now inserts the callback */
1452 cblist = malloc(sizeof(struct ast_state_cb));
1454 ast_mutex_unlock(&hintlock);
1457 memset(cblist, 0, sizeof(struct ast_state_cb));
1458 cblist->id = stateid++;
1459 cblist->callback = callback;
1460 cblist->data = data;
1462 cblist->next = list->callbacks;
1463 list->callbacks = cblist;
1465 ast_mutex_unlock(&hintlock);
1469 int ast_extension_state_del(int id, ast_state_cb_type callback)
1471 struct ast_hint *list;
1472 struct ast_state_cb *cblist, *cbprev;
1474 if (!id && !callback)
1477 ast_mutex_lock(&hintlock);
1479 /* id is zero is a callback without extension */
1484 if (cblist->callback == callback) {
1486 statecbs = cblist->next;
1488 cbprev->next = cblist->next;
1492 ast_mutex_unlock(&hintlock);
1496 cblist = cblist->next;
1499 ast_mutex_lock(&hintlock);
1503 /* id greater zero is a callback with extension */
1506 cblist = list->callbacks;
1509 if (cblist->id==id) {
1511 list->callbacks = cblist->next;
1513 cbprev->next = cblist->next;
1517 ast_mutex_unlock(&hintlock);
1521 cblist = cblist->next;
1526 ast_mutex_unlock(&hintlock);
1530 static int ast_add_hint(struct ast_exten *e)
1532 struct ast_hint *list;
1536 ast_mutex_lock(&hintlock);
1539 /* Search if hint exists, do nothing */
1541 if (list->exten == e) {
1542 ast_mutex_unlock(&hintlock);
1548 list = malloc(sizeof(struct ast_hint));
1550 ast_mutex_unlock(&hintlock);
1553 /* Initialize and insert new item */
1554 memset(list, 0, sizeof(struct ast_hint));
1556 list->laststate = ast_extension_state2(e);
1560 ast_mutex_unlock(&hintlock);
1564 static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
1566 struct ast_hint *list;
1568 ast_mutex_lock(&hintlock);
1573 if (list->exten == oe) {
1575 ast_mutex_unlock(&hintlock);
1580 ast_mutex_unlock(&hintlock);
1585 static int ast_remove_hint(struct ast_exten *e)
1587 /* Cleanup the Notifys if hint is removed */
1588 struct ast_hint *list, *prev = NULL;
1589 struct ast_state_cb *cblist, *cbprev;
1594 ast_mutex_lock(&hintlock);
1598 if (list->exten==e) {
1600 cblist = list->callbacks;
1602 /* Notify with -1 and remove all callbacks */
1604 cblist = cblist->next;
1605 cbprev->callback(list->exten->parent->name, list->exten->exten, -1, cbprev->data);
1608 list->callbacks = NULL;
1613 prev->next = list->next;
1617 ast_mutex_unlock(&hintlock);
1625 ast_mutex_unlock(&hintlock);
1630 int ast_get_hint(char *hint, int maxlen, struct ast_channel *c, char *context, char *exten)
1632 struct ast_exten *e;
1633 e = ast_hint_extension(c, context, exten);
1635 strncpy(hint, ast_get_extension_app(e), maxlen);
1641 int ast_exists_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid)
1643 return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_EXISTS);
1646 int ast_canmatch_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid)
1648 return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_CANMATCH);
1651 int ast_matchmore_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid)
1653 return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_MATCHMORE);
1656 int ast_spawn_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid)
1658 return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_SPAWN);
1661 int ast_pbx_run(struct ast_channel *c)
1670 /* A little initial setup here */
1672 ast_log(LOG_WARNING, "%s already has PBX structure??\n", c->name);
1673 c->pbx = malloc(sizeof(struct ast_pbx));
1675 ast_log(LOG_ERROR, "Out of memory\n");
1680 ast_log(LOG_WARNING, "%s already has a call record??\n", c->name);
1682 c->cdr = ast_cdr_alloc();
1684 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
1688 ast_cdr_init(c->cdr, c);
1691 memset(c->pbx, 0, sizeof(struct ast_pbx));
1692 /* Set reasonable defaults */
1693 c->pbx->rtimeout = 10;
1694 c->pbx->dtimeout = 5;
1696 /* Start by trying whatever the channel is set to */
1697 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
1698 /* JK02: If not successfull fall back to 's' */
1699 strncpy(c->exten, "s", sizeof(c->exten)-1);
1700 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
1701 /* JK02: And finally back to default if everything else failed */
1702 strncpy(c->context, "default", sizeof(c->context)-1);
1707 ast_cdr_start(c->cdr);
1711 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
1712 memset(exten, 0, sizeof(exten));
1713 manager_event(EVENT_FLAG_CALL, "Newexten",
1719 c->name, c->context, c->exten, c->priority, c->uniqueid);
1720 if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->callerid))) {
1721 /* Something bad happened, or a hangup has been requested. */
1722 if (((res >= '0') && (res <= '9')) || ((res >= 'A') && (res <= 'F')) ||
1723 (res == '*') || (res == '#')) {
1724 ast_log(LOG_DEBUG, "Oooh, got something to jump out with ('%c')!\n", res);
1725 memset(exten, 0, sizeof(exten));
1727 exten[pos++] = digit = res;
1731 case AST_PBX_KEEPALIVE:
1733 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
1734 else if (option_verbose > 1)
1735 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
1740 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
1741 else if (option_verbose > 1)
1742 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
1743 if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
1748 if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
1758 if ((c->_softhangup == AST_SOFTHANGUP_TIMEOUT) && (ast_exists_extension(c,c->context,"T",1,c->callerid))) {
1759 strncpy(c->exten,"T",sizeof(c->exten) - 1);
1760 /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
1761 c->whentohangup = 0;
1763 c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
1764 } else if (c->_softhangup) {
1765 ast_log(LOG_DEBUG, "Extension %s, priority %d returned normally even though call was hung up\n",
1766 c->exten, c->priority);
1772 if (!ast_exists_extension(c, c->context, c->exten, 1, c->callerid)) {
1773 /* It's not a valid extension anymore */
1774 if (ast_exists_extension(c, c->context, "i", 1, c->callerid)) {
1775 if (option_verbose > 2)
1776 ast_verbose(VERBOSE_PREFIX_3 "Sent into invalid extension '%s' in context '%s' on %s\n", c->exten, c->context, c->name);
1777 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", c->exten);
1778 strncpy(c->exten, "i", sizeof(c->exten)-1);
1781 ast_log(LOG_WARNING, "Channel '%s' sent into invalid extension '%s' in context '%s', but no invalid handler\n",
1782 c->name, c->exten, c->context);
1785 } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
1786 /* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */
1789 /* Done, wait for an extension */
1791 waittime = c->pbx->dtimeout;
1793 waittime = c->pbx->rtimeout;
1794 while (ast_matchmore_extension(c, c->context, exten, 1, c->callerid)) {
1795 /* As long as we're willing to wait, and as long as it's not defined,
1796 keep reading digits until we can't possibly get a right answer anymore. */
1797 digit = ast_waitfordigit(c, waittime * 1000);
1798 if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
1805 /* Error, maybe a hangup */
1807 exten[pos++] = digit;
1808 waittime = c->pbx->dtimeout;
1811 if (ast_exists_extension(c, c->context, exten, 1, c->callerid)) {
1812 /* Prepare the next cycle */
1813 strncpy(c->exten, exten, sizeof(c->exten)-1);
1816 /* No such extension */
1817 if (strlen(exten)) {
1818 /* An invalid extension */
1819 if (ast_exists_extension(c, c->context, "i", 1, c->callerid)) {
1820 if (option_verbose > 2)
1821 ast_verbose( VERBOSE_PREFIX_3 "Invalid extension '%s' in context '%s' on %s\n", exten, c->context, c->name);
1822 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", exten);
1823 strncpy(c->exten, "i", sizeof(c->exten)-1);
1826 ast_log(LOG_WARNING, "Invalid extension, but no rule 'i' in context '%s'\n", c->context);
1830 /* A simple timeout */
1831 if (ast_exists_extension(c, c->context, "t", 1, c->callerid)) {
1832 if (option_verbose > 2)
1833 ast_verbose( VERBOSE_PREFIX_3 "Timeout on %s\n", c->name);
1834 strncpy(c->exten, "t", sizeof(c->exten)-1);
1837 ast_log(LOG_WARNING, "Timeout, but no rule 't' in context '%s'\n", c->context);
1843 if (option_verbose > 2)
1844 ast_verbose(VERBOSE_PREFIX_2 "CDR updated on %s\n",c->name);
1850 ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", c->name);
1852 if ((res != AST_PBX_KEEPALIVE) && ast_exists_extension(c, c->context, "h", 1, c->callerid)) {
1853 strcpy(c->exten, "h");
1855 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
1856 if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->callerid))) {
1857 /* Something bad happened, or a hangup has been requested. */
1859 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
1860 else if (option_verbose > 1)
1861 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
1868 pbx_destroy(c->pbx);
1870 if (res != AST_PBX_KEEPALIVE)
1875 static void *pbx_thread(void *data)
1877 /* Oh joyeous kernel, we're a new thread, with nothing to do but
1878 answer this channel and get it going. The setjmp stuff is fairly
1879 confusing, but necessary to get smooth transitions between
1880 the execution of different applications (without the use of
1881 additional threads) */
1882 struct ast_channel *c = data;
1888 int ast_pbx_start(struct ast_channel *c)
1891 pthread_attr_t attr;
1893 ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
1897 /* Start a new thread, and get something handling this channel. */
1898 pthread_attr_init(&attr);
1899 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1900 if (pthread_create(&t, &attr, pbx_thread, c)) {
1901 ast_log(LOG_WARNING, "Failed to create new channel thread\n");
1908 * This function locks contexts list by &conlist, search for the rigt context
1909 * structure, leave context list locked and call ast_context_remove_include2
1910 * which removes include, unlock contexts list and return ...
1912 int ast_context_remove_include(char *context, char *include, char *registrar)
1914 struct ast_context *c;
1916 if (ast_lock_contexts()) return -1;
1918 /* walk contexts and search for the right one ...*/
1919 c = ast_walk_contexts(NULL);
1921 /* we found one ... */
1922 if (!strcmp(ast_get_context_name(c), context)) {
1924 /* remove include from this context ... */
1925 ret = ast_context_remove_include2(c, include, registrar);
1927 ast_unlock_contexts();
1929 /* ... return results */
1932 c = ast_walk_contexts(c);
1935 /* we can't find the right one context */
1936 ast_unlock_contexts();
1941 * When we call this function, &conlock lock must be locked, because when
1942 * we giving *con argument, some process can remove/change this context
1943 * and after that there can be segfault.
1945 * This function locks given context, removes include, unlock context and
1948 int ast_context_remove_include2(struct ast_context *con, char *include, char *registrar)
1950 struct ast_include *i, *pi = NULL;
1952 if (ast_mutex_lock(&con->lock)) return -1;
1957 /* find our include */
1958 if (!strcmp(i->name, include) &&
1959 (!strcmp(i->registrar, registrar) || !registrar)) {
1960 /* remove from list */
1964 con->includes = i->next;
1965 /* free include and return */
1967 ast_mutex_unlock(&con->lock);
1974 /* we can't find the right include */
1975 ast_mutex_unlock(&con->lock);
1980 * This function locks contexts list by &conlist, search for the rigt context
1981 * structure, leave context list locked and call ast_context_remove_switch2
1982 * which removes switch, unlock contexts list and return ...
1984 int ast_context_remove_switch(char *context, char *sw, char *data, char *registrar)
1986 struct ast_context *c;
1988 if (ast_lock_contexts()) return -1;
1990 /* walk contexts and search for the right one ...*/
1991 c = ast_walk_contexts(NULL);
1993 /* we found one ... */
1994 if (!strcmp(ast_get_context_name(c), context)) {
1996 /* remove switch from this context ... */
1997 ret = ast_context_remove_switch2(c, sw, data, registrar);
1999 ast_unlock_contexts();
2001 /* ... return results */
2004 c = ast_walk_contexts(c);
2007 /* we can't find the right one context */
2008 ast_unlock_contexts();
2013 * When we call this function, &conlock lock must be locked, because when
2014 * we giving *con argument, some process can remove/change this context
2015 * and after that there can be segfault.
2017 * This function locks given context, removes switch, unlock context and
2020 int ast_context_remove_switch2(struct ast_context *con, char *sw, char *data, char *registrar)
2022 struct ast_sw *i, *pi = NULL;
2024 if (ast_mutex_lock(&con->lock)) return -1;
2029 /* find our switch */
2030 if (!strcmp(i->name, sw) && !strcmp(i->data, data) &&
2031 (!strcmp(i->registrar, registrar) || !registrar)) {
2032 /* remove from list */
2036 con->alts = i->next;
2037 /* free switch and return */
2039 ast_mutex_unlock(&con->lock);
2046 /* we can't find the right switch */
2047 ast_mutex_unlock(&con->lock);
2052 * This functions lock contexts list, search for the right context,
2053 * call ast_context_remove_extension2, unlock contexts list and return.
2054 * In this function we are using
2056 int ast_context_remove_extension(char *context, char *extension, int priority, char *registrar)
2058 struct ast_context *c;
2060 if (ast_lock_contexts()) return -1;
2062 /* walk contexts ... */
2063 c = ast_walk_contexts(NULL);
2065 /* ... search for the right one ... */
2066 if (!strcmp(ast_get_context_name(c), context)) {
2067 /* ... remove extension ... */
2068 int ret = ast_context_remove_extension2(c, extension, priority,
2070 /* ... unlock contexts list and return */
2071 ast_unlock_contexts();
2074 c = ast_walk_contexts(c);
2077 /* we can't find the right context */
2078 ast_unlock_contexts();
2083 * When do you want to call this function, make sure that &conlock is locked,
2084 * because some process can handle with your *con context before you lock
2087 * This functionc locks given context, search for the right extension and
2088 * fires out all peer in this extensions with given priority. If priority
2089 * is set to 0, all peers are removed. After that, unlock context and
2092 int ast_context_remove_extension2(struct ast_context *con, char *extension, int priority, char *registrar)
2094 struct ast_exten *exten, *prev_exten = NULL;
2096 if (ast_mutex_lock(&con->lock)) return -1;
2098 /* go through all extensions in context and search the right one ... */
2102 /* look for right extension */
2103 if (!strcmp(exten->exten, extension) &&
2104 (!strcmp(exten->registrar, registrar) || !registrar)) {
2105 struct ast_exten *peer;
2107 /* should we free all peers in this extension? (priority == 0)? */
2108 if (priority == 0) {
2109 /* remove this extension from context list */
2111 prev_exten->next = exten->next;
2113 con->root = exten->next;
2115 /* fire out all peers */
2120 if (!peer->priority==PRIORITY_HINT)
2121 ast_remove_hint(peer);
2123 peer->datad(peer->data);
2129 ast_mutex_unlock(&con->lock);
2132 /* remove only extension with exten->priority == priority */
2133 struct ast_exten *previous_peer = NULL;
2137 /* is this our extension? */
2138 if (peer->priority == priority &&
2139 (!strcmp(peer->registrar, registrar) || !registrar)) {
2140 /* we are first priority extension? */
2141 if (!previous_peer) {
2142 /* exists previous extension here? */
2144 /* yes, so we must change next pointer in
2145 * previous connection to next peer
2148 prev_exten->next = peer->peer;
2149 peer->peer->next = exten->next;
2151 prev_exten->next = exten->next;
2153 /* no previous extension, we are first
2154 * extension, so change con->root ...
2157 con->root = peer->peer;
2159 con->root = exten->next;
2162 /* we are not first priority in extension */
2163 previous_peer->peer = peer->peer;
2166 /* now, free whole priority extension */
2167 if (peer->priority==PRIORITY_HINT)
2168 ast_remove_hint(peer);
2169 peer->datad(peer->data);
2172 ast_mutex_unlock(&con->lock);
2175 /* this is not right extension, skip to next peer */
2176 previous_peer = peer;
2181 ast_mutex_unlock(&con->lock);
2187 exten = exten->next;
2190 /* we can't find right extension */
2191 ast_mutex_unlock(&con->lock);
2196 int ast_register_application(char *app, int (*execute)(struct ast_channel *, void *), char *synopsis, char *description)
2198 struct ast_app *tmp, *prev, *cur;
2200 if (ast_mutex_lock(&applock)) {
2201 ast_log(LOG_ERROR, "Unable to lock application list\n");
2206 if (!strcasecmp(app, tmp->name)) {
2207 ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
2208 ast_mutex_unlock(&applock);
2213 tmp = malloc(sizeof(struct ast_app));
2215 memset(tmp, 0, sizeof(struct ast_app));
2216 strncpy(tmp->name, app, sizeof(tmp->name)-1);
2217 tmp->execute = execute;
2218 tmp->synopsis = synopsis;
2219 tmp->description = description;
2220 /* Store in alphabetical order */
2224 if (strcasecmp(tmp->name, cur->name) < 0)
2230 tmp->next = prev->next;
2237 ast_log(LOG_ERROR, "Out of memory\n");
2238 ast_mutex_unlock(&applock);
2241 if (option_verbose > 1)
2242 ast_verbose( VERBOSE_PREFIX_2 "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
2243 ast_mutex_unlock(&applock);
2247 int ast_register_switch(struct ast_switch *sw)
2249 struct ast_switch *tmp, *prev=NULL;
2250 if (ast_mutex_lock(&switchlock)) {
2251 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
2256 if (!strcasecmp(tmp->name, sw->name))
2262 ast_mutex_unlock(&switchlock);
2263 ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name);
2271 ast_mutex_unlock(&switchlock);
2275 void ast_unregister_switch(struct ast_switch *sw)
2277 struct ast_switch *tmp, *prev=NULL;
2278 if (ast_mutex_lock(&switchlock)) {
2279 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
2286 prev->next = tmp->next;
2288 switches = tmp->next;
2295 ast_mutex_unlock(&switchlock);
2299 * Help for CLI commands ...
2301 static char show_application_help[] =
2302 "Usage: show application <application> [<application> [<application> [...]]]\n"
2303 " Describes a particular application.\n";
2305 static char show_applications_help[] =
2306 "Usage: show applications\n"
2307 " List applications which are currently available.\n";
2309 static char show_dialplan_help[] =
2310 "Usage: show dialplan [exten@][context]\n"
2313 static char show_switches_help[] =
2314 "Usage: show switches\n"
2315 " Show registered switches\n";
2318 * IMPLEMENTATION OF CLI FUNCTIONS IS IN THE SAME ORDER AS COMMANDS HELPS
2323 * 'show application' CLI command implementation functions ...
2327 * There is a possibility to show informations about more than one
2328 * application at one time. You can type 'show application Dial Echo' and
2329 * you will see informations about these two applications ...
2331 static char *complete_show_application(char *line, char *word,
2337 /* try to lock applications list ... */
2338 if (ast_mutex_lock(&applock)) {
2339 ast_log(LOG_ERROR, "Unable to lock application list\n");
2343 /* ... walk all applications ... */
2346 /* ... check if word matches this application ... */
2347 if (!strncasecmp(word, a->name, strlen(word))) {
2348 /* ... if this is right app serve it ... */
2349 if (++which > state) {
2350 char *ret = strdup(a->name);
2351 ast_mutex_unlock(&applock);
2358 /* no application match */
2359 ast_mutex_unlock(&applock);
2363 static int handle_show_application(int fd, int argc, char *argv[])
2366 int app, no_registered_app = 1;
2368 if (argc < 3) return RESULT_SHOWUSAGE;
2370 /* try to lock applications list ... */
2371 if (ast_mutex_lock(&applock)) {
2372 ast_log(LOG_ERROR, "Unable to lock application list\n");
2376 /* ... go through all applications ... */
2379 /* ... compare this application name with all arguments given
2380 * to 'show application' command ... */
2381 for (app = 2; app < argc; app++) {
2382 if (!strcasecmp(a->name, argv[app])) {
2383 /* Maximum number of characters added by terminal coloring is 22 */
2384 char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
2385 char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
2386 int synopsis_size, description_size;
2388 no_registered_app = 0;
2391 synopsis_size = strlen(a->synopsis) + 23;
2393 synopsis_size = strlen("Not available") + 23;
2394 synopsis = alloca(synopsis_size);
2397 description_size = strlen(a->description) + 23;
2399 description_size = strlen("Not available") + 23;
2400 description = alloca(description_size);
2402 if (synopsis && description) {
2403 snprintf(info, 64 + AST_MAX_APP, "\n -= Info about application '%s' =- \n\n", a->name);
2404 term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
2405 term_color(syntitle, "[Synopsis]:\n", COLOR_MAGENTA, 0, 40);
2406 term_color(destitle, "[Description]:\n", COLOR_MAGENTA, 0, 40);
2407 term_color(synopsis,
2408 a->synopsis ? a->synopsis : "Not available",
2409 COLOR_CYAN, 0, synopsis_size);
2410 term_color(description,
2411 a->description ? a->description : "Not available",
2412 COLOR_CYAN, 0, description_size);
2414 ast_cli(fd,"%s%s%s\n\n%s%s\n", infotitle, syntitle, synopsis, destitle, description);
2416 /* ... one of our applications, show info ...*/
2417 ast_cli(fd,"\n -= Info about application '%s' =- \n\n"
2418 "[Synopsis]:\n %s\n\n"
2419 "[Description]:\n%s\n",
2421 a->synopsis ? a->synopsis : "Not available",
2422 a->description ? a->description : "Not available");
2429 ast_mutex_unlock(&applock);
2431 /* we found at least one app? no? */
2432 if (no_registered_app) {
2433 ast_cli(fd, "Your application(s) is (are) not registered\n");
2434 return RESULT_FAILURE;
2437 return RESULT_SUCCESS;
2440 static int handle_show_switches(int fd, int argc, char *argv[])
2442 struct ast_switch *sw;
2444 ast_cli(fd, "There are no registered alternative switches\n");
2445 return RESULT_SUCCESS;
2447 /* ... we have applications ... */
2448 ast_cli(fd, "\n -= Registered Asterisk Alternative Switches =-\n");
2449 if (ast_mutex_lock(&switchlock)) {
2450 ast_log(LOG_ERROR, "Unable to lock switches\n");
2455 ast_cli(fd, "%s: %s\n", sw->name, sw->description);
2458 ast_mutex_unlock(&switchlock);
2459 return RESULT_SUCCESS;
2463 * 'show applications' CLI command implementation functions ...
2465 static int handle_show_applications(int fd, int argc, char *argv[])
2469 /* try to lock applications list ... */
2470 if (ast_mutex_lock(&applock)) {
2471 ast_log(LOG_ERROR, "Unable to lock application list\n");
2475 /* ... go to first application ... */
2478 /* ... have we got at least one application (first)? no? */
2480 ast_cli(fd, "There is no registered applications\n");
2481 ast_mutex_unlock(&applock);
2485 /* ... we have applications ... */
2486 ast_cli(fd, "\n -= Registered Asterisk Applications =-\n");
2488 /* ... go through all applications ... */
2490 /* ... show informations about applications ... */
2491 ast_cli(fd," %20s: %s\n",
2493 a->synopsis ? a->synopsis : "<Synopsis not available>");
2497 /* ... unlock and return */
2498 ast_mutex_unlock(&applock);
2500 return RESULT_SUCCESS;
2504 * 'show dialplan' CLI command implementation functions ...
2506 static char *complete_show_dialplan_context(char *line, char *word, int pos,
2509 struct ast_context *c;
2512 /* we are do completion of [exten@]context on second position only */
2513 if (pos != 2) return NULL;
2515 /* try to lock contexts list ... */
2516 if (ast_lock_contexts()) {
2517 ast_log(LOG_ERROR, "Unable to lock context list\n");
2521 /* ... walk through all contexts ... */
2522 c = ast_walk_contexts(NULL);
2524 /* ... word matches context name? yes? ... */
2525 if (!strncasecmp(word, ast_get_context_name(c), strlen(word))) {
2526 /* ... for serve? ... */
2527 if (++which > state) {
2528 /* ... yes, serve this context name ... */
2529 char *ret = strdup(ast_get_context_name(c));
2530 ast_unlock_contexts();
2534 c = ast_walk_contexts(c);
2537 /* ... unlock and return */
2538 ast_unlock_contexts();
2542 static int handle_show_dialplan(int fd, int argc, char *argv[])
2544 struct ast_context *c;
2545 char *exten = NULL, *context = NULL;
2546 int context_existence = 0, extension_existence = 0;
2548 if (argc != 3 && argc != 2) return -1;
2550 /* we obtain [exten@]context? if yes, split them ... */
2552 char *splitter = argv[2];
2553 /* is there a '@' character? */
2554 if (strchr(argv[2], '@')) {
2555 /* yes, split into exten & context ... */
2556 exten = strsep(&splitter, "@");
2559 /* check for length and change to NULL if !strlen() */
2560 if (!strlen(exten)) exten = NULL;
2561 if (!strlen(context)) context = NULL;
2564 /* no '@' char, only context given */
2566 if (!strlen(context)) context = NULL;
2570 /* try to lock contexts */
2571 if (ast_lock_contexts()) {
2572 ast_log(LOG_WARNING, "Failed to lock contexts list\n");
2573 return RESULT_FAILURE;
2576 /* walk all contexts ... */
2577 c = ast_walk_contexts(NULL);
2579 /* show this context? */
2581 !strcmp(ast_get_context_name(c), context)) {
2582 context_existence = 1;
2584 /* try to lock context before walking in ... */
2585 if (!ast_lock_context(c)) {
2586 struct ast_exten *e;
2587 struct ast_include *i;
2588 struct ast_ignorepat *ip;
2590 char buf[256], buf2[256];
2591 int context_info_printed = 0;
2593 /* are we looking for exten too? if yes, we print context
2594 * if we our extension only
2597 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
2598 ast_get_context_name(c), ast_get_context_registrar(c));
2599 context_info_printed = 1;
2602 /* walk extensions ... */
2603 e = ast_walk_context_extensions(c, NULL);
2605 struct ast_exten *p;
2607 /* looking for extension? is this our extension? */
2609 strcmp(ast_get_extension_name(e), exten))
2611 /* we are looking for extension and it's not our
2612 * extension, so skip to next extension */
2613 e = ast_walk_context_extensions(c, e);
2617 extension_existence = 1;
2619 /* may we print context info? */
2620 if (!context_info_printed) {
2621 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
2622 ast_get_context_name(c),
2623 ast_get_context_registrar(c));
2624 context_info_printed = 1;
2627 /* write extension name and first peer */
2628 bzero(buf, sizeof(buf));
2629 snprintf(buf, sizeof(buf), "'%s' =>",
2630 ast_get_extension_name(e));
2632 snprintf(buf2, sizeof(buf2),
2634 ast_get_extension_priority(e),
2635 ast_get_extension_app(e),
2636 (char *)ast_get_extension_app_data(e));
2638 ast_cli(fd, " %-17s %-45s [%s]\n", buf, buf2,
2639 ast_get_extension_registrar(e));
2641 /* walk next extension peers */
2642 p = ast_walk_extension_priorities(e, e);
2644 bzero((void *)buf2, sizeof(buf2));
2646 snprintf(buf2, sizeof(buf2),
2648 ast_get_extension_priority(p),
2649 ast_get_extension_app(p),
2650 (char *)ast_get_extension_app_data(p));
2652 ast_cli(fd," %-17s %-45s [%s]\n",
2654 ast_get_extension_registrar(p));
2656 p = ast_walk_extension_priorities(e, p);
2658 e = ast_walk_context_extensions(c, e);
2661 /* include & ignorepat we all printing if we are not
2662 * looking for exact extension
2665 if (ast_walk_context_extensions(c, NULL))
2668 /* walk included and write info ... */
2669 i = ast_walk_context_includes(c, NULL);
2671 bzero(buf, sizeof(buf));
2672 snprintf(buf, sizeof(buf), "'%s'",
2673 ast_get_include_name(i));
2674 ast_cli(fd, " Include => %-45s [%s]\n",
2675 buf, ast_get_include_registrar(i));
2676 i = ast_walk_context_includes(c, i);
2679 /* walk ignore patterns and write info ... */
2680 ip = ast_walk_context_ignorepats(c, NULL);
2682 bzero(buf, sizeof(buf));
2683 snprintf(buf, sizeof(buf), "'%s'",
2684 ast_get_ignorepat_name(ip));
2685 ast_cli(fd, " Ignore pattern => %-45s [%s]\n",
2686 buf, ast_get_ignorepat_registrar(ip));
2687 ip = ast_walk_context_ignorepats(c, ip);
2689 sw = ast_walk_context_switches(c, NULL);
2691 bzero(buf, sizeof(buf));
2692 snprintf(buf, sizeof(buf), "'%s/%s'",
2693 ast_get_switch_name(sw),
2694 ast_get_switch_data(sw));
2695 ast_cli(fd, " Alt. Switch => %-45s [%s]\n",
2696 buf, ast_get_switch_registrar(sw));
2697 sw = ast_walk_context_switches(c, sw);
2701 ast_unlock_context(c);
2703 /* if we print something in context, make an empty line */
2704 if (context_info_printed) ast_cli(fd, "\n");
2707 c = ast_walk_contexts(c);
2709 ast_unlock_contexts();
2711 /* check for input failure and throw some error messages */
2712 if (context && !context_existence) {
2713 ast_cli(fd, "There is no existence of '%s' context\n",
2715 return RESULT_FAILURE;
2718 if (exten && !extension_existence) {
2720 ast_cli(fd, "There is no existence of %s@%s extension\n",
2724 "There is no existence of '%s' extension in all contexts\n",
2726 return RESULT_FAILURE;
2730 return RESULT_SUCCESS;
2734 * CLI entries for upper commands ...
2736 static struct ast_cli_entry show_applications_cli =
2737 { { "show", "applications", NULL },
2738 handle_show_applications, "Shows registered applications",
2739 show_applications_help };
2741 static struct ast_cli_entry show_application_cli =
2742 { { "show", "application", NULL },
2743 handle_show_application, "Describe a specific application",
2744 show_application_help, complete_show_application };
2746 static struct ast_cli_entry show_dialplan_cli =
2747 { { "show", "dialplan", NULL },
2748 handle_show_dialplan, "Show dialplan",
2749 show_dialplan_help, complete_show_dialplan_context };
2751 static struct ast_cli_entry show_switches_cli =
2752 { { "show", "switches", NULL },
2753 handle_show_switches, "Show alternative switches",
2754 show_switches_help, NULL };
2756 int ast_unregister_application(char *app) {
2757 struct ast_app *tmp, *tmpl = NULL;
2758 if (ast_mutex_lock(&applock)) {
2759 ast_log(LOG_ERROR, "Unable to lock application list\n");
2764 if (!strcasecmp(app, tmp->name)) {
2766 tmpl->next = tmp->next;
2769 if (option_verbose > 1)
2770 ast_verbose( VERBOSE_PREFIX_2 "Unregistered application '%s'\n", tmp->name);
2771 ast_mutex_unlock(&applock);
2777 ast_mutex_unlock(&applock);
2781 struct ast_context *ast_context_create(struct ast_context **extcontexts, char *name, char *registrar)
2783 struct ast_context *tmp, **local_contexts;
2785 local_contexts = &contexts;
2786 ast_mutex_lock(&conlock);
2788 local_contexts = extcontexts;
2790 tmp = *local_contexts;
2792 if (!strcasecmp(tmp->name, name)) {
2793 ast_mutex_unlock(&conlock);
2794 ast_log(LOG_WARNING, "Tried to register context '%s', already in use\n", name);
2796 ast_mutex_unlock(&conlock);
2801 tmp = malloc(sizeof(struct ast_context));
2803 memset(tmp, 0, sizeof(struct ast_context));
2804 ast_mutex_init(&tmp->lock);
2805 strncpy(tmp->name, name, sizeof(tmp->name)-1);
2807 tmp->registrar = registrar;
2808 tmp->next = *local_contexts;
2809 tmp->includes = NULL;
2810 tmp->ignorepats = NULL;
2811 *local_contexts = tmp;
2813 ast_log(LOG_DEBUG, "Registered context '%s'\n", tmp->name);
2814 else if (option_verbose > 2)
2815 ast_verbose( VERBOSE_PREFIX_3 "Registered extension context '%s'\n", tmp->name);
2817 ast_log(LOG_ERROR, "Out of memory\n");
2820 ast_mutex_unlock(&conlock);
2824 void __ast_context_destroy(struct ast_context *con, char *registrar, int lock);
2826 void ast_merge_contexts_and_delete(struct ast_context **extcontexts, char *registrar) {
2827 struct ast_context *tmp, *lasttmp = NULL;
2829 ast_mutex_lock(&conlock);
2831 __ast_context_destroy(NULL,registrar,0);
2838 __ast_context_destroy(tmp,tmp->registrar,0);
2844 lasttmp->next = contexts;
2845 contexts = *extcontexts;
2846 *extcontexts = NULL;
2848 ast_log(LOG_WARNING, "Requested contexts didn't get merged\n");
2849 ast_mutex_unlock(&conlock);
2855 * EBUSY - can't lock
2856 * ENOENT - no existence of context
2858 int ast_context_add_include(char *context, char *include, char *registrar)
2860 struct ast_context *c;
2862 if (ast_lock_contexts()) {
2867 /* walk contexts ... */
2868 c = ast_walk_contexts(NULL);
2870 /* ... search for the right one ... */
2871 if (!strcmp(ast_get_context_name(c), context)) {
2872 int ret = ast_context_add_include2(c, include, registrar);
2873 /* ... unlock contexts list and return */
2874 ast_unlock_contexts();
2877 c = ast_walk_contexts(c);
2880 /* we can't find the right context */
2881 ast_unlock_contexts();
2889 while(*c && (*c != '|')) c++; \
2890 if (*c) { *c = '\0'; c++; } else c = NULL; \
2893 static void get_timerange(struct ast_include *i, char *times)
2902 //start disabling all times, fill the fields with 0's, as they may contain garbage
2903 memset(i->minmask, 0, sizeof(i->minmask));
2905 /* Star is all times */
2906 if (!strlen(times) || !strcmp(times, "*")) {
2908 i->minmask[x] = (1 << 30) - 1;
2911 /* Otherwise expect a range */
2912 e = strchr(times, '-');
2914 ast_log(LOG_WARNING, "Time range is not valid. Assuming no restrictions based on time.\n");
2919 while(*e && !isdigit(*e)) e++;
2921 ast_log(LOG_WARNING, "Invalid time range. Assuming no restrictions based on time.\n");
2924 if (sscanf(times, "%d:%d", &s1, &s2) != 2) {
2925 ast_log(LOG_WARNING, "%s isn't a time. Assuming no restrictions based on time.\n", times);
2928 if (sscanf(e, "%d:%d", &e1, &e2) != 2) {
2929 ast_log(LOG_WARNING, "%s isn't a time. Assuming no restrictions based on time.\n", e);
2934 s1 = s1 * 30 + s2/2;
2935 if ((s1 < 0) || (s1 >= 24*30)) {
2936 ast_log(LOG_WARNING, "%s isn't a valid start time. Assuming no time.\n", times);
2939 e1 = e1 * 30 + e2/2;
2940 if ((e1 < 0) || (e1 >= 24*30)) {
2941 ast_log(LOG_WARNING, "%s isn't a valid end time. Assuming no time.\n", e);
2944 /* Go through the time and enable each appropriate bit */
2945 for (x=s1;x != e1;x = (x + 1) % (24 * 30)) {
2946 i->minmask[x/30] |= (1 << (x % 30));
2948 /* Do the last one */
2949 i->minmask[x/30] |= (1 << (x % 30));
2951 for (cth=0;cth<24;cth++) {
2952 /* Initialize masks to blank */
2953 i->minmask[cth] = 0;
2954 for (ctm=0;ctm<30;ctm++) {
2956 /* First hour with more than one hour */
2957 (((cth == s1) && (ctm >= s2)) &&
2960 || (((cth == s1) && (ctm >= s2)) &&
2961 ((cth == e1) && (ctm <= e2)))
2962 /* In between first and last hours (more than 2 hours) */
2965 /* Last hour with more than one hour */
2967 ((cth == e1) && (ctm <= e2)))
2969 i->minmask[cth] |= (1 << (ctm / 2));
2977 static char *days[] =
2988 static unsigned int get_dow(char *dow)
2991 /* The following line is coincidence, really! */
2994 /* Check for all days */
2995 if (!strlen(dow) || !strcmp(dow, "*"))
2996 return (1 << 7) - 1;
2997 /* Get start and ending days */
2998 c = strchr(dow, '-');
3004 /* Find the start */
3006 while((s < 7) && strcasecmp(dow, days[s])) s++;
3008 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", dow);
3013 while((e < 7) && strcasecmp(c, days[e])) e++;
3015 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
3021 for (x=s;x!=e;x = (x + 1) % 7) {
3029 static unsigned int get_day(char *day)
3032 /* The following line is coincidence, really! */
3035 /* Check for all days */
3036 if (!strlen(day) || !strcmp(day, "*")) {
3037 mask = (1 << 30) + ((1 << 30) - 1);
3040 /* Get start and ending days */
3041 c = strchr(day, '-');
3046 /* Find the start */
3047 if (sscanf(day, "%d", &s) != 1) {
3048 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", day);
3051 if ((s < 1) || (s > 31)) {
3052 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", day);
3057 if (sscanf(c, "%d", &e) != 1) {
3058 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
3061 if ((e < 1) || (e > 31)) {
3062 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
3069 for (x=s;x!=e;x = (x + 1) % 31) {
3076 static char *months[] =
3092 static unsigned int get_month(char *mon)
3095 /* The following line is coincidence, really! */
3098 /* Check for all days */
3099 if (!strlen(mon) || !strcmp(mon, "*"))