2 * Asterisk -- A telephony toolkit for Linux.
6 * Copyright (C) 1999-2004, Digium, Inc.
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>
31 #include <asterisk/causes.h>
46 * The speed of extension handling will likely be among the most important
47 * aspects of this PBX. The switching scheme as it exists right now isn't
48 * terribly bad (it's O(N+M), where N is the # of extensions and M is the avg #
49 * of priorities, but a constant search time here would be great ;-)
54 #define EXT_DATA_SIZE 256
56 #define EXT_DATA_SIZE 8192
60 #define VAR_SOFTTRAN 2
61 #define VAR_HARDTRAN 3
65 /* ast_exten: An extension */
67 char *exten; /* Extension name */
68 int matchcid; /* Match caller id ? */
69 char *cidmatch; /* Caller id to match for this extension */
70 int priority; /* Priority */
71 char *label; /* Label */
72 struct ast_context *parent; /* The context this extension belongs to */
73 char *app; /* Application to execute */
74 void *data; /* Data to use (arguments) */
75 void (*datad)(void *); /* Data destructor */
76 struct ast_exten *peer; /* Next higher priority with our extension */
77 const char *registrar; /* Registrar */
78 struct ast_exten *next; /* Extension with a greater ID */
82 /* ast_include: include= support in extensions.conf */
85 char *rname; /* Context to include */
86 const char *registrar; /* Registrar */
87 int hastime; /* If time construct exists */
88 struct ast_timing timing; /* time construct */
89 struct ast_include *next; /* Link them together */
93 /* ast_sw: Switch statement in extensions.conf */
96 const char *registrar; /* Registrar */
97 char *data; /* Data load */
98 struct ast_sw *next; /* Link them together */
102 struct ast_ignorepat {
103 const char *registrar;
104 struct ast_ignorepat *next;
108 /* ast_context: An extension context */
110 ast_mutex_t lock; /* A lock to prevent multiple threads from clobbering the context */
111 struct ast_exten *root; /* The root of the list of extensions */
112 struct ast_context *next; /* Link them together */
113 struct ast_include *includes; /* Include other contexts */
114 struct ast_ignorepat *ignorepats; /* Patterns for which to continue playing dialtone */
115 const char *registrar; /* Registrar */
116 struct ast_sw *alts; /* Alternative switches */
117 char name[0]; /* Name of the context */
121 /* ast_app: An application */
123 int (*execute)(struct ast_channel *chan, void *data);
124 const char *synopsis; /* Synopsis text for 'show applications' */
125 const char *description; /* Description (help text) for 'show application <name>' */
126 struct ast_app *next; /* Next app in list */
127 char name[0]; /* Name of the application */
130 /* ast_state_cb: An extension state notify */
131 struct ast_state_cb {
134 ast_state_cb_type callback;
135 struct ast_state_cb *next;
138 /* ast_state_cb: An extension state notify */
139 struct ast_devstate_cb {
141 ast_devstate_cb_type callback;
142 struct ast_devstate_cb *next;
145 static struct ast_devstate_cb *devcbs;
148 struct ast_exten *exten;
150 struct ast_state_cb *callbacks;
151 struct ast_hint *next;
154 int ast_pbx_outgoing_cdr_failed(void);
156 static int pbx_builtin_prefix(struct ast_channel *, void *);
157 static int pbx_builtin_suffix(struct ast_channel *, void *);
158 static int pbx_builtin_stripmsd(struct ast_channel *, void *);
159 static int pbx_builtin_answer(struct ast_channel *, void *);
160 static int pbx_builtin_goto(struct ast_channel *, void *);
161 static int pbx_builtin_hangup(struct ast_channel *, void *);
162 static int pbx_builtin_background(struct ast_channel *, void *);
163 static int pbx_builtin_dtimeout(struct ast_channel *, void *);
164 static int pbx_builtin_rtimeout(struct ast_channel *, void *);
165 static int pbx_builtin_atimeout(struct ast_channel *, void *);
166 static int pbx_builtin_wait(struct ast_channel *, void *);
167 static int pbx_builtin_waitexten(struct ast_channel *, void *);
168 static int pbx_builtin_setlanguage(struct ast_channel *, void *);
169 static int pbx_builtin_resetcdr(struct ast_channel *, void *);
170 static int pbx_builtin_setaccount(struct ast_channel *, void *);
171 static int pbx_builtin_setamaflags(struct ast_channel *, void *);
172 static int pbx_builtin_ringing(struct ast_channel *, void *);
173 static int pbx_builtin_progress(struct ast_channel *, void *);
174 static int pbx_builtin_congestion(struct ast_channel *, void *);
175 static int pbx_builtin_busy(struct ast_channel *, void *);
176 static int pbx_builtin_setglobalvar(struct ast_channel *, void *);
177 static int pbx_builtin_noop(struct ast_channel *, void *);
178 static int pbx_builtin_gotoif(struct ast_channel *, void *);
179 static int pbx_builtin_gotoiftime(struct ast_channel *, void *);
180 static int pbx_builtin_saynumber(struct ast_channel *, void *);
181 static int pbx_builtin_saydigits(struct ast_channel *, void *);
182 static int pbx_builtin_saycharacters(struct ast_channel *, void *);
183 static int pbx_builtin_sayphonetic(struct ast_channel *, void *);
184 int pbx_builtin_setvar(struct ast_channel *, void *);
185 static int pbx_builtin_importvar(struct ast_channel *, void *);
186 void pbx_builtin_setvar_helper(struct ast_channel *chan, char *name, char *value);
187 char *pbx_builtin_getvar_helper(struct ast_channel *chan, char *name);
189 static struct varshead globals;
191 static int autofallthrough = 0;
193 static struct pbx_builtin {
194 char name[AST_MAX_APP];
195 int (*execute)(struct ast_channel *chan, void *data);
200 /* These applications are built into the PBX core and do not
201 need separate modules
205 { "AbsoluteTimeout", pbx_builtin_atimeout,
206 "Set absolute maximum time of call",
207 " AbsoluteTimeout(seconds): Set the absolute maximum amount of time permitted\n"
208 "for a call. A setting of 0 disables the timeout. Always returns 0.\n"
211 { "Answer", pbx_builtin_answer,
212 "Answer a channel if ringing",
213 " Answer(): If the channel is ringing, answer it, otherwise do nothing. \n"
214 "Returns 0 unless it tries to answer the channel and fails.\n"
217 { "BackGround", pbx_builtin_background,
218 "Play a file while awaiting extension",
219 " Background(filename1[&filename2...][|options[|langoverride]]): Plays\n"
220 "given files, while simultaneously waiting for the user to begin typing\n"
221 "an extension. The timeouts do not count until the last BackGround\n"
222 "application has ended. Options may also be included following a pipe \n"
223 "symbol. The 'skip' option causes the playback of the message to be \n"
224 "skipped if the channel is not in the 'up' state (i.e. it hasn't been\n"
225 "answered yet. If 'skip' is specified, the application will return\n"
226 "immediately should the channel not be off hook. Otherwise, unless \n"
227 "'noanswer' is specified, the channel channel will be answered before the\n"
228 "sound is played. Not all channels support playing messages while still\n"
229 "hook. The 'langoverride' may be a language to use for playing the prompt\n"
230 "which differs from the current language of the channel. Returns -1 if \n"
231 "the channel was hung up, or if the file does not exist. Returns 0 otherwise.\n"
234 { "Busy", pbx_builtin_busy,
235 "Indicate busy condition and stop",
236 " Busy([timeout]): Requests that the channel indicate busy condition and\n"
237 "then waits for the user to hang up or the optional timeout to expire.\n"
241 { "Congestion", pbx_builtin_congestion,
242 "Indicate congestion and stop",
243 " Congestion([timeout]): Requests that the channel indicate congestion\n"
244 "and then waits for the user to hang up or for the optional timeout to\n"
245 "expire. Always returns -1."
248 { "DigitTimeout", pbx_builtin_dtimeout,
249 "Set maximum timeout between digits",
250 " DigitTimeout(seconds): Set the maximum amount of time permitted between\n"
251 "digits when the user is typing in an extension. When this timeout expires,\n"
252 "after the user has started to type in an extension, the extension will be\n"
253 "considered complete, and will be interpreted. Note that if an extension\n"
254 "typed in is valid, it will not have to timeout to be tested, so typically\n"
255 "at the expiry of this timeout, the extension will be considered invalid\n"
256 "(and thus control would be passed to the 'i' extension, or if it doesn't\n"
257 "exist the call would be terminated). Always returns 0.\n"
260 { "Goto", pbx_builtin_goto,
261 "Goto a particular priority, extension, or context",
262 " Goto([[context|]extension|]priority): Set the priority to the specified\n"
263 "value, optionally setting the extension and optionally the context as well.\n"
264 "The extension BYEXTENSION is special in that it uses the current extension,\n"
265 "thus permitting you to go to a different context, without specifying a\n"
266 "specific extension. Always returns 0, even if the given context, extension,\n"
267 "or priority is invalid.\n"
270 { "GotoIf", pbx_builtin_gotoif,
272 " GotoIf(Condition?label1:label2): Go to label 1 if condition is\n"
273 "true, to label2 if condition is false. Either label1 or label2 may be\n"
274 "omitted (in that case, we just don't take the particular branch) but not\n"
275 "both. Look for the condition syntax in examples or documentation."
278 { "GotoIfTime", pbx_builtin_gotoiftime,
279 "Conditional goto on current time",
280 " GotoIfTime(<times>|<weekdays>|<mdays>|<months>?[[context|]extension|]pri):\n"
281 "If the current time matches the specified time, then branch to the specified\n"
282 "extension. Each of the elements may be specified either as '*' (for always)\n"
283 "or as a range. See the 'include' syntax for details."
286 { "Hangup", pbx_builtin_hangup,
287 "Unconditional hangup",
288 " Hangup(): Unconditionally hangs up a given channel by returning -1 always.\n"
291 { "NoOp", pbx_builtin_noop,
293 " NoOp(): No-operation; Does nothing."
296 { "Prefix", pbx_builtin_prefix,
297 "Prepend leading digits",
298 " Prefix(digits): Prepends the digit string specified by digits to the\n"
299 "channel's associated extension. For example, the number 1212 when prefixed\n"
300 "with '555' will become 5551212. This app always returns 0, and the PBX will\n"
301 "continue processing at the next priority for the *new* extension.\n"
302 " So, for example, if priority 3 of 1212 is Prefix 555, the next step\n"
303 "executed will be priority 4 of 5551212. If you switch into an extension\n"
304 "which has no first step, the PBX will treat it as though the user dialed an\n"
305 "invalid extension.\n"
308 { "Progress", pbx_builtin_progress,
310 " Progress(): Request that the channel indicate in-band progress is \n"
311 "available to the user.\nAlways returns 0.\n"
314 { "ResetCDR", pbx_builtin_resetcdr,
315 "Resets the Call Data Record",
316 " ResetCDR([options]): Causes the Call Data Record to be reset, optionally\n"
317 "storing the current CDR before zeroing it out (if 'w' option is specifed).\n"
318 "record WILL be stored.\nAlways returns 0.\n"
321 { "ResponseTimeout", pbx_builtin_rtimeout,
322 "Set maximum timeout awaiting response",
323 " ResponseTimeout(seconds): Set the maximum amount of time permitted after\n"
324 "falling through a series of priorities for a channel in which the user may\n"
325 "begin typing an extension. If the user does not type an extension in this\n"
326 "amount of time, control will pass to the 't' extension if it exists, and\n"
327 "if not the call would be terminated.\nAlways returns 0.\n"
330 { "Ringing", pbx_builtin_ringing,
331 "Indicate ringing tone",
332 " Ringing(): Request that the channel indicate ringing tone to the user.\n"
333 "Always returns 0.\n"
336 { "SayNumber", pbx_builtin_saynumber,
338 " SayNumber(digits[,gender]): Says the passed number. SayNumber is using\n"
339 "the current language setting for the channel. (See app SetLanguage).\n"
342 { "SayDigits", pbx_builtin_saydigits,
344 " SayDigits(digits): Says the passed digits. SayDigits is using the\n"
345 "current language setting for the channel. (See app setLanguage)\n"
348 { "SayAlpha", pbx_builtin_saycharacters,
350 " SayAlpha(string): Spells the passed string\n"
353 { "SayPhonetic", pbx_builtin_sayphonetic,
355 " SayPhonetic(string): Spells the passed string with phonetic alphabet\n"
358 { "SetAccount", pbx_builtin_setaccount,
360 " SetAccount([account]): Set the channel account code for billing\n"
361 "purposes. Always returns 0.\n"
364 { "SetAMAFlags", pbx_builtin_setamaflags,
366 " SetAMAFlags([flag]): Set the channel AMA Flags for billing\n"
367 "purposes. Always returns 0.\n"
370 { "SetGlobalVar", pbx_builtin_setglobalvar,
371 "Set global variable to value",
372 " SetGlobalVar(#n=value): Sets global variable n to value. Global\n"
373 "variable are available across channels.\n"
376 { "SetLanguage", pbx_builtin_setlanguage,
377 "Sets user language",
378 " SetLanguage(language): Set the channel language to 'language'. This\n"
379 "information is used for the syntax in generation of numbers, and to choose\n"
380 "a natural language file when available.\n"
381 " For example, if language is set to 'fr' and the file 'demo-congrats' is \n"
382 "requested to be played, if the file 'fr/demo-congrats' exists, then\n"
383 "it will play that file, and if not will play the normal 'demo-congrats'.\n"
384 "Always returns 0.\n"
387 { "SetVar", pbx_builtin_setvar,
388 "Set variable to value",
389 " SetVar(#n=value): Sets variable n to value. If prefixed with _, single\n"
390 "inheritance assumed. If prefixed with __, infinite inheritance is assumed.\n" },
392 { "ImportVar", pbx_builtin_importvar,
393 "Set variable to value",
394 " ImportVar(#n=channel|variable): Sets variable n to variable as evaluated on\n"
395 "the specified channel (instead of current). If prefixed with _, single\n"
396 "inheritance assumed. If prefixed with __, infinite inheritance is assumed.\n" },
398 { "StripMSD", pbx_builtin_stripmsd,
399 "Strip leading digits",
400 " StripMSD(count): Strips the leading 'count' digits from the channel's\n"
401 "associated extension. For example, the number 5551212 when stripped with a\n"
402 "count of 3 would be changed to 1212. This app always returns 0, and the PBX\n"
403 "will continue processing at the next priority for the *new* extension.\n"
404 " So, for example, if priority 3 of 5551212 is StripMSD 3, the next step\n"
405 "executed will be priority 4 of 1212. If you switch into an extension which\n"
406 "has no first step, the PBX will treat it as though the user dialed an\n"
407 "invalid extension.\n"
410 { "Suffix", pbx_builtin_suffix,
411 "Append trailing digits",
412 " Suffix(digits): Appends the digit string specified by digits to the\n"
413 "channel's associated extension. For example, the number 555 when suffixed\n"
414 "with '1212' will become 5551212. This app always returns 0, and the PBX will\n"
415 "continue processing at the next priority for the *new* extension.\n"
416 " So, for example, if priority 3 of 555 is Suffix 1212, the next step\n"
417 "executed will be priority 4 of 5551212. If you switch into an extension\n"
418 "which has no first step, the PBX will treat it as though the user dialed an\n"
419 "invalid extension.\n"
422 { "Wait", pbx_builtin_wait,
423 "Waits for some time",
424 " Wait(seconds): Waits for a specified number of seconds, then returns 0.\n"
425 "seconds can be passed with fractions of a second. (eg: 1.5 = 1.5 seconds)\n"
428 { "WaitExten", pbx_builtin_waitexten,
429 "Waits for an extension to be entered",
430 " WaitExten([seconds]): Waits for the user to enter a new extension for the \n"
431 "specified number of seconds, then returns 0. Seconds can be passed with\n"
432 "fractions of a seconds (eg: 1.5 = 1.5 seconds) or if unspecified the\n"
433 "default extension timeout will be used.\n"
438 AST_MUTEX_DEFINE_STATIC(applock); /* Lock for the application list */
439 static struct ast_context *contexts = NULL;
440 AST_MUTEX_DEFINE_STATIC(conlock); /* Lock for the ast_context list */
441 static struct ast_app *apps = NULL;
443 AST_MUTEX_DEFINE_STATIC(switchlock); /* Lock for switches */
444 struct ast_switch *switches = NULL;
446 AST_MUTEX_DEFINE_STATIC(hintlock); /* Lock for extension state notifys */
447 static int stateid = 1;
448 struct ast_hint *hints = NULL;
449 struct ast_state_cb *statecbs = NULL;
451 int pbx_exec(struct ast_channel *c, /* Channel */
452 struct ast_app *app, /* Application */
453 void *data, /* Data for execution */
454 int newstack) /* Force stack increment */
456 /* This function is special. It saves the stack so that no matter
457 how many times it is called, it returns to the same place */
463 int (*execute)(struct ast_channel *chan, void *data) = app->execute;
467 ast_cdr_setapp(c->cdr, app->name, data);
469 /* save channel values */
470 saved_c_appl= c->appl;
471 saved_c_data= c->data;
475 res = execute(c, data);
476 /* restore channel values */
477 c->appl= saved_c_appl;
478 c->data= saved_c_data;
481 ast_log(LOG_WARNING, "You really didn't want to call this function with newstack set to 0\n");
486 /* Go no deeper than this through includes (not counting loops) */
487 #define AST_PBX_MAX_STACK 64
489 #define HELPER_EXISTS 0
490 #define HELPER_SPAWN 1
491 #define HELPER_EXEC 2
492 #define HELPER_CANMATCH 3
493 #define HELPER_MATCHMORE 4
494 #define HELPER_FINDLABEL 5
496 struct ast_app *pbx_findapp(const char *app)
500 if (ast_mutex_lock(&applock)) {
501 ast_log(LOG_WARNING, "Unable to obtain application lock\n");
506 if (!strcasecmp(tmp->name, app))
510 ast_mutex_unlock(&applock);
514 static struct ast_switch *pbx_findswitch(const char *sw)
516 struct ast_switch *asw;
518 if (ast_mutex_lock(&switchlock)) {
519 ast_log(LOG_WARNING, "Unable to obtain application lock\n");
524 if (!strcasecmp(asw->name, sw))
528 ast_mutex_unlock(&switchlock);
532 static inline int include_valid(struct ast_include *i)
537 return ast_check_timing(&(i->timing));
540 static void pbx_destroy(struct ast_pbx *p)
545 #define EXTENSION_MATCH_CORE(data,pattern,match) {\
546 /* All patterns begin with _ */\
547 if (pattern[0] != '_') \
549 /* Start optimistic */\
552 while(match && *data && *pattern && (*pattern != '/')) {\
553 while (*data == '-' && (*(data+1) != '\0')) data++;\
554 switch(toupper(*pattern)) {\
561 where=strchr(pattern,']');\
563 border=(int)(where-pattern);\
564 if (!where || border > strlen(pattern)) {\
565 ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");\
568 for (i=0; i<border; i++) {\
571 if (pattern[i+1]=='-') {\
572 if (*data >= pattern[i] && *data <= pattern[i+2]) {\
579 if (res==1 || *data==pattern[i]) {\
588 if ((*data < '2') || (*data > '9'))\
592 if ((*data < '0') || (*data > '9'))\
596 if ((*data < '1') || (*data > '9'))\
604 /* Ignore these characters */\
608 if (*data != *pattern)\
616 int ast_extension_match(const char *pattern, const char *data)
619 /* If they're the same return */
620 if (!strcmp(pattern, data))
622 EXTENSION_MATCH_CORE(data,pattern,match);
623 /* Must be at the end of both */
624 if (*data || (*pattern && (*pattern != '/')))
629 int ast_extension_close(const char *pattern, const char *data, int needmore)
632 /* If "data" is longer, it can'be a subset of pattern unless
633 pattern is a pattern match */
634 if ((strlen(pattern) < strlen(data)) && (pattern[0] != '_'))
637 if ((ast_strlen_zero((char *)data) || !strncasecmp(pattern, data, strlen(data))) &&
638 (!needmore || (strlen(pattern) > strlen(data)))) {
641 EXTENSION_MATCH_CORE(data,pattern,match);
642 /* If there's more or we don't care about more, return non-zero, otlherwise it's a miss */
643 if (!needmore || *pattern) {
649 struct ast_context *ast_context_find(const char *name)
651 struct ast_context *tmp;
652 ast_mutex_lock(&conlock);
656 if (!strcasecmp(name, tmp->name))
662 ast_mutex_unlock(&conlock);
666 #define STATUS_NO_CONTEXT 1
667 #define STATUS_NO_EXTENSION 2
668 #define STATUS_NO_PRIORITY 3
669 #define STATUS_NO_LABEL 4
670 #define STATUS_SUCCESS 5
672 static int matchcid(const char *cidpattern, const char *callerid)
676 /* If the Caller*ID pattern is empty, then we're matching NO Caller*ID, so
677 failing to get a number should count as a match, otherwise not */
680 if (!ast_strlen_zero(cidpattern))
688 return ast_extension_match(cidpattern, callerid);
691 static struct ast_exten *pbx_find_extension(struct ast_channel *chan, struct ast_context *bypass, const char *context, const char *exten, int priority, const char *label, const char *callerid, int action, char *incstack[], int *stacklen, int *status, struct ast_switch **swo, char **data, const char **foundcontext)
694 struct ast_context *tmp;
695 struct ast_exten *e, *eroot;
696 struct ast_include *i;
698 struct ast_switch *asw;
700 /* Initialize status if appropriate */
702 *status = STATUS_NO_CONTEXT;
706 /* Check for stack overflow */
707 if (*stacklen >= AST_PBX_MAX_STACK) {
708 ast_log(LOG_WARNING, "Maximum PBX stack exceeded\n");
711 /* Check first to see if we've already been checked */
712 for (x=0;x<*stacklen;x++) {
713 if (!strcasecmp(incstack[x], context))
722 if (bypass || !strcmp(tmp->name, context)) {
723 if (*status < STATUS_NO_EXTENSION)
724 *status = STATUS_NO_EXTENSION;
727 /* Match extension */
728 if ((((action != HELPER_MATCHMORE) && ast_extension_match(eroot->exten, exten)) ||
729 ((action == HELPER_CANMATCH) && (ast_extension_close(eroot->exten, exten, 0))) ||
730 ((action == HELPER_MATCHMORE) && (ast_extension_close(eroot->exten, exten, 1)))) &&
731 (!eroot->matchcid || matchcid(eroot->cidmatch, callerid))) {
733 if (*status < STATUS_NO_PRIORITY)
734 *status = STATUS_NO_PRIORITY;
737 if (action == HELPER_FINDLABEL) {
738 if (*status < STATUS_NO_LABEL)
739 *status = STATUS_NO_LABEL;
740 if (label && e->label && !strcmp(label, e->label)) {
741 *status = STATUS_SUCCESS;
742 *foundcontext = context;
745 } else if (e->priority == priority) {
746 *status = STATUS_SUCCESS;
747 *foundcontext = context;
755 /* Check alternative switches */
758 if ((asw = pbx_findswitch(sw->name))) {
759 if (action == HELPER_CANMATCH)
760 res = asw->canmatch ? asw->canmatch(chan, context, exten, priority, callerid, sw->data) : 0;
761 else if (action == HELPER_MATCHMORE)
762 res = asw->matchmore ? asw->matchmore(chan, context, exten, priority, callerid, sw->data) : 0;
764 res = asw->exists ? asw->exists(chan, context, exten, priority, callerid, sw->data) : 0;
769 *foundcontext = context;
773 ast_log(LOG_WARNING, "No such switch '%s'\n", sw->name);
777 /* Setup the stack */
778 incstack[*stacklen] = tmp->name;
780 /* Now try any includes we have in this context */
783 if (include_valid(i)) {
784 if ((e = pbx_find_extension(chan, bypass, i->rname, exten, priority, label, callerid, action, incstack, stacklen, status, swo, data, foundcontext)))
798 void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp)
801 char tmpvar[80] = "";
803 struct tm brokentime;
805 struct ast_var_t *variables;
810 /* Now we have the variable name on cp3 */
811 if (!strncasecmp(var,"LEN(",4)) {
814 if (strrchr(var,')')) {
816 strncpy(cp3, var, sizeof(cp3) - 1);
817 cp3[len-len_len-1]='\0';
818 sprintf(workspace,"%d",(int)strlen(cp3));
824 } else if ((first=strchr(var,':'))) {
825 strncpy(tmpvar, var, sizeof(tmpvar) - 1);
826 first = strchr(tmpvar, ':');
828 first = tmpvar + strlen(tmpvar);
830 pbx_retrieve_variable(c,tmpvar,ret,workspace,workspacelen - 1, headp);
832 offset=atoi(first+1);
833 if ((second=strchr(first+1,':'))) {
835 offset2=atoi(second+1);
837 offset2=strlen(*ret)-offset;
838 if (abs(offset)>strlen(*ret)) {
842 offset=-strlen(*ret);
844 if ((offset<0 && offset2>-offset) || (offset>=0 && offset+offset2>strlen(*ret))) {
846 offset2=strlen(*ret)-offset;
848 offset2=strlen(*ret)+offset;
853 *ret+=strlen(*ret)+offset;
854 (*ret)[offset2] = '\0';
855 } else if (c && !strcmp(var, "CALLERIDNUM")) {
856 if (c->cid.cid_num) {
857 strncpy(workspace, c->cid.cid_num, workspacelen - 1);
861 } else if (c && !strcmp(var, "CALLERANI")) {
862 if (c->cid.cid_ani) {
863 strncpy(workspace, c->cid.cid_ani, workspacelen - 1);
867 } else if (c && !strcmp(var, "CALLERIDNAME")) {
868 if (c->cid.cid_name) {
869 strncpy(workspace, c->cid.cid_name, workspacelen - 1);
873 } else if (c && !strcmp(var, "CALLERID")) {
874 if (c->cid.cid_num) {
875 if (c->cid.cid_name) {
876 snprintf(workspace, workspacelen, "\"%s\" <%s>", c->cid.cid_name, c->cid.cid_num);
878 strncpy(workspace, c->cid.cid_num, workspacelen - 1);
881 } else if (c->cid.cid_name) {
882 strncpy(workspace, c->cid.cid_name, workspacelen - 1);
886 } else if (c && !strcmp(var, "DNID")) {
887 if (c->cid.cid_dnid) {
888 strncpy(workspace, c->cid.cid_dnid, workspacelen - 1);
892 } else if (c && !strcmp(var, "HINT")) {
893 if (!ast_get_hint(workspace, workspacelen, c, c->context, c->exten))
897 } else if (c && !strcmp(var, "EXTEN")) {
898 strncpy(workspace, c->exten, workspacelen - 1);
900 } else if (c && !strcmp(var, "RDNIS")) {
901 if (c->cid.cid_rdnis) {
902 strncpy(workspace, c->cid.cid_rdnis, workspacelen - 1);
906 } else if (c && !strcmp(var, "CONTEXT")) {
907 strncpy(workspace, c->context, workspacelen - 1);
909 } else if (c && !strcmp(var, "PRIORITY")) {
910 snprintf(workspace, workspacelen, "%d", c->priority);
912 } else if (c && !strcmp(var, "CALLINGPRES")) {
913 snprintf(workspace, workspacelen, "%d", c->cid.cid_pres);
915 } else if (c && !strcmp(var, "CALLINGANI2")) {
916 snprintf(workspace, workspacelen, "%d", c->cid.cid_ani2);
918 } else if (c && !strcmp(var, "CALLINGTON")) {
919 snprintf(workspace, workspacelen, "%d", c->cid.cid_ton);
921 } else if (c && !strcmp(var, "CALLINGTNS")) {
922 snprintf(workspace, workspacelen, "%d", c->cid.cid_tns);
924 } else if (c && !strcmp(var, "CHANNEL")) {
925 strncpy(workspace, c->name, workspacelen - 1);
927 } else if (c && !strcmp(var, "EPOCH")) {
928 snprintf(workspace, workspacelen, "%u",(int)time(NULL));
930 } else if (c && !strcmp(var, "DATETIME")) {
932 localtime_r(&thistime, &brokentime);
933 snprintf(workspace, workspacelen, "%02d%02d%04d-%02d:%02d:%02d",
936 brokentime.tm_year+1900,
942 } else if (c && !strcmp(var, "TIMESTAMP")) {
944 localtime_r(&thistime, &brokentime);
945 /* 20031130-150612 */
946 snprintf(workspace, workspacelen, "%04d%02d%02d-%02d%02d%02d",
947 brokentime.tm_year+1900,
955 } else if (c && !strcmp(var, "UNIQUEID")) {
956 snprintf(workspace, workspacelen, "%s", c->uniqueid);
958 } else if (c && !strcmp(var, "HANGUPCAUSE")) {
959 snprintf(workspace, workspacelen, "%i", c->hangupcause);
961 } else if (c && !strcmp(var, "ACCOUNTCODE")) {
962 strncpy(workspace, c->accountcode, workspacelen - 1);
964 } else if (c && !strcmp(var, "LANGUAGE")) {
965 strncpy(workspace, c->language, workspacelen - 1);
969 AST_LIST_TRAVERSE(headp,variables,entries) {
971 ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",var,ast_var_name(variables));
973 if (strcasecmp(ast_var_name(variables),var)==0) {
974 *ret=ast_var_value(variables);
976 strncpy(workspace, *ret, workspacelen - 1);
985 AST_LIST_TRAVERSE(&globals,variables,entries) {
987 ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",var,ast_var_name(variables));
989 if (strcasecmp(ast_var_name(variables),var)==0) {
990 *ret=ast_var_value(variables);
992 strncpy(workspace, *ret, workspacelen - 1);
1000 int len_env=strlen("ENV(");
1001 if (len > (len_env+1) && !strncasecmp(var,"ENV(",len_env) && !strcmp(var+len-1,")")) {
1003 strncpy(cp3, var, sizeof(cp3) - 1);
1005 *ret=getenv(cp3+len_env);
1007 strncpy(workspace, *ret, workspacelen - 1);
1015 static void pbx_substitute_variables_helper_full(struct ast_channel *c, const char *cp1, char *cp2, int count, struct varshead *headp)
1018 const char *tmp, *whereweare;
1020 char workspace[4096];
1021 char ltmp[4096], var[4096];
1022 char *nextvar, *nextexp;
1024 int pos, brackets, needsub, len;
1026 /* Substitutes variables into cp2, based on string cp1, and assuming cp2 to be
1029 while(!ast_strlen_zero(whereweare) && count) {
1030 /* Assume we're copying the whole remaining string */
1031 pos = strlen(whereweare);
1033 /* Look for a variable */
1034 nextvar = strstr(whereweare, "${");
1036 /* Look for an expression */
1037 nextexp = strstr(whereweare, "$[");
1039 /* Pick the first one only */
1040 if (nextvar && nextexp) {
1041 if (nextvar < nextexp)
1047 /* If there is one, we only go that far */
1049 pos = nextvar - whereweare;
1051 pos = nextexp - whereweare;
1053 /* Can't copy more than 'count' bytes */
1057 /* Copy that many bytes */
1058 memcpy(cp2, whereweare, pos);
1065 /* We have a variable. Find the start and end, and determine
1066 if we are going to have to recursively call ourselves on the
1068 vars = vare = nextvar + 2;
1072 /* Find the end of it */
1073 while(brackets && *vare) {
1074 if ((vare[0] == '$') && (vare[1] == '{')) {
1077 } else if (vare[0] == '}') {
1079 } else if ((vare[0] == '$') && (vare[1] == '['))
1084 ast_log(LOG_NOTICE, "Error in extension logic (missing '}')\n");
1085 len = vare - vars - 1;
1087 /* Skip totally over variable name */
1088 whereweare += ( len + 3);
1090 /* Store variable name (and truncate) */
1091 memset(var, 0, sizeof(var));
1092 strncpy(var, vars, sizeof(var) - 1);
1095 /* Substitute if necessary */
1097 memset(ltmp, 0, sizeof(ltmp));
1098 pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1);
1104 /* Retrieve variable value */
1105 workspace[0] = '\0';
1106 pbx_retrieve_variable(c,vars,&cp4, workspace, sizeof(workspace), headp);
1108 length = strlen(cp4);
1111 memcpy(cp2, cp4, length);
1116 } else if (nextexp) {
1117 /* We have an expression. Find the start and end, and determine
1118 if we are going to have to recursively call ourselves on the
1120 vars = vare = nextexp + 2;
1124 /* Find the end of it */
1125 while(brackets && *vare) {
1126 if ((vare[0] == '$') && (vare[1] == '[')) {
1130 } else if (vare[0] == '[') {
1132 } else if (vare[0] == ']') {
1134 } else if ((vare[0] == '$') && (vare[1] == '{')) {
1141 ast_log(LOG_NOTICE, "Error in extension logic (missing ']')\n");
1142 len = vare - vars - 1;
1144 /* Skip totally over variable name */
1145 whereweare += ( len + 3);
1147 /* Store variable name (and truncate) */
1148 memset(var, 0, sizeof(var));
1149 strncpy(var, vars, sizeof(var) - 1);
1152 /* Substitute if necessary */
1154 memset(ltmp, 0, sizeof(ltmp));
1155 pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1);
1161 /* Evaluate expression */
1162 cp4 = ast_expr(vars);
1164 ast_log(LOG_DEBUG, "Expression is '%s'\n", cp4);
1167 length = strlen(cp4);
1170 memcpy(cp2, cp4, length);
1181 void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
1183 pbx_substitute_variables_helper_full(c, cp1, cp2, count, NULL);
1186 void pbx_substitute_variables_varshead(struct varshead *headp, const char *cp1, char *cp2, int count)
1188 pbx_substitute_variables_helper_full(NULL, cp1, cp2, count, headp);
1191 static void pbx_substitute_variables(char *passdata, int datalen, struct ast_channel *c, struct ast_exten *e) {
1193 memset(passdata, 0, datalen);
1195 /* No variables or expressions in e->data, so why scan it? */
1196 if (!strstr(e->data,"${") && !strstr(e->data,"$[")) {
1197 strncpy(passdata, e->data, datalen - 1);
1198 passdata[datalen-1] = '\0';
1202 pbx_substitute_variables_helper(c, e->data, passdata, datalen - 1);
1205 static int pbx_extension_helper(struct ast_channel *c, struct ast_context *con, const char *context, const char *exten, int priority, const char *label, const char *callerid, int action)
1207 struct ast_exten *e;
1208 struct ast_app *app;
1209 struct ast_switch *sw;
1211 const char *foundcontext=NULL;
1215 char *incstack[AST_PBX_MAX_STACK];
1216 char passdata[EXT_DATA_SIZE];
1220 char tmp3[EXT_DATA_SIZE];
1222 if (ast_mutex_lock(&conlock)) {
1223 ast_log(LOG_WARNING, "Unable to obtain lock\n");
1224 if ((action == HELPER_EXISTS) || (action == HELPER_CANMATCH) || (action == HELPER_MATCHMORE))
1229 e = pbx_find_extension(c, con, context, exten, priority, label, callerid, action, incstack, &stacklen, &status, &sw, &data, &foundcontext);
1232 case HELPER_CANMATCH:
1233 ast_mutex_unlock(&conlock);
1236 ast_mutex_unlock(&conlock);
1238 case HELPER_FINDLABEL:
1240 ast_mutex_unlock(&conlock);
1242 case HELPER_MATCHMORE:
1243 ast_mutex_unlock(&conlock);
1249 app = pbx_findapp(e->app);
1250 ast_mutex_unlock(&conlock);
1252 if (c->context != context)
1253 strncpy(c->context, context, sizeof(c->context)-1);
1254 if (c->exten != exten)
1255 strncpy(c->exten, exten, sizeof(c->exten)-1);
1256 c->priority = priority;
1257 pbx_substitute_variables(passdata, sizeof(passdata), c, e);
1259 ast_log(LOG_DEBUG, "Launching '%s'\n", app->name);
1260 if (option_verbose > 2)
1261 ast_verbose( VERBOSE_PREFIX_3 "Executing %s(\"%s\", \"%s\") %s\n",
1262 term_color(tmp, app->name, COLOR_BRCYAN, 0, sizeof(tmp)),
1263 term_color(tmp2, c->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
1264 term_color(tmp3, (!ast_strlen_zero(passdata) ? (char *)passdata : ""), COLOR_BRMAGENTA, 0, sizeof(tmp3)),
1265 (newstack ? "in new stack" : "in same stack"));
1266 manager_event(EVENT_FLAG_CALL, "Newexten",
1271 "Application: %s\r\n"
1274 c->name, c->context, c->exten, c->priority, app->name, passdata ? passdata : "(NULL)", c->uniqueid);
1275 res = pbx_exec(c, app, passdata, newstack);
1278 ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
1282 ast_log(LOG_WARNING, "Huh (%d)?\n", action); return -1;
1286 case HELPER_CANMATCH:
1287 ast_mutex_unlock(&conlock);
1290 ast_mutex_unlock(&conlock);
1292 case HELPER_MATCHMORE:
1293 ast_mutex_unlock(&conlock);
1295 case HELPER_FINDLABEL:
1296 ast_mutex_unlock(&conlock);
1302 ast_mutex_unlock(&conlock);
1304 res = sw->exec(c, foundcontext ? foundcontext : context, exten, priority, callerid, newstack, data);
1306 ast_log(LOG_WARNING, "No execution engine for switch %s\n", sw->name);
1311 ast_log(LOG_WARNING, "Huh (%d)?\n", action);
1315 ast_mutex_unlock(&conlock);
1317 case STATUS_NO_CONTEXT:
1318 if ((action != HELPER_EXISTS) && (action != HELPER_MATCHMORE))
1319 ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", context);
1321 case STATUS_NO_EXTENSION:
1322 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1323 ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, context);
1325 case STATUS_NO_PRIORITY:
1326 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1327 ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, context);
1329 case STATUS_NO_LABEL:
1331 ast_log(LOG_NOTICE, "No such label '%s' in extension '%s' in context '%s'\n", label, exten, context);
1334 ast_log(LOG_DEBUG, "Shouldn't happen!\n");
1337 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1345 static struct ast_exten *ast_hint_extension(struct ast_channel *c, const char *context, const char *exten)
1347 struct ast_exten *e;
1348 struct ast_switch *sw;
1350 const char *foundcontext = NULL;
1352 char *incstack[AST_PBX_MAX_STACK];
1355 if (ast_mutex_lock(&conlock)) {
1356 ast_log(LOG_WARNING, "Unable to obtain lock\n");
1359 e = pbx_find_extension(c, NULL, context, exten, PRIORITY_HINT, NULL, "", HELPER_EXISTS, incstack, &stacklen, &status, &sw, &data, &foundcontext);
1360 ast_mutex_unlock(&conlock);
1364 static int ast_extension_state2(struct ast_exten *e)
1366 char hint[AST_MAX_EXTENSION] = "";
1369 int allunavailable = 1, allbusy = 1, allfree = 1;
1372 strncpy(hint, ast_get_extension_app(e), sizeof(hint)-1);
1376 rest = strchr(cur, '&');
1382 res = ast_device_state(cur);
1384 case AST_DEVICE_NOT_INUSE:
1388 case AST_DEVICE_INUSE:
1389 return AST_EXTENSION_INUSE;
1390 case AST_DEVICE_BUSY:
1395 case AST_DEVICE_UNAVAILABLE:
1396 case AST_DEVICE_INVALID:
1409 return AST_EXTENSION_NOT_INUSE;
1411 return AST_EXTENSION_BUSY;
1413 return AST_EXTENSION_UNAVAILABLE;
1415 return AST_EXTENSION_INUSE;
1417 return AST_EXTENSION_NOT_INUSE;
1421 int ast_extension_state(struct ast_channel *c, char *context, char *exten)
1423 struct ast_exten *e;
1425 e = ast_hint_extension(c, context, exten);
1429 return ast_extension_state2(e);
1432 int ast_device_state_changed(const char *fmt, ...)
1434 struct ast_hint *list;
1435 struct ast_state_cb *cblist;
1436 struct ast_devstate_cb *devcb;
1437 char hint[AST_MAX_EXTENSION] = "";
1438 char device[AST_MAX_EXTENSION];
1445 vsnprintf(device, sizeof(device), fmt, ap);
1448 rest = strchr(device, '-');
1453 state = ast_device_state(device);
1455 ast_mutex_lock(&hintlock);
1459 if (devcb->callback)
1460 devcb->callback(device, state, devcb->data);
1461 devcb = devcb->next;
1467 strncpy(hint, ast_get_extension_app(list->exten), sizeof(hint) - 1);
1470 rest = strchr(cur, '&');
1476 if (!strcmp(cur, device)) {
1477 /* Found extension execute callbacks */
1478 state = ast_extension_state2(list->exten);
1479 if ((state != -1) && (state != list->laststate)) {
1480 /* For general callbacks */
1483 cblist->callback(list->exten->parent->name, list->exten->exten, state, cblist->data);
1484 cblist = cblist->next;
1487 /* For extension callbacks */
1488 cblist = list->callbacks;
1490 cblist->callback(list->exten->parent->name, list->exten->exten, state, cblist->data);
1491 cblist = cblist->next;
1494 list->laststate = state;
1502 ast_mutex_unlock(&hintlock);
1506 int ast_devstate_add(ast_devstate_cb_type callback, void *data)
1508 struct ast_devstate_cb *devcb;
1509 devcb = malloc(sizeof(struct ast_devstate_cb));
1511 memset(devcb, 0, sizeof(struct ast_devstate_cb));
1512 ast_mutex_lock(&hintlock);
1514 devcb->callback = callback;
1515 devcb->next = devcbs;
1517 ast_mutex_unlock(&hintlock);
1522 void ast_devstate_del(ast_devstate_cb_type callback, void *data)
1524 struct ast_devstate_cb *devcb, *prev = NULL, *next;
1525 ast_mutex_lock(&hintlock);
1529 if ((devcb->data == data) && (devcb->callback == callback)) {
1539 ast_mutex_unlock(&hintlock);
1542 int ast_extension_state_add(const char *context, const char *exten,
1543 ast_state_cb_type callback, void *data)
1545 struct ast_hint *list;
1546 struct ast_state_cb *cblist;
1547 struct ast_exten *e;
1549 /* No context and extension add callback to statecbs list */
1550 if (!context && !exten) {
1551 ast_mutex_lock(&hintlock);
1555 if (cblist->callback == callback) {
1556 cblist->data = data;
1557 ast_mutex_unlock(&hintlock);
1559 cblist = cblist->next;
1562 /* Now inserts the callback */
1563 cblist = malloc(sizeof(struct ast_state_cb));
1565 ast_mutex_unlock(&hintlock);
1568 memset(cblist, 0, sizeof(struct ast_state_cb));
1570 cblist->callback = callback;
1571 cblist->data = data;
1573 cblist->next = statecbs;
1576 ast_mutex_unlock(&hintlock);
1580 if (!context || !exten)
1583 /* This callback type is for only one hint */
1584 e = ast_hint_extension(NULL, context, exten);
1589 ast_mutex_lock(&hintlock);
1593 if (list->exten == e)
1599 ast_mutex_unlock(&hintlock);
1603 /* Now inserts the callback */
1604 cblist = malloc(sizeof(struct ast_state_cb));
1606 ast_mutex_unlock(&hintlock);
1609 memset(cblist, 0, sizeof(struct ast_state_cb));
1610 cblist->id = stateid++;
1611 cblist->callback = callback;
1612 cblist->data = data;
1614 cblist->next = list->callbacks;
1615 list->callbacks = cblist;
1617 ast_mutex_unlock(&hintlock);
1621 int ast_extension_state_del(int id, ast_state_cb_type callback)
1623 struct ast_hint *list;
1624 struct ast_state_cb *cblist, *cbprev;
1626 if (!id && !callback)
1629 ast_mutex_lock(&hintlock);
1631 /* id is zero is a callback without extension */
1636 if (cblist->callback == callback) {
1638 statecbs = cblist->next;
1640 cbprev->next = cblist->next;
1644 ast_mutex_unlock(&hintlock);
1648 cblist = cblist->next;
1651 ast_mutex_lock(&hintlock);
1655 /* id greater than zero is a callback with extension */
1658 cblist = list->callbacks;
1661 if (cblist->id==id) {
1663 list->callbacks = cblist->next;
1665 cbprev->next = cblist->next;
1669 ast_mutex_unlock(&hintlock);
1673 cblist = cblist->next;
1678 ast_mutex_unlock(&hintlock);
1682 static int ast_add_hint(struct ast_exten *e)
1684 struct ast_hint *list;
1689 ast_mutex_lock(&hintlock);
1692 /* Search if hint exists, do nothing */
1694 if (list->exten == e) {
1695 ast_mutex_unlock(&hintlock);
1701 list = malloc(sizeof(struct ast_hint));
1703 ast_mutex_unlock(&hintlock);
1706 /* Initialize and insert new item */
1707 memset(list, 0, sizeof(struct ast_hint));
1709 list->laststate = ast_extension_state2(e);
1713 ast_mutex_unlock(&hintlock);
1717 static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
1719 struct ast_hint *list;
1721 ast_mutex_lock(&hintlock);
1725 if (list->exten == oe) {
1727 ast_mutex_unlock(&hintlock);
1732 ast_mutex_unlock(&hintlock);
1737 static int ast_remove_hint(struct ast_exten *e)
1739 /* Cleanup the Notifys if hint is removed */
1740 struct ast_hint *list, *prev = NULL;
1741 struct ast_state_cb *cblist, *cbprev;
1746 ast_mutex_lock(&hintlock);
1750 if (list->exten==e) {
1752 cblist = list->callbacks;
1754 /* Notify with -1 and remove all callbacks */
1756 cblist = cblist->next;
1757 cbprev->callback(list->exten->parent->name, list->exten->exten, -1, cbprev->data);
1760 list->callbacks = NULL;
1765 prev->next = list->next;
1768 ast_mutex_unlock(&hintlock);
1776 ast_mutex_unlock(&hintlock);
1781 int ast_get_hint(char *hint, int hintsize, struct ast_channel *c, const char *context, const char *exten)
1783 struct ast_exten *e;
1784 e = ast_hint_extension(c, context, exten);
1786 strncpy(hint, ast_get_extension_app(e), hintsize - 1);
1792 int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
1794 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_EXISTS);
1797 int ast_findlabel_extension(struct ast_channel *c, const char *context, const char *exten, const char *label, const char *callerid)
1799 return pbx_extension_helper(c, NULL, context, exten, 0, label, callerid, HELPER_FINDLABEL);
1802 int ast_findlabel_extension2(struct ast_channel *c, struct ast_context *con, const char *exten, const char *label, const char *callerid)
1804 return pbx_extension_helper(c, con, NULL, exten, 0, label, callerid, HELPER_FINDLABEL);
1807 int ast_canmatch_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
1809 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_CANMATCH);
1812 int ast_matchmore_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
1814 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_MATCHMORE);
1817 int ast_spawn_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
1819 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_SPAWN);
1822 int ast_exec_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
1824 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_EXEC);
1827 int ast_pbx_run(struct ast_channel *c)
1836 /* A little initial setup here */
1838 ast_log(LOG_WARNING, "%s already has PBX structure??\n", c->name);
1839 c->pbx = malloc(sizeof(struct ast_pbx));
1841 ast_log(LOG_ERROR, "Out of memory\n");
1846 c->cdr = ast_cdr_alloc();
1848 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
1852 ast_cdr_init(c->cdr, c);
1855 memset(c->pbx, 0, sizeof(struct ast_pbx));
1856 /* Set reasonable defaults */
1857 c->pbx->rtimeout = 10;
1858 c->pbx->dtimeout = 5;
1860 /* Start by trying whatever the channel is set to */
1861 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
1862 /* JK02: If not successfull fall back to 's' */
1863 if (option_verbose > 1)
1864 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);
1865 strncpy(c->exten, "s", sizeof(c->exten)-1);
1866 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
1867 /* JK02: And finally back to default if everything else failed */
1868 if (option_verbose > 1)
1869 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);
1870 strncpy(c->context, "default", sizeof(c->context)-1);
1874 if (c->cdr && !c->cdr->start.tv_sec && !c->cdr->start.tv_usec)
1875 ast_cdr_start(c->cdr);
1879 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
1880 memset(exten, 0, sizeof(exten));
1881 if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
1882 /* Something bad happened, or a hangup has been requested. */
1883 if (((res >= '0') && (res <= '9')) || ((res >= 'A') && (res <= 'F')) ||
1884 (res == '*') || (res == '#')) {
1885 ast_log(LOG_DEBUG, "Oooh, got something to jump out with ('%c')!\n", res);
1886 memset(exten, 0, sizeof(exten));
1888 exten[pos++] = digit = res;
1892 case AST_PBX_KEEPALIVE:
1894 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
1895 else if (option_verbose > 1)
1896 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
1901 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
1902 else if (option_verbose > 1)
1903 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
1904 if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
1909 if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
1919 if ((c->_softhangup == AST_SOFTHANGUP_TIMEOUT) && (ast_exists_extension(c,c->context,"T",1,c->cid.cid_num))) {
1920 strncpy(c->exten,"T",sizeof(c->exten) - 1);
1921 /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
1922 c->whentohangup = 0;
1924 c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
1925 } else if (c->_softhangup) {
1926 ast_log(LOG_DEBUG, "Extension %s, priority %d returned normally even though call was hung up\n",
1927 c->exten, c->priority);
1933 if (!ast_exists_extension(c, c->context, c->exten, 1, c->cid.cid_num)) {
1934 /* It's not a valid extension anymore */
1935 if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
1936 if (option_verbose > 2)
1937 ast_verbose(VERBOSE_PREFIX_3 "Sent into invalid extension '%s' in context '%s' on %s\n", c->exten, c->context, c->name);
1938 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", c->exten);
1939 strncpy(c->exten, "i", sizeof(c->exten)-1);
1942 ast_log(LOG_WARNING, "Channel '%s' sent into invalid extension '%s' in context '%s', but no invalid handler\n",
1943 c->name, c->exten, c->context);
1946 } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
1947 /* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */
1950 /* Done, wait for an extension */
1953 waittime = c->pbx->dtimeout;
1954 else if (!autofallthrough)
1955 waittime = c->pbx->rtimeout;
1957 while (ast_matchmore_extension(c, c->context, exten, 1, c->cid.cid_num)) {
1958 /* As long as we're willing to wait, and as long as it's not defined,
1959 keep reading digits until we can't possibly get a right answer anymore. */
1960 digit = ast_waitfordigit(c, waittime * 1000);
1961 if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
1968 /* Error, maybe a hangup */
1970 exten[pos++] = digit;
1971 waittime = c->pbx->dtimeout;
1974 if (ast_exists_extension(c, c->context, exten, 1, c->cid.cid_num)) {
1975 /* Prepare the next cycle */
1976 strncpy(c->exten, exten, sizeof(c->exten)-1);
1979 /* No such extension */
1980 if (!ast_strlen_zero(exten)) {
1981 /* An invalid extension */
1982 if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
1983 if (option_verbose > 2)
1984 ast_verbose( VERBOSE_PREFIX_3 "Invalid extension '%s' in context '%s' on %s\n", exten, c->context, c->name);
1985 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", exten);
1986 strncpy(c->exten, "i", sizeof(c->exten)-1);
1989 ast_log(LOG_WARNING, "Invalid extension '%s', but no rule 'i' in context '%s'\n", exten, c->context);
1993 /* A simple timeout */
1994 if (ast_exists_extension(c, c->context, "t", 1, c->cid.cid_num)) {
1995 if (option_verbose > 2)
1996 ast_verbose( VERBOSE_PREFIX_3 "Timeout on %s\n", c->name);
1997 strncpy(c->exten, "t", sizeof(c->exten)-1);
2000 ast_log(LOG_WARNING, "Timeout, but no rule 't' in context '%s'\n", c->context);
2006 if (option_verbose > 2)
2007 ast_verbose(VERBOSE_PREFIX_2 "CDR updated on %s\n",c->name);
2011 if (option_verbose > 0) {
2013 status = pbx_builtin_getvar_helper(c, "DIALSTATUS");
2016 if (option_verbose > 2)
2017 ast_verbose(VERBOSE_PREFIX_2 "Auto fallthrough, channel '%s' status is '%s'\n", c->name, status);
2018 if (!strcasecmp(status, "CONGESTION"))
2019 res = pbx_builtin_congestion(c, "10");
2020 else if (!strcasecmp(status, "CHANUNAVAIL"))
2021 res = pbx_builtin_congestion(c, "10");
2022 else if (!strcasecmp(status, "BUSY"))
2023 res = pbx_builtin_busy(c, "10");
2030 ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", c->name);
2032 if ((res != AST_PBX_KEEPALIVE) && ast_exists_extension(c, c->context, "h", 1, c->cid.cid_num)) {
2036 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2037 if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
2038 /* Something bad happened, or a hangup has been requested. */
2040 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2041 else if (option_verbose > 1)
2042 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2049 pbx_destroy(c->pbx);
2051 if (res != AST_PBX_KEEPALIVE)
2056 static void *pbx_thread(void *data)
2058 /* Oh joyeous kernel, we're a new thread, with nothing to do but
2059 answer this channel and get it going. The setjmp stuff is fairly
2060 confusing, but necessary to get smooth transitions between
2061 the execution of different applications (without the use of
2062 additional threads) */
2063 struct ast_channel *c = data;
2069 int ast_pbx_start(struct ast_channel *c)
2072 pthread_attr_t attr;
2074 ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
2078 /* Start a new thread, and get something handling this channel. */
2079 pthread_attr_init(&attr);
2080 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
2081 if (ast_pthread_create(&t, &attr, pbx_thread, c)) {
2082 ast_log(LOG_WARNING, "Failed to create new channel thread\n");
2088 int pbx_set_autofallthrough(int newval)
2091 oldval = autofallthrough;
2092 if (oldval != newval)
2093 autofallthrough = newval;
2098 * This function locks contexts list by &conlist, search for the right context
2099 * structure, leave context list locked and call ast_context_remove_include2
2100 * which removes include, unlock contexts list and return ...
2102 int ast_context_remove_include(const char *context, const char *include, const char *registrar)
2104 struct ast_context *c;
2106 if (ast_lock_contexts()) return -1;
2108 /* walk contexts and search for the right one ...*/
2109 c = ast_walk_contexts(NULL);
2111 /* we found one ... */
2112 if (!strcmp(ast_get_context_name(c), context)) {
2114 /* remove include from this context ... */
2115 ret = ast_context_remove_include2(c, include, registrar);
2117 ast_unlock_contexts();
2119 /* ... return results */
2122 c = ast_walk_contexts(c);
2125 /* we can't find the right one context */
2126 ast_unlock_contexts();
2131 * When we call this function, &conlock lock must be locked, because when
2132 * we giving *con argument, some process can remove/change this context
2133 * and after that there can be segfault.
2135 * This function locks given context, removes include, unlock context and
2138 int ast_context_remove_include2(struct ast_context *con, const char *include, const char *registrar)
2140 struct ast_include *i, *pi = NULL;
2142 if (ast_mutex_lock(&con->lock)) return -1;
2147 /* find our include */
2148 if (!strcmp(i->name, include) &&
2149 (!registrar || !strcmp(i->registrar, registrar))) {
2150 /* remove from list */
2154 con->includes = i->next;
2155 /* free include and return */
2157 ast_mutex_unlock(&con->lock);
2164 /* we can't find the right include */
2165 ast_mutex_unlock(&con->lock);
2170 * This function locks contexts list by &conlist, search for the rigt context
2171 * structure, leave context list locked and call ast_context_remove_switch2
2172 * which removes switch, unlock contexts list and return ...
2174 int ast_context_remove_switch(const char *context, const char *sw, const char *data, const char *registrar)
2176 struct ast_context *c;
2178 if (ast_lock_contexts()) return -1;
2180 /* walk contexts and search for the right one ...*/
2181 c = ast_walk_contexts(NULL);
2183 /* we found one ... */
2184 if (!strcmp(ast_get_context_name(c), context)) {
2186 /* remove switch from this context ... */
2187 ret = ast_context_remove_switch2(c, sw, data, registrar);
2189 ast_unlock_contexts();
2191 /* ... return results */
2194 c = ast_walk_contexts(c);
2197 /* we can't find the right one context */
2198 ast_unlock_contexts();
2203 * When we call this function, &conlock lock must be locked, because when
2204 * we giving *con argument, some process can remove/change this context
2205 * and after that there can be segfault.
2207 * This function locks given context, removes switch, unlock context and
2210 int ast_context_remove_switch2(struct ast_context *con, const char *sw, const char *data, const char *registrar)
2212 struct ast_sw *i, *pi = NULL;
2214 if (ast_mutex_lock(&con->lock)) return -1;
2219 /* find our switch */
2220 if (!strcmp(i->name, sw) && !strcmp(i->data, data) &&
2221 (!registrar || !strcmp(i->registrar, registrar))) {
2222 /* remove from list */
2226 con->alts = i->next;
2227 /* free switch and return */
2229 ast_mutex_unlock(&con->lock);
2236 /* we can't find the right switch */
2237 ast_mutex_unlock(&con->lock);
2242 * This functions lock contexts list, search for the right context,
2243 * call ast_context_remove_extension2, unlock contexts list and return.
2244 * In this function we are using
2246 int ast_context_remove_extension(const char *context, const char *extension, int priority, const char *registrar)
2248 struct ast_context *c;
2250 if (ast_lock_contexts()) return -1;
2252 /* walk contexts ... */
2253 c = ast_walk_contexts(NULL);
2255 /* ... search for the right one ... */
2256 if (!strcmp(ast_get_context_name(c), context)) {
2257 /* ... remove extension ... */
2258 int ret = ast_context_remove_extension2(c, extension, priority,
2260 /* ... unlock contexts list and return */
2261 ast_unlock_contexts();
2264 c = ast_walk_contexts(c);
2267 /* we can't find the right context */
2268 ast_unlock_contexts();
2273 * When do you want to call this function, make sure that &conlock is locked,
2274 * because some process can handle with your *con context before you lock
2277 * This functionc locks given context, search for the right extension and
2278 * fires out all peer in this extensions with given priority. If priority
2279 * is set to 0, all peers are removed. After that, unlock context and
2282 int ast_context_remove_extension2(struct ast_context *con, const char *extension, int priority, const char *registrar)
2284 struct ast_exten *exten, *prev_exten = NULL;
2286 if (ast_mutex_lock(&con->lock)) return -1;
2288 /* go through all extensions in context and search the right one ... */
2292 /* look for right extension */
2293 if (!strcmp(exten->exten, extension) &&
2294 (!registrar || !strcmp(exten->registrar, registrar))) {
2295 struct ast_exten *peer;
2297 /* should we free all peers in this extension? (priority == 0)? */
2298 if (priority == 0) {
2299 /* remove this extension from context list */
2301 prev_exten->next = exten->next;
2303 con->root = exten->next;
2305 /* fire out all peers */
2310 if (!peer->priority==PRIORITY_HINT)
2311 ast_remove_hint(peer);
2313 peer->datad(peer->data);
2319 ast_mutex_unlock(&con->lock);
2322 /* remove only extension with exten->priority == priority */
2323 struct ast_exten *previous_peer = NULL;
2327 /* is this our extension? */
2328 if (peer->priority == priority &&
2329 (!registrar || !strcmp(peer->registrar, registrar) )) {
2330 /* we are first priority extension? */
2331 if (!previous_peer) {
2332 /* exists previous extension here? */
2334 /* yes, so we must change next pointer in
2335 * previous connection to next peer
2338 prev_exten->next = peer->peer;
2339 peer->peer->next = exten->next;
2341 prev_exten->next = exten->next;
2343 /* no previous extension, we are first
2344 * extension, so change con->root ...
2347 con->root = peer->peer;
2349 con->root = exten->next;
2352 /* we are not first priority in extension */
2353 previous_peer->peer = peer->peer;
2356 /* now, free whole priority extension */
2357 if (peer->priority==PRIORITY_HINT)
2358 ast_remove_hint(peer);
2359 peer->datad(peer->data);
2362 ast_mutex_unlock(&con->lock);
2365 /* this is not right extension, skip to next peer */
2366 previous_peer = peer;
2371 ast_mutex_unlock(&con->lock);
2377 exten = exten->next;
2380 /* we can't find right extension */
2381 ast_mutex_unlock(&con->lock);
2386 int ast_register_application(const char *app, int (*execute)(struct ast_channel *, void *), const char *synopsis, const char *description)
2388 struct ast_app *tmp, *prev, *cur;
2391 length = sizeof(struct ast_app);
2392 length += strlen(app) + 1;
2393 if (ast_mutex_lock(&applock)) {
2394 ast_log(LOG_ERROR, "Unable to lock application list\n");
2399 if (!strcasecmp(app, tmp->name)) {
2400 ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
2401 ast_mutex_unlock(&applock);
2406 tmp = malloc(length);
2408 memset(tmp, 0, length);
2409 strcpy(tmp->name, app);
2410 tmp->execute = execute;
2411 tmp->synopsis = synopsis;
2412 tmp->description = description;
2413 /* Store in alphabetical order */
2417 if (strcasecmp(tmp->name, cur->name) < 0)
2423 tmp->next = prev->next;
2430 ast_log(LOG_ERROR, "Out of memory\n");
2431 ast_mutex_unlock(&applock);
2434 if (option_verbose > 1)
2435 ast_verbose( VERBOSE_PREFIX_2 "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
2436 ast_mutex_unlock(&applock);
2440 int ast_register_switch(struct ast_switch *sw)
2442 struct ast_switch *tmp, *prev=NULL;
2443 if (ast_mutex_lock(&switchlock)) {
2444 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
2449 if (!strcasecmp(tmp->name, sw->name))
2455 ast_mutex_unlock(&switchlock);
2456 ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name);
2464 ast_mutex_unlock(&switchlock);
2468 void ast_unregister_switch(struct ast_switch *sw)
2470 struct ast_switch *tmp, *prev=NULL;
2471 if (ast_mutex_lock(&switchlock)) {
2472 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
2479 prev->next = tmp->next;
2481 switches = tmp->next;
2488 ast_mutex_unlock(&switchlock);
2492 * Help for CLI commands ...
2494 static char show_application_help[] =
2495 "Usage: show application <application> [<application> [<application> [...]]]\n"
2496 " Describes a particular application.\n";
2498 static char show_applications_help[] =
2499 "Usage: show applications [{like|describing} <text>]\n"
2500 " List applications which are currently available.\n"
2501 " If 'like', <text> will be a substring of the app name\n"
2502 " If 'describing', <text> will be a substring of the description\n";
2504 static char show_dialplan_help[] =
2505 "Usage: show dialplan [exten@][context]\n"
2508 static char show_switches_help[] =
2509 "Usage: show switches\n"
2510 " Show registered switches\n";
2513 * IMPLEMENTATION OF CLI FUNCTIONS IS IN THE SAME ORDER AS COMMANDS HELPS
2518 * 'show application' CLI command implementation functions ...
2522 * There is a possibility to show informations about more than one
2523 * application at one time. You can type 'show application Dial Echo' and
2524 * you will see informations about these two applications ...
2526 static char *complete_show_application(char *line, char *word,
2532 /* try to lock applications list ... */
2533 if (ast_mutex_lock(&applock)) {
2534 ast_log(LOG_ERROR, "Unable to lock application list\n");
2538 /* ... walk all applications ... */
2541 /* ... check if word matches this application ... */
2542 if (!strncasecmp(word, a->name, strlen(word))) {
2543 /* ... if this is right app serve it ... */
2544 if (++which > state) {
2545 char *ret = strdup(a->name);
2546 ast_mutex_unlock(&applock);
2553 /* no application match */
2554 ast_mutex_unlock(&applock);
2558 static int handle_show_application(int fd, int argc, char *argv[])
2561 int app, no_registered_app = 1;
2563 if (argc < 3) return RESULT_SHOWUSAGE;
2565 /* try to lock applications list ... */
2566 if (ast_mutex_lock(&applock)) {
2567 ast_log(LOG_ERROR, "Unable to lock application list\n");
2571 /* ... go through all applications ... */
2574 /* ... compare this application name with all arguments given
2575 * to 'show application' command ... */
2576 for (app = 2; app < argc; app++) {
2577 if (!strcasecmp(a->name, argv[app])) {
2578 /* Maximum number of characters added by terminal coloring is 22 */
2579 char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
2580 char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
2581 int synopsis_size, description_size;
2583 no_registered_app = 0;
2586 synopsis_size = strlen(a->synopsis) + 23;
2588 synopsis_size = strlen("Not available") + 23;
2589 synopsis = alloca(synopsis_size);
2592 description_size = strlen(a->description) + 23;
2594 description_size = strlen("Not available") + 23;
2595 description = alloca(description_size);
2597 if (synopsis && description) {
2598 snprintf(info, 64 + AST_MAX_APP, "\n -= Info about application '%s' =- \n\n", a->name);
2599 term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
2600 term_color(syntitle, "[Synopsis]:\n", COLOR_MAGENTA, 0, 40);
2601 term_color(destitle, "[Description]:\n", COLOR_MAGENTA, 0, 40);
2602 term_color(synopsis,
2603 a->synopsis ? a->synopsis : "Not available",
2604 COLOR_CYAN, 0, synopsis_size);
2605 term_color(description,
2606 a->description ? a->description : "Not available",
2607 COLOR_CYAN, 0, description_size);
2609 ast_cli(fd,"%s%s%s\n\n%s%s\n", infotitle, syntitle, synopsis, destitle, description);
2611 /* ... one of our applications, show info ...*/
2612 ast_cli(fd,"\n -= Info about application '%s' =- \n\n"
2613 "[Synopsis]:\n %s\n\n"
2614 "[Description]:\n%s\n",
2616 a->synopsis ? a->synopsis : "Not available",
2617 a->description ? a->description : "Not available");
2624 ast_mutex_unlock(&applock);
2626 /* we found at least one app? no? */
2627 if (no_registered_app) {
2628 ast_cli(fd, "Your application(s) is (are) not registered\n");
2629 return RESULT_FAILURE;
2632 return RESULT_SUCCESS;
2635 static int handle_show_switches(int fd, int argc, char *argv[])
2637 struct ast_switch *sw;
2639 ast_cli(fd, "There are no registered alternative switches\n");
2640 return RESULT_SUCCESS;
2642 /* ... we have applications ... */
2643 ast_cli(fd, "\n -= Registered Asterisk Alternative Switches =-\n");
2644 if (ast_mutex_lock(&switchlock)) {
2645 ast_log(LOG_ERROR, "Unable to lock switches\n");
2650 ast_cli(fd, "%s: %s\n", sw->name, sw->description);
2653 ast_mutex_unlock(&switchlock);
2654 return RESULT_SUCCESS;
2658 * 'show applications' CLI command implementation functions ...
2660 static int handle_show_applications(int fd, int argc, char *argv[])
2663 int like=0, describing=0;
2664 int total_match = 0; /* Number of matches in like clause */
2665 int total_apps = 0; /* Number of apps registered */
2667 /* try to lock applications list ... */
2668 if (ast_mutex_lock(&applock)) {
2669 ast_log(LOG_ERROR, "Unable to lock application list\n");
2673 /* ... have we got at least one application (first)? no? */
2675 ast_cli(fd, "There are no registered applications\n");
2676 ast_mutex_unlock(&applock);
2680 /* show applications like <keyword> */
2681 if ((argc == 4) && (!strcmp(argv[2], "like"))) {
2683 } else if ((argc > 3) && (!strcmp(argv[2], "describing"))) {
2687 /* show applications describing <keyword1> [<keyword2>] [...] */
2688 if ((!like) && (!describing)) {
2689 ast_cli(fd, " -= Registered Asterisk Applications =-\n");
2691 ast_cli(fd, " -= Matching Asterisk Applications =-\n");
2694 /* ... go through all applications ... */
2695 for (a = apps; a; a = a->next) {
2696 /* ... show informations about applications ... */
2700 if (ast_strcasestr(a->name, argv[3])) {
2704 } else if (describing) {
2705 if (a->description) {
2706 /* Match all words on command line */
2709 for (i=3;i<argc;i++) {
2710 if (! ast_strcasestr(a->description, argv[i])) {
2722 ast_cli(fd," %20s: %s\n", a->name, a->synopsis ? a->synopsis : "<Synopsis not available>");
2725 if ((!like) && (!describing)) {
2726 ast_cli(fd, " -= %d Applications Registered =-\n",total_apps);
2728 ast_cli(fd, " -= %d Applications Matching =-\n",total_match);
2731 /* ... unlock and return */
2732 ast_mutex_unlock(&applock);
2734 return RESULT_SUCCESS;
2737 static char *complete_show_applications(char *line, char *word, int pos, int state)
2740 if (ast_strlen_zero(word)) {
2743 return strdup("like");
2745 return strdup("describing");
2749 } else if (! strncasecmp(word, "like", strlen(word))) {
2751 return strdup("like");
2755 } else if (! strncasecmp(word, "describing", strlen(word))) {
2757 return strdup("describing");
2767 * 'show dialplan' CLI command implementation functions ...
2769 static char *complete_show_dialplan_context(char *line, char *word, int pos,
2772 struct ast_context *c;
2775 /* we are do completion of [exten@]context on second position only */
2776 if (pos != 2) return NULL;
2778 /* try to lock contexts list ... */
2779 if (ast_lock_contexts()) {
2780 ast_log(LOG_ERROR, "Unable to lock context list\n");
2784 /* ... walk through all contexts ... */
2785 c = ast_walk_contexts(NULL);
2787 /* ... word matches context name? yes? ... */
2788 if (!strncasecmp(word, ast_get_context_name(c), strlen(word))) {
2789 /* ... for serve? ... */
2790 if (++which > state) {
2791 /* ... yes, serve this context name ... */
2792 char *ret = strdup(ast_get_context_name(c));
2793 ast_unlock_contexts();
2797 c = ast_walk_contexts(c);
2800 /* ... unlock and return */
2801 ast_unlock_contexts();
2805 static int handle_show_dialplan(int fd, int argc, char *argv[])
2807 struct ast_context *c;
2808 char *exten = NULL, *context = NULL;
2809 int context_existence = 0, extension_existence = 0;
2810 /* Variables used for different counters */
2811 int total_context = 0, total_exten = 0, total_prio = 0;
2813 if (argc != 3 && argc != 2) return -1;
2815 /* we obtain [exten@]context? if yes, split them ... */
2817 char *splitter = argv[2];
2818 /* is there a '@' character? */
2819 if (strchr(argv[2], '@')) {
2820 /* yes, split into exten & context ... */
2821 exten = strsep(&splitter, "@");
2824 /* check for length and change to NULL if ast_strlen_zero() */
2825 if (ast_strlen_zero(exten)) exten = NULL;
2826 if (ast_strlen_zero(context)) context = NULL;
2829 /* no '@' char, only context given */
2831 if (ast_strlen_zero(context)) context = NULL;
2835 /* try to lock contexts */
2836 if (ast_lock_contexts()) {
2837 ast_log(LOG_WARNING, "Failed to lock contexts list\n");
2838 return RESULT_FAILURE;
2841 /* walk all contexts ... */
2842 c = ast_walk_contexts(NULL);
2844 /* show this context? */
2846 !strcmp(ast_get_context_name(c), context)) {
2847 context_existence = 1;
2849 /* try to lock context before walking in ... */
2850 if (!ast_lock_context(c)) {
2851 struct ast_exten *e;
2852 struct ast_include *i;
2853 struct ast_ignorepat *ip;
2855 char buf[256], buf2[256];
2856 int context_info_printed = 0;
2858 /* are we looking for exten too? if yes, we print context
2859 * if we our extension only
2863 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
2864 ast_get_context_name(c), ast_get_context_registrar(c));
2865 context_info_printed = 1;
2868 /* walk extensions ... */
2869 e = ast_walk_context_extensions(c, NULL);
2871 struct ast_exten *p;
2873 /* looking for extension? is this our extension? */
2875 strcmp(ast_get_extension_name(e), exten))
2877 /* we are looking for extension and it's not our
2878 * extension, so skip to next extension */
2879 e = ast_walk_context_extensions(c, e);
2883 extension_existence = 1;
2885 /* may we print context info? */
2886 if (!context_info_printed) {
2888 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
2889 ast_get_context_name(c),
2890 ast_get_context_registrar(c));
2891 context_info_printed = 1;
2895 /* write extension name and first peer */
2896 bzero(buf, sizeof(buf));
2897 snprintf(buf, sizeof(buf), "'%s' =>",
2898 ast_get_extension_name(e));
2900 snprintf(buf2, sizeof(buf2),
2902 ast_get_extension_priority(e),
2903 ast_get_extension_app(e),
2904 (char *)ast_get_extension_app_data(e));
2906 ast_cli(fd, " %-17s %-45s [%s]\n", buf, buf2,
2907 ast_get_extension_registrar(e));
2910 /* walk next extension peers */
2911 p = ast_walk_extension_priorities(e, e);
2914 bzero((void *)buf2, sizeof(buf2));
2915 bzero((void *)buf, sizeof(buf));
2916 if (ast_get_extension_label(p))
2917 snprintf(buf, sizeof(buf), " [%s]", ast_get_extension_label(p));
2918 snprintf(buf2, sizeof(buf2),
2920 ast_get_extension_priority(p),
2921 ast_get_extension_app(p),
2922 (char *)ast_get_extension_app_data(p));
2924 ast_cli(fd," %-17s %-45s [%s]\n",
2926 ast_get_extension_registrar(p));
2928 p = ast_walk_extension_priorities(e, p);
2930 e = ast_walk_context_extensions(c, e);
2933 /* include & ignorepat we all printing if we are not
2934 * looking for exact extension
2937 if (ast_walk_context_extensions(c, NULL))
2940 /* walk included and write info ... */
2941 i = ast_walk_context_includes(c, NULL);
2943 bzero(buf, sizeof(buf));
2944 snprintf(buf, sizeof(buf), "'%s'",
2945 ast_get_include_name(i));
2946 ast_cli(fd, " Include => %-45s [%s]\n",
2947 buf, ast_get_include_registrar(i));
2948 i = ast_walk_context_includes(c, i);
2951 /* walk ignore patterns and write info ... */
2952 ip = ast_walk_context_ignorepats(c, NULL);
2954 bzero(buf, sizeof(buf));
2955 snprintf(buf, sizeof(buf), "'%s'",
2956 ast_get_ignorepat_name(ip));
2957 ast_cli(fd, " Ignore pattern => %-45s [%s]\n",
2958 buf, ast_get_ignorepat_registrar(ip));
2959 ip = ast_walk_context_ignorepats(c, ip);
2961 sw = ast_walk_context_switches(c, NULL);
2963 bzero(buf, sizeof(buf));
2964 snprintf(buf, sizeof(buf), "'%s/%s'",
2965 ast_get_switch_name(sw),
2966 ast_get_switch_data(sw));
2967 ast_cli(fd, " Alt. Switch => %-45s [%s]\n",
2968 buf, ast_get_switch_registrar(sw));
2969 sw = ast_walk_context_switches(c, sw);
2973 ast_unlock_context(c);
2975 /* if we print something in context, make an empty line */
2976 if (context_info_printed) ast_cli(fd, "\n");
2979 c = ast_walk_contexts(c);
2981 ast_unlock_contexts();
2983 /* check for input failure and throw some error messages */
2984 if (context && !context_existence) {
2985 ast_cli(fd, "There is no existence of '%s' context\n",
2987 return RESULT_FAILURE;
2990 if (exten && !extension_existence) {
2992 ast_cli(fd, "There is no existence of %s@%s extension\n",
2996 "There is no existence of '%s' extension in all contexts\n",
2998 return RESULT_FAILURE;
3000 ast_cli(fd,"-= %d extensions (%d priorities) in %d contexts. =-\n",total_exten, total_prio, total_context);
3003 return RESULT_SUCCESS;
3007 * CLI entries for upper commands ...
3009 static struct ast_cli_entry show_applications_cli =
3010 { { "show", "applications", NULL },
3011 handle_show_applications, "Shows registered applications",
3012 show_applications_help, complete_show_applications };
3014 static struct ast_cli_entry show_application_cli =
3015 { { "show", "application", NULL },
3016 handle_show_application, "Describe a specific application",
3017 show_application_help, complete_show_application };
3019 static struct ast_cli_entry show_dialplan_cli =
3020 { { "show", "dialplan", NULL },
3021 handle_show_dialplan, "Show dialplan",
3022 show_dialplan_help, complete_show_dialplan_context };
3024 static struct ast_cli_entry show_switches_cli =
3025 { { "show", "switches", NULL },
3026 handle_show_switches, "Show alternative switches",
3027 show_switches_help, NULL };
3029 int ast_unregister_application(const char *app) {
3030 struct ast_app *tmp, *tmpl = NULL;
3031 if (ast_mutex_lock(&applock)) {
3032 ast_log(LOG_ERROR, "Unable to lock application list\n");
3037 if (!strcasecmp(app, tmp->name)) {
3039 tmpl->next = tmp->next;
3042 if (option_verbose > 1)
3043 ast_verbose( VERBOSE_PREFIX_2 "Unregistered application '%s'\n", tmp->name);
3045 ast_mutex_unlock(&applock);
3051 ast_mutex_unlock(&applock);
3055 struct ast_context *ast_context_create(struct ast_context **extcontexts, const char *name, const char *registrar)
3057 struct ast_context *tmp, **local_contexts;
3059 length = sizeof(struct ast_context);
3060 length += strlen(name) + 1;
3062 local_contexts = &contexts;
3063 ast_mutex_lock(&conlock);
3065 local_contexts = extcontexts;
3067 tmp = *local_contexts;
3069 if (!strcasecmp(tmp->name, name)) {
3070 ast_mutex_unlock(&conlock);
3071 ast_log(LOG_WARNING, "Tried to register context '%s', already in use\n", name);
3073 ast_mutex_unlock(&conlock);
3078 tmp = malloc(length);
3080 memset(tmp, 0, length);
3081 ast_mutex_init(&tmp->lock);
3082 strcpy(tmp->name, name);
3084 tmp->registrar = registrar;
3085 tmp->next = *local_contexts;
3086 tmp->includes = NULL;
3087 tmp->ignorepats = NULL;
3088 *local_contexts = tmp;
3090 ast_log(LOG_DEBUG, "Registered context '%s'\n", tmp->name);
3091 else if (option_verbose > 2)
3092 ast_verbose( VERBOSE_PREFIX_3 "Registered extension context '%s'\n", tmp->name);
3094 ast_log(LOG_ERROR, "Out of memory\n");
3097 ast_mutex_unlock(&conlock);
3101 void __ast_context_destroy(struct ast_context *con, const char *registrar);
3103 void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char *registrar) {
3104 struct ast_context *tmp, *lasttmp = NULL;
3106 ast_mutex_lock(&conlock);
3108 __ast_context_destroy(NULL,registrar);
3115 __ast_context_destroy(tmp,tmp->registrar);
3121 lasttmp->next = contexts;
3122 contexts = *extcontexts;
3123 *extcontexts = NULL;
3125 ast_log(LOG_WARNING, "Requested contexts didn't get merged\n");
3126 ast_mutex_unlock(&conlock);
3132 * EBUSY - can't lock
3133 * ENOENT - no existence of context
3135 int ast_context_add_include(const char *context, const char *include, const char *registrar)
3137 struct ast_context *c;
3139 if (ast_lock_contexts()) {
3144 /* walk contexts ... */
3145 c = ast_walk_contexts(NULL);
3147 /* ... search for the right one ... */
3148 if (!strcmp(ast_get_context_name(c), context)) {
3149 int ret = ast_context_add_include2(c, include, registrar);
3150 /* ... unlock contexts list and return */
3151 ast_unlock_contexts();
3154 c = ast_walk_contexts(c);
3157 /* we can't find the right context */
3158 ast_unlock_contexts();
3166 while(*c && (*c != '|')) c++; \
3167 if (*c) { *c = '\0'; c++; } else c = NULL; \
3170 static void get_timerange(struct ast_timing *i, char *times)
3178 /* start disabling all times, fill the fields with 0's, as they may contain garbage */
3179 memset(i->minmask, 0, sizeof(i->minmask));
3181 /* Star is all times */
3182 if (ast_strlen_zero(times) || !strcmp(times, "*")) {
3184 i->minmask[x] = (1 << 30) - 1;
3187 /* Otherwise expect a range */
3188 e = strchr(times, '-');
3190 ast_log(LOG_WARNING, "Time range is not valid. Assuming no restrictions based on time.\n");
3195 while(*e && !isdigit(*e)) e++;
3197 ast_log(LOG_WARNING, "Invalid time range. Assuming no restrictions based on time.\n");
3200 if (sscanf(times, "%d:%d", &s1, &s2) != 2) {
3201 ast_log(LOG_WARNING, "%s isn't a time. Assuming no restrictions based on time.\n", times);
3204 if (sscanf(e, "%d:%d", &e1, &e2) != 2) {
3205 ast_log(LOG_WARNING, "%s isn't a time. Assuming no restrictions based on time.\n", e);
3210 s1 = s1 * 30 + s2/2;
3211 if ((s1 < 0) || (s1 >= 24*30)) {
3212 ast_log(LOG_WARNING, "%s isn't a valid start time. Assuming no time.\n", times);
3215 e1 = e1 * 30 + e2/2;
3216 if ((e1 < 0) || (e1 >= 24*30)) {
3217 ast_log(LOG_WARNING, "%s isn't a valid end time. Assuming no time.\n", e);
3220 /* Go through the time and enable each appropriate bit */
3221 for (x=s1;x != e1;x = (x + 1) % (24 * 30)) {
3222 i->minmask[x/30] |= (1 << (x % 30));
3224 /* Do the last one */
3225 i->minmask[x/30] |= (1 << (x % 30));
3227 for (cth=0;cth<24;cth++) {
3228 /* Initialize masks to blank */
3229 i->minmask[cth] = 0;
3230 for (ctm=0;ctm<30;ctm++) {
3232 /* First hour with more than one hour */
3233 (((cth == s1) && (ctm >= s2)) &&
3236 || (((cth == s1) && (ctm >= s2)) &&
3237 ((cth == e1) && (ctm <= e2)))
3238 /* In between first and last hours (more than 2 hours) */
3241 /* Last hour with more than one hour */
3243 ((cth == e1) && (ctm <= e2)))
3245 i->minmask[cth] |= (1 << (ctm / 2));
3253 static char *days[] =
3264 static unsigned int get_dow(char *dow)
3267 /* The following line is coincidence, really! */
3271 /* Check for all days */
3272 if (ast_strlen_zero(dow) || !strcmp(dow, "*"))
3273 return (1 << 7) - 1;
3274 /* Get start and ending days */
3275 c = strchr(dow, '-');
3281 /* Find the start */
3283 while((s < 7) && strcasecmp(dow, days[s])) s++;
3285 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", dow);
3290 while((e < 7) && strcasecmp(c, days[e])) e++;
3292 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
3298 for (x=s; x != e; x = (x + 1) % 7) {
3306 static unsigned int get_day(char *day)
3309 /* The following line is coincidence, really! */
3313 /* Check for all days */
3314 if (ast_strlen_zero(day) || !strcmp(day, "*")) {
3315 mask = (1 << 30) + ((1 << 30) - 1);
3318 /* Get start and ending days */
3319 c = strchr(day, '-');
3324 /* Find the start */
3325 if (sscanf(day, "%d", &s) != 1) {
3326 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", day);
3329 if ((s < 1) || (s > 31)) {
3330 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", day);
3335 if (sscanf(c, "%d", &e) != 1) {
3336 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
3339 if ((e < 1) || (e > 31)) {
3340 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
3347 for (x=s;x!=e;x = (x + 1) % 31) {
3354 static char *months[] =
3370 static unsigned int get_month(char *mon)
3373 /* The following line is coincidence, really! */
3377 /* Check for all days */
3378 if (ast_strlen_zero(mon) || !strcmp(mon, "*"))
3379 return (1 << 12) - 1;
3380 /* Get start and ending days */
3381 c = strchr(mon, '-');
3386 /* Find the start */
3388 while((s < 12) && strcasecmp(mon, months[s])) s++;
3390 ast_log(LOG_WARNING, "Invalid month '%s', assuming none\n", mon);
3395 while((e < 12) && strcasecmp(mon, months[e])) e++;
3397 ast_log(LOG_WARNING, "Invalid month '%s', assuming none\n", c);
3403 for (x=s; x!=e; x = (x + 1) % 12) {
3411 int ast_build_timing(struct ast_timing *i, char *info_in)
3413 char info_save[256];
3417 /* Check for empty just in case */
3418 if (ast_strlen_zero(info_in))
3420 /* make a copy just in case we were passed a static string */
3421 strncpy(info_save, info_in, sizeof(info_save));
3423 /* Assume everything except time */
3424 i->monthmask = (1 << 12) - 1;
3425 i->daymask = (1 << 30) - 1 + (1 << 30);
3426 i->dowmask = (1 << 7) - 1;
3427 /* Avoid using str tok */
3429 /* Info has the time range, start with that */
3430 get_timerange(i, info);
3435 /* Now check for day of week */
3436 i->dowmask = get_dow(info);
3442 /* Now check for the day of the month */
3443 i->daymask = get_day(info);
3448 /* And finally go for the month */
3449 i->monthmask = get_month(info);
3454 int ast_check_timing(struct ast_timing *i)
3460 localtime_r(&t,&tm);
3462 /* If it's not the right month, return */
3463 if (!(i->monthmask & (1 << tm.tm_mon))) {
3467 /* If it's not that time of the month.... */
3468 /* Warning, tm_mday has range 1..31! */