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" },
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 derprecated 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);
886 AST_LIST_TRAVERSE(headp,variables,entries) {
888 ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",var,ast_var_name(variables));
890 if (strcasecmp(ast_var_name(variables),var)==0) {
891 *ret=ast_var_value(variables);
893 strncpy(workspace, *ret, workspacelen - 1);
901 AST_LIST_TRAVERSE(&globals,variables,entries) {
903 ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",var,ast_var_name(variables));
905 if (strcasecmp(ast_var_name(variables),var)==0) {
906 *ret=ast_var_value(variables);
908 strncpy(workspace, *ret, workspacelen - 1);
916 int len_env=strlen("ENV(");
917 if (len > (len_env+1) && !strncasecmp(var,"ENV(",len_env) && !strcmp(var+len-1,")")) {
919 strncpy(cp3, var, sizeof(cp3) - 1);
921 *ret=getenv(cp3+len_env);
923 strncpy(workspace, *ret, workspacelen - 1);
928 if (!(*ret) && !strncasecmp(var,"LEN(",4)) {
931 if (len > (len_len+1) && !strncasecmp(var,"LEN(",len_len) && strchr(var+len_len+2,')')) {
933 strncpy(cp3, var, sizeof(cp3) - 1);
934 cp3[len-len_len-1]='\0';
935 sprintf(workspace,"%d",strlen(cp3));
937 } else ast_log(LOG_NOTICE, "Wrong use of LEN(VARIABLE)\n");
942 void pbx_substitute_variables_helper(struct ast_channel *c,const char *cp1,char *cp2,int count)
945 const char *tmp, *whereweare;
948 char ltmp[256], var[256];
949 char *nextvar, *nextexp;
951 int pos, brackets, needsub, len;
953 /* Substitutes variables into cp2, based on string cp1, and assuming cp2 to be
956 while(strlen(whereweare) && count) {
957 /* Assume we're copying the whole remaining string */
958 pos = strlen(whereweare);
960 /* Look for a variable */
961 nextvar = strstr(whereweare, "${");
963 nextexp = strstr(whereweare, "$[");
965 if (nextvar && nextexp) {
966 if (nextvar < nextexp)
972 /* If there is one, we only go that far */
974 pos = nextvar - whereweare;
976 pos = nextexp - whereweare;
978 /* Can't copy more than 'count' bytes */
982 /* Copy that many bytes */
983 memcpy(cp2, whereweare, pos);
990 /* We have a variable. Find the start and end, and determine
991 if we are going to have to recursively call ourselves on the
993 vars = vare = nextvar + 2;
997 /* Find the end of it */
998 while(brackets && *vare) {
999 if ((vare[0] == '$') && (vare[1] == '{')) {
1002 } else if (vare[0] == '}') {
1004 } else if ((vare[0] == '$') && (vare[1] == '['))
1009 ast_log(LOG_NOTICE, "Error in extension logic (missing '}')\n");
1010 len = vare - vars - 1;
1012 /* Skip totally over variable name */
1013 whereweare += ( len + 3);
1015 /* Store variable name (and truncate) */
1016 memset(var, 0, sizeof(var));
1017 strncpy(var, vars, sizeof(var) - 1);
1020 /* Substitute if necessary */
1022 memset(ltmp, 0, sizeof(ltmp));
1023 pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1);
1029 /* Retrieve variable value */
1030 strcpy(workspace, "");
1031 pbx_substitute_variables_temp(c,vars,&cp4, workspace, sizeof(workspace));
1033 length = strlen(cp4);
1036 memcpy(cp2, cp4, length);
1041 } else if (nextexp) {
1042 /* We have an expression. Find the start and end, and determine
1043 if we are going to have to recursively call ourselves on the
1045 vars = vare = nextexp + 2;
1049 /* Find the end of it */
1050 while(brackets && *vare) {
1051 if ((vare[0] == '$') && (vare[1] == '[')) {
1054 } else if (vare[0] == ']') {
1056 } else if ((vare[0] == '$') && (vare[1] == '{'))
1061 ast_log(LOG_NOTICE, "Error in extension logic (missing ']')\n");
1062 len = vare - vars - 1;
1064 /* Skip totally over variable name */
1065 whereweare += ( len + 3);
1067 /* Store variable name (and truncate) */
1068 memset(var, 0, sizeof(var));
1069 strncpy(var, vars, sizeof(var) - 1);
1072 /* Substitute if necessary */
1074 memset(ltmp, 0, sizeof(ltmp));
1075 pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1);
1081 /* Evaluate expression */
1082 cp4 = ast_expr(vars);
1084 ast_log(LOG_DEBUG, "Expression is '%s'\n", cp4);
1087 length = strlen(cp4);
1090 memcpy(cp2, cp4, length);
1101 static void pbx_substitute_variables(char *passdata, int datalen, struct ast_channel *c, struct ast_exten *e) {
1103 memset(passdata, 0, datalen);
1105 /* No variables or expressions in e->data, so why scan it? */
1106 if (!strstr(e->data,"${") && !strstr(e->data,"$[")) {
1107 strncpy(passdata, e->data, datalen - 1);
1108 passdata[datalen-1] = '\0';
1112 pbx_substitute_variables_helper(c,e->data,passdata, datalen - 1);
1115 static int pbx_extension_helper(struct ast_channel *c, char *context, char *exten, int priority, char *callerid, int action)
1117 struct ast_exten *e;
1118 struct ast_app *app;
1119 struct ast_switch *sw;
1124 char *incstack[AST_PBX_MAX_STACK];
1130 if (ast_mutex_lock(&conlock)) {
1131 ast_log(LOG_WARNING, "Unable to obtain lock\n");
1132 if ((action == HELPER_EXISTS) || (action == HELPER_CANMATCH) || (action == HELPER_MATCHMORE))
1137 e = pbx_find_extension(c, context, exten, priority, callerid, action, incstack, &stacklen, &status, &sw, &data);
1140 case HELPER_CANMATCH:
1141 ast_mutex_unlock(&conlock);
1144 ast_mutex_unlock(&conlock);
1146 case HELPER_MATCHMORE:
1147 ast_mutex_unlock(&conlock);
1153 app = pbx_findapp(e->app);
1154 ast_mutex_unlock(&conlock);
1156 if (c->context != context)
1157 strncpy(c->context, context, sizeof(c->context)-1);
1158 if (c->exten != exten)
1159 strncpy(c->exten, exten, sizeof(c->exten)-1);
1160 c->priority = priority;
1161 pbx_substitute_variables(passdata, sizeof(passdata), c, e);
1163 ast_log(LOG_DEBUG, "Launching '%s'\n", app->name);
1164 else if (option_verbose > 2)
1165 ast_verbose( VERBOSE_PREFIX_3 "Executing %s(\"%s\", \"%s\") %s\n",
1166 term_color(tmp, app->name, COLOR_BRCYAN, 0, sizeof(tmp)),
1167 term_color(tmp2, c->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
1168 term_color(tmp3, (strlen(passdata) ? (char *)passdata : ""), COLOR_BRMAGENTA, 0, sizeof(tmp3)),
1169 (newstack ? "in new stack" : "in same stack"));
1170 res = pbx_exec(c, app, passdata, newstack);
1173 ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
1177 ast_log(LOG_WARNING, "Huh (%d)?\n", action); return -1;
1181 case HELPER_CANMATCH:
1182 ast_mutex_unlock(&conlock);
1185 ast_mutex_unlock(&conlock);
1187 case HELPER_MATCHMORE:
1188 ast_mutex_unlock(&conlock);
1194 ast_mutex_unlock(&conlock);
1196 res = sw->exec(c, context, exten, priority, callerid, newstack, data);
1198 ast_log(LOG_WARNING, "No execution engine for switch %s\n", sw->name);
1203 ast_log(LOG_WARNING, "Huh (%d)?\n", action);
1207 ast_mutex_unlock(&conlock);
1209 case STATUS_NO_CONTEXT:
1210 if ((action != HELPER_EXISTS) && (action != HELPER_MATCHMORE))
1211 ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", context);
1213 case STATUS_NO_EXTENSION:
1214 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1215 ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, context);
1217 case STATUS_NO_PRIORITY:
1218 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1219 ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, context);
1222 ast_log(LOG_DEBUG, "Shouldn't happen!\n");
1224 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1232 static struct ast_exten *ast_hint_extension(struct ast_channel *c, char *context, char *exten)
1234 struct ast_exten *e;
1235 struct ast_switch *sw;
1238 char *incstack[AST_PBX_MAX_STACK];
1241 if (ast_mutex_lock(&conlock)) {
1242 ast_log(LOG_WARNING, "Unable to obtain lock\n");
1245 e = pbx_find_extension(c, context, exten, PRIORITY_HINT, "", HELPER_EXISTS, incstack, &stacklen, &status, &sw, &data);
1246 ast_mutex_unlock(&conlock);
1250 static int ast_extension_state2(struct ast_exten *e)
1252 char hint[AST_MAX_EXTENSION] = "";
1255 int allunavailable = 1, allbusy = 1, allfree = 1;
1258 strncpy(hint, ast_get_extension_app(e), sizeof(hint)-1);
1262 rest = strchr(cur, '&');
1268 res = ast_device_state(cur);
1270 case AST_DEVICE_NOT_INUSE:
1274 case AST_DEVICE_INUSE:
1275 return AST_EXTENSION_INUSE;
1276 case AST_DEVICE_BUSY:
1281 case AST_DEVICE_UNAVAILABLE:
1282 case AST_DEVICE_INVALID:
1295 return AST_EXTENSION_NOT_INUSE;
1297 return AST_EXTENSION_BUSY;
1299 return AST_EXTENSION_UNAVAILABLE;
1301 return AST_EXTENSION_INUSE;
1303 return AST_EXTENSION_NOT_INUSE;
1307 int ast_extension_state(struct ast_channel *c, char *context, char *exten)
1309 struct ast_exten *e;
1311 e = ast_hint_extension(c, context, exten);
1315 return ast_extension_state2(e);
1318 int ast_device_state_changed(const char *fmt, ...)
1320 struct ast_hint *list;
1321 struct ast_state_cb *cblist;
1322 char hint[AST_MAX_EXTENSION];
1323 char device[AST_MAX_EXTENSION];
1330 vsnprintf(device, sizeof(device)-1, fmt, ap);
1333 rest = strchr(device, '-');
1338 ast_mutex_lock(&hintlock);
1344 strcpy(hint, ast_get_extension_app(list->exten));
1347 rest = strchr(cur, '&');
1353 if (!strcmp(cur, device)) {
1354 // Found extension execute callbacks
1355 state = ast_extension_state2(list->exten);
1356 if ((state != -1) && (state != list->laststate)) {
1357 // For general callbacks
1360 cblist->callback(list->exten->parent->name, list->exten->exten, state, cblist->data);
1361 cblist = cblist->next;
1364 // For extension callbacks
1365 cblist = list->callbacks;
1367 cblist->callback(list->exten->parent->name, list->exten->exten, state, cblist->data);
1368 cblist = cblist->next;
1371 list->laststate = state;
1381 ast_mutex_unlock(&hintlock);
1385 int ast_extension_state_add(char *context, char *exten,
1386 ast_state_cb_type callback, void *data)
1388 struct ast_hint *list;
1389 struct ast_state_cb *cblist;
1390 struct ast_exten *e;
1392 /* No context and extension add callback to statecbs list */
1393 if (!context && !exten) {
1394 ast_mutex_lock(&hintlock);
1398 if (cblist->callback == callback) {
1399 cblist->data = data;
1400 ast_mutex_unlock(&hintlock);
1403 cblist = cblist->next;
1406 /* Now inserts the callback */
1407 cblist = malloc(sizeof(struct ast_state_cb));
1409 ast_mutex_unlock(&hintlock);
1412 memset(cblist, 0, sizeof(struct ast_state_cb));
1414 cblist->callback = callback;
1415 cblist->data = data;
1417 cblist->next = statecbs;
1420 ast_mutex_unlock(&hintlock);
1424 if (!context || !exten)
1427 /* This callback type is for only one hint */
1428 e = ast_hint_extension(NULL, context, exten);
1433 ast_mutex_lock(&hintlock);
1437 if (list->exten == e)
1443 ast_mutex_unlock(&hintlock);
1447 /* Now inserts the callback */
1448 cblist = malloc(sizeof(struct ast_state_cb));
1450 ast_mutex_unlock(&hintlock);
1453 memset(cblist, 0, sizeof(struct ast_state_cb));
1454 cblist->id = stateid++;
1455 cblist->callback = callback;
1456 cblist->data = data;
1458 cblist->next = list->callbacks;
1459 list->callbacks = cblist;
1461 ast_mutex_unlock(&hintlock);
1465 int ast_extension_state_del(int id, ast_state_cb_type callback)
1467 struct ast_hint *list;
1468 struct ast_state_cb *cblist, *cbprev;
1470 if (!id && !callback)
1473 ast_mutex_lock(&hintlock);
1475 /* id is zero is a callback without extension */
1480 if (cblist->callback == callback) {
1482 statecbs = cblist->next;
1484 cbprev->next = cblist->next;
1488 ast_mutex_unlock(&hintlock);
1492 cblist = cblist->next;
1495 ast_mutex_lock(&hintlock);
1499 /* id greater zero is a callback with extension */
1502 cblist = list->callbacks;
1505 if (cblist->id==id) {
1507 list->callbacks = cblist->next;
1509 cbprev->next = cblist->next;
1513 ast_mutex_unlock(&hintlock);
1517 cblist = cblist->next;
1522 ast_mutex_unlock(&hintlock);
1526 static int ast_add_hint(struct ast_exten *e)
1528 struct ast_hint *list;
1532 ast_mutex_lock(&hintlock);
1535 /* Search if hint exists, do nothing */
1537 if (list->exten == e) {
1538 ast_mutex_unlock(&hintlock);
1544 list = malloc(sizeof(struct ast_hint));
1546 ast_mutex_unlock(&hintlock);
1549 /* Initialize and insert new item */
1550 memset(list, 0, sizeof(struct ast_hint));
1552 list->laststate = ast_extension_state2(e);
1556 ast_mutex_unlock(&hintlock);
1560 static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
1562 struct ast_hint *list;
1564 ast_mutex_lock(&hintlock);
1569 if (list->exten == oe) {
1571 ast_mutex_unlock(&hintlock);
1576 ast_mutex_unlock(&hintlock);
1581 static int ast_remove_hint(struct ast_exten *e)
1583 /* Cleanup the Notifys if hint is removed */
1584 struct ast_hint *list, *prev = NULL;
1585 struct ast_state_cb *cblist, *cbprev;
1590 ast_mutex_lock(&hintlock);
1594 if (list->exten==e) {
1596 cblist = list->callbacks;
1598 /* Notify with -1 and remove all callbacks */
1600 cblist = cblist->next;
1601 cbprev->callback(list->exten->parent->name, list->exten->exten, -1, cbprev->data);
1604 list->callbacks = NULL;
1609 prev->next = list->next;
1613 ast_mutex_unlock(&hintlock);
1621 ast_mutex_unlock(&hintlock);
1626 int ast_get_hint(char *hint, int maxlen, struct ast_channel *c, char *context, char *exten)
1628 struct ast_exten *e;
1629 e = ast_hint_extension(c, context, exten);
1631 strncpy(hint, ast_get_extension_app(e), maxlen);
1637 int ast_exists_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid)
1639 return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_EXISTS);
1642 int ast_canmatch_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid)
1644 return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_CANMATCH);
1647 int ast_matchmore_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid)
1649 return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_MATCHMORE);
1652 int ast_spawn_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid)
1654 return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_SPAWN);
1657 int ast_pbx_run(struct ast_channel *c)
1666 /* A little initial setup here */
1668 ast_log(LOG_WARNING, "%s already has PBX structure??\n", c->name);
1669 c->pbx = malloc(sizeof(struct ast_pbx));
1671 ast_log(LOG_WARNING, "Out of memory\n");
1676 ast_log(LOG_WARNING, "%s already has a call record??\n", c->name);
1678 c->cdr = ast_cdr_alloc();
1680 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
1684 ast_cdr_init(c->cdr, c);
1687 memset(c->pbx, 0, sizeof(struct ast_pbx));
1688 /* Set reasonable defaults */
1689 c->pbx->rtimeout = 10;
1690 c->pbx->dtimeout = 5;
1692 /* Start by trying whatever the channel is set to */
1693 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
1694 /* JK02: If not successfull fall back to 's' */
1695 strncpy(c->exten, "s", sizeof(c->exten)-1);
1696 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
1697 /* JK02: And finally back to default if everything else failed */
1698 strncpy(c->context, "default", sizeof(c->context)-1);
1703 ast_cdr_start(c->cdr);
1707 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
1708 memset(exten, 0, sizeof(exten));
1709 manager_event(EVENT_FLAG_CALL, "Newexten",
1715 c->name, c->context, c->exten, c->priority, c->uniqueid);
1716 if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->callerid))) {
1717 /* Something bad happened, or a hangup has been requested. */
1718 if (((res >= '0') && (res <= '9')) || ((res >= 'A') && (res <= 'F')) ||
1719 (res == '*') || (res == '#')) {
1720 ast_log(LOG_DEBUG, "Oooh, got something to jump out with ('%c')!\n", res);
1721 memset(exten, 0, sizeof(exten));
1723 exten[pos++] = digit = res;
1727 case AST_PBX_KEEPALIVE:
1729 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
1730 else if (option_verbose > 1)
1731 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
1736 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
1737 else if (option_verbose > 1)
1738 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
1739 if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
1744 if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
1750 if ((c->_softhangup == AST_SOFTHANGUP_TIMEOUT) && (ast_exists_extension(c,c->context,"T",1,c->callerid))) {
1751 strncpy(c->exten,"T",sizeof(c->exten) - 1);
1752 /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
1753 c->whentohangup = 0;
1755 c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
1756 } else if (c->_softhangup) {
1757 ast_log(LOG_DEBUG, "Extension %s, priority %d returned normally even though call was hung up\n",
1758 c->exten, c->priority);
1764 if (!ast_exists_extension(c, c->context, c->exten, 1, c->callerid)) {
1765 /* It's not a valid extension anymore */
1766 if (ast_exists_extension(c, c->context, "i", 1, c->callerid)) {
1767 if (option_verbose > 2)
1768 ast_verbose(VERBOSE_PREFIX_3 "Sent into invalid extension '%s' in context '%s' on %s\n", c->exten, c->context, c->name);
1769 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", c->exten);
1770 strncpy(c->exten, "i", sizeof(c->exten)-1);
1773 ast_log(LOG_WARNING, "Channel '%s' sent into invalid extension '%s' in context '%s', but no invalid handler\n",
1774 c->name, c->exten, c->context);
1777 } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
1778 /* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */
1781 /* Done, wait for an extension */
1783 waittime = c->pbx->dtimeout;
1785 waittime = c->pbx->rtimeout;
1786 while (ast_matchmore_extension(c, c->context, exten, 1, c->callerid)) {
1787 /* As long as we're willing to wait, and as long as it's not defined,
1788 keep reading digits until we can't possibly get a right answer anymore. */
1789 digit = ast_waitfordigit(c, waittime * 1000);
1790 if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
1797 /* Error, maybe a hangup */
1799 exten[pos++] = digit;
1800 waittime = c->pbx->dtimeout;
1803 if (ast_exists_extension(c, c->context, exten, 1, c->callerid)) {
1804 /* Prepare the next cycle */
1805 strncpy(c->exten, exten, sizeof(c->exten)-1);
1808 /* No such extension */
1809 if (strlen(exten)) {
1810 /* An invalid extension */
1811 if (ast_exists_extension(c, c->context, "i", 1, c->callerid)) {
1812 if (option_verbose > 2)
1813 ast_verbose( VERBOSE_PREFIX_3 "Invalid extension '%s' in context '%s' on %s\n", exten, c->context, c->name);
1814 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", exten);
1815 strncpy(c->exten, "i", sizeof(c->exten)-1);
1818 ast_log(LOG_WARNING, "Invalid extension, but no rule 'i' in context '%s'\n", c->context);
1822 /* A simple timeout */
1823 if (ast_exists_extension(c, c->context, "t", 1, c->callerid)) {
1824 if (option_verbose > 2)
1825 ast_verbose( VERBOSE_PREFIX_3 "Timeout on %s\n", c->name);
1826 strncpy(c->exten, "t", sizeof(c->exten)-1);
1829 ast_log(LOG_WARNING, "Timeout, but no rule 't' in context '%s'\n", c->context);
1835 if (option_verbose > 2)
1836 ast_verbose(VERBOSE_PREFIX_2 "CDR updated on %s\n",c->name);
1842 ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", c->name);
1844 if ((res != AST_PBX_KEEPALIVE) && ast_exists_extension(c, c->context, "h", 1, c->callerid)) {
1845 strcpy(c->exten, "h");
1847 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
1848 if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->callerid))) {
1849 /* Something bad happened, or a hangup has been requested. */
1851 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
1852 else if (option_verbose > 1)
1853 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
1860 pbx_destroy(c->pbx);
1862 if (res != AST_PBX_KEEPALIVE)
1867 static void *pbx_thread(void *data)
1869 /* Oh joyeous kernel, we're a new thread, with nothing to do but
1870 answer this channel and get it going. The setjmp stuff is fairly
1871 confusing, but necessary to get smooth transitions between
1872 the execution of different applications (without the use of
1873 additional threads) */
1874 struct ast_channel *c = data;
1880 int ast_pbx_start(struct ast_channel *c)
1883 pthread_attr_t attr;
1885 ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
1889 /* Start a new thread, and get something handling this channel. */
1890 pthread_attr_init(&attr);
1891 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1892 if (pthread_create(&t, &attr, pbx_thread, c)) {
1893 ast_log(LOG_WARNING, "Failed to create new channel thread\n");
1900 * This function locks contexts list by &conlist, search for the rigt context
1901 * structure, leave context list locked and call ast_context_remove_include2
1902 * which removes include, unlock contexts list and return ...
1904 int ast_context_remove_include(char *context, char *include, char *registrar)
1906 struct ast_context *c;
1908 if (ast_lock_contexts()) return -1;
1910 /* walk contexts and search for the right one ...*/
1911 c = ast_walk_contexts(NULL);
1913 /* we found one ... */
1914 if (!strcmp(ast_get_context_name(c), context)) {
1916 /* remove include from this context ... */
1917 ret = ast_context_remove_include2(c, include, registrar);
1919 ast_unlock_contexts();
1921 /* ... return results */
1924 c = ast_walk_contexts(c);
1927 /* we can't find the right one context */
1928 ast_unlock_contexts();
1933 * When we call this function, &conlock lock must be locked, because when
1934 * we giving *con argument, some process can remove/change this context
1935 * and after that there can be segfault.
1937 * This function locks given context, removes include, unlock context and
1940 int ast_context_remove_include2(struct ast_context *con, char *include, char *registrar)
1942 struct ast_include *i, *pi = NULL;
1944 if (ast_mutex_lock(&con->lock)) return -1;
1949 /* find our include */
1950 if (!strcmp(i->name, include) &&
1951 (!strcmp(i->registrar, registrar) || !registrar)) {
1952 /* remove from list */
1956 con->includes = i->next;
1957 /* free include and return */
1959 ast_mutex_unlock(&con->lock);
1966 /* we can't find the right include */
1967 ast_mutex_unlock(&con->lock);
1972 * This function locks contexts list by &conlist, search for the rigt context
1973 * structure, leave context list locked and call ast_context_remove_switch2
1974 * which removes switch, unlock contexts list and return ...
1976 int ast_context_remove_switch(char *context, char *sw, char *data, char *registrar)
1978 struct ast_context *c;
1980 if (ast_lock_contexts()) return -1;
1982 /* walk contexts and search for the right one ...*/
1983 c = ast_walk_contexts(NULL);
1985 /* we found one ... */
1986 if (!strcmp(ast_get_context_name(c), context)) {
1988 /* remove switch from this context ... */
1989 ret = ast_context_remove_switch2(c, sw, data, registrar);
1991 ast_unlock_contexts();
1993 /* ... return results */
1996 c = ast_walk_contexts(c);
1999 /* we can't find the right one context */
2000 ast_unlock_contexts();
2005 * When we call this function, &conlock lock must be locked, because when
2006 * we giving *con argument, some process can remove/change this context
2007 * and after that there can be segfault.
2009 * This function locks given context, removes switch, unlock context and
2012 int ast_context_remove_switch2(struct ast_context *con, char *sw, char *data, char *registrar)
2014 struct ast_sw *i, *pi = NULL;
2016 if (ast_mutex_lock(&con->lock)) return -1;
2021 /* find our switch */
2022 if (!strcmp(i->name, sw) && !strcmp(i->data, data) &&
2023 (!strcmp(i->registrar, registrar) || !registrar)) {
2024 /* remove from list */
2028 con->alts = i->next;
2029 /* free switch and return */
2031 ast_mutex_unlock(&con->lock);
2038 /* we can't find the right switch */
2039 ast_mutex_unlock(&con->lock);
2044 * This functions lock contexts list, search for the right context,
2045 * call ast_context_remove_extension2, unlock contexts list and return.
2046 * In this function we are using
2048 int ast_context_remove_extension(char *context, char *extension, int priority, char *registrar)
2050 struct ast_context *c;
2052 if (ast_lock_contexts()) return -1;
2054 /* walk contexts ... */
2055 c = ast_walk_contexts(NULL);
2057 /* ... search for the right one ... */
2058 if (!strcmp(ast_get_context_name(c), context)) {
2059 /* ... remove extension ... */
2060 int ret = ast_context_remove_extension2(c, extension, priority,
2062 /* ... unlock contexts list and return */
2063 ast_unlock_contexts();
2066 c = ast_walk_contexts(c);
2069 /* we can't find the right context */
2070 ast_unlock_contexts();
2075 * When do you want to call this function, make sure that &conlock is locked,
2076 * because some process can handle with your *con context before you lock
2079 * This functionc locks given context, search for the right extension and
2080 * fires out all peer in this extensions with given priority. If priority
2081 * is set to 0, all peers are removed. After that, unlock context and
2084 int ast_context_remove_extension2(struct ast_context *con, char *extension, int priority, char *registrar)
2086 struct ast_exten *exten, *prev_exten = NULL;
2088 if (ast_mutex_lock(&con->lock)) return -1;
2090 /* go through all extensions in context and search the right one ... */
2094 /* look for right extension */
2095 if (!strcmp(exten->exten, extension) &&
2096 (!strcmp(exten->registrar, registrar) || !registrar)) {
2097 struct ast_exten *peer;
2099 /* should we free all peers in this extension? (priority == 0)? */
2100 if (priority == 0) {
2101 /* remove this extension from context list */
2103 prev_exten->next = exten->next;
2105 con->root = exten->next;
2107 /* fire out all peers */
2112 if (!peer->priority==PRIORITY_HINT)
2113 ast_remove_hint(peer);
2115 peer->datad(peer->data);
2121 ast_mutex_unlock(&con->lock);
2124 /* remove only extension with exten->priority == priority */
2125 struct ast_exten *previous_peer = NULL;
2129 /* is this our extension? */
2130 if (peer->priority == priority &&
2131 (!strcmp(peer->registrar, registrar) || !registrar)) {
2132 /* we are first priority extension? */
2133 if (!previous_peer) {
2134 /* exists previous extension here? */
2136 /* yes, so we must change next pointer in
2137 * previous connection to next peer
2140 prev_exten->next = peer->peer;
2141 peer->peer->next = exten->next;
2143 prev_exten->next = exten->next;
2145 /* no previous extension, we are first
2146 * extension, so change con->root ...
2149 con->root = peer->peer;
2151 con->root = exten->next;
2154 /* we are not first priority in extension */
2155 previous_peer->peer = peer->peer;
2158 /* now, free whole priority extension */
2159 if (peer->priority==PRIORITY_HINT)
2160 ast_remove_hint(peer);
2161 peer->datad(peer->data);
2164 ast_mutex_unlock(&con->lock);
2167 /* this is not right extension, skip to next peer */
2168 previous_peer = peer;
2173 ast_mutex_unlock(&con->lock);
2179 exten = exten->next;
2182 /* we can't find right extension */
2183 ast_mutex_unlock(&con->lock);
2188 int ast_register_application(char *app, int (*execute)(struct ast_channel *, void *), char *synopsis, char *description)
2190 struct ast_app *tmp, *prev, *cur;
2192 if (ast_mutex_lock(&applock)) {
2193 ast_log(LOG_ERROR, "Unable to lock application list\n");
2198 if (!strcasecmp(app, tmp->name)) {
2199 ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
2200 ast_mutex_unlock(&applock);
2205 tmp = malloc(sizeof(struct ast_app));
2207 memset(tmp, 0, sizeof(struct ast_app));
2208 strncpy(tmp->name, app, sizeof(tmp->name)-1);
2209 tmp->execute = execute;
2210 tmp->synopsis = synopsis;
2211 tmp->description = description;
2212 /* Store in alphabetical order */
2216 if (strcasecmp(tmp->name, cur->name) < 0)
2222 tmp->next = prev->next;
2229 ast_log(LOG_WARNING, "Out of memory\n");
2230 ast_mutex_unlock(&applock);
2233 if (option_verbose > 1)
2234 ast_verbose( VERBOSE_PREFIX_2 "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
2235 ast_mutex_unlock(&applock);
2239 int ast_register_switch(struct ast_switch *sw)
2241 struct ast_switch *tmp, *prev=NULL;
2242 if (ast_mutex_lock(&switchlock)) {
2243 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
2248 if (!strcasecmp(tmp->name, sw->name))
2254 ast_mutex_unlock(&switchlock);
2255 ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name);
2263 ast_mutex_unlock(&switchlock);
2267 void ast_unregister_switch(struct ast_switch *sw)
2269 struct ast_switch *tmp, *prev=NULL;
2270 if (ast_mutex_lock(&switchlock)) {
2271 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
2278 prev->next = tmp->next;
2280 switches = tmp->next;
2287 ast_mutex_unlock(&switchlock);
2291 * Help for CLI commands ...
2293 static char show_application_help[] =
2294 "Usage: show application <application> [<application> [<application> [...]]]\n"
2295 " Describes a particular application.\n";
2297 static char show_applications_help[] =
2298 "Usage: show applications\n"
2299 " List applications which are currently available.\n";
2301 static char show_dialplan_help[] =
2302 "Usage: show dialplan [exten@][context]\n"
2305 static char show_switches_help[] =
2306 "Usage: show switches\n"
2307 " Show registered switches\n";
2310 * IMPLEMENTATION OF CLI FUNCTIONS IS IN THE SAME ORDER AS COMMANDS HELPS
2315 * 'show application' CLI command implementation functions ...
2319 * There is a possibility to show informations about more than one
2320 * application at one time. You can type 'show application Dial Echo' and
2321 * you will see informations about these two applications ...
2323 static char *complete_show_application(char *line, char *word,
2329 /* try to lock applications list ... */
2330 if (ast_mutex_lock(&applock)) {
2331 ast_log(LOG_ERROR, "Unable to lock application list\n");
2335 /* ... walk all applications ... */
2338 /* ... check if word matches this application ... */
2339 if (!strncasecmp(word, a->name, strlen(word))) {
2340 /* ... if this is right app serve it ... */
2341 if (++which > state) {
2342 char *ret = strdup(a->name);
2343 ast_mutex_unlock(&applock);
2350 /* no application match */
2351 ast_mutex_unlock(&applock);
2355 static int handle_show_application(int fd, int argc, char *argv[])
2358 int app, no_registered_app = 1;
2360 if (argc < 3) return RESULT_SHOWUSAGE;
2362 /* try to lock applications list ... */
2363 if (ast_mutex_lock(&applock)) {
2364 ast_log(LOG_ERROR, "Unable to lock application list\n");
2368 /* ... go through all applications ... */
2371 /* ... compare this application name with all arguments given
2372 * to 'show application' command ... */
2373 for (app = 2; app < argc; app++) {
2374 if (!strcasecmp(a->name, argv[app])) {
2375 /* Maximum number of characters added by terminal coloring is 22 */
2376 char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
2377 char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
2378 int synopsis_size, description_size;
2380 no_registered_app = 0;
2383 synopsis_size = strlen(a->synopsis) + 23;
2385 synopsis_size = strlen("Not available") + 23;
2386 synopsis = alloca(synopsis_size);
2389 description_size = strlen(a->description) + 23;
2391 description_size = strlen("Not available") + 23;
2392 description = alloca(description_size);
2394 if (synopsis && description) {
2395 snprintf(info, 64 + AST_MAX_APP, "\n -= Info about application '%s' =- \n\n", a->name);
2396 term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
2397 term_color(syntitle, "[Synopsis]:\n", COLOR_MAGENTA, 0, 40);
2398 term_color(destitle, "[Description]:\n", COLOR_MAGENTA, 0, 40);
2399 term_color(synopsis,
2400 a->synopsis ? a->synopsis : "Not available",
2401 COLOR_CYAN, 0, synopsis_size);
2402 term_color(description,
2403 a->description ? a->description : "Not available",
2404 COLOR_CYAN, 0, description_size);
2406 ast_cli(fd,"%s%s%s\n\n%s%s\n", infotitle, syntitle, synopsis, destitle, description);
2408 /* ... one of our applications, show info ...*/
2409 ast_cli(fd,"\n -= Info about application '%s' =- \n\n"
2410 "[Synopsis]:\n %s\n\n"
2411 "[Description]:\n%s\n",
2413 a->synopsis ? a->synopsis : "Not available",
2414 a->description ? a->description : "Not available");
2421 ast_mutex_unlock(&applock);
2423 /* we found at least one app? no? */
2424 if (no_registered_app) {
2425 ast_cli(fd, "Your application(s) is (are) not registered\n");
2426 return RESULT_FAILURE;
2429 return RESULT_SUCCESS;
2432 static int handle_show_switches(int fd, int argc, char *argv[])
2434 struct ast_switch *sw;
2436 ast_cli(fd, "There are no registered alternative switches\n");
2437 return RESULT_SUCCESS;
2439 /* ... we have applications ... */
2440 ast_cli(fd, "\n -= Registered Asterisk Alternative Switches =-\n");
2441 if (ast_mutex_lock(&switchlock)) {
2442 ast_log(LOG_ERROR, "Unable to lock switches\n");
2447 ast_cli(fd, "%s: %s\n", sw->name, sw->description);
2450 ast_mutex_unlock(&switchlock);
2451 return RESULT_SUCCESS;
2455 * 'show applications' CLI command implementation functions ...
2457 static int handle_show_applications(int fd, int argc, char *argv[])
2461 /* try to lock applications list ... */
2462 if (ast_mutex_lock(&applock)) {
2463 ast_log(LOG_ERROR, "Unable to lock application list\n");
2467 /* ... go to first application ... */
2470 /* ... have we got at least one application (first)? no? */
2472 ast_cli(fd, "There is no registered applications\n");
2473 ast_mutex_unlock(&applock);
2477 /* ... we have applications ... */
2478 ast_cli(fd, "\n -= Registered Asterisk Applications =-\n");
2480 /* ... go through all applications ... */
2482 /* ... show informations about applications ... */
2483 ast_cli(fd," %15s: %s\n",
2485 a->synopsis ? a->synopsis : "<Synopsis not available>");
2489 /* ... unlock and return */
2490 ast_mutex_unlock(&applock);
2492 return RESULT_SUCCESS;
2496 * 'show dialplan' CLI command implementation functions ...
2498 static char *complete_show_dialplan_context(char *line, char *word, int pos,
2501 struct ast_context *c;
2504 /* we are do completion of [exten@]context on second position only */
2505 if (pos != 2) return NULL;
2507 /* try to lock contexts list ... */
2508 if (ast_lock_contexts()) {
2509 ast_log(LOG_ERROR, "Unable to lock context list\n");
2513 /* ... walk through all contexts ... */
2514 c = ast_walk_contexts(NULL);
2516 /* ... word matches context name? yes? ... */
2517 if (!strncasecmp(word, ast_get_context_name(c), strlen(word))) {
2518 /* ... for serve? ... */
2519 if (++which > state) {
2520 /* ... yes, serve this context name ... */
2521 char *ret = strdup(ast_get_context_name(c));
2522 ast_unlock_contexts();
2526 c = ast_walk_contexts(c);
2529 /* ... unlock and return */
2530 ast_unlock_contexts();
2534 static int handle_show_dialplan(int fd, int argc, char *argv[])
2536 struct ast_context *c;
2537 char *exten = NULL, *context = NULL;
2538 int context_existence = 0, extension_existence = 0;
2540 if (argc != 3 && argc != 2) return -1;
2542 /* we obtain [exten@]context? if yes, split them ... */
2544 char *splitter = argv[2];
2545 /* is there a '@' character? */
2546 if (strchr(argv[2], '@')) {
2547 /* yes, split into exten & context ... */
2548 exten = strsep(&splitter, "@");
2551 /* check for length and change to NULL if !strlen() */
2552 if (!strlen(exten)) exten = NULL;
2553 if (!strlen(context)) context = NULL;
2556 /* no '@' char, only context given */
2558 if (!strlen(context)) context = NULL;
2562 /* try to lock contexts */
2563 if (ast_lock_contexts()) {
2564 ast_log(LOG_WARNING, "Failed to lock contexts list\n");
2565 return RESULT_FAILURE;
2568 /* walk all contexts ... */
2569 c = ast_walk_contexts(NULL);
2571 /* show this context? */
2573 !strcmp(ast_get_context_name(c), context)) {
2574 context_existence = 1;
2576 /* try to lock context before walking in ... */
2577 if (!ast_lock_context(c)) {
2578 struct ast_exten *e;
2579 struct ast_include *i;
2580 struct ast_ignorepat *ip;
2582 char buf[256], buf2[256];
2583 int context_info_printed = 0;
2585 /* are we looking for exten too? if yes, we print context
2586 * if we our extension only
2589 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
2590 ast_get_context_name(c), ast_get_context_registrar(c));
2591 context_info_printed = 1;
2594 /* walk extensions ... */
2595 e = ast_walk_context_extensions(c, NULL);
2597 struct ast_exten *p;
2599 /* looking for extension? is this our extension? */
2601 strcmp(ast_get_extension_name(e), exten))
2603 /* we are looking for extension and it's not our
2604 * extension, so skip to next extension */
2605 e = ast_walk_context_extensions(c, e);
2609 extension_existence = 1;
2611 /* may we print context info? */
2612 if (!context_info_printed) {
2613 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
2614 ast_get_context_name(c),
2615 ast_get_context_registrar(c));
2616 context_info_printed = 1;
2619 /* write extension name and first peer */
2620 bzero(buf, sizeof(buf));
2621 snprintf(buf, sizeof(buf), "'%s' =>",
2622 ast_get_extension_name(e));
2624 snprintf(buf2, sizeof(buf2),
2626 ast_get_extension_priority(e),
2627 ast_get_extension_app(e),
2628 (char *)ast_get_extension_app_data(e));
2630 ast_cli(fd, " %-17s %-45s [%s]\n", buf, buf2,
2631 ast_get_extension_registrar(e));
2633 /* walk next extension peers */
2634 p = ast_walk_extension_priorities(e, e);
2636 bzero((void *)buf2, sizeof(buf2));
2638 snprintf(buf2, sizeof(buf2),
2640 ast_get_extension_priority(p),
2641 ast_get_extension_app(p),
2642 (char *)ast_get_extension_app_data(p));
2644 ast_cli(fd," %-17s %-45s [%s]\n",
2646 ast_get_extension_registrar(p));
2648 p = ast_walk_extension_priorities(e, p);
2650 e = ast_walk_context_extensions(c, e);
2653 /* include & ignorepat we all printing if we are not
2654 * looking for exact extension
2657 if (ast_walk_context_extensions(c, NULL))
2660 /* walk included and write info ... */
2661 i = ast_walk_context_includes(c, NULL);
2663 bzero(buf, sizeof(buf));
2664 snprintf(buf, sizeof(buf), "'%s'",
2665 ast_get_include_name(i));
2666 ast_cli(fd, " Include => %-45s [%s]\n",
2667 buf, ast_get_include_registrar(i));
2668 i = ast_walk_context_includes(c, i);
2671 /* walk ignore patterns and write info ... */
2672 ip = ast_walk_context_ignorepats(c, NULL);
2674 bzero(buf, sizeof(buf));
2675 snprintf(buf, sizeof(buf), "'%s'",
2676 ast_get_ignorepat_name(ip));
2677 ast_cli(fd, " Ignore pattern => %-45s [%s]\n",
2678 buf, ast_get_ignorepat_registrar(ip));
2679 ip = ast_walk_context_ignorepats(c, ip);
2681 sw = ast_walk_context_switches(c, NULL);
2683 bzero(buf, sizeof(buf));
2684 snprintf(buf, sizeof(buf), "'%s/%s'",
2685 ast_get_switch_name(sw),
2686 ast_get_switch_data(sw));
2687 ast_cli(fd, " Alt. Switch => %-45s [%s]\n",
2688 buf, ast_get_switch_registrar(sw));
2689 sw = ast_walk_context_switches(c, sw);
2693 ast_unlock_context(c);
2695 /* if we print something in context, make an empty line */
2696 if (context_info_printed) ast_cli(fd, "\n");
2699 c = ast_walk_contexts(c);
2701 ast_unlock_contexts();
2703 /* check for input failure and throw some error messages */
2704 if (context && !context_existence) {
2705 ast_cli(fd, "There is no existence of '%s' context\n",
2707 return RESULT_FAILURE;
2710 if (exten && !extension_existence) {
2712 ast_cli(fd, "There is no existence of %s@%s extension\n",
2716 "There is no existence of '%s' extension in all contexts\n",
2718 return RESULT_FAILURE;
2722 return RESULT_SUCCESS;
2726 * CLI entries for upper commands ...
2728 static struct ast_cli_entry show_applications_cli =
2729 { { "show", "applications", NULL },
2730 handle_show_applications, "Shows registered applications",
2731 show_applications_help };
2733 static struct ast_cli_entry show_application_cli =
2734 { { "show", "application", NULL },
2735 handle_show_application, "Describe a specific application",
2736 show_application_help, complete_show_application };
2738 static struct ast_cli_entry show_dialplan_cli =
2739 { { "show", "dialplan", NULL },
2740 handle_show_dialplan, "Show dialplan",
2741 show_dialplan_help, complete_show_dialplan_context };
2743 static struct ast_cli_entry show_switches_cli =
2744 { { "show", "switches", NULL },
2745 handle_show_switches, "Show alternative switches",
2746 show_switches_help, NULL };
2748 int ast_unregister_application(char *app) {
2749 struct ast_app *tmp, *tmpl = NULL;
2750 if (ast_mutex_lock(&applock)) {
2751 ast_log(LOG_ERROR, "Unable to lock application list\n");
2756 if (!strcasecmp(app, tmp->name)) {
2758 tmpl->next = tmp->next;
2761 if (option_verbose > 1)
2762 ast_verbose( VERBOSE_PREFIX_2 "Unregistered application '%s'\n", tmp->name);
2763 ast_mutex_unlock(&applock);
2769 ast_mutex_unlock(&applock);
2773 struct ast_context *ast_context_create(struct ast_context **extcontexts, char *name, char *registrar)
2775 struct ast_context *tmp, **local_contexts;
2777 local_contexts = &contexts;
2778 ast_mutex_lock(&conlock);
2780 local_contexts = extcontexts;
2782 tmp = *local_contexts;
2784 if (!strcasecmp(tmp->name, name)) {
2785 ast_mutex_unlock(&conlock);
2786 ast_log(LOG_WARNING, "Tried to register context '%s', already in use\n", name);
2788 ast_mutex_unlock(&conlock);
2793 tmp = malloc(sizeof(struct ast_context));
2795 memset(tmp, 0, sizeof(struct ast_context));
2796 ast_mutex_init(&tmp->lock);
2797 strncpy(tmp->name, name, sizeof(tmp->name)-1);
2799 tmp->registrar = registrar;
2800 tmp->next = *local_contexts;
2801 tmp->includes = NULL;
2802 tmp->ignorepats = NULL;
2803 *local_contexts = tmp;
2805 ast_log(LOG_DEBUG, "Registered context '%s'\n", tmp->name);
2806 else if (option_verbose > 2)
2807 ast_verbose( VERBOSE_PREFIX_3 "Registered extension context '%s'\n", tmp->name);
2809 ast_log(LOG_WARNING, "Out of memory\n");
2812 ast_mutex_unlock(&conlock);
2816 void __ast_context_destroy(struct ast_context *con, char *registrar, int lock);
2818 void ast_merge_contexts_and_delete(struct ast_context **extcontexts, char *registrar) {
2819 struct ast_context *tmp, *lasttmp = NULL;
2821 ast_mutex_lock(&conlock);
2823 __ast_context_destroy(NULL,registrar,0);
2830 __ast_context_destroy(tmp,tmp->registrar,0);
2836 lasttmp->next = contexts;
2837 contexts = *extcontexts;
2838 *extcontexts = NULL;
2840 ast_log(LOG_WARNING, "Requested contexts didn't get merged\n");
2841 ast_mutex_unlock(&conlock);
2847 * EBUSY - can't lock
2848 * ENOENT - no existence of context
2850 int ast_context_add_include(char *context, char *include, char *registrar)
2852 struct ast_context *c;
2854 if (ast_lock_contexts()) {
2859 /* walk contexts ... */
2860 c = ast_walk_contexts(NULL);
2862 /* ... search for the right one ... */
2863 if (!strcmp(ast_get_context_name(c), context)) {
2864 int ret = ast_context_add_include2(c, include, registrar);
2865 /* ... unlock contexts list and return */
2866 ast_unlock_contexts();
2869 c = ast_walk_contexts(c);
2872 /* we can't find the right context */
2873 ast_unlock_contexts();
2881 while(*c && (*c != '|')) c++; \
2882 if (*c) { *c = '\0'; c++; } else c = NULL; \
2885 static void get_timerange(struct ast_include *i, char *times)
2893 //start disabling all times, fill the fields with 0's, as they may contain garbage
2894 memset(i->minmask, 0, sizeof(i->minmask));
2896 /* Star is all times */
2897 if (!strlen(times) || !strcmp(times, "*")) {
2899 i->minmask[x] = (1 << 30) - 1;
2902 /* Otherwise expect a range */
2903 e = strchr(times, '-');
2905 ast_log(LOG_WARNING, "Time range is not valid. Assuming no time.\n");
2910 while(*e && !isdigit(*e)) e++;
2912 ast_log(LOG_WARNING, "Invalid time range. Assuming no time.\n");
2915 if (sscanf(times, "%d:%d", &s1, &s2) != 2) {
2916 ast_log(LOG_WARNING, "%s isn't a time. Assuming no time.\n", times);
2919 if (sscanf(e, "%d:%d", &e1, &e2) != 2) {
2920 ast_log(LOG_WARNING, "%s isn't a time. Assuming no time.\n", e);
2923 s1 = s1 * 30 + s2/2;
2924 if ((s1 < 0) || (s1 >= 24*30)) {
2925 ast_log(LOG_WARNING, "%s isn't a valid star time. Assuming no time.\n", times);
2928 e1 = e1 * 30 + e2/2;
2929 if ((e1 < 0) || (e2 >= 24*30)) {
2930 ast_log(LOG_WARNING, "%s isn't a valid start time. Assuming no time.\n", times);
2933 /* Go through the time and enable each appropriate bit */
2934 for (x=s1;x != e1;x = (x + 1) % (24 * 30)) {
2935 i->minmask[x/30] |= (1 << (x % 30));
2937 /* Do the last one */
2938 i->minmask[x/30] |= (1 << (x % 30));
2943 static char *days[] =
2954 static unsigned int get_dow(char *dow)
2957 /* The following line is coincidence, really! */
2960 /* Check for all days */
2961 if (!strlen(dow) || !strcmp(dow, "*"))
2962 return (1 << 7) - 1;
2963 /* Get start and ending days */
2964 c = strchr(dow, '-');
2970 /* Find the start */
2972 while((s < 7) && strcasecmp(dow, days[s])) s++;
2974 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", dow);
2979 while((e < 7) && strcasecmp(c, days[e])) e++;
2981 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
2987 for (x=s;x!=e;x = (x + 1) % 7) {
2995 static unsigned int get_day(char *day)
2998 /* The following line is coincidence, really! */
3001 /* Check for all days */
3002 if (!strlen(day) || !strcmp(day, "*")) {
3003 mask = (1 << 30) + ((1 << 30) - 1);
3006 /* Get start and ending days */
3007 c = strchr(day, '-');
3012 /* Find the start */
3013 if (sscanf(day, "%d", &s) != 1) {
3014 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", day);
3017 if ((s < 1) || (s > 31)) {
3018 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", day);
3023 if (sscanf(c, "%d", &e) != 1) {
3024 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
3027 if ((e < 1) || (e > 31)) {
3028 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
3035 for (x=s;x!=e;x = (x + 1) % 31) {
3042 static char *months[] =
3058 static unsigned int get_month(char *mon)
3061 /* The following line is coincidence, really! */
3064 /* Check for all days */
3065 if (!strlen(mon) || !strcmp(mon, "*"))
3066 return (1 << 12) - 1;
3067 /* Get start and ending days */
3068 c = strchr(mon, '-');
3073 /* Find the start */
3075 while((s < 12) && strcasecmp(mon, months[s])) s++;
3077 ast_log(LOG_WARNING, "Invalid month '%s', assuming none\n", mon);
3082 while((e < 12) && strcasecmp(mon, months[e])) e++;
3084 ast_log(LOG_WARNING, "Invalid month '%s', assuming none\n", c);
3090 for (x=s;x!=e;x = (x + 1) % 12) {
3098 static void build_timing(struct ast_include *i, char *info)
3101 /* Check for empty just in case */
3105 /* Assume everything except time */
3106 i->monthmask = (1 << 12) - 1;
3107 i->daymask = (1 << 30) - 1 + (1 << 30);