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, "UNIQUEID")) {
863 snprintf(workspace, workspacelen -1, "%s", c->uniqueid);
865 } else if (c && !strcmp(var, "HANGUPCAUSE")) {
866 snprintf(workspace, workspacelen -1, "%i", c->hangupcause);
868 } else if (c && !strcmp(var, "ACCOUNTCODE")) {
869 strncpy(workspace, c->accountcode, workspacelen - 1);
873 AST_LIST_TRAVERSE(headp,variables,entries) {
875 ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",var,ast_var_name(variables));
877 if (strcasecmp(ast_var_name(variables),var)==0) {
878 *ret=ast_var_value(variables);
880 strncpy(workspace, *ret, workspacelen - 1);
888 AST_LIST_TRAVERSE(&globals,variables,entries) {
890 ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",var,ast_var_name(variables));
892 if (strcasecmp(ast_var_name(variables),var)==0) {
893 *ret=ast_var_value(variables);
895 strncpy(workspace, *ret, workspacelen - 1);
903 int len_env=strlen("ENV(");
904 if (len > (len_env+1) && !strncasecmp(var,"ENV(",len_env) && !strcmp(var+len-1,")")) {
906 strncpy(cp3, var, sizeof(cp3) - 1);
908 *ret=getenv(cp3+len_env);
910 strncpy(workspace, *ret, workspacelen - 1);
915 if (!(*ret) && !strncasecmp(var,"LEN(",4)) {
918 if (len > (len_len+1) && !strncasecmp(var,"LEN(",len_len) && strchr(var+len_len+2,')')) {
920 strncpy(cp3, var, sizeof(cp3) - 1);
921 cp3[len-len_len-1]='\0';
922 sprintf(workspace,"%d",strlen(cp3));
924 } else ast_log(LOG_NOTICE, "Wrong use of LEN(VARIABLE)\n");
929 void pbx_substitute_variables_helper(struct ast_channel *c,const char *cp1,char *cp2,int count)
932 const char *tmp, *whereweare;
935 char ltmp[256], var[256];
936 char *nextvar, *nextexp;
938 int pos, brackets, needsub, len;
940 /* Substitutes variables into cp2, based on string cp1, and assuming cp2 to be
943 while(strlen(whereweare) && count) {
944 /* Assume we're copying the whole remaining string */
945 pos = strlen(whereweare);
947 /* Look for a variable */
948 nextvar = strstr(whereweare, "${");
950 nextexp = strstr(whereweare, "$[");
952 if (nextvar && nextexp) {
953 if (nextvar < nextexp)
959 /* If there is one, we only go that far */
961 pos = nextvar - whereweare;
963 pos = nextexp - whereweare;
965 /* Can't copy more than 'count' bytes */
969 /* Copy that many bytes */
970 memcpy(cp2, whereweare, pos);
977 /* We have a variable. Find the start and end, and determine
978 if we are going to have to recursively call ourselves on the
980 vars = vare = nextvar + 2;
984 /* Find the end of it */
985 while(brackets && *vare) {
986 if ((vare[0] == '$') && (vare[1] == '{')) {
989 } else if (vare[0] == '}') {
991 } else if ((vare[0] == '$') && (vare[1] == '['))
996 ast_log(LOG_NOTICE, "Error in extension logic (missing '}')\n");
997 len = vare - vars - 1;
999 /* Skip totally over variable name */
1000 whereweare += ( len + 3);
1002 /* Store variable name (and truncate) */
1003 memset(var, 0, sizeof(var));
1004 strncpy(var, vars, sizeof(var) - 1);
1007 /* Substitute if necessary */
1009 memset(ltmp, 0, sizeof(ltmp));
1010 pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1);
1016 /* Retrieve variable value */
1017 strcpy(workspace, "");
1018 pbx_substitute_variables_temp(c,vars,&cp4, workspace, sizeof(workspace));
1020 length = strlen(cp4);
1023 memcpy(cp2, cp4, length);
1028 } else if (nextexp) {
1029 /* We have an expression. Find the start and end, and determine
1030 if we are going to have to recursively call ourselves on the
1032 vars = vare = nextexp + 2;
1036 /* Find the end of it */
1037 while(brackets && *vare) {
1038 if ((vare[0] == '$') && (vare[1] == '[')) {
1041 } else if (vare[0] == ']') {
1043 } else if ((vare[0] == '$') && (vare[1] == '{'))
1048 ast_log(LOG_NOTICE, "Error in extension logic (missing ']')\n");
1049 len = vare - vars - 1;
1051 /* Skip totally over variable name */
1052 whereweare += ( len + 3);
1054 /* Store variable name (and truncate) */
1055 memset(var, 0, sizeof(var));
1056 strncpy(var, vars, sizeof(var) - 1);
1059 /* Substitute if necessary */
1061 memset(ltmp, 0, sizeof(ltmp));
1062 pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1);
1068 /* Evaluate expression */
1069 cp4 = ast_expr(vars);
1071 ast_log(LOG_DEBUG, "Expression is '%s'\n", cp4);
1074 length = strlen(cp4);
1077 memcpy(cp2, cp4, length);
1088 static void pbx_substitute_variables(char *passdata, int datalen, struct ast_channel *c, struct ast_exten *e) {
1090 memset(passdata, 0, datalen);
1092 /* No variables or expressions in e->data, so why scan it? */
1093 if (!strstr(e->data,"${") && !strstr(e->data,"$[")) {
1094 strncpy(passdata, e->data, datalen - 1);
1095 passdata[datalen-1] = '\0';
1099 pbx_substitute_variables_helper(c,e->data,passdata, datalen - 1);
1102 static int pbx_extension_helper(struct ast_channel *c, char *context, char *exten, int priority, char *callerid, int action)
1104 struct ast_exten *e;
1105 struct ast_app *app;
1106 struct ast_switch *sw;
1111 char *incstack[AST_PBX_MAX_STACK];
1117 if (ast_mutex_lock(&conlock)) {
1118 ast_log(LOG_WARNING, "Unable to obtain lock\n");
1119 if ((action == HELPER_EXISTS) || (action == HELPER_CANMATCH) || (action == HELPER_MATCHMORE))
1124 e = pbx_find_extension(c, context, exten, priority, callerid, action, incstack, &stacklen, &status, &sw, &data);
1127 case HELPER_CANMATCH:
1128 ast_mutex_unlock(&conlock);
1131 ast_mutex_unlock(&conlock);
1133 case HELPER_MATCHMORE:
1134 ast_mutex_unlock(&conlock);
1140 app = pbx_findapp(e->app);
1141 ast_mutex_unlock(&conlock);
1143 if (c->context != context)
1144 strncpy(c->context, context, sizeof(c->context)-1);
1145 if (c->exten != exten)
1146 strncpy(c->exten, exten, sizeof(c->exten)-1);
1147 c->priority = priority;
1148 pbx_substitute_variables(passdata, sizeof(passdata), c, e);
1150 ast_log(LOG_DEBUG, "Launching '%s'\n", app->name);
1151 else if (option_verbose > 2)
1152 ast_verbose( VERBOSE_PREFIX_3 "Executing %s(\"%s\", \"%s\") %s\n",
1153 term_color(tmp, app->name, COLOR_BRCYAN, 0, sizeof(tmp)),
1154 term_color(tmp2, c->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
1155 term_color(tmp3, (strlen(passdata) ? (char *)passdata : ""), COLOR_BRMAGENTA, 0, sizeof(tmp3)),
1156 (newstack ? "in new stack" : "in same stack"));
1157 res = pbx_exec(c, app, passdata, newstack);
1160 ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
1164 ast_log(LOG_WARNING, "Huh (%d)?\n", action); return -1;
1168 case HELPER_CANMATCH:
1169 ast_mutex_unlock(&conlock);
1172 ast_mutex_unlock(&conlock);
1174 case HELPER_MATCHMORE:
1175 ast_mutex_unlock(&conlock);
1181 ast_mutex_unlock(&conlock);
1183 res = sw->exec(c, context, exten, priority, callerid, newstack, data);
1185 ast_log(LOG_WARNING, "No execution engine for switch %s\n", sw->name);
1190 ast_log(LOG_WARNING, "Huh (%d)?\n", action);
1194 ast_mutex_unlock(&conlock);
1196 case STATUS_NO_CONTEXT:
1197 if ((action != HELPER_EXISTS) && (action != HELPER_MATCHMORE))
1198 ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", context);
1200 case STATUS_NO_EXTENSION:
1201 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1202 ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, context);
1204 case STATUS_NO_PRIORITY:
1205 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1206 ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, context);
1209 ast_log(LOG_DEBUG, "Shouldn't happen!\n");
1211 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1219 static struct ast_exten *ast_hint_extension(struct ast_channel *c, char *context, char *exten)
1221 struct ast_exten *e;
1222 struct ast_switch *sw;
1225 char *incstack[AST_PBX_MAX_STACK];
1228 if (ast_mutex_lock(&conlock)) {
1229 ast_log(LOG_WARNING, "Unable to obtain lock\n");
1232 e = pbx_find_extension(c, context, exten, PRIORITY_HINT, "", HELPER_EXISTS, incstack, &stacklen, &status, &sw, &data);
1233 ast_mutex_unlock(&conlock);
1237 static int ast_extension_state2(struct ast_exten *e)
1239 char hint[AST_MAX_EXTENSION] = "";
1242 int allunavailable = 1, allbusy = 1, allfree = 1;
1245 strncpy(hint, ast_get_extension_app(e), sizeof(hint)-1);
1249 rest = strchr(cur, '&');
1255 res = ast_device_state(cur);
1257 case AST_DEVICE_NOT_INUSE:
1261 case AST_DEVICE_INUSE:
1262 return AST_EXTENSION_INUSE;
1263 case AST_DEVICE_BUSY:
1268 case AST_DEVICE_UNAVAILABLE:
1269 case AST_DEVICE_INVALID:
1282 return AST_EXTENSION_NOT_INUSE;
1284 return AST_EXTENSION_BUSY;
1286 return AST_EXTENSION_UNAVAILABLE;
1288 return AST_EXTENSION_INUSE;
1290 return AST_EXTENSION_NOT_INUSE;
1294 int ast_extension_state(struct ast_channel *c, char *context, char *exten)
1296 struct ast_exten *e;
1298 e = ast_hint_extension(c, context, exten);
1302 return ast_extension_state2(e);
1305 int ast_device_state_changed(const char *fmt, ...)
1307 struct ast_hint *list;
1308 struct ast_state_cb *cblist;
1309 char hint[AST_MAX_EXTENSION];
1310 char device[AST_MAX_EXTENSION];
1317 vsnprintf(device, sizeof(device)-1, fmt, ap);
1320 rest = strchr(device, '-');
1325 ast_mutex_lock(&hintlock);
1331 strcpy(hint, ast_get_extension_app(list->exten));
1334 rest = strchr(cur, '&');
1340 if (!strcmp(cur, device)) {
1341 // Found extension execute callbacks
1342 state = ast_extension_state2(list->exten);
1343 if ((state != -1) && (state != list->laststate)) {
1344 // For general callbacks
1347 cblist->callback(list->exten->parent->name, list->exten->exten, state, cblist->data);
1348 cblist = cblist->next;
1351 // For extension callbacks
1352 cblist = list->callbacks;
1354 cblist->callback(list->exten->parent->name, list->exten->exten, state, cblist->data);
1355 cblist = cblist->next;
1358 list->laststate = state;
1368 ast_mutex_unlock(&hintlock);
1372 int ast_extension_state_add(char *context, char *exten,
1373 ast_state_cb_type callback, void *data)
1375 struct ast_hint *list;
1376 struct ast_state_cb *cblist;
1377 struct ast_exten *e;
1379 /* No context and extension add callback to statecbs list */
1380 if (!context && !exten) {
1381 ast_mutex_lock(&hintlock);
1385 if (cblist->callback == callback) {
1386 cblist->data = data;
1387 ast_mutex_unlock(&hintlock);
1390 cblist = cblist->next;
1393 /* Now inserts the callback */
1394 cblist = malloc(sizeof(struct ast_state_cb));
1396 ast_mutex_unlock(&hintlock);
1399 memset(cblist, 0, sizeof(struct ast_state_cb));
1401 cblist->callback = callback;
1402 cblist->data = data;
1404 cblist->next = statecbs;
1407 ast_mutex_unlock(&hintlock);
1411 if (!context || !exten)
1414 /* This callback type is for only one hint */
1415 e = ast_hint_extension(NULL, context, exten);
1420 ast_mutex_lock(&hintlock);
1424 if (list->exten == e)
1430 ast_mutex_unlock(&hintlock);
1434 /* Now inserts the callback */
1435 cblist = malloc(sizeof(struct ast_state_cb));
1437 ast_mutex_unlock(&hintlock);
1440 memset(cblist, 0, sizeof(struct ast_state_cb));
1441 cblist->id = stateid++;
1442 cblist->callback = callback;
1443 cblist->data = data;
1445 cblist->next = list->callbacks;
1446 list->callbacks = cblist;
1448 ast_mutex_unlock(&hintlock);
1452 int ast_extension_state_del(int id, ast_state_cb_type callback)
1454 struct ast_hint *list;
1455 struct ast_state_cb *cblist, *cbprev;
1457 if (!id && !callback)
1460 ast_mutex_lock(&hintlock);
1462 /* id is zero is a callback without extension */
1467 if (cblist->callback == callback) {
1469 statecbs = cblist->next;
1471 cbprev->next = cblist->next;
1475 ast_mutex_unlock(&hintlock);
1479 cblist = cblist->next;
1482 ast_mutex_lock(&hintlock);
1486 /* id greater zero is a callback with extension */
1489 cblist = list->callbacks;
1492 if (cblist->id==id) {
1494 list->callbacks = cblist->next;
1496 cbprev->next = cblist->next;
1500 ast_mutex_unlock(&hintlock);
1504 cblist = cblist->next;
1509 ast_mutex_unlock(&hintlock);
1513 static int ast_add_hint(struct ast_exten *e)
1515 struct ast_hint *list;
1519 ast_mutex_lock(&hintlock);
1522 /* Search if hint exists, do nothing */
1524 if (list->exten == e) {
1525 ast_mutex_unlock(&hintlock);
1531 list = malloc(sizeof(struct ast_hint));
1533 ast_mutex_unlock(&hintlock);
1536 /* Initialize and insert new item */
1537 memset(list, 0, sizeof(struct ast_hint));
1539 list->laststate = ast_extension_state2(e);
1543 ast_mutex_unlock(&hintlock);
1547 static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
1549 struct ast_hint *list;
1551 ast_mutex_lock(&hintlock);
1556 if (list->exten == oe) {
1558 ast_mutex_unlock(&hintlock);
1563 ast_mutex_unlock(&hintlock);
1568 static int ast_remove_hint(struct ast_exten *e)
1570 /* Cleanup the Notifys if hint is removed */
1571 struct ast_hint *list, *prev = NULL;
1572 struct ast_state_cb *cblist, *cbprev;
1577 ast_mutex_lock(&hintlock);
1581 if (list->exten==e) {
1583 cblist = list->callbacks;
1585 /* Notify with -1 and remove all callbacks */
1587 cblist = cblist->next;
1588 cbprev->callback(list->exten->parent->name, list->exten->exten, -1, cbprev->data);
1591 list->callbacks = NULL;
1596 prev->next = list->next;
1600 ast_mutex_unlock(&hintlock);
1608 ast_mutex_unlock(&hintlock);
1613 int ast_get_hint(char *hint, int maxlen, struct ast_channel *c, char *context, char *exten)
1615 struct ast_exten *e;
1616 e = ast_hint_extension(c, context, exten);
1618 strncpy(hint, ast_get_extension_app(e), maxlen);
1624 int ast_exists_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid)
1626 return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_EXISTS);
1629 int ast_canmatch_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid)
1631 return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_CANMATCH);
1634 int ast_matchmore_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid)
1636 return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_MATCHMORE);
1639 int ast_spawn_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid)
1641 return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_SPAWN);
1644 int ast_pbx_run(struct ast_channel *c)
1653 /* A little initial setup here */
1655 ast_log(LOG_WARNING, "%s already has PBX structure??\n", c->name);
1656 c->pbx = malloc(sizeof(struct ast_pbx));
1658 ast_log(LOG_WARNING, "Out of memory\n");
1663 ast_log(LOG_WARNING, "%s already has a call record??\n", c->name);
1665 c->cdr = ast_cdr_alloc();
1667 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
1671 ast_cdr_init(c->cdr, c);
1674 memset(c->pbx, 0, sizeof(struct ast_pbx));
1675 /* Set reasonable defaults */
1676 c->pbx->rtimeout = 10;
1677 c->pbx->dtimeout = 5;
1679 /* Start by trying whatever the channel is set to */
1680 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
1681 /* JK02: If not successfull fall back to 's' */
1682 strncpy(c->exten, "s", sizeof(c->exten)-1);
1683 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
1684 /* JK02: And finally back to default if everything else failed */
1685 strncpy(c->context, "default", sizeof(c->context)-1);
1690 ast_cdr_start(c->cdr);
1694 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
1695 memset(exten, 0, sizeof(exten));
1696 manager_event(EVENT_FLAG_CALL, "Newexten",
1702 c->name, c->context, c->exten, c->priority, c->uniqueid);
1703 if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->callerid))) {
1704 /* Something bad happened, or a hangup has been requested. */
1705 if (((res >= '0') && (res <= '9')) || ((res >= 'A') && (res <= 'F')) ||
1706 (res == '*') || (res == '#')) {
1707 ast_log(LOG_DEBUG, "Oooh, got something to jump out with ('%c')!\n", res);
1708 memset(exten, 0, sizeof(exten));
1710 exten[pos++] = digit = res;
1714 case AST_PBX_KEEPALIVE:
1716 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
1717 else if (option_verbose > 1)
1718 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
1723 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
1724 else if (option_verbose > 1)
1725 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
1726 if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
1731 if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
1737 if ((c->_softhangup == AST_SOFTHANGUP_TIMEOUT) && (ast_exists_extension(c,c->context,"T",1,c->callerid))) {
1738 strncpy(c->exten,"T",sizeof(c->exten) - 1);
1739 /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
1740 c->whentohangup = 0;
1742 c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
1743 } else if (c->_softhangup) {
1744 ast_log(LOG_DEBUG, "Extension %s, priority %d returned normally even though call was hung up\n",
1745 c->exten, c->priority);
1751 if (!ast_exists_extension(c, c->context, c->exten, 1, c->callerid)) {
1752 /* It's not a valid extension anymore */
1753 if (ast_exists_extension(c, c->context, "i", 1, c->callerid)) {
1754 if (option_verbose > 2)
1755 ast_verbose(VERBOSE_PREFIX_3 "Sent into invalid extension '%s' in context '%s' on %s\n", c->exten, c->context, c->name);
1756 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", c->exten);
1757 strncpy(c->exten, "i", sizeof(c->exten)-1);
1760 ast_log(LOG_WARNING, "Channel '%s' sent into invalid extension '%s' in context '%s', but no invalid handler\n",
1761 c->name, c->exten, c->context);
1764 } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
1765 /* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */
1768 /* Done, wait for an extension */
1770 waittime = c->pbx->dtimeout;
1772 waittime = c->pbx->rtimeout;
1773 while (ast_matchmore_extension(c, c->context, exten, 1, c->callerid)) {
1774 /* As long as we're willing to wait, and as long as it's not defined,
1775 keep reading digits until we can't possibly get a right answer anymore. */
1776 digit = ast_waitfordigit(c, waittime * 1000);
1777 if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
1784 /* Error, maybe a hangup */
1786 exten[pos++] = digit;
1787 waittime = c->pbx->dtimeout;
1790 if (ast_exists_extension(c, c->context, exten, 1, c->callerid)) {
1791 /* Prepare the next cycle */
1792 strncpy(c->exten, exten, sizeof(c->exten)-1);
1795 /* No such extension */
1796 if (strlen(exten)) {
1797 /* An invalid extension */
1798 if (ast_exists_extension(c, c->context, "i", 1, c->callerid)) {
1799 if (option_verbose > 2)
1800 ast_verbose( VERBOSE_PREFIX_3 "Invalid extension '%s' in context '%s' on %s\n", exten, c->context, c->name);
1801 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", exten);
1802 strncpy(c->exten, "i", sizeof(c->exten)-1);
1805 ast_log(LOG_WARNING, "Invalid extension, but no rule 'i' in context '%s'\n", c->context);
1809 /* A simple timeout */
1810 if (ast_exists_extension(c, c->context, "t", 1, c->callerid)) {
1811 if (option_verbose > 2)
1812 ast_verbose( VERBOSE_PREFIX_3 "Timeout on %s\n", c->name);
1813 strncpy(c->exten, "t", sizeof(c->exten)-1);
1816 ast_log(LOG_WARNING, "Timeout, but no rule 't' in context '%s'\n", c->context);
1822 if (option_verbose > 2)
1823 ast_verbose(VERBOSE_PREFIX_2 "CDR updated on %s\n",c->name);
1829 ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", c->name);
1831 if ((res != AST_PBX_KEEPALIVE) && ast_exists_extension(c, c->context, "h", 1, c->callerid)) {
1832 strcpy(c->exten, "h");
1834 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
1835 if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->callerid))) {
1836 /* Something bad happened, or a hangup has been requested. */
1838 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
1839 else if (option_verbose > 1)
1840 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
1847 pbx_destroy(c->pbx);
1849 if (res != AST_PBX_KEEPALIVE)
1854 static void *pbx_thread(void *data)
1856 /* Oh joyeous kernel, we're a new thread, with nothing to do but
1857 answer this channel and get it going. The setjmp stuff is fairly
1858 confusing, but necessary to get smooth transitions between
1859 the execution of different applications (without the use of
1860 additional threads) */
1861 struct ast_channel *c = data;
1867 int ast_pbx_start(struct ast_channel *c)
1870 pthread_attr_t attr;
1872 ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
1876 /* Start a new thread, and get something handling this channel. */
1877 pthread_attr_init(&attr);
1878 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1879 if (pthread_create(&t, &attr, pbx_thread, c)) {
1880 ast_log(LOG_WARNING, "Failed to create new channel thread\n");
1887 * This function locks contexts list by &conlist, search for the rigt context
1888 * structure, leave context list locked and call ast_context_remove_include2
1889 * which removes include, unlock contexts list and return ...
1891 int ast_context_remove_include(char *context, char *include, char *registrar)
1893 struct ast_context *c;
1895 if (ast_lock_contexts()) return -1;
1897 /* walk contexts and search for the right one ...*/
1898 c = ast_walk_contexts(NULL);
1900 /* we found one ... */
1901 if (!strcmp(ast_get_context_name(c), context)) {
1903 /* remove include from this context ... */
1904 ret = ast_context_remove_include2(c, include, registrar);
1906 ast_unlock_contexts();
1908 /* ... return results */
1911 c = ast_walk_contexts(c);
1914 /* we can't find the right one context */
1915 ast_unlock_contexts();
1920 * When we call this function, &conlock lock must be locked, because when
1921 * we giving *con argument, some process can remove/change this context
1922 * and after that there can be segfault.
1924 * This function locks given context, removes include, unlock context and
1927 int ast_context_remove_include2(struct ast_context *con, char *include, char *registrar)
1929 struct ast_include *i, *pi = NULL;
1931 if (ast_mutex_lock(&con->lock)) return -1;
1936 /* find our include */
1937 if (!strcmp(i->name, include) &&
1938 (!strcmp(i->registrar, registrar) || !registrar)) {
1939 /* remove from list */
1943 con->includes = i->next;
1944 /* free include and return */
1946 ast_mutex_unlock(&con->lock);
1953 /* we can't find the right include */
1954 ast_mutex_unlock(&con->lock);
1959 * This function locks contexts list by &conlist, search for the rigt context
1960 * structure, leave context list locked and call ast_context_remove_switch2
1961 * which removes switch, unlock contexts list and return ...
1963 int ast_context_remove_switch(char *context, char *sw, char *data, char *registrar)
1965 struct ast_context *c;
1967 if (ast_lock_contexts()) return -1;
1969 /* walk contexts and search for the right one ...*/
1970 c = ast_walk_contexts(NULL);
1972 /* we found one ... */
1973 if (!strcmp(ast_get_context_name(c), context)) {
1975 /* remove switch from this context ... */
1976 ret = ast_context_remove_switch2(c, sw, data, registrar);
1978 ast_unlock_contexts();
1980 /* ... return results */
1983 c = ast_walk_contexts(c);
1986 /* we can't find the right one context */
1987 ast_unlock_contexts();
1992 * When we call this function, &conlock lock must be locked, because when
1993 * we giving *con argument, some process can remove/change this context
1994 * and after that there can be segfault.
1996 * This function locks given context, removes switch, unlock context and
1999 int ast_context_remove_switch2(struct ast_context *con, char *sw, char *data, char *registrar)
2001 struct ast_sw *i, *pi = NULL;
2003 if (ast_mutex_lock(&con->lock)) return -1;
2008 /* find our switch */
2009 if (!strcmp(i->name, sw) && !strcmp(i->data, data) &&
2010 (!strcmp(i->registrar, registrar) || !registrar)) {
2011 /* remove from list */
2015 con->alts = i->next;
2016 /* free switch and return */
2018 ast_mutex_unlock(&con->lock);
2025 /* we can't find the right switch */
2026 ast_mutex_unlock(&con->lock);
2031 * This functions lock contexts list, search for the right context,
2032 * call ast_context_remove_extension2, unlock contexts list and return.
2033 * In this function we are using
2035 int ast_context_remove_extension(char *context, char *extension, int priority, char *registrar)
2037 struct ast_context *c;
2039 if (ast_lock_contexts()) return -1;
2041 /* walk contexts ... */
2042 c = ast_walk_contexts(NULL);
2044 /* ... search for the right one ... */
2045 if (!strcmp(ast_get_context_name(c), context)) {
2046 /* ... remove extension ... */
2047 int ret = ast_context_remove_extension2(c, extension, priority,
2049 /* ... unlock contexts list and return */
2050 ast_unlock_contexts();
2053 c = ast_walk_contexts(c);
2056 /* we can't find the right context */
2057 ast_unlock_contexts();
2062 * When do you want to call this function, make sure that &conlock is locked,
2063 * because some process can handle with your *con context before you lock
2066 * This functionc locks given context, search for the right extension and
2067 * fires out all peer in this extensions with given priority. If priority
2068 * is set to 0, all peers are removed. After that, unlock context and
2071 int ast_context_remove_extension2(struct ast_context *con, char *extension, int priority, char *registrar)
2073 struct ast_exten *exten, *prev_exten = NULL;
2075 if (ast_mutex_lock(&con->lock)) return -1;
2077 /* go through all extensions in context and search the right one ... */
2081 /* look for right extension */
2082 if (!strcmp(exten->exten, extension) &&
2083 (!strcmp(exten->registrar, registrar) || !registrar)) {
2084 struct ast_exten *peer;
2086 /* should we free all peers in this extension? (priority == 0)? */
2087 if (priority == 0) {
2088 /* remove this extension from context list */
2090 prev_exten->next = exten->next;
2092 con->root = exten->next;
2094 /* fire out all peers */
2099 if (!peer->priority==PRIORITY_HINT)
2100 ast_remove_hint(peer);
2102 peer->datad(peer->data);
2108 ast_mutex_unlock(&con->lock);
2111 /* remove only extension with exten->priority == priority */
2112 struct ast_exten *previous_peer = NULL;
2116 /* is this our extension? */
2117 if (peer->priority == priority &&
2118 (!strcmp(peer->registrar, registrar) || !registrar)) {
2119 /* we are first priority extension? */
2120 if (!previous_peer) {
2121 /* exists previous extension here? */
2123 /* yes, so we must change next pointer in
2124 * previous connection to next peer
2127 prev_exten->next = peer->peer;
2128 peer->peer->next = exten->next;
2130 prev_exten->next = exten->next;
2132 /* no previous extension, we are first
2133 * extension, so change con->root ...
2136 con->root = peer->peer;
2138 con->root = exten->next;
2141 /* we are not first priority in extension */
2142 previous_peer->peer = peer->peer;
2145 /* now, free whole priority extension */
2146 if (peer->priority==PRIORITY_HINT)
2147 ast_remove_hint(peer);
2148 peer->datad(peer->data);
2151 ast_mutex_unlock(&con->lock);
2154 /* this is not right extension, skip to next peer */
2155 previous_peer = peer;
2160 ast_mutex_unlock(&con->lock);
2166 exten = exten->next;
2169 /* we can't find right extension */
2170 ast_mutex_unlock(&con->lock);
2175 int ast_register_application(char *app, int (*execute)(struct ast_channel *, void *), char *synopsis, char *description)
2177 struct ast_app *tmp, *prev, *cur;
2179 if (ast_mutex_lock(&applock)) {
2180 ast_log(LOG_ERROR, "Unable to lock application list\n");
2185 if (!strcasecmp(app, tmp->name)) {
2186 ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
2187 ast_mutex_unlock(&applock);
2192 tmp = malloc(sizeof(struct ast_app));
2194 memset(tmp, 0, sizeof(struct ast_app));
2195 strncpy(tmp->name, app, sizeof(tmp->name)-1);
2196 tmp->execute = execute;
2197 tmp->synopsis = synopsis;
2198 tmp->description = description;
2199 /* Store in alphabetical order */
2203 if (strcasecmp(tmp->name, cur->name) < 0)
2209 tmp->next = prev->next;
2216 ast_log(LOG_WARNING, "Out of memory\n");
2217 ast_mutex_unlock(&applock);
2220 if (option_verbose > 1)
2221 ast_verbose( VERBOSE_PREFIX_2 "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
2222 ast_mutex_unlock(&applock);
2226 int ast_register_switch(struct ast_switch *sw)
2228 struct ast_switch *tmp, *prev=NULL;
2229 if (ast_mutex_lock(&switchlock)) {
2230 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
2235 if (!strcasecmp(tmp->name, sw->name))
2241 ast_mutex_unlock(&switchlock);
2242 ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name);
2250 ast_mutex_unlock(&switchlock);
2254 void ast_unregister_switch(struct ast_switch *sw)
2256 struct ast_switch *tmp, *prev=NULL;
2257 if (ast_mutex_lock(&switchlock)) {
2258 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
2265 prev->next = tmp->next;
2267 switches = tmp->next;
2274 ast_mutex_unlock(&switchlock);
2278 * Help for CLI commands ...
2280 static char show_application_help[] =
2281 "Usage: show application <application> [<application> [<application> [...]]]\n"
2282 " Describes a particular application.\n";
2284 static char show_applications_help[] =
2285 "Usage: show applications\n"
2286 " List applications which are currently available.\n";
2288 static char show_dialplan_help[] =
2289 "Usage: show dialplan [exten@][context]\n"
2292 static char show_switches_help[] =
2293 "Usage: show switches\n"
2294 " Show registered switches\n";
2297 * IMPLEMENTATION OF CLI FUNCTIONS IS IN THE SAME ORDER AS COMMANDS HELPS
2302 * 'show application' CLI command implementation functions ...
2306 * There is a possibility to show informations about more than one
2307 * application at one time. You can type 'show application Dial Echo' and
2308 * you will see informations about these two applications ...
2310 static char *complete_show_application(char *line, char *word,
2316 /* try to lock applications list ... */
2317 if (ast_mutex_lock(&applock)) {
2318 ast_log(LOG_ERROR, "Unable to lock application list\n");
2322 /* ... walk all applications ... */
2325 /* ... check if word matches this application ... */
2326 if (!strncasecmp(word, a->name, strlen(word))) {
2327 /* ... if this is right app serve it ... */
2328 if (++which > state) {
2329 char *ret = strdup(a->name);
2330 ast_mutex_unlock(&applock);
2337 /* no application match */
2338 ast_mutex_unlock(&applock);
2342 static int handle_show_application(int fd, int argc, char *argv[])
2345 int app, no_registered_app = 1;
2347 if (argc < 3) return RESULT_SHOWUSAGE;
2349 /* try to lock applications list ... */
2350 if (ast_mutex_lock(&applock)) {
2351 ast_log(LOG_ERROR, "Unable to lock application list\n");
2355 /* ... go through all applications ... */
2358 /* ... compare this application name with all arguments given
2359 * to 'show application' command ... */
2360 for (app = 2; app < argc; app++) {
2361 if (!strcasecmp(a->name, argv[app])) {
2362 /* Maximum number of characters added by terminal coloring is 22 */
2363 char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
2364 char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
2365 int synopsis_size, description_size;
2367 no_registered_app = 0;
2370 synopsis_size = strlen(a->synopsis) + 23;
2372 synopsis_size = strlen("Not available") + 23;
2373 synopsis = alloca(synopsis_size);
2376 description_size = strlen(a->description) + 23;
2378 description_size = strlen("Not available") + 23;
2379 description = alloca(description_size);
2381 if (synopsis && description) {
2382 snprintf(info, 64 + AST_MAX_APP, "\n -= Info about application '%s' =- \n\n", a->name);
2383 term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
2384 term_color(syntitle, "[Synopsis]:\n", COLOR_MAGENTA, 0, 40);
2385 term_color(destitle, "[Description]:\n", COLOR_MAGENTA, 0, 40);
2386 term_color(synopsis,
2387 a->synopsis ? a->synopsis : "Not available",
2388 COLOR_CYAN, 0, synopsis_size);
2389 term_color(description,
2390 a->description ? a->description : "Not available",
2391 COLOR_CYAN, 0, description_size);
2393 ast_cli(fd,"%s%s%s\n\n%s%s\n", infotitle, syntitle, synopsis, destitle, description);
2395 /* ... one of our applications, show info ...*/
2396 ast_cli(fd,"\n -= Info about application '%s' =- \n\n"
2397 "[Synopsis]:\n %s\n\n"
2398 "[Description]:\n%s\n",
2400 a->synopsis ? a->synopsis : "Not available",
2401 a->description ? a->description : "Not available");
2408 ast_mutex_unlock(&applock);
2410 /* we found at least one app? no? */
2411 if (no_registered_app) {
2412 ast_cli(fd, "Your application(s) is (are) not registered\n");
2413 return RESULT_FAILURE;
2416 return RESULT_SUCCESS;
2419 static int handle_show_switches(int fd, int argc, char *argv[])
2421 struct ast_switch *sw;
2423 ast_cli(fd, "There are no registered alternative switches\n");
2424 return RESULT_SUCCESS;
2426 /* ... we have applications ... */
2427 ast_cli(fd, "\n -= Registered Asterisk Alternative Switches =-\n");
2428 if (ast_mutex_lock(&switchlock)) {
2429 ast_log(LOG_ERROR, "Unable to lock switches\n");
2434 ast_cli(fd, "%s: %s\n", sw->name, sw->description);
2437 ast_mutex_unlock(&switchlock);
2438 return RESULT_SUCCESS;
2442 * 'show applications' CLI command implementation functions ...
2444 static int handle_show_applications(int fd, int argc, char *argv[])
2448 /* try to lock applications list ... */
2449 if (ast_mutex_lock(&applock)) {
2450 ast_log(LOG_ERROR, "Unable to lock application list\n");
2454 /* ... go to first application ... */
2457 /* ... have we got at least one application (first)? no? */
2459 ast_cli(fd, "There is no registered applications\n");
2460 ast_mutex_unlock(&applock);
2464 /* ... we have applications ... */
2465 ast_cli(fd, "\n -= Registered Asterisk Applications =-\n");
2467 /* ... go through all applications ... */
2469 /* ... show informations about applications ... */
2470 ast_cli(fd," %15s: %s\n",
2472 a->synopsis ? a->synopsis : "<Synopsis not available>");
2476 /* ... unlock and return */
2477 ast_mutex_unlock(&applock);
2479 return RESULT_SUCCESS;
2483 * 'show dialplan' CLI command implementation functions ...
2485 static char *complete_show_dialplan_context(char *line, char *word, int pos,
2488 struct ast_context *c;
2491 /* we are do completion of [exten@]context on second position only */
2492 if (pos != 2) return NULL;
2494 /* try to lock contexts list ... */
2495 if (ast_lock_contexts()) {
2496 ast_log(LOG_ERROR, "Unable to lock context list\n");
2500 /* ... walk through all contexts ... */
2501 c = ast_walk_contexts(NULL);
2503 /* ... word matches context name? yes? ... */
2504 if (!strncasecmp(word, ast_get_context_name(c), strlen(word))) {
2505 /* ... for serve? ... */
2506 if (++which > state) {
2507 /* ... yes, serve this context name ... */
2508 char *ret = strdup(ast_get_context_name(c));
2509 ast_unlock_contexts();
2513 c = ast_walk_contexts(c);
2516 /* ... unlock and return */
2517 ast_unlock_contexts();
2521 static int handle_show_dialplan(int fd, int argc, char *argv[])
2523 struct ast_context *c;
2524 char *exten = NULL, *context = NULL;
2525 int context_existence = 0, extension_existence = 0;
2527 if (argc != 3 && argc != 2) return -1;
2529 /* we obtain [exten@]context? if yes, split them ... */
2531 char *splitter = argv[2];
2532 /* is there a '@' character? */
2533 if (strchr(argv[2], '@')) {
2534 /* yes, split into exten & context ... */
2535 exten = strsep(&splitter, "@");
2538 /* check for length and change to NULL if !strlen() */
2539 if (!strlen(exten)) exten = NULL;
2540 if (!strlen(context)) context = NULL;
2543 /* no '@' char, only context given */
2545 if (!strlen(context)) context = NULL;
2549 /* try to lock contexts */
2550 if (ast_lock_contexts()) {
2551 ast_log(LOG_WARNING, "Failed to lock contexts list\n");
2552 return RESULT_FAILURE;
2555 /* walk all contexts ... */
2556 c = ast_walk_contexts(NULL);
2558 /* show this context? */
2560 !strcmp(ast_get_context_name(c), context)) {
2561 context_existence = 1;
2563 /* try to lock context before walking in ... */
2564 if (!ast_lock_context(c)) {
2565 struct ast_exten *e;
2566 struct ast_include *i;
2567 struct ast_ignorepat *ip;
2569 char buf[256], buf2[256];
2570 int context_info_printed = 0;
2572 /* are we looking for exten too? if yes, we print context
2573 * if we our extension only
2576 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
2577 ast_get_context_name(c), ast_get_context_registrar(c));
2578 context_info_printed = 1;
2581 /* walk extensions ... */
2582 e = ast_walk_context_extensions(c, NULL);
2584 struct ast_exten *p;
2586 /* looking for extension? is this our extension? */
2588 strcmp(ast_get_extension_name(e), exten))
2590 /* we are looking for extension and it's not our
2591 * extension, so skip to next extension */
2592 e = ast_walk_context_extensions(c, e);
2596 extension_existence = 1;
2598 /* may we print context info? */
2599 if (!context_info_printed) {
2600 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
2601 ast_get_context_name(c),
2602 ast_get_context_registrar(c));
2603 context_info_printed = 1;
2606 /* write extension name and first peer */
2607 bzero(buf, sizeof(buf));
2608 snprintf(buf, sizeof(buf), "'%s' =>",
2609 ast_get_extension_name(e));
2611 snprintf(buf2, sizeof(buf2),
2613 ast_get_extension_priority(e),
2614 ast_get_extension_app(e),
2615 (char *)ast_get_extension_app_data(e));
2617 ast_cli(fd, " %-17s %-45s [%s]\n", buf, buf2,
2618 ast_get_extension_registrar(e));
2620 /* walk next extension peers */
2621 p = ast_walk_extension_priorities(e, e);
2623 bzero((void *)buf2, sizeof(buf2));
2625 snprintf(buf2, sizeof(buf2),
2627 ast_get_extension_priority(p),
2628 ast_get_extension_app(p),
2629 (char *)ast_get_extension_app_data(p));
2631 ast_cli(fd," %-17s %-45s [%s]\n",
2633 ast_get_extension_registrar(p));
2635 p = ast_walk_extension_priorities(e, p);
2637 e = ast_walk_context_extensions(c, e);
2640 /* include & ignorepat we all printing if we are not
2641 * looking for exact extension
2644 if (ast_walk_context_extensions(c, NULL))
2647 /* walk included and write info ... */
2648 i = ast_walk_context_includes(c, NULL);
2650 bzero(buf, sizeof(buf));
2651 snprintf(buf, sizeof(buf), "'%s'",
2652 ast_get_include_name(i));
2653 ast_cli(fd, " Include => %-45s [%s]\n",
2654 buf, ast_get_include_registrar(i));
2655 i = ast_walk_context_includes(c, i);
2658 /* walk ignore patterns and write info ... */
2659 ip = ast_walk_context_ignorepats(c, NULL);
2661 bzero(buf, sizeof(buf));
2662 snprintf(buf, sizeof(buf), "'%s'",
2663 ast_get_ignorepat_name(ip));
2664 ast_cli(fd, " Ignore pattern => %-45s [%s]\n",
2665 buf, ast_get_ignorepat_registrar(ip));
2666 ip = ast_walk_context_ignorepats(c, ip);
2668 sw = ast_walk_context_switches(c, NULL);
2670 bzero(buf, sizeof(buf));
2671 snprintf(buf, sizeof(buf), "'%s/%s'",
2672 ast_get_switch_name(sw),
2673 ast_get_switch_data(sw));
2674 ast_cli(fd, " Alt. Switch => %-45s [%s]\n",
2675 buf, ast_get_switch_registrar(sw));
2676 sw = ast_walk_context_switches(c, sw);
2680 ast_unlock_context(c);
2682 /* if we print something in context, make an empty line */
2683 if (context_info_printed) ast_cli(fd, "\n");
2686 c = ast_walk_contexts(c);
2688 ast_unlock_contexts();
2690 /* check for input failure and throw some error messages */
2691 if (context && !context_existence) {
2692 ast_cli(fd, "There is no existence of '%s' context\n",
2694 return RESULT_FAILURE;
2697 if (exten && !extension_existence) {
2699 ast_cli(fd, "There is no existence of %s@%s extension\n",
2703 "There is no existence of '%s' extension in all contexts\n",
2705 return RESULT_FAILURE;
2709 return RESULT_SUCCESS;
2713 * CLI entries for upper commands ...
2715 static struct ast_cli_entry show_applications_cli =
2716 { { "show", "applications", NULL },
2717 handle_show_applications, "Shows registered applications",
2718 show_applications_help };
2720 static struct ast_cli_entry show_application_cli =
2721 { { "show", "application", NULL },
2722 handle_show_application, "Describe a specific application",
2723 show_application_help, complete_show_application };
2725 static struct ast_cli_entry show_dialplan_cli =
2726 { { "show", "dialplan", NULL },
2727 handle_show_dialplan, "Show dialplan",
2728 show_dialplan_help, complete_show_dialplan_context };
2730 static struct ast_cli_entry show_switches_cli =
2731 { { "show", "switches", NULL },
2732 handle_show_switches, "Show alternative switches",
2733 show_switches_help, NULL };
2735 int ast_unregister_application(char *app) {
2736 struct ast_app *tmp, *tmpl = NULL;
2737 if (ast_mutex_lock(&applock)) {
2738 ast_log(LOG_ERROR, "Unable to lock application list\n");
2743 if (!strcasecmp(app, tmp->name)) {
2745 tmpl->next = tmp->next;
2748 if (option_verbose > 1)
2749 ast_verbose( VERBOSE_PREFIX_2 "Unregistered application '%s'\n", tmp->name);
2750 ast_mutex_unlock(&applock);
2756 ast_mutex_unlock(&applock);
2760 struct ast_context *ast_context_create(struct ast_context **extcontexts, char *name, char *registrar)
2762 struct ast_context *tmp, **local_contexts;
2764 local_contexts = &contexts;
2765 ast_mutex_lock(&conlock);
2767 local_contexts = extcontexts;
2769 tmp = *local_contexts;
2771 if (!strcasecmp(tmp->name, name)) {
2772 ast_mutex_unlock(&conlock);
2773 ast_log(LOG_WARNING, "Tried to register context '%s', already in use\n", name);
2775 ast_mutex_unlock(&conlock);
2780 tmp = malloc(sizeof(struct ast_context));
2782 memset(tmp, 0, sizeof(struct ast_context));
2783 ast_mutex_init(&tmp->lock);
2784 strncpy(tmp->name, name, sizeof(tmp->name)-1);
2786 tmp->registrar = registrar;
2787 tmp->next = *local_contexts;
2788 tmp->includes = NULL;
2789 tmp->ignorepats = NULL;
2790 *local_contexts = tmp;
2792 ast_log(LOG_DEBUG, "Registered context '%s'\n", tmp->name);
2793 else if (option_verbose > 2)
2794 ast_verbose( VERBOSE_PREFIX_3 "Registered extension context '%s'\n", tmp->name);
2796 ast_log(LOG_WARNING, "Out of memory\n");
2799 ast_mutex_unlock(&conlock);
2803 void __ast_context_destroy(struct ast_context *con, char *registrar, int lock);
2805 void ast_merge_contexts_and_delete(struct ast_context **extcontexts, char *registrar) {
2806 struct ast_context *tmp, *lasttmp = NULL;
2808 ast_mutex_lock(&conlock);
2810 __ast_context_destroy(NULL,registrar,0);
2817 __ast_context_destroy(tmp,tmp->registrar,0);
2823 lasttmp->next = contexts;
2824 contexts = *extcontexts;
2825 *extcontexts = NULL;
2827 ast_log(LOG_WARNING, "Requested contexts didn't get merged\n");
2828 ast_mutex_unlock(&conlock);
2834 * EBUSY - can't lock
2835 * ENOENT - no existence of context
2837 int ast_context_add_include(char *context, char *include, char *registrar)
2839 struct ast_context *c;
2841 if (ast_lock_contexts()) {
2846 /* walk contexts ... */
2847 c = ast_walk_contexts(NULL);
2849 /* ... search for the right one ... */
2850 if (!strcmp(ast_get_context_name(c), context)) {
2851 int ret = ast_context_add_include2(c, include, registrar);
2852 /* ... unlock contexts list and return */
2853 ast_unlock_contexts();
2856 c = ast_walk_contexts(c);
2859 /* we can't find the right context */
2860 ast_unlock_contexts();
2868 while(*c && (*c != '|')) c++; \
2869 if (*c) { *c = '\0'; c++; } else c = NULL; \
2872 static void get_timerange(struct ast_include *i, char *times)
2880 //start disabling all times, fill the fields with 0's, as they may contain garbage
2881 memset(i->minmask, 0, sizeof(i->minmask));
2883 /* Star is all times */
2884 if (!strlen(times) || !strcmp(times, "*")) {
2886 i->minmask[x] = (1 << 30) - 1;
2889 /* Otherwise expect a range */
2890 e = strchr(times, '-');
2892 ast_log(LOG_WARNING, "Time range is not valid. Assuming no time.\n");
2897 while(*e && !isdigit(*e)) e++;
2899 ast_log(LOG_WARNING, "Invalid time range. Assuming no time.\n");
2902 if (sscanf(times, "%d:%d", &s1, &s2) != 2) {
2903 ast_log(LOG_WARNING, "%s isn't a time. Assuming no time.\n", times);
2906 if (sscanf(e, "%d:%d", &e1, &e2) != 2) {
2907 ast_log(LOG_WARNING, "%s isn't a time. Assuming no time.\n", e);
2910 s1 = s1 * 30 + s2/2;
2911 if ((s1 < 0) || (s1 >= 24*30)) {
2912 ast_log(LOG_WARNING, "%s isn't a valid star time. Assuming no time.\n", times);
2915 e1 = e1 * 30 + e2/2;
2916 if ((e1 < 0) || (e2 >= 24*30)) {
2917 ast_log(LOG_WARNING, "%s isn't a valid start time. Assuming no time.\n", times);
2920 /* Go through the time and enable each appropriate bit */
2921 for (x=s1;x != e1;x = (x + 1) % (24 * 30)) {
2922 i->minmask[x/30] |= (1 << (x % 30));
2924 /* Do the last one */
2925 i->minmask[x/30] |= (1 << (x % 30));
2930 static char *days[] =
2941 static unsigned int get_dow(char *dow)
2944 /* The following line is coincidence, really! */
2947 /* Check for all days */
2948 if (!strlen(dow) || !strcmp(dow, "*"))
2949 return (1 << 7) - 1;
2950 /* Get start and ending days */
2951 c = strchr(dow, '-');
2957 /* Find the start */
2959 while((s < 7) && strcasecmp(dow, days[s])) s++;
2961 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", dow);
2966 while((e < 7) && strcasecmp(c, days[e])) e++;
2968 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
2974 for (x=s;x!=e;x = (x + 1) % 7) {
2982 static unsigned int get_day(char *day)
2985 /* The following line is coincidence, really! */
2988 /* Check for all days */
2989 if (!strlen(day) || !strcmp(day, "*")) {
2990 mask = (1 << 30) + ((1 << 30) - 1);
2993 /* Get start and ending days */
2994 c = strchr(day, '-');
2999 /* Find the start */
3000 if (sscanf(day, "%d", &s) != 1) {
3001 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", day);
3004 if ((s < 1) || (s > 31)) {
3005 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", day);
3010 if (sscanf(c, "%d", &e) != 1) {
3011 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
3014 if ((e < 1) || (e > 31)) {
3015 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
3022 for (x=s;x!=e;x = (x + 1) % 31) {
3029 static char *months[] =
3045 static unsigned int get_month(char *mon)
3048 /* The following line is coincidence, really! */
3051 /* Check for all days */
3052 if (!strlen(mon) || !strcmp(mon, "*"))
3053 return (1 << 12) - 1;
3054 /* Get start and ending days */
3055 c = strchr(mon, '-');
3060 /* Find the start */
3062 while((s < 12) && strcasecmp(mon, months[s])) s++;
3064 ast_log(LOG_WARNING, "Invalid month '%s', assuming none\n", mon);
3069 while((e < 12) && strcasecmp(mon, months[e])) e++;
3071 ast_log(LOG_WARNING, "Invalid month '%s', assuming none\n", c);
3077 for (x=s;x!=e;x = (x + 1) % 12) {
3085 static void build_timing(struct ast_include *i, char *info)
3088 /* Check for empty just in case */
3092 /* Assume everything except time */
3093 i->monthmask = (1 << 12) - 1;
3094 i->daymask = (1 << 30) - 1 + (1 << 30);
3095 i->dowmask = (1 << 7) - 1;
3096 /* Avoid using str tok */
3098 /* Info has the time range, start with that */
3099 get_timerange(i, info);
3104 /* Now check for day of week */
3105 i->dowmask = get_dow(info);