2 * Asterisk -- A telephony toolkit for Linux.
6 * Copyright (C) 1999, Mark Spencer
8 * Mark Spencer <markster@digium.com>
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>
30 #include <asterisk/utils.h>
45 * The speed of extension handling will likely be among the most important
46 * aspects of this PBX. The switching scheme as it exists right now isn't
47 * terribly bad (it's O(N+M), where N is the # of extensions and M is the avg #
48 * of priorities, but a constant search time here would be great ;-)
53 #define EXT_DATA_SIZE 256
55 #define EXT_DATA_SIZE 8192
60 /* ast_exten: An extension */
62 char exten[AST_MAX_EXTENSION]; /* Extension name */
63 int matchcid; /* Match caller id ? */
64 char cidmatch[AST_MAX_EXTENSION]; /* Caller id to match for this extension */
65 int priority; /* Priority */
66 struct ast_context *parent; /* An extension */
67 char app[AST_MAX_EXTENSION]; /* Application to execute */
68 void *data; /* Data to use */
69 void (*datad)(void *); /* Data destructor */
70 struct ast_exten *peer; /* Next higher priority with our extension */
71 char *registrar; /* Registrar */
72 struct ast_exten *next; /* Extension with a greater ID */
75 /* ast_include: include= support in extensions.conf */
77 char name[AST_MAX_EXTENSION];
78 char rname[AST_MAX_EXTENSION]; /* Context to include */
79 char *registrar; /* Registrar */
80 int hastime; /* If time construct exists */
81 unsigned int monthmask; /* Mask for month */
82 unsigned int daymask; /* Mask for date */
83 unsigned int dowmask; /* Mask for day of week (mon-sun) */
84 unsigned int minmask[24]; /* Mask for minute */
85 struct ast_include *next; /* Link them together */
88 /* ast_sw: Switch statement in extensions.conf */
90 char name[AST_MAX_EXTENSION];
91 char *registrar; /* Registrar */
92 char data[AST_MAX_EXTENSION]; /* Data load */
93 struct ast_sw *next; /* Link them together */
96 struct ast_ignorepat {
97 char pattern[AST_MAX_EXTENSION];
99 struct ast_ignorepat *next;
102 /* ast_context: An extension context */
104 char name[AST_MAX_EXTENSION]; /* Name of the context */
105 ast_mutex_t lock; /* A lock to prevent multiple threads from clobbering the context */
106 struct ast_exten *root; /* The root of the list of extensions */
107 struct ast_context *next; /* Link them together */
108 struct ast_include *includes; /* Include other contexts */
109 struct ast_ignorepat *ignorepats; /* Patterns for which to continue playing dialtone */
110 char *registrar; /* Registrar */
111 struct ast_sw *alts; /* Alternative switches */
115 /* ast_app: An application */
117 char name[AST_MAX_APP]; /* Name of the application */
118 int (*execute)(struct ast_channel *chan, void *data);
119 char *synopsis; /* Synopsis text for 'show applications' */
120 char *description; /* Description (help text) for 'show application <name>' */
121 struct ast_app *next; /* Next app in list */
124 /* ast_state_cb: An extension state notify */
125 struct ast_state_cb {
128 ast_state_cb_type callback;
129 struct ast_state_cb *next;
133 struct ast_exten *exten;
135 struct ast_state_cb *callbacks;
136 struct ast_hint *next;
140 static int pbx_builtin_prefix(struct ast_channel *, void *);
141 static int pbx_builtin_suffix(struct ast_channel *, void *);
142 static int pbx_builtin_stripmsd(struct ast_channel *, void *);
143 static int pbx_builtin_answer(struct ast_channel *, void *);
144 static int pbx_builtin_goto(struct ast_channel *, void *);
145 static int pbx_builtin_hangup(struct ast_channel *, void *);
146 static int pbx_builtin_background(struct ast_channel *, void *);
147 static int pbx_builtin_dtimeout(struct ast_channel *, void *);
148 static int pbx_builtin_rtimeout(struct ast_channel *, void *);
149 static int pbx_builtin_atimeout(struct ast_channel *, void *);
150 static int pbx_builtin_wait(struct ast_channel *, void *);
151 static int pbx_builtin_waitexten(struct ast_channel *, void *);
152 static int pbx_builtin_setlanguage(struct ast_channel *, void *);
153 static int pbx_builtin_resetcdr(struct ast_channel *, void *);
154 static int pbx_builtin_setaccount(struct ast_channel *, void *);
155 static int pbx_builtin_setamaflags(struct ast_channel *, void *);
156 static int pbx_builtin_ringing(struct ast_channel *, void *);
157 static int pbx_builtin_progress(struct ast_channel *, void *);
158 static int pbx_builtin_congestion(struct ast_channel *, void *);
159 static int pbx_builtin_busy(struct ast_channel *, void *);
160 static int pbx_builtin_setglobalvar(struct ast_channel *, void *);
161 static int pbx_builtin_noop(struct ast_channel *, void *);
162 static int pbx_builtin_gotoif(struct ast_channel *, void *);
163 static int pbx_builtin_gotoiftime(struct ast_channel *, void *);
164 static int pbx_builtin_saynumber(struct ast_channel *, void *);
165 static int pbx_builtin_saydigits(struct ast_channel *, void *);
166 static int pbx_builtin_saycharacters(struct ast_channel *, void *);
167 static int pbx_builtin_sayphonetic(struct ast_channel *, void *);
168 int pbx_builtin_setvar(struct ast_channel *, void *);
169 void pbx_builtin_setvar_helper(struct ast_channel *chan, char *name, char *value);
170 char *pbx_builtin_getvar_helper(struct ast_channel *chan, char *name);
172 static struct varshead globals;
174 static struct pbx_builtin {
175 char name[AST_MAX_APP];
176 int (*execute)(struct ast_channel *chan, void *data);
181 /* These applications are built into the PBX core and do not
182 need separate modules
186 { "AbsoluteTimeout", pbx_builtin_atimeout,
187 "Set absolute maximum time of call",
188 " AbsoluteTimeout(seconds): Set the absolute maximum amount of time permitted\n"
189 "for a call. A setting of 0 disables the timeout. Always returns 0.\n"
192 { "Answer", pbx_builtin_answer,
193 "Answer a channel if ringing",
194 " Answer(): If the channel is ringing, answer it, otherwise do nothing. \n"
195 "Returns 0 unless it tries to answer the channel and fails.\n"
198 { "BackGround", pbx_builtin_background,
199 "Play a file while awaiting extension",
200 " Background(filename[|options[|langoverride]]): Plays a given file, while simultaneously\n"
201 "waiting for the user to begin typing an extension. The timeouts do not\n"
202 "count until the last BackGround application has ended.\n"
203 "Options may also be included following a pipe symbol. The 'skip'\n"
204 "option causes the playback of the message to be skipped if the channel\n"
205 "is not in the 'up' state (i.e. it hasn't been answered yet. If 'skip' is \n"
206 "specified, the application will return immediately should the channel not be\n"
207 "off hook. Otherwise, unless 'noanswer' is specified, the channel channel will\n"
208 "be answered before the sound is played. Not all channels support playing\n"
209 "messages while still hook. The 'langoverride' may be a language to use for\n"
210 "playing the prompt which differs from the current language of the channel\n"
211 "Returns -1 if the channel was hung up, or if the file does not exist. \n"
212 "Returns 0 otherwise.\n"
215 { "Busy", pbx_builtin_busy,
216 "Indicate busy condition and stop",
217 " Busy([timeout]): Requests that the channel indicate busy condition and\n"
218 "then waits for the user to hang up or the optional timeout to expire.\n"
222 { "Congestion", pbx_builtin_congestion,
223 "Indicate congestion and stop",
224 " Congestion([timeout]): Requests that the channel indicate congestion\n"
225 "and then waits for the user to hang up or for the optional timeout to\n"
226 "expire. Always returns -1."
229 { "DigitTimeout", pbx_builtin_dtimeout,
230 "Set maximum timeout between digits",
231 " DigitTimeout(seconds): Set the maximum amount of time permitted between\n"
232 "digits when the user is typing in an extension. When this timeout expires,\n"
233 "after the user has started to type in an extension, the extension will be\n"
234 "considered complete, and will be interpreted. Note that if an extension\n"
235 "typed in is valid, it will not have to timeout to be tested, so typically\n"
236 "at the expiry of this timeout, the extension will be considered invalid\n"
237 "(and thus control would be passed to the 'i' extension, or if it doesn't\n"
238 "exist the call would be terminated). Always returns 0.\n"
241 { "Goto", pbx_builtin_goto,
242 "Goto a particular priority, extension, or context",
243 " Goto([[context|]extension|]priority): Set the priority to the specified\n"
244 "value, optionally setting the extension and optionally the context as well.\n"
245 "The extension BYEXTENSION is special in that it uses the current extension,\n"
246 "thus permitting you to go to a different context, without specifying a\n"
247 "specific extension. Always returns 0, even if the given context, extension,\n"
248 "or priority is invalid.\n"
251 { "GotoIf", pbx_builtin_gotoif,
253 " GotoIf(Condition?label1:label2): Go to label 1 if condition is\n"
254 "true, to label2 if condition is false. Either label1 or label2 may be\n"
255 "omitted (in that case, we just don't take the particular branch) but not\n"
256 "both. Look for the condition syntax in examples or documentation."
259 { "GotoIfTime", pbx_builtin_gotoiftime,
260 "Conditional goto on current time",
261 " GotoIfTime(<times>|<weekdays>|<mdays>|<months>?[[context|]extension|]pri):\n"
262 "If the current time matches the specified time, then branch to the specified\n"
263 "extension. Each of the elements may be specified either as '*' (for always)\n"
264 "or as a range. See the 'include' syntax for details."
267 { "Hangup", pbx_builtin_hangup,
268 "Unconditional hangup",
269 " Hangup(): Unconditionally hangs up a given channel by returning -1 always.\n"
272 { "NoOp", pbx_builtin_noop,
274 " NoOp(): No-operation; Does nothing."
277 { "Prefix", pbx_builtin_prefix,
278 "Prepend leading digits",
279 " Prefix(digits): Prepends the digit string specified by digits to the\n"
280 "channel's associated extension. For example, the number 1212 when prefixed\n"
281 "with '555' will become 5551212. This app always returns 0, and the PBX will\n"
282 "continue processing at the next priority for the *new* extension.\n"
283 " So, for example, if priority 3 of 1212 is Prefix 555, the next step\n"
284 "executed will be priority 4 of 5551212. If you switch into an extension\n"
285 "which has no first step, the PBX will treat it as though the user dialed an\n"
286 "invalid extension.\n"
289 { "Progress", pbx_builtin_progress,
291 " Progress(): Request that the channel indicate in-band progress is \n"
292 "available to the user.\nAlways returns 0.\n"
295 { "ResetCDR", pbx_builtin_resetcdr,
296 "Resets the Call Data Record",
297 " ResetCDR([options]): Causes the Call Data Record to be reset, optionally\n"
298 "storing the current CDR before zeroing it out (if 'w' option is specifed).\n"
299 "record WILL be stored.\nAlways returns 0.\n"
302 { "ResponseTimeout", pbx_builtin_rtimeout,
303 "Set maximum timeout awaiting response",
304 " ResponseTimeout(seconds): Set the maximum amount of time permitted after\n"
305 "falling through a series of priorities for a channel in which the user may\n"
306 "begin typing an extension. If the user does not type an extension in this\n"
307 "amount of time, control will pass to the 't' extension if it exists, and\n"
308 "if not the call would be terminated.\nAlways returns 0.\n"
311 { "Ringing", pbx_builtin_ringing,
312 "Indicate ringing tone",
313 " Ringing(): Request that the channel indicate ringing tone to the user.\n"
314 "Always returns 0.\n"
317 { "SayNumber", pbx_builtin_saynumber,
319 " SayNumber(digits[,gender]): Says the passed number. SayNumber is using\n"
320 "the current language setting for the channel. (See app SetLanguage).\n"
323 { "SayDigits", pbx_builtin_saydigits,
325 " SayDigits(digits): Says the passed digits. SayDigits is using the\n"
326 "current language setting for the channel. (See app setLanguage)\n"
329 { "SayAlpha", pbx_builtin_saycharacters,
331 " SayAlpha(string): Spells the passed string\n"
334 { "SayPhonetic", pbx_builtin_sayphonetic,
336 " SayPhonetic(string): Spells the passed string with phonetic alphabet\n"
339 { "SetAccount", pbx_builtin_setaccount,
341 " SetAccount([account]): Set the channel account code for billing\n"
342 "purposes. Always returns 0.\n"
345 { "SetAMAFlags", pbx_builtin_setamaflags,
347 " SetAMAFlags([flag]): Set the channel AMA Flags for billing\n"
348 "purposes. Always returns 0.\n"
351 { "SetGlobalVar", pbx_builtin_setglobalvar,
352 "Set global variable to value",
353 " SetGlobalVar(#n=value): Sets global variable n to value. Global\n"
354 "variable are available across channels.\n"
357 { "SetLanguage", pbx_builtin_setlanguage,
358 "Sets user language",
359 " SetLanguage(language): Set the channel language to 'language'. This\n"
360 "information is used for the syntax in generation of numbers, and to choose\n"
361 "a natural language file when available.\n"
362 " For example, if language is set to 'fr' and the file 'demo-congrats' is \n"
363 "requested to be played, if the file 'fr/demo-congrats' exists, then\n"
364 "it will play that file, and if not will play the normal 'demo-congrats'.\n"
365 "Always returns 0.\n"
368 { "SetVar", pbx_builtin_setvar,
369 "Set variable to value",
370 " Setvar(#n=value): Sets channel specific variable n to value"
373 { "StripMSD", pbx_builtin_stripmsd,
374 "Strip leading digits",
375 " StripMSD(count): Strips the leading 'count' digits from the channel's\n"
376 "associated extension. For example, the number 5551212 when stripped with a\n"
377 "count of 3 would be changed to 1212. This app always returns 0, and the PBX\n"
378 "will continue processing at the next priority for the *new* extension.\n"
379 " So, for example, if priority 3 of 5551212 is StripMSD 3, the next step\n"
380 "executed will be priority 4 of 1212. If you switch into an extension which\n"
381 "has no first step, the PBX will treat it as though the user dialed an\n"
382 "invalid extension.\n"
385 { "Suffix", pbx_builtin_suffix,
386 "Append trailing digits",
387 " Suffix(digits): Appends the digit string specified by digits to the\n"
388 "channel's associated extension. For example, the number 555 when suffixed\n"
389 "with '1212' will become 5551212. This app always returns 0, and the PBX will\n"
390 "continue processing at the next priority for the *new* extension.\n"
391 " So, for example, if priority 3 of 555 is Suffix 1212, the next step\n"
392 "executed will be priority 4 of 5551212. If you switch into an extension\n"
393 "which has no first step, the PBX will treat it as though the user dialed an\n"
394 "invalid extension.\n"
397 { "Wait", pbx_builtin_wait,
398 "Waits for some time",
399 " Wait(seconds): Waits for a specified number of seconds, then returns 0.\n"
400 "seconds can be passed with fractions of a second. (eg: 1.5 = 1.5 seconds)\n"
403 { "WaitExten", pbx_builtin_waitexten,
404 "Waits for some time",
405 " Wait(seconds): Waits for the user to enter a new extension for the \n"
406 "specified number of seconds, then returns 0. Seconds can be passed with\n"
407 "fractions of a second. (eg: 1.5 = 1.5 seconds)\n"
412 AST_MUTEX_DEFINE_STATIC(applock); /* Lock for the application list */
413 static struct ast_context *contexts = NULL;
414 AST_MUTEX_DEFINE_STATIC(conlock); /* Lock for the ast_context list */
415 static struct ast_app *apps = NULL;
417 AST_MUTEX_DEFINE_STATIC(switchlock); /* Lock for switches */
418 struct ast_switch *switches = NULL;
420 AST_MUTEX_DEFINE_STATIC(hintlock); /* Lock for extension state notifys */
421 static int stateid = 1;
422 struct ast_hint *hints = NULL;
423 struct ast_state_cb *statecbs = NULL;
425 int pbx_exec(struct ast_channel *c, /* Channel */
426 struct ast_app *app, /* Application */
427 void *data, /* Data for execution */
428 int newstack) /* Force stack increment */
430 /* This function is special. It saves the stack so that no matter
431 how many times it is called, it returns to the same place */
437 int stack = c->stack;
438 int (*execute)(struct ast_channel *chan, void *data) = app->execute;
440 if (newstack && stack > AST_CHANNEL_MAX_STACK - 2) {
441 /* Don't allow us to go over the max number of stacks we
443 ast_log(LOG_WARNING, "Stack overflow, cannot create another stack\n");
446 if (newstack && (res = setjmp(c->jmp[++c->stack]))) {
447 /* Okay, here's where it gets weird. If newstack is non-zero,
448 then we increase the stack increment, but setjmp is not going
449 to return until longjmp is called -- when the application
450 exec'd is finished running. */
453 if (c->stack != stack + 1)
454 ast_log(LOG_WARNING, "Stack returned to an unexpected place!\n");
455 else if (c->app[c->stack])
456 ast_log(LOG_WARNING, "Application may have forgotten to free its memory\n");
461 ast_cdr_setapp(c->cdr, app->name, data);
463 /* save channel values */
464 saved_c_appl= c->appl;
465 saved_c_data= c->data;
469 res = execute(c, data);
470 /* restore channel values */
471 c->appl= saved_c_appl;
472 c->data= saved_c_data;
474 /* Any application that returns, we longjmp back, just in case. */
475 if (c->stack != stack + 1)
476 ast_log(LOG_WARNING, "Stack is not at expected value\n");
477 longjmp(c->jmp[stack+1], res);
483 /* Go no deeper than this through includes (not counting loops) */
484 #define AST_PBX_MAX_STACK 64
486 #define HELPER_EXISTS 0
487 #define HELPER_SPAWN 1
488 #define HELPER_EXEC 2
489 #define HELPER_CANMATCH 3
490 #define HELPER_MATCHMORE 4
492 struct ast_app *pbx_findapp(char *app)
496 if (ast_mutex_lock(&applock)) {
497 ast_log(LOG_WARNING, "Unable to obtain application lock\n");
502 if (!strcasecmp(tmp->name, app))
506 ast_mutex_unlock(&applock);
510 static struct ast_switch *pbx_findswitch(char *sw)
512 struct ast_switch *asw;
514 if (ast_mutex_lock(&switchlock)) {
515 ast_log(LOG_WARNING, "Unable to obtain application lock\n");
520 if (!strcasecmp(asw->name, sw))
524 ast_mutex_unlock(&switchlock);
528 static inline int include_valid(struct ast_include *i)
538 /* If it's not the right month, return */
539 if (!(i->monthmask & (1 << tm.tm_mon))) {
543 /* If it's not that time of the month.... */
544 /* Warning, tm_mday has range 1..31! */
545 if (!(i->daymask & (1 << (tm.tm_mday-1))))
548 /* If it's not the right day of the week */
549 if (!(i->dowmask & (1 << tm.tm_wday)))
552 /* Sanity check the hour just to be safe */
553 if ((tm.tm_hour < 0) || (tm.tm_hour > 23)) {
554 ast_log(LOG_WARNING, "Insane time...\n");
558 /* Now the tough part, we calculate if it fits
559 in the right time based on min/hour */
560 if (!(i->minmask[tm.tm_hour] & (1 << (tm.tm_min / 2))))
563 /* If we got this far, then we're good */
567 static void pbx_destroy(struct ast_pbx *p)
572 #define EXTENSION_MATCH_CORE(data,pattern,match) {\
573 /* All patterns begin with _ */\
574 if (pattern[0] != '_') \
576 /* Start optimistic */\
579 while(match && *data && *pattern && (*pattern != '/')) {\
580 switch(toupper(*pattern)) {\
587 where=strchr(pattern,']');\
589 border=(int)(where-pattern);\
590 if (!where || border > strlen(pattern)) {\
591 ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");\
594 for (i=0; i<border; i++) {\
597 if (pattern[i+1]=='-') {\
598 if (*data >= pattern[i] && *data <= pattern[i+2]) {\
605 if (res==1 || *data==pattern[i]) {\
614 if ((*data < '2') || (*data > '9'))\
618 if ((*data < '0') || (*data > '9'))\
622 if ((*data < '1') || (*data > '9'))\
630 /* Ignore these characters */\
634 if (*data != *pattern)\
642 int ast_extension_match(char *pattern, char *data)
645 /* If they're the same return */
646 if (!strcmp(pattern, data))
648 EXTENSION_MATCH_CORE(data,pattern,match);
649 /* Must be at the end of both */
650 if (*data || (*pattern && (*pattern != '/')))
655 static int extension_close(char *pattern, char *data, int needmore)
658 /* If "data" is longer, it can'be a subset of pattern unless
659 pattern is a pattern match */
660 if ((strlen(pattern) < strlen(data)) && (pattern[0] != '_'))
663 if ((ast_strlen_zero((char *)data) || !strncasecmp(pattern, data, strlen(data))) &&
664 (!needmore || (strlen(pattern) > strlen(data)))) {
667 EXTENSION_MATCH_CORE(data,pattern,match);
668 /* If there's more or we don't care about more, return non-zero, otlherwise it's a miss */
669 if (!needmore || *pattern) {
675 struct ast_context *ast_context_find(char *name)
677 struct ast_context *tmp;
678 ast_mutex_lock(&conlock);
682 if (!strcasecmp(name, tmp->name))
688 ast_mutex_unlock(&conlock);
692 #define STATUS_NO_CONTEXT 1
693 #define STATUS_NO_EXTENSION 2
694 #define STATUS_NO_PRIORITY 3
695 #define STATUS_SUCCESS 4
697 static int matchcid(char *cidpattern, char *callerid)
699 char tmp[AST_MAX_EXTENSION];
703 /* If the Caller*ID pattern is empty, then we're matching NO Caller*ID, so
704 failing to get a number should count as a match, otherwise not */
707 if (!ast_strlen_zero(cidpattern))
715 /* Copy original Caller*ID */
716 strncpy(tmp, callerid, sizeof(tmp)-1);
718 if (ast_callerid_parse(tmp, &name, &num))
722 ast_shrink_phone_number(num);
723 return ast_extension_match(cidpattern, num);
726 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)
729 struct ast_context *tmp;
730 struct ast_exten *e, *eroot;
731 struct ast_include *i;
733 struct ast_switch *asw;
735 /* Initialize status if appropriate */
737 *status = STATUS_NO_CONTEXT;
741 /* Check for stack overflow */
742 if (*stacklen >= AST_PBX_MAX_STACK) {
743 ast_log(LOG_WARNING, "Maximum PBX stack exceeded\n");
746 /* Check first to see if we've already been checked */
747 for (x=0;x<*stacklen;x++) {
748 if (!strcasecmp(incstack[x], context))
754 if (!strcmp(tmp->name, context)) {
755 if (*status < STATUS_NO_EXTENSION)
756 *status = STATUS_NO_EXTENSION;
759 /* Match extension */
760 if ((((action != HELPER_MATCHMORE) && ast_extension_match(eroot->exten, exten)) ||
761 ((action == HELPER_CANMATCH) && (extension_close(eroot->exten, exten, 0))) ||
762 ((action == HELPER_MATCHMORE) && (extension_close(eroot->exten, exten, 1)))) &&
763 (!eroot->matchcid || matchcid(eroot->cidmatch, callerid))) {
765 if (*status < STATUS_NO_PRIORITY)
766 *status = STATUS_NO_PRIORITY;
769 if (e->priority == priority) {
770 *status = STATUS_SUCCESS;
778 /* Check alternative switches */
781 if ((asw = pbx_findswitch(sw->name))) {
782 if (action == HELPER_CANMATCH)
783 res = asw->canmatch ? asw->canmatch(chan, context, exten, priority, callerid, sw->data) : 0;
784 else if (action == HELPER_MATCHMORE)
785 res = asw->matchmore ? asw->matchmore(chan, context, exten, priority, callerid, sw->data) : 0;
787 res = asw->exists ? asw->exists(chan, context, exten, priority, callerid, sw->data) : 0;
795 ast_log(LOG_WARNING, "No such switch '%s'\n", sw->name);
799 /* Setup the stack */
800 incstack[*stacklen] = tmp->name;
802 /* Now try any includes we have in this context */
805 if (include_valid(i)) {
806 if ((e = pbx_find_extension(chan, i->rname, exten, priority, callerid, action, incstack, stacklen, status, swo, data)))
819 static void pbx_substitute_variables_temp(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen)
822 char tmpvar[80] = "";
824 struct tm brokentime;
826 struct ast_var_t *variables;
827 char *name, *num; /* for callerid name + num variables */
828 struct varshead *headp=NULL;
833 /* Now we have the variable name on cp3 */
834 if (!strncasecmp(var,"LEN(",4)) {
837 if (strrchr(var,')')) {
839 strncpy(cp3, var, sizeof(cp3) - 1);
840 cp3[len-len_len-1]='\0';
841 sprintf(workspace,"%d",(int)strlen(cp3));
847 } else if ((first=strchr(var,':'))) {
848 strncpy(tmpvar, var, sizeof(tmpvar) - 1);
849 first = strchr(tmpvar, ':');
851 first = tmpvar + strlen(tmpvar);
853 pbx_substitute_variables_temp(c,tmpvar,ret,workspace,workspacelen - 1);
855 offset=atoi(first+1);
856 if ((second=strchr(first+1,':'))) {
858 offset2=atoi(second+1);
860 offset2=strlen(*ret)-offset;
861 if (abs(offset)>strlen(*ret)) {
865 offset=-strlen(*ret);
867 if ((offset<0 && offset2>-offset) || (offset>=0 && offset+offset2>strlen(*ret))) {
869 offset2=strlen(*ret)-offset;
871 offset2=strlen(*ret)+offset;
876 *ret+=strlen(*ret)+offset;
877 (*ret)[offset2] = '\0';
878 } else if (c && !strcmp(var, "CALLERIDNUM")) {
880 strncpy(workspace, c->callerid, workspacelen - 1);
881 ast_callerid_parse(workspace, &name, &num);
883 ast_shrink_phone_number(num);
887 } else if (c && !strcmp(var, "CALLERIDNAME")) {
889 strncpy(workspace, c->callerid, workspacelen - 1);
890 ast_callerid_parse(workspace, &name, &num);
895 } else if (c && !strcmp(var, "CALLERID")) {
897 strncpy(workspace, c->callerid, workspacelen - 1);
901 } else if (c && !strcmp(var, "DNID")) {
903 strncpy(workspace, c->dnid, workspacelen - 1);
907 } else if (c && !strcmp(var, "HINT")) {
908 if (!ast_get_hint(workspace, workspacelen, c, c->context, c->exten))
912 } else if (c && !strcmp(var, "EXTEN")) {
913 strncpy(workspace, c->exten, workspacelen - 1);
915 } else if (c && !strncmp(var, "EXTEN-", strlen("EXTEN-")) &&
916 /* XXX Remove me eventually */
917 (sscanf(var + strlen("EXTEN-"), "%d", &offset) == 1)) {
920 if (offset > strlen(c->exten))
921 offset = strlen(c->exten);
922 strncpy(workspace, c->exten + offset, workspacelen - 1);
924 ast_log(LOG_WARNING, "The use of 'EXTEN-foo' has been deprecated in favor of 'EXTEN:foo'\n");
925 } else if (c && !strcmp(var, "RDNIS")) {
927 strncpy(workspace, c->rdnis, workspacelen - 1);
931 } else if (c && !strcmp(var, "CONTEXT")) {
932 strncpy(workspace, c->context, workspacelen - 1);
934 } else if (c && !strcmp(var, "PRIORITY")) {
935 snprintf(workspace, workspacelen, "%d", c->priority);
937 } else if (c && !strcmp(var, "CHANNEL")) {
938 strncpy(workspace, c->name, workspacelen - 1);
940 } else if (c && !strcmp(var, "EPOCH")) {
941 snprintf(workspace, workspacelen, "%u",(int)time(NULL));
943 } else if (c && !strcmp(var, "DATETIME")) {
945 localtime_r(&thistime, &brokentime);
946 snprintf(workspace, workspacelen, "%02d%02d%04d-%02d:%02d:%02d",
949 brokentime.tm_year+1900,
955 } else if (c && !strcmp(var, "TIMESTAMP")) {
957 localtime_r(&thistime, &brokentime);
958 /* 20031130-150612 */
959 snprintf(workspace, workspacelen, "%04d%02d%02d-%02d%02d%02d",
960 brokentime.tm_year+1900,
968 } else if (c && !strcmp(var, "UNIQUEID")) {
969 snprintf(workspace, workspacelen, "%s", c->uniqueid);
971 } else if (c && !strcmp(var, "HANGUPCAUSE")) {
972 snprintf(workspace, workspacelen, "%i", c->hangupcause);
974 } else if (c && !strcmp(var, "ACCOUNTCODE")) {
975 strncpy(workspace, c->accountcode, workspacelen - 1);
977 } else if (c && !strcmp(var, "LANGUAGE")) {
978 strncpy(workspace, c->language, workspacelen - 1);
982 AST_LIST_TRAVERSE(headp,variables,entries) {
984 ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",var,ast_var_name(variables));
986 if (strcasecmp(ast_var_name(variables),var)==0) {
987 *ret=ast_var_value(variables);
989 strncpy(workspace, *ret, workspacelen - 1);
998 AST_LIST_TRAVERSE(&globals,variables,entries) {
1000 ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",var,ast_var_name(variables));
1002 if (strcasecmp(ast_var_name(variables),var)==0) {
1003 *ret=ast_var_value(variables);
1005 strncpy(workspace, *ret, workspacelen - 1);
1012 int len=strlen(var);
1013 int len_env=strlen("ENV(");
1014 if (len > (len_env+1) && !strncasecmp(var,"ENV(",len_env) && !strcmp(var+len-1,")")) {
1016 strncpy(cp3, var, sizeof(cp3) - 1);
1018 *ret=getenv(cp3+len_env);
1020 strncpy(workspace, *ret, workspacelen - 1);
1028 void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
1031 const char *tmp, *whereweare;
1033 char workspace[4096];
1034 char ltmp[4096], var[4096];
1035 char *nextvar, *nextexp;
1037 int pos, brackets, needsub, len;
1039 /* Substitutes variables into cp2, based on string cp1, and assuming cp2 to be
1042 while(!ast_strlen_zero(whereweare) && count) {
1043 /* Assume we're copying the whole remaining string */
1044 pos = strlen(whereweare);
1046 /* Look for a variable */
1047 nextvar = strstr(whereweare, "${");
1049 /* Look for an expression */
1050 nextexp = strstr(whereweare, "$[");
1052 /* Pick the first one only */
1053 if (nextvar && nextexp) {
1054 if (nextvar < nextexp)
1060 /* If there is one, we only go that far */
1062 pos = nextvar - whereweare;
1064 pos = nextexp - whereweare;
1066 /* Can't copy more than 'count' bytes */
1070 /* Copy that many bytes */
1071 memcpy(cp2, whereweare, pos);
1078 /* We have a variable. Find the start and end, and determine
1079 if we are going to have to recursively call ourselves on the
1081 vars = vare = nextvar + 2;
1085 /* Find the end of it */
1086 while(brackets && *vare) {
1087 if ((vare[0] == '$') && (vare[1] == '{')) {
1090 } else if (vare[0] == '}') {
1092 } else if ((vare[0] == '$') && (vare[1] == '['))
1097 ast_log(LOG_NOTICE, "Error in extension logic (missing '}')\n");
1098 len = vare - vars - 1;
1100 /* Skip totally over variable name */
1101 whereweare += ( len + 3);
1103 /* Store variable name (and truncate) */
1104 memset(var, 0, sizeof(var));
1105 strncpy(var, vars, sizeof(var) - 1);
1108 /* Substitute if necessary */
1110 memset(ltmp, 0, sizeof(ltmp));
1111 pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1);
1117 /* Retrieve variable value */
1118 workspace[0] = '\0';
1119 pbx_substitute_variables_temp(c,vars,&cp4, workspace, sizeof(workspace));
1121 length = strlen(cp4);
1124 memcpy(cp2, cp4, length);
1129 } else if (nextexp) {
1130 /* We have an expression. Find the start and end, and determine
1131 if we are going to have to recursively call ourselves on the
1133 vars = vare = nextexp + 2;
1137 /* Find the end of it */
1138 while(brackets && *vare) {
1139 if ((vare[0] == '$') && (vare[1] == '[')) {
1143 } else if (vare[0] == '[') {
1145 } else if (vare[0] == ']') {
1147 } else if ((vare[0] == '$') && (vare[1] == '{')) {
1154 ast_log(LOG_NOTICE, "Error in extension logic (missing ']')\n");
1155 len = vare - vars - 1;
1157 /* Skip totally over variable name */
1158 whereweare += ( len + 3);
1160 /* Store variable name (and truncate) */
1161 memset(var, 0, sizeof(var));
1162 strncpy(var, vars, sizeof(var) - 1);
1165 /* Substitute if necessary */
1167 memset(ltmp, 0, sizeof(ltmp));
1168 pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1);
1174 /* Evaluate expression */
1175 cp4 = ast_expr(vars);
1177 ast_log(LOG_DEBUG, "Expression is '%s'\n", cp4);
1180 length = strlen(cp4);
1183 memcpy(cp2, cp4, length);
1194 static void pbx_substitute_variables(char *passdata, int datalen, struct ast_channel *c, struct ast_exten *e) {
1196 memset(passdata, 0, datalen);
1198 /* No variables or expressions in e->data, so why scan it? */
1199 if (!strstr(e->data,"${") && !strstr(e->data,"$[")) {
1200 strncpy(passdata, e->data, datalen - 1);
1201 passdata[datalen-1] = '\0';
1205 pbx_substitute_variables_helper(c, e->data, passdata, datalen - 1);
1208 static int pbx_extension_helper(struct ast_channel *c, char *context, char *exten, int priority, char *callerid, int action)
1210 struct ast_exten *e;
1211 struct ast_app *app;
1212 struct ast_switch *sw;
1217 char *incstack[AST_PBX_MAX_STACK];
1218 char passdata[EXT_DATA_SIZE];
1222 char tmp3[EXT_DATA_SIZE];
1224 if (ast_mutex_lock(&conlock)) {
1225 ast_log(LOG_WARNING, "Unable to obtain lock\n");
1226 if ((action == HELPER_EXISTS) || (action == HELPER_CANMATCH) || (action == HELPER_MATCHMORE))
1231 e = pbx_find_extension(c, context, exten, priority, callerid, action, incstack, &stacklen, &status, &sw, &data);
1234 case HELPER_CANMATCH:
1235 ast_mutex_unlock(&conlock);
1238 ast_mutex_unlock(&conlock);
1240 case HELPER_MATCHMORE:
1241 ast_mutex_unlock(&conlock);
1247 app = pbx_findapp(e->app);
1248 ast_mutex_unlock(&conlock);
1250 if (c->context != context)
1251 strncpy(c->context, context, sizeof(c->context)-1);
1252 if (c->exten != exten)
1253 strncpy(c->exten, exten, sizeof(c->exten)-1);
1254 c->priority = priority;
1255 pbx_substitute_variables(passdata, sizeof(passdata), c, e);
1257 ast_log(LOG_DEBUG, "Launching '%s'\n", app->name);
1258 else if (option_verbose > 2)
1259 ast_verbose( VERBOSE_PREFIX_3 "Executing %s(\"%s\", \"%s\") %s\n",
1260 term_color(tmp, app->name, COLOR_BRCYAN, 0, sizeof(tmp)),
1261 term_color(tmp2, c->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
1262 term_color(tmp3, (!ast_strlen_zero(passdata) ? (char *)passdata : ""), COLOR_BRMAGENTA, 0, sizeof(tmp3)),
1263 (newstack ? "in new stack" : "in same stack"));
1264 manager_event(EVENT_FLAG_CALL, "Newexten",
1269 "Application: %s\r\n"
1272 c->name, c->context, c->exten, c->priority, app->name, passdata ? passdata : "(NULL)", c->uniqueid);
1273 res = pbx_exec(c, app, passdata, newstack);
1276 ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
1280 ast_log(LOG_WARNING, "Huh (%d)?\n", action); return -1;
1284 case HELPER_CANMATCH:
1285 ast_mutex_unlock(&conlock);
1288 ast_mutex_unlock(&conlock);
1290 case HELPER_MATCHMORE:
1291 ast_mutex_unlock(&conlock);
1297 ast_mutex_unlock(&conlock);
1299 res = sw->exec(c, context, exten, priority, callerid, newstack, data);
1301 ast_log(LOG_WARNING, "No execution engine for switch %s\n", sw->name);
1306 ast_log(LOG_WARNING, "Huh (%d)?\n", action);
1310 ast_mutex_unlock(&conlock);
1312 case STATUS_NO_CONTEXT:
1313 if ((action != HELPER_EXISTS) && (action != HELPER_MATCHMORE))
1314 ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", context);
1316 case STATUS_NO_EXTENSION:
1317 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1318 ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, context);
1320 case STATUS_NO_PRIORITY:
1321 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1322 ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, context);
1325 ast_log(LOG_DEBUG, "Shouldn't happen!\n");
1328 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1336 static struct ast_exten *ast_hint_extension(struct ast_channel *c, char *context, char *exten)
1338 struct ast_exten *e;
1339 struct ast_switch *sw;
1342 char *incstack[AST_PBX_MAX_STACK];
1345 if (ast_mutex_lock(&conlock)) {
1346 ast_log(LOG_WARNING, "Unable to obtain lock\n");
1349 e = pbx_find_extension(c, context, exten, PRIORITY_HINT, "", HELPER_EXISTS, incstack, &stacklen, &status, &sw, &data);
1350 ast_mutex_unlock(&conlock);
1354 static int ast_extension_state2(struct ast_exten *e)
1356 char hint[AST_MAX_EXTENSION] = "";
1359 int allunavailable = 1, allbusy = 1, allfree = 1;
1362 strncpy(hint, ast_get_extension_app(e), sizeof(hint)-1);
1366 rest = strchr(cur, '&');
1372 res = ast_device_state(cur);
1374 case AST_DEVICE_NOT_INUSE:
1378 case AST_DEVICE_INUSE:
1379 return AST_EXTENSION_INUSE;
1380 case AST_DEVICE_BUSY:
1385 case AST_DEVICE_UNAVAILABLE:
1386 case AST_DEVICE_INVALID:
1399 return AST_EXTENSION_NOT_INUSE;
1401 return AST_EXTENSION_BUSY;
1403 return AST_EXTENSION_UNAVAILABLE;
1405 return AST_EXTENSION_INUSE;
1407 return AST_EXTENSION_NOT_INUSE;
1411 int ast_extension_state(struct ast_channel *c, char *context, char *exten)
1413 struct ast_exten *e;
1415 e = ast_hint_extension(c, context, exten);
1419 return ast_extension_state2(e);
1422 int ast_device_state_changed(const char *fmt, ...)
1424 struct ast_hint *list;
1425 struct ast_state_cb *cblist;
1426 char hint[AST_MAX_EXTENSION] = "";
1427 char device[AST_MAX_EXTENSION];
1434 vsnprintf(device, sizeof(device), fmt, ap);
1437 rest = strchr(device, '-');
1442 ast_mutex_lock(&hintlock);
1448 strncpy(hint, ast_get_extension_app(list->exten), sizeof(hint) - 1);
1451 rest = strchr(cur, '&');
1457 if (!strcmp(cur, device)) {
1458 /* Found extension execute callbacks */
1459 state = ast_extension_state2(list->exten);
1460 if ((state != -1) && (state != list->laststate)) {
1461 /* For general callbacks */
1464 cblist->callback(list->exten->parent->name, list->exten->exten, state, cblist->data);
1465 cblist = cblist->next;
1468 /* For extension callbacks */
1469 cblist = list->callbacks;
1471 cblist->callback(list->exten->parent->name, list->exten->exten, state, cblist->data);
1472 cblist = cblist->next;
1475 list->laststate = state;
1483 ast_mutex_unlock(&hintlock);
1487 int ast_extension_state_add(char *context, char *exten,
1488 ast_state_cb_type callback, void *data)
1490 struct ast_hint *list;
1491 struct ast_state_cb *cblist;
1492 struct ast_exten *e;
1494 /* No context and extension add callback to statecbs list */
1495 if (!context && !exten) {
1496 ast_mutex_lock(&hintlock);
1500 if (cblist->callback == callback) {
1501 cblist->data = data;
1502 ast_mutex_unlock(&hintlock);
1504 cblist = cblist->next;
1507 /* Now inserts the callback */
1508 cblist = malloc(sizeof(struct ast_state_cb));
1510 ast_mutex_unlock(&hintlock);
1513 memset(cblist, 0, sizeof(struct ast_state_cb));
1515 cblist->callback = callback;
1516 cblist->data = data;
1518 cblist->next = statecbs;
1521 ast_mutex_unlock(&hintlock);
1525 if (!context || !exten)
1528 /* This callback type is for only one hint */
1529 e = ast_hint_extension(NULL, context, exten);
1534 ast_mutex_lock(&hintlock);
1538 if (list->exten == e)
1544 ast_mutex_unlock(&hintlock);
1548 /* Now inserts the callback */
1549 cblist = malloc(sizeof(struct ast_state_cb));
1551 ast_mutex_unlock(&hintlock);
1554 memset(cblist, 0, sizeof(struct ast_state_cb));
1555 cblist->id = stateid++;
1556 cblist->callback = callback;
1557 cblist->data = data;
1559 cblist->next = list->callbacks;
1560 list->callbacks = cblist;
1562 ast_mutex_unlock(&hintlock);
1566 int ast_extension_state_del(int id, ast_state_cb_type callback)
1568 struct ast_hint *list;
1569 struct ast_state_cb *cblist, *cbprev;
1571 if (!id && !callback)
1574 ast_mutex_lock(&hintlock);
1576 /* id is zero is a callback without extension */
1581 if (cblist->callback == callback) {
1583 statecbs = cblist->next;
1585 cbprev->next = cblist->next;
1589 ast_mutex_unlock(&hintlock);
1593 cblist = cblist->next;
1596 ast_mutex_lock(&hintlock);
1600 /* id greater than zero is a callback with extension */
1603 cblist = list->callbacks;
1606 if (cblist->id==id) {
1608 list->callbacks = cblist->next;
1610 cbprev->next = cblist->next;
1614 ast_mutex_unlock(&hintlock);
1618 cblist = cblist->next;
1623 ast_mutex_unlock(&hintlock);
1627 static int ast_add_hint(struct ast_exten *e)
1629 struct ast_hint *list;
1634 ast_mutex_lock(&hintlock);
1637 /* Search if hint exists, do nothing */
1639 if (list->exten == e) {
1640 ast_mutex_unlock(&hintlock);
1646 list = malloc(sizeof(struct ast_hint));
1648 ast_mutex_unlock(&hintlock);
1651 /* Initialize and insert new item */
1652 memset(list, 0, sizeof(struct ast_hint));
1654 list->laststate = ast_extension_state2(e);
1658 ast_mutex_unlock(&hintlock);
1662 static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
1664 struct ast_hint *list;
1666 ast_mutex_lock(&hintlock);
1670 if (list->exten == oe) {
1672 ast_mutex_unlock(&hintlock);
1677 ast_mutex_unlock(&hintlock);
1682 static int ast_remove_hint(struct ast_exten *e)
1684 /* Cleanup the Notifys if hint is removed */
1685 struct ast_hint *list, *prev = NULL;
1686 struct ast_state_cb *cblist, *cbprev;
1691 ast_mutex_lock(&hintlock);
1695 if (list->exten==e) {
1697 cblist = list->callbacks;
1699 /* Notify with -1 and remove all callbacks */
1701 cblist = cblist->next;
1702 cbprev->callback(list->exten->parent->name, list->exten->exten, -1, cbprev->data);
1705 list->callbacks = NULL;
1710 prev->next = list->next;
1713 ast_mutex_unlock(&hintlock);
1721 ast_mutex_unlock(&hintlock);
1726 int ast_get_hint(char *hint, int hintsize, struct ast_channel *c, char *context, char *exten)
1728 struct ast_exten *e;
1729 e = ast_hint_extension(c, context, exten);
1731 strncpy(hint, ast_get_extension_app(e), hintsize - 1);
1737 int ast_exists_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid)
1739 return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_EXISTS);
1742 int ast_canmatch_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid)
1744 return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_CANMATCH);
1747 int ast_matchmore_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid)
1749 return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_MATCHMORE);
1752 int ast_spawn_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid)
1754 return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_SPAWN);
1757 int ast_pbx_run(struct ast_channel *c)
1766 /* A little initial setup here */
1768 ast_log(LOG_WARNING, "%s already has PBX structure??\n", c->name);
1769 c->pbx = malloc(sizeof(struct ast_pbx));
1771 ast_log(LOG_ERROR, "Out of memory\n");
1776 ast_log(LOG_WARNING, "%s already has a call record??\n", c->name);
1778 c->cdr = ast_cdr_alloc();
1780 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
1784 ast_cdr_init(c->cdr, c);
1787 memset(c->pbx, 0, sizeof(struct ast_pbx));
1788 /* Set reasonable defaults */
1789 c->pbx->rtimeout = 10;
1790 c->pbx->dtimeout = 5;
1792 /* Start by trying whatever the channel is set to */
1793 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
1794 /* JK02: If not successfull fall back to 's' */
1795 if (option_verbose > 1)
1796 ast_verbose( VERBOSE_PREFIX_2 "Starting %s at %s,%s,%d failed so falling back to exten 's'\n", c->name, c->context, c->exten, c->priority);
1797 strncpy(c->exten, "s", sizeof(c->exten)-1);
1798 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
1799 /* JK02: And finally back to default if everything else failed */
1800 if (option_verbose > 1)
1801 ast_verbose( VERBOSE_PREFIX_2 "Starting %s at %s,%s,%d still failed so falling back to context 'default'\n", c->name, c->context, c->exten, c->priority);
1802 strncpy(c->context, "default", sizeof(c->context)-1);
1807 ast_cdr_start(c->cdr);
1811 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
1812 memset(exten, 0, sizeof(exten));
1813 if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->callerid))) {
1814 /* Something bad happened, or a hangup has been requested. */
1815 if (((res >= '0') && (res <= '9')) || ((res >= 'A') && (res <= 'F')) ||
1816 (res == '*') || (res == '#')) {
1817 ast_log(LOG_DEBUG, "Oooh, got something to jump out with ('%c')!\n", res);
1818 memset(exten, 0, sizeof(exten));
1820 exten[pos++] = digit = res;
1824 case AST_PBX_KEEPALIVE:
1826 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
1827 else if (option_verbose > 1)
1828 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
1833 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
1834 else if (option_verbose > 1)
1835 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
1836 if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
1841 if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
1851 if ((c->_softhangup == AST_SOFTHANGUP_TIMEOUT) && (ast_exists_extension(c,c->context,"T",1,c->callerid))) {
1852 strncpy(c->exten,"T",sizeof(c->exten) - 1);
1853 /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
1854 c->whentohangup = 0;
1856 c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
1857 } else if (c->_softhangup) {
1858 ast_log(LOG_DEBUG, "Extension %s, priority %d returned normally even though call was hung up\n",
1859 c->exten, c->priority);
1865 if (!ast_exists_extension(c, c->context, c->exten, 1, c->callerid)) {
1866 /* It's not a valid extension anymore */
1867 if (ast_exists_extension(c, c->context, "i", 1, c->callerid)) {
1868 if (option_verbose > 2)
1869 ast_verbose(VERBOSE_PREFIX_3 "Sent into invalid extension '%s' in context '%s' on %s\n", c->exten, c->context, c->name);
1870 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", c->exten);
1871 strncpy(c->exten, "i", sizeof(c->exten)-1);
1874 ast_log(LOG_WARNING, "Channel '%s' sent into invalid extension '%s' in context '%s', but no invalid handler\n",
1875 c->name, c->exten, c->context);
1878 } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
1879 /* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */
1882 /* Done, wait for an extension */
1884 waittime = c->pbx->dtimeout;
1886 waittime = c->pbx->rtimeout;
1887 while (ast_matchmore_extension(c, c->context, exten, 1, c->callerid)) {
1888 /* As long as we're willing to wait, and as long as it's not defined,
1889 keep reading digits until we can't possibly get a right answer anymore. */
1890 digit = ast_waitfordigit(c, waittime * 1000);
1891 if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
1898 /* Error, maybe a hangup */
1900 exten[pos++] = digit;
1901 waittime = c->pbx->dtimeout;
1904 if (ast_exists_extension(c, c->context, exten, 1, c->callerid)) {
1905 /* Prepare the next cycle */
1906 strncpy(c->exten, exten, sizeof(c->exten)-1);
1909 /* No such extension */
1910 if (!ast_strlen_zero(exten)) {
1911 /* An invalid extension */
1912 if (ast_exists_extension(c, c->context, "i", 1, c->callerid)) {
1913 if (option_verbose > 2)
1914 ast_verbose( VERBOSE_PREFIX_3 "Invalid extension '%s' in context '%s' on %s\n", exten, c->context, c->name);
1915 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", exten);
1916 strncpy(c->exten, "i", sizeof(c->exten)-1);
1919 ast_log(LOG_WARNING, "Invalid extension '%s', but no rule 'i' in context '%s'\n", exten, c->context);
1923 /* A simple timeout */
1924 if (ast_exists_extension(c, c->context, "t", 1, c->callerid)) {
1925 if (option_verbose > 2)
1926 ast_verbose( VERBOSE_PREFIX_3 "Timeout on %s\n", c->name);
1927 strncpy(c->exten, "t", sizeof(c->exten)-1);
1930 ast_log(LOG_WARNING, "Timeout, but no rule 't' in context '%s'\n", c->context);
1936 if (option_verbose > 2)
1937 ast_verbose(VERBOSE_PREFIX_2 "CDR updated on %s\n",c->name);
1943 ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", c->name);
1945 if ((res != AST_PBX_KEEPALIVE) && ast_exists_extension(c, c->context, "h", 1, c->callerid)) {
1949 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
1950 if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->callerid))) {
1951 /* Something bad happened, or a hangup has been requested. */
1953 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
1954 else if (option_verbose > 1)
1955 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
1962 pbx_destroy(c->pbx);
1964 if (res != AST_PBX_KEEPALIVE)
1969 static void *pbx_thread(void *data)
1971 /* Oh joyeous kernel, we're a new thread, with nothing to do but
1972 answer this channel and get it going. The setjmp stuff is fairly
1973 confusing, but necessary to get smooth transitions between
1974 the execution of different applications (without the use of
1975 additional threads) */
1976 struct ast_channel *c = data;
1982 int ast_pbx_start(struct ast_channel *c)
1985 pthread_attr_t attr;
1987 ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
1991 /* Start a new thread, and get something handling this channel. */
1992 pthread_attr_init(&attr);
1993 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1994 if (ast_pthread_create(&t, &attr, pbx_thread, c)) {
1995 ast_log(LOG_WARNING, "Failed to create new channel thread\n");
2002 * This function locks contexts list by &conlist, search for the right context
2003 * structure, leave context list locked and call ast_context_remove_include2
2004 * which removes include, unlock contexts list and return ...
2006 int ast_context_remove_include(char *context, char *include, char *registrar)
2008 struct ast_context *c;
2010 if (ast_lock_contexts()) return -1;
2012 /* walk contexts and search for the right one ...*/
2013 c = ast_walk_contexts(NULL);
2015 /* we found one ... */
2016 if (!strcmp(ast_get_context_name(c), context)) {
2018 /* remove include from this context ... */
2019 ret = ast_context_remove_include2(c, include, registrar);
2021 ast_unlock_contexts();
2023 /* ... return results */
2026 c = ast_walk_contexts(c);
2029 /* we can't find the right one context */
2030 ast_unlock_contexts();
2035 * When we call this function, &conlock lock must be locked, because when
2036 * we giving *con argument, some process can remove/change this context
2037 * and after that there can be segfault.
2039 * This function locks given context, removes include, unlock context and
2042 int ast_context_remove_include2(struct ast_context *con, char *include, char *registrar)
2044 struct ast_include *i, *pi = NULL;
2046 if (ast_mutex_lock(&con->lock)) return -1;
2051 /* find our include */
2052 if (!strcmp(i->name, include) &&
2053 (!registrar || !strcmp(i->registrar, registrar))) {
2054 /* remove from list */
2058 con->includes = i->next;
2059 /* free include and return */
2061 ast_mutex_unlock(&con->lock);
2068 /* we can't find the right include */
2069 ast_mutex_unlock(&con->lock);
2074 * This function locks contexts list by &conlist, search for the rigt context
2075 * structure, leave context list locked and call ast_context_remove_switch2
2076 * which removes switch, unlock contexts list and return ...
2078 int ast_context_remove_switch(char *context, char *sw, char *data, char *registrar)
2080 struct ast_context *c;
2082 if (ast_lock_contexts()) return -1;
2084 /* walk contexts and search for the right one ...*/
2085 c = ast_walk_contexts(NULL);
2087 /* we found one ... */
2088 if (!strcmp(ast_get_context_name(c), context)) {
2090 /* remove switch from this context ... */
2091 ret = ast_context_remove_switch2(c, sw, data, registrar);
2093 ast_unlock_contexts();
2095 /* ... return results */
2098 c = ast_walk_contexts(c);
2101 /* we can't find the right one context */
2102 ast_unlock_contexts();
2107 * When we call this function, &conlock lock must be locked, because when
2108 * we giving *con argument, some process can remove/change this context
2109 * and after that there can be segfault.
2111 * This function locks given context, removes switch, unlock context and
2114 int ast_context_remove_switch2(struct ast_context *con, char *sw, char *data, char *registrar)
2116 struct ast_sw *i, *pi = NULL;
2118 if (ast_mutex_lock(&con->lock)) return -1;
2123 /* find our switch */
2124 if (!strcmp(i->name, sw) && !strcmp(i->data, data) &&
2125 (!registrar || !strcmp(i->registrar, registrar))) {
2126 /* remove from list */
2130 con->alts = i->next;
2131 /* free switch and return */
2133 ast_mutex_unlock(&con->lock);
2140 /* we can't find the right switch */
2141 ast_mutex_unlock(&con->lock);
2146 * This functions lock contexts list, search for the right context,
2147 * call ast_context_remove_extension2, unlock contexts list and return.
2148 * In this function we are using
2150 int ast_context_remove_extension(char *context, char *extension, int priority, char *registrar)
2152 struct ast_context *c;
2154 if (ast_lock_contexts()) return -1;
2156 /* walk contexts ... */
2157 c = ast_walk_contexts(NULL);
2159 /* ... search for the right one ... */
2160 if (!strcmp(ast_get_context_name(c), context)) {
2161 /* ... remove extension ... */
2162 int ret = ast_context_remove_extension2(c, extension, priority,
2164 /* ... unlock contexts list and return */
2165 ast_unlock_contexts();
2168 c = ast_walk_contexts(c);
2171 /* we can't find the right context */
2172 ast_unlock_contexts();
2177 * When do you want to call this function, make sure that &conlock is locked,
2178 * because some process can handle with your *con context before you lock
2181 * This functionc locks given context, search for the right extension and
2182 * fires out all peer in this extensions with given priority. If priority
2183 * is set to 0, all peers are removed. After that, unlock context and
2186 int ast_context_remove_extension2(struct ast_context *con, char *extension, int priority, char *registrar)
2188 struct ast_exten *exten, *prev_exten = NULL;
2190 if (ast_mutex_lock(&con->lock)) return -1;
2192 /* go through all extensions in context and search the right one ... */
2196 /* look for right extension */
2197 if (!strcmp(exten->exten, extension) &&
2198 (!registrar || !strcmp(exten->registrar, registrar))) {
2199 struct ast_exten *peer;
2201 /* should we free all peers in this extension? (priority == 0)? */
2202 if (priority == 0) {
2203 /* remove this extension from context list */
2205 prev_exten->next = exten->next;
2207 con->root = exten->next;
2209 /* fire out all peers */
2214 if (!peer->priority==PRIORITY_HINT)
2215 ast_remove_hint(peer);
2217 peer->datad(peer->data);
2223 ast_mutex_unlock(&con->lock);
2226 /* remove only extension with exten->priority == priority */
2227 struct ast_exten *previous_peer = NULL;
2231 /* is this our extension? */
2232 if (peer->priority == priority &&
2233 (!registrar || !strcmp(peer->registrar, registrar) )) {
2234 /* we are first priority extension? */
2235 if (!previous_peer) {
2236 /* exists previous extension here? */
2238 /* yes, so we must change next pointer in
2239 * previous connection to next peer
2242 prev_exten->next = peer->peer;
2243 peer->peer->next = exten->next;
2245 prev_exten->next = exten->next;
2247 /* no previous extension, we are first
2248 * extension, so change con->root ...
2251 con->root = peer->peer;
2253 con->root = exten->next;
2256 /* we are not first priority in extension */
2257 previous_peer->peer = peer->peer;
2260 /* now, free whole priority extension */
2261 if (peer->priority==PRIORITY_HINT)
2262 ast_remove_hint(peer);
2263 peer->datad(peer->data);
2266 ast_mutex_unlock(&con->lock);
2269 /* this is not right extension, skip to next peer */
2270 previous_peer = peer;
2275 ast_mutex_unlock(&con->lock);
2281 exten = exten->next;
2284 /* we can't find right extension */
2285 ast_mutex_unlock(&con->lock);
2290 int ast_register_application(char *app, int (*execute)(struct ast_channel *, void *), char *synopsis, char *description)
2292 struct ast_app *tmp, *prev, *cur;
2294 if (ast_mutex_lock(&applock)) {
2295 ast_log(LOG_ERROR, "Unable to lock application list\n");
2300 if (!strcasecmp(app, tmp->name)) {
2301 ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
2302 ast_mutex_unlock(&applock);
2307 tmp = malloc(sizeof(struct ast_app));
2309 memset(tmp, 0, sizeof(struct ast_app));
2310 strncpy(tmp->name, app, sizeof(tmp->name)-1);
2311 tmp->execute = execute;
2312 tmp->synopsis = synopsis;
2313 tmp->description = description;
2314 /* Store in alphabetical order */
2318 if (strcasecmp(tmp->name, cur->name) < 0)
2324 tmp->next = prev->next;
2331 ast_log(LOG_ERROR, "Out of memory\n");
2332 ast_mutex_unlock(&applock);
2335 if (option_verbose > 1)
2336 ast_verbose( VERBOSE_PREFIX_2 "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
2337 ast_mutex_unlock(&applock);
2341 int ast_register_switch(struct ast_switch *sw)
2343 struct ast_switch *tmp, *prev=NULL;
2344 if (ast_mutex_lock(&switchlock)) {
2345 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
2350 if (!strcasecmp(tmp->name, sw->name))
2356 ast_mutex_unlock(&switchlock);
2357 ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name);
2365 ast_mutex_unlock(&switchlock);
2369 void ast_unregister_switch(struct ast_switch *sw)
2371 struct ast_switch *tmp, *prev=NULL;
2372 if (ast_mutex_lock(&switchlock)) {
2373 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
2380 prev->next = tmp->next;
2382 switches = tmp->next;
2389 ast_mutex_unlock(&switchlock);
2393 * Help for CLI commands ...
2395 static char show_application_help[] =
2396 "Usage: show application <application> [<application> [<application> [...]]]\n"
2397 " Describes a particular application.\n";
2399 static char show_applications_help[] =
2400 "Usage: show applications [{like|describing} <text>]\n"
2401 " List applications which are currently available.\n"
2402 " If 'like', <text> will be a substring of the app name\n"
2403 " If 'describing', <text> will be a substring of the description\n";
2405 static char show_dialplan_help[] =
2406 "Usage: show dialplan [exten@][context]\n"
2409 static char show_switches_help[] =
2410 "Usage: show switches\n"
2411 " Show registered switches\n";
2414 * IMPLEMENTATION OF CLI FUNCTIONS IS IN THE SAME ORDER AS COMMANDS HELPS
2419 * 'show application' CLI command implementation functions ...
2423 * There is a possibility to show informations about more than one
2424 * application at one time. You can type 'show application Dial Echo' and
2425 * you will see informations about these two applications ...
2427 static char *complete_show_application(char *line, char *word,
2433 /* try to lock applications list ... */
2434 if (ast_mutex_lock(&applock)) {
2435 ast_log(LOG_ERROR, "Unable to lock application list\n");
2439 /* ... walk all applications ... */
2442 /* ... check if word matches this application ... */
2443 if (!strncasecmp(word, a->name, strlen(word))) {
2444 /* ... if this is right app serve it ... */
2445 if (++which > state) {
2446 char *ret = strdup(a->name);
2447 ast_mutex_unlock(&applock);
2454 /* no application match */
2455 ast_mutex_unlock(&applock);
2459 static int handle_show_application(int fd, int argc, char *argv[])
2462 int app, no_registered_app = 1;
2464 if (argc < 3) return RESULT_SHOWUSAGE;
2466 /* try to lock applications list ... */
2467 if (ast_mutex_lock(&applock)) {
2468 ast_log(LOG_ERROR, "Unable to lock application list\n");
2472 /* ... go through all applications ... */
2475 /* ... compare this application name with all arguments given
2476 * to 'show application' command ... */
2477 for (app = 2; app < argc; app++) {
2478 if (!strcasecmp(a->name, argv[app])) {
2479 /* Maximum number of characters added by terminal coloring is 22 */
2480 char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
2481 char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
2482 int synopsis_size, description_size;
2484 no_registered_app = 0;
2487 synopsis_size = strlen(a->synopsis) + 23;
2489 synopsis_size = strlen("Not available") + 23;
2490 synopsis = alloca(synopsis_size);
2493 description_size = strlen(a->description) + 23;
2495 description_size = strlen("Not available") + 23;
2496 description = alloca(description_size);
2498 if (synopsis && description) {
2499 snprintf(info, 64 + AST_MAX_APP, "\n -= Info about application '%s' =- \n\n", a->name);
2500 term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
2501 term_color(syntitle, "[Synopsis]:\n", COLOR_MAGENTA, 0, 40);
2502 term_color(destitle, "[Description]:\n", COLOR_MAGENTA, 0, 40);
2503 term_color(synopsis,
2504 a->synopsis ? a->synopsis : "Not available",
2505 COLOR_CYAN, 0, synopsis_size);
2506 term_color(description,
2507 a->description ? a->description : "Not available",
2508 COLOR_CYAN, 0, description_size);
2510 ast_cli(fd,"%s%s%s\n\n%s%s\n", infotitle, syntitle, synopsis, destitle, description);
2512 /* ... one of our applications, show info ...*/
2513 ast_cli(fd,"\n -= Info about application '%s' =- \n\n"
2514 "[Synopsis]:\n %s\n\n"
2515 "[Description]:\n%s\n",
2517 a->synopsis ? a->synopsis : "Not available",
2518 a->description ? a->description : "Not available");
2525 ast_mutex_unlock(&applock);
2527 /* we found at least one app? no? */
2528 if (no_registered_app) {
2529 ast_cli(fd, "Your application(s) is (are) not registered\n");
2530 return RESULT_FAILURE;
2533 return RESULT_SUCCESS;
2536 static int handle_show_switches(int fd, int argc, char *argv[])
2538 struct ast_switch *sw;
2540 ast_cli(fd, "There are no registered alternative switches\n");
2541 return RESULT_SUCCESS;
2543 /* ... we have applications ... */
2544 ast_cli(fd, "\n -= Registered Asterisk Alternative Switches =-\n");
2545 if (ast_mutex_lock(&switchlock)) {
2546 ast_log(LOG_ERROR, "Unable to lock switches\n");
2551 ast_cli(fd, "%s: %s\n", sw->name, sw->description);
2554 ast_mutex_unlock(&switchlock);
2555 return RESULT_SUCCESS;
2559 * 'show applications' CLI command implementation functions ...
2561 static int handle_show_applications(int fd, int argc, char *argv[])
2564 int like=0, describing=0;
2566 /* try to lock applications list ... */
2567 if (ast_mutex_lock(&applock)) {
2568 ast_log(LOG_ERROR, "Unable to lock application list\n");
2572 /* ... have we got at least one application (first)? no? */
2574 ast_cli(fd, "There are no registered applications\n");
2575 ast_mutex_unlock(&applock);
2579 /* show applications like <keyword> */
2580 if ((argc == 4) && (!strcmp(argv[2], "like"))) {
2582 } else if ((argc > 3) && (!strcmp(argv[2], "describing"))) {
2586 /* show applications describing <keyword1> [<keyword2>] [...] */
2587 if ((!like) && (!describing)) {
2588 ast_cli(fd, " -= Registered Asterisk Applications =-\n");
2590 ast_cli(fd, " -= Matching Asterisk Applications =-\n");
2593 /* ... go through all applications ... */
2594 for (a = apps; a; a = a->next) {
2595 /* ... show informations about applications ... */
2599 if (ast_strcasestr(a->name, argv[3])) {
2602 } else if (describing) {
2603 if (a->description) {
2604 /* Match all words on command line */
2607 for (i=3;i<argc;i++) {
2608 if (! ast_strcasestr(a->description, argv[i])) {
2618 ast_cli(fd," %20s: %s\n", a->name, a->synopsis ? a->synopsis : "<Synopsis not available>");
2622 /* ... unlock and return */
2623 ast_mutex_unlock(&applock);
2625 return RESULT_SUCCESS;
2628 static char *complete_show_applications(char *line, char *word, int pos, int state)
2631 if (ast_strlen_zero(word)) {
2634 return strdup("like");
2636 return strdup("describing");
2640 } else if (! strncasecmp(word, "like", strlen(word))) {
2642 return strdup("like");
2646 } else if (! strncasecmp(word, "describing", strlen(word))) {
2648 return strdup("describing");
2658 * 'show dialplan' CLI command implementation functions ...
2660 static char *complete_show_dialplan_context(char *line, char *word, int pos,
2663 struct ast_context *c;
2666 /* we are do completion of [exten@]context on second position only */
2667 if (pos != 2) return NULL;
2669 /* try to lock contexts list ... */
2670 if (ast_lock_contexts()) {
2671 ast_log(LOG_ERROR, "Unable to lock context list\n");
2675 /* ... walk through all contexts ... */
2676 c = ast_walk_contexts(NULL);
2678 /* ... word matches context name? yes? ... */
2679 if (!strncasecmp(word, ast_get_context_name(c), strlen(word))) {
2680 /* ... for serve? ... */
2681 if (++which > state) {
2682 /* ... yes, serve this context name ... */
2683 char *ret = strdup(ast_get_context_name(c));
2684 ast_unlock_contexts();
2688 c = ast_walk_contexts(c);
2691 /* ... unlock and return */
2692 ast_unlock_contexts();
2696 static int handle_show_dialplan(int fd, int argc, char *argv[])
2698 struct ast_context *c;
2699 char *exten = NULL, *context = NULL;
2700 int context_existence = 0, extension_existence = 0;
2702 if (argc != 3 && argc != 2) return -1;
2704 /* we obtain [exten@]context? if yes, split them ... */
2706 char *splitter = argv[2];
2707 /* is there a '@' character? */
2708 if (strchr(argv[2], '@')) {
2709 /* yes, split into exten & context ... */
2710 exten = strsep(&splitter, "@");
2713 /* check for length and change to NULL if ast_strlen_zero() */
2714 if (ast_strlen_zero(exten)) exten = NULL;
2715 if (ast_strlen_zero(context)) context = NULL;
2718 /* no '@' char, only context given */
2720 if (ast_strlen_zero(context)) context = NULL;
2724 /* try to lock contexts */
2725 if (ast_lock_contexts()) {
2726 ast_log(LOG_WARNING, "Failed to lock contexts list\n");
2727 return RESULT_FAILURE;
2730 /* walk all contexts ... */
2731 c = ast_walk_contexts(NULL);
2733 /* show this context? */
2735 !strcmp(ast_get_context_name(c), context)) {
2736 context_existence = 1;
2738 /* try to lock context before walking in ... */
2739 if (!ast_lock_context(c)) {
2740 struct ast_exten *e;
2741 struct ast_include *i;
2742 struct ast_ignorepat *ip;
2744 char buf[256], buf2[256];
2745 int context_info_printed = 0;
2747 /* are we looking for exten too? if yes, we print context
2748 * if we our extension only
2751 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
2752 ast_get_context_name(c), ast_get_context_registrar(c));
2753 context_info_printed = 1;
2756 /* walk extensions ... */
2757 e = ast_walk_context_extensions(c, NULL);
2759 struct ast_exten *p;
2761 /* looking for extension? is this our extension? */
2763 strcmp(ast_get_extension_name(e), exten))
2765 /* we are looking for extension and it's not our
2766 * extension, so skip to next extension */
2767 e = ast_walk_context_extensions(c, e);
2771 extension_existence = 1;
2773 /* may we print context info? */
2774 if (!context_info_printed) {
2775 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
2776 ast_get_context_name(c),
2777 ast_get_context_registrar(c));
2778 context_info_printed = 1;
2781 /* write extension name and first peer */
2782 bzero(buf, sizeof(buf));
2783 snprintf(buf, sizeof(buf), "'%s' =>",
2784 ast_get_extension_name(e));
2786 snprintf(buf2, sizeof(buf2),
2788 ast_get_extension_priority(e),
2789 ast_get_extension_app(e),
2790 (char *)ast_get_extension_app_data(e));
2792 ast_cli(fd, " %-17s %-45s [%s]\n", buf, buf2,
2793 ast_get_extension_registrar(e));
2795 /* walk next extension peers */
2796 p = ast_walk_extension_priorities(e, e);
2798 bzero((void *)buf2, sizeof(buf2));
2800 snprintf(buf2, sizeof(buf2),
2802 ast_get_extension_priority(p),
2803 ast_get_extension_app(p),
2804 (char *)ast_get_extension_app_data(p));
2806 ast_cli(fd," %-17s %-45s [%s]\n",
2808 ast_get_extension_registrar(p));
2810 p = ast_walk_extension_priorities(e, p);
2812 e = ast_walk_context_extensions(c, e);
2815 /* include & ignorepat we all printing if we are not
2816 * looking for exact extension
2819 if (ast_walk_context_extensions(c, NULL))
2822 /* walk included and write info ... */
2823 i = ast_walk_context_includes(c, NULL);
2825 bzero(buf, sizeof(buf));
2826 snprintf(buf, sizeof(buf), "'%s'",
2827 ast_get_include_name(i));
2828 ast_cli(fd, " Include => %-45s [%s]\n",
2829 buf, ast_get_include_registrar(i));
2830 i = ast_walk_context_includes(c, i);
2833 /* walk ignore patterns and write info ... */
2834 ip = ast_walk_context_ignorepats(c, NULL);
2836 bzero(buf, sizeof(buf));
2837 snprintf(buf, sizeof(buf), "'%s'",
2838 ast_get_ignorepat_name(ip));
2839 ast_cli(fd, " Ignore pattern => %-45s [%s]\n",
2840 buf, ast_get_ignorepat_registrar(ip));
2841 ip = ast_walk_context_ignorepats(c, ip);
2843 sw = ast_walk_context_switches(c, NULL);
2845 bzero(buf, sizeof(buf));
2846 snprintf(buf, sizeof(buf), "'%s/%s'",
2847 ast_get_switch_name(sw),
2848 ast_get_switch_data(sw));
2849 ast_cli(fd, " Alt. Switch => %-45s [%s]\n",
2850 buf, ast_get_switch_registrar(sw));
2851 sw = ast_walk_context_switches(c, sw);
2855 ast_unlock_context(c);
2857 /* if we print something in context, make an empty line */
2858 if (context_info_printed) ast_cli(fd, "\n");
2861 c = ast_walk_contexts(c);
2863 ast_unlock_contexts();
2865 /* check for input failure and throw some error messages */
2866 if (context && !context_existence) {
2867 ast_cli(fd, "There is no existence of '%s' context\n",
2869 return RESULT_FAILURE;
2872 if (exten && !extension_existence) {
2874 ast_cli(fd, "There is no existence of %s@%s extension\n",
2878 "There is no existence of '%s' extension in all contexts\n",
2880 return RESULT_FAILURE;
2884 return RESULT_SUCCESS;
2888 * CLI entries for upper commands ...
2890 static struct ast_cli_entry show_applications_cli =
2891 { { "show", "applications", NULL },
2892 handle_show_applications, "Shows registered applications",
2893 show_applications_help, complete_show_applications };
2895 static struct ast_cli_entry show_application_cli =
2896 { { "show", "application", NULL },
2897 handle_show_application, "Describe a specific application",
2898 show_application_help, complete_show_application };
2900 static struct ast_cli_entry show_dialplan_cli =
2901 { { "show", "dialplan", NULL },
2902 handle_show_dialplan, "Show dialplan",
2903 show_dialplan_help, complete_show_dialplan_context };
2905 static struct ast_cli_entry show_switches_cli =
2906 { { "show", "switches", NULL },
2907 handle_show_switches, "Show alternative switches",
2908 show_switches_help, NULL };
2910 int ast_unregister_application(char *app) {
2911 struct ast_app *tmp, *tmpl = NULL;
2912 if (ast_mutex_lock(&applock)) {
2913 ast_log(LOG_ERROR, "Unable to lock application list\n");
2918 if (!strcasecmp(app, tmp->name)) {
2920 tmpl->next = tmp->next;
2923 if (option_verbose > 1)
2924 ast_verbose( VERBOSE_PREFIX_2 "Unregistered application '%s'\n", tmp->name);
2926 ast_mutex_unlock(&applock);
2932 ast_mutex_unlock(&applock);
2936 struct ast_context *ast_context_create(struct ast_context **extcontexts, char *name, char *registrar)
2938 struct ast_context *tmp, **local_contexts;
2940 local_contexts = &contexts;
2941 ast_mutex_lock(&conlock);
2943 local_contexts = extcontexts;
2945 tmp = *local_contexts;
2947 if (!strcasecmp(tmp->name, name)) {
2948 ast_mutex_unlock(&conlock);
2949 ast_log(LOG_WARNING, "Tried to register context '%s', already in use\n", name);
2951 ast_mutex_unlock(&conlock);
2956 tmp = malloc(sizeof(struct ast_context));
2958 memset(tmp, 0, sizeof(struct ast_context));
2959 ast_mutex_init(&tmp->lock);
2960 strncpy(tmp->name, name, sizeof(tmp->name)-1);
2962 tmp->registrar = registrar;
2963 tmp->next = *local_contexts;
2964 tmp->includes = NULL;
2965 tmp->ignorepats = NULL;
2966 *local_contexts = tmp;
2968 ast_log(LOG_DEBUG, "Registered context '%s'\n", tmp->name);
2969 else if (option_verbose > 2)
2970 ast_verbose( VERBOSE_PREFIX_3 "Registered extension context '%s'\n", tmp->name);
2972 ast_log(LOG_ERROR, "Out of memory\n");
2975 ast_mutex_unlock(&conlock);
2979 void __ast_context_destroy(struct ast_context *con, char *registrar);
2981 void ast_merge_contexts_and_delete(struct ast_context **extcontexts, char *registrar) {
2982 struct ast_context *tmp, *lasttmp = NULL;
2984 ast_mutex_lock(&conlock);
2986 __ast_context_destroy(NULL,registrar);
2993 __ast_context_destroy(tmp,tmp->registrar);
2999 lasttmp->next = contexts;
3000 contexts = *extcontexts;
3001 *extcontexts = NULL;
3003 ast_log(LOG_WARNING, "Requested contexts didn't get merged\n");
3004 ast_mutex_unlock(&conlock);
3010 * EBUSY - can't lock
3011 * ENOENT - no existence of context
3013 int ast_context_add_include(char *context, char *include, char *registrar)
3015 struct ast_context *c;
3017 if (ast_lock_contexts()) {
3022 /* walk contexts ... */
3023 c = ast_walk_contexts(NULL);
3025 /* ... search for the right one ... */
3026 if (!strcmp(ast_get_context_name(c), context)) {
3027 int ret = ast_context_add_include2(c, include, registrar);
3028 /* ... unlock contexts list and return */
3029 ast_unlock_contexts();
3032 c = ast_walk_contexts(c);
3035 /* we can't find the right context */
3036 ast_unlock_contexts();
3044 while(*c && (*c != '|')) c++; \
3045 if (*c) { *c = '\0'; c++; } else c = NULL; \
3048 static void get_timerange(struct ast_include *i, char *times)
3056 /* start disabling all times, fill the fields with 0's, as they may contain garbage */
3057 memset(i->minmask, 0, sizeof(i->minmask));
3059 /* Star is all times */
3060 if (ast_strlen_zero(times) || !strcmp(times, "*")) {
3062 i->minmask[x] = (1 << 30) - 1;
3065 /* Otherwise expect a range */
3066 e = strchr(times, '-');
3068 ast_log(LOG_WARNING, "Time range is not valid. Assuming no restrictions based on time.\n");
3073 while(*e && !isdigit(*e)) e++;
3075 ast_log(LOG_WARNING, "Invalid time range. Assuming no restrictions based on time.\n");
3078 if (sscanf(times, "%d:%d", &s1, &s2) != 2) {
3079 ast_log(LOG_WARNING, "%s isn't a time. Assuming no restrictions based on time.\n", times);
3082 if (sscanf(e, "%d:%d", &e1, &e2) != 2) {
3083 ast_log(LOG_WARNING, "%s isn't a time. Assuming no restrictions based on time.\n", e);
3088 s1 = s1 * 30 + s2/2;
3089 if ((s1 < 0) || (s1 >= 24*30)) {
3090 ast_log(LOG_WARNING, "%s isn't a valid start time. Assuming no time.\n", times);
3093 e1 = e1 * 30 + e2/2;
3094 if ((e1 < 0) || (e1 >= 24*30)) {
3095 ast_log(LOG_WARNING, "%s isn't a valid end time. Assuming no time.\n", e);
3098 /* Go through the time and enable each appropriate bit */
3099 for (x=s1;x != e1;x = (x + 1) % (24 * 30)) {
3100 i->minmask[x/30] |= (1 << (x % 30));
3102 /* Do the last one */
3103 i->minmask[x/30] |= (1 << (x % 30));
3105 for (cth=0;cth<24;cth++) {
3106 /* Initialize masks to blank */
3107 i->minmask[cth] = 0;
3108 for (ctm=0;ctm<30;ctm++) {
3110 /* First hour with more than one hour */
3111 (((cth == s1) && (ctm >= s2)) &&
3114 || (((cth == s1) && (ctm >= s2)) &&
3115 ((cth == e1) && (ctm <= e2)))
3116 /* In between first and last hours (more than 2 hours) */
3119 /* Last hour with more than one hour */
3121 ((cth == e1) && (ctm <= e2)))
3123 i->minmask[cth] |= (1 << (ctm / 2));
3131 static char *days[] =
3142 static unsigned int get_dow(char *dow)
3145 /* The following line is coincidence, really! */
3149 /* Check for all days */
3150 if (ast_strlen_zero(dow) || !strcmp(dow, "*"))
3151 return (1 << 7) - 1;
3152 /* Get start and ending days */
3153 c = strchr(dow, '-');
3159 /* Find the start */
3161 while((s < 7) && strcasecmp(dow, days[s])) s++;
3163 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", dow);
3168 while((e < 7) && strcasecmp(c, days[e])) e++;
3170 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
3176 for (x=s; x != e; x = (x + 1) % 7) {
3184 static unsigned int get_day(char *day)
3187 /* The following line is coincidence, really! */
3191 /* Check for all days */
3192 if (ast_strlen_zero(day) || !strcmp(day, "*")) {
3193 mask = (1 << 30) + ((1 << 30) - 1);
3196 /* Get start and ending days */
3197 c = strchr(day, '-');
3202 /* Find the start */
3203 if (sscanf(day, "%d", &s) != 1) {
3204 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", day);
3207 if ((s < 1) || (s > 31)) {
3208 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", day);
3213 if (sscanf(c, "%d", &e) != 1) {
3214 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
3217 if ((e < 1) || (e > 31)) {
3218 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
3225 for (x=s;x!=e;x = (x + 1) % 31) {
3232 static char *months[] =
3248 static unsigned int get_month(char *mon)
3251 /* The following line is coincidence, really! */
3255 /* Check for all days */
3256 if (ast_strlen_zero(mon) || !strcmp(mon, "*"))
3257 return (1 << 12) - 1;
3258 /* Get start and ending days */
3259 c = strchr(mon, '-');
3264 /* Find the start */
3266 while((s < 12) && strcasecmp(mon, months[s])) s++;
3268 ast_log(LOG_WARNING, "Invalid month '%s', assuming none\n", mon);
3273 while((e < 12) && strcasecmp(mon, months[e])) e++;
3275 ast_log(LOG_WARNING, "Invalid month '%s', assuming none\n", c);
3281 for (x=s; x!=e; x = (x + 1) % 12) {
3289 static void build_timing(struct ast_include *i, char *info)
3293 /* Check for empty just in case */
3294 if (ast_strlen_zero(info))
3297 /* Assume everything except time */
3298 i->monthmask = (1 << 12) - 1;
3299 i->daymask = (1 << 30) - 1 + (1 << 30);
3300 i->dowmask = (1 << 7) - 1;
3301 /* Avoid using str tok */
3303 /* Info has the time range, start with that */
3304 get_timerange(i, info);
3309 /* Now check for day of week */
3310 i->dowmask = get_dow(info);
3316 /* Now check for the day of the month */
3317 i->daymask = get_day(info);
3322 /* And finally go for the month */
3323 i->monthmask = get_month(info);
3328 * ENOMEM - out of memory
3329 * EBUSY - can't lock
3330 * EEXIST - already included
3331 * EINVAL - there is no existence of context for inclusion
3333 int ast_context_add_include2(struct ast_context *con, char *value,
3336 struct ast_include *new_include;
3338 struct ast_include *i, *il = NULL; /* include, include_last */
3340 /* allocate new include structure ... */
3341 if (!(new_include = malloc(sizeof(struct ast_include)))) {
3342 ast_log(LOG_ERROR, "Out of memory\n");
3347 /* ... fill in this structure ... */
3348 memset(new_include, 0, sizeof(struct ast_include));
3349 strncpy(new_include->name, value, sizeof(new_include->name)-1);
3350 strncpy(new_include->rname, value, sizeof(new_include->rname)-1);
3351 c = new_include->rname;
3352 /* Strip off timing info */
3353 while(*c && (*c != '|')) c++;
3354 /* Process if it's there */
3356 build_timing(new_include, c+1);
3359 new_include->next = NULL;
3360 new_include->registrar = registrar;
3362 /* ... try to lock this context ... */
3363 if (ast_mutex_lock(&con->lock)) {
3369 /* ... go to last include and check if context is already included too... */
3372 if (!strcasecmp(i->name, new_include->name)) {
3374 ast_mutex_unlock(&con->lock);
3382 /* ... include new context into context list, unlock, return */
3384 il->next = new_include;
3386 con->includes = new_include;
3387 if (option_verbose > 2)
3388 ast_verbose(VERBOSE_PREFIX_3 "Including context '%s' in context '%s'\n", new_include->name, ast_get_context_name(con));
3389 ast_mutex_unlock(&con->lock);
3396 * EBUSY - can't lock
3397 * ENOENT - no existence of context
3399 int ast_context_add_switch(char *context, char *sw, char *data, char *registrar)
3401 struct ast_context *c;
3403 if (ast_lock_contexts()) {
3408 /* walk contexts ... */
3409 c = ast_walk_contexts(NULL);
3411 /* ... search for the right one ... */
3412 if (!strcmp(ast_get_context_name(c), context)) {
3413 int ret = ast_context_add_switch2(c, sw, data, registrar);
3414 /* ... unlock contexts list and return */
3415 ast_unlock_contexts();
3418 c = ast_walk_contexts(c);
3421 /* we can't find the right context */
3422 ast_unlock_contexts();
3429 * ENOMEM - out of memory
3430 * EBUSY - can't lock
3431 * EEXIST - already included
3432 * EINVAL - there is no existence of context for inclusion
3434 int ast_context_add_switch2(struct ast_context *con, char *value,
3435 char *data, char *registrar)
3437 struct ast_sw *new_sw;
3438 struct ast_sw *i, *il = NULL; /* sw, sw_last */
3440 /* allocate new sw structure ... */
3441 if (!(new_sw = malloc(sizeof(struct ast_sw)))) {
3442 ast_log(LOG_ERROR, "Out of memory\n");
3447 /* ... fill in this structure ... */
3448 memset(new_sw, 0, sizeof(struct ast_sw));
3449 strncpy(new_sw->name, value, sizeof(new_sw->name)-1);
3451 strncpy(new_sw->data, data, sizeof(new_sw->data)-1);
3453 strncpy(new_sw->data, "", sizeof(new_sw->data)-1);
3454 new_sw->next = NULL;
3455 new_sw->registrar = registrar;
3457 /* ... try to lock this context ... */
3458 if (ast_mutex_lock(&con->lock)) {
3464 /* ... go to last sw and check if context is already swd too... */
3467 if (!strcasecmp(i->name, new_sw->name) && !strcasecmp(i->data, new_sw->data)) {
3469 ast_mutex_unlock(&con->lock);
3477 /* ... sw new context into context list, unlock, return */
3482 if (option_verbose > 2)
3483 ast_verbose(VERBOSE_PREFIX_3 "Including switch '%s/%s' in context '%s'\n", new_sw->name, new_sw->data, ast_get_context_name(con));
3484 ast_mutex_unlock(&con->lock);
3490 * EBUSY - can't lock
3491 * ENOENT - there is not context existence
3493 int ast_context_remove_ignorepat(char *context, char *ignorepat, char *registrar)
3495 struct ast_context *c;
3497 if (ast_lock_contexts()) {
3502 c = ast_walk_contexts(NULL);
3504 if (!strcmp(ast_get_context_name(c), context)) {
3505 int ret = ast_context_remove_ignorepat2(c, ignorepat, registrar);
3506 ast_unlock_contexts();
3509 c = ast_walk_contexts(c);
3512 ast_unlock_contexts();
3517 int ast_context_remove_ignorepat2(struct ast_context *con, char *ignorepat, char *regist