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([delay]): If the channel is ringing, answer it, otherwise do nothing. \n"
214 "If delay is specified, asterisk will pause execution for the specified amount\n"
215 "of milliseconds if an answer is required, in order to give audio a chance to\n"
216 "become ready. Returns 0 unless it tries to answer the channel and fails.\n"
219 { "BackGround", pbx_builtin_background,
220 "Play a file while awaiting extension",
221 " Background(filename1[&filename2...][|options[|langoverride]]): Plays\n"
222 "given files, while simultaneously waiting for the user to begin typing\n"
223 "an extension. The timeouts do not count until the last BackGround\n"
224 "application has ended. Options may also be included following a pipe \n"
225 "symbol. The 'skip' option causes the playback of the message to be \n"
226 "skipped if the channel is not in the 'up' state (i.e. it hasn't been\n"
227 "answered yet. If 'skip' is specified, the application will return\n"
228 "immediately should the channel not be off hook. Otherwise, unless \n"
229 "'noanswer' is specified, the channel channel will be answered before the\n"
230 "sound is played. Not all channels support playing messages while still\n"
231 "hook. The 'langoverride' may be a language to use for playing the prompt\n"
232 "which differs from the current language of the channel. Returns -1 if \n"
233 "the channel was hung up, or if the file does not exist. Returns 0 otherwise.\n"
236 { "Busy", pbx_builtin_busy,
237 "Indicate busy condition and stop",
238 " Busy([timeout]): Requests that the channel indicate busy condition and\n"
239 "then waits for the user to hang up or the optional timeout to expire.\n"
243 { "Congestion", pbx_builtin_congestion,
244 "Indicate congestion and stop",
245 " Congestion([timeout]): Requests that the channel indicate congestion\n"
246 "and then waits for the user to hang up or for the optional timeout to\n"
247 "expire. Always returns -1."
250 { "DigitTimeout", pbx_builtin_dtimeout,
251 "Set maximum timeout between digits",
252 " DigitTimeout(seconds): Set the maximum amount of time permitted between\n"
253 "digits when the user is typing in an extension. When this timeout expires,\n"
254 "after the user has started to type in an extension, the extension will be\n"
255 "considered complete, and will be interpreted. Note that if an extension\n"
256 "typed in is valid, it will not have to timeout to be tested, so typically\n"
257 "at the expiry of this timeout, the extension will be considered invalid\n"
258 "(and thus control would be passed to the 'i' extension, or if it doesn't\n"
259 "exist the call would be terminated). Always returns 0.\n"
262 { "Goto", pbx_builtin_goto,
263 "Goto a particular priority, extension, or context",
264 " Goto([[context|]extension|]priority): Set the priority to the specified\n"
265 "value, optionally setting the extension and optionally the context as well.\n"
266 "The extension BYEXTENSION is special in that it uses the current extension,\n"
267 "thus permitting you to go to a different context, without specifying a\n"
268 "specific extension. Always returns 0, even if the given context, extension,\n"
269 "or priority is invalid.\n"
272 { "GotoIf", pbx_builtin_gotoif,
274 " GotoIf(Condition?label1:label2): Go to label 1 if condition is\n"
275 "true, to label2 if condition is false. Either label1 or label2 may be\n"
276 "omitted (in that case, we just don't take the particular branch) but not\n"
277 "both. Look for the condition syntax in examples or documentation."
280 { "GotoIfTime", pbx_builtin_gotoiftime,
281 "Conditional goto on current time",
282 " GotoIfTime(<times>|<weekdays>|<mdays>|<months>?[[context|]extension|]pri):\n"
283 "If the current time matches the specified time, then branch to the specified\n"
284 "extension. Each of the elements may be specified either as '*' (for always)\n"
285 "or as a range. See the 'include' syntax for details."
288 { "Hangup", pbx_builtin_hangup,
289 "Unconditional hangup",
290 " Hangup(): Unconditionally hangs up a given channel by returning -1 always.\n"
293 { "NoOp", pbx_builtin_noop,
295 " NoOp(): No-operation; Does nothing."
298 { "Prefix", pbx_builtin_prefix,
299 "Prepend leading digits",
300 " Prefix(digits): Prepends the digit string specified by digits to the\n"
301 "channel's associated extension. For example, the number 1212 when prefixed\n"
302 "with '555' will become 5551212. This app always returns 0, and the PBX will\n"
303 "continue processing at the next priority for the *new* extension.\n"
304 " So, for example, if priority 3 of 1212 is Prefix 555, the next step\n"
305 "executed will be priority 4 of 5551212. If you switch into an extension\n"
306 "which has no first step, the PBX will treat it as though the user dialed an\n"
307 "invalid extension.\n"
310 { "Progress", pbx_builtin_progress,
312 " Progress(): Request that the channel indicate in-band progress is \n"
313 "available to the user.\nAlways returns 0.\n"
316 { "ResetCDR", pbx_builtin_resetcdr,
317 "Resets the Call Data Record",
318 " ResetCDR([options]): Causes the Call Data Record to be reset, optionally\n"
319 "storing the current CDR before zeroing it out (if 'w' option is specifed).\n"
320 "record WILL be stored.\nAlways returns 0.\n"
323 { "ResponseTimeout", pbx_builtin_rtimeout,
324 "Set maximum timeout awaiting response",
325 " ResponseTimeout(seconds): Set the maximum amount of time permitted after\n"
326 "falling through a series of priorities for a channel in which the user may\n"
327 "begin typing an extension. If the user does not type an extension in this\n"
328 "amount of time, control will pass to the 't' extension if it exists, and\n"
329 "if not the call would be terminated.\nAlways returns 0.\n"
332 { "Ringing", pbx_builtin_ringing,
333 "Indicate ringing tone",
334 " Ringing(): Request that the channel indicate ringing tone to the user.\n"
335 "Always returns 0.\n"
338 { "SayNumber", pbx_builtin_saynumber,
340 " SayNumber(digits[,gender]): Says the passed number. SayNumber is using\n"
341 "the current language setting for the channel. (See app SetLanguage).\n"
344 { "SayDigits", pbx_builtin_saydigits,
346 " SayDigits(digits): Says the passed digits. SayDigits is using the\n"
347 "current language setting for the channel. (See app setLanguage)\n"
350 { "SayAlpha", pbx_builtin_saycharacters,
352 " SayAlpha(string): Spells the passed string\n"
355 { "SayPhonetic", pbx_builtin_sayphonetic,
357 " SayPhonetic(string): Spells the passed string with phonetic alphabet\n"
360 { "SetAccount", pbx_builtin_setaccount,
362 " SetAccount([account]): Set the channel account code for billing\n"
363 "purposes. Always returns 0.\n"
366 { "SetAMAFlags", pbx_builtin_setamaflags,
368 " SetAMAFlags([flag]): Set the channel AMA Flags for billing\n"
369 "purposes. Always returns 0.\n"
372 { "SetGlobalVar", pbx_builtin_setglobalvar,
373 "Set global variable to value",
374 " SetGlobalVar(#n=value): Sets global variable n to value. Global\n"
375 "variable are available across channels.\n"
378 { "SetLanguage", pbx_builtin_setlanguage,
379 "Sets user language",
380 " SetLanguage(language): Set the channel language to 'language'. This\n"
381 "information is used for the syntax in generation of numbers, and to choose\n"
382 "a natural language file when available.\n"
383 " For example, if language is set to 'fr' and the file 'demo-congrats' is \n"
384 "requested to be played, if the file 'fr/demo-congrats' exists, then\n"
385 "it will play that file, and if not will play the normal 'demo-congrats'.\n"
386 "Always returns 0.\n"
389 { "SetVar", pbx_builtin_setvar,
390 "Set variable to value",
391 " SetVar(#n=value): Sets variable n to value. If prefixed with _, single\n"
392 "inheritance assumed. If prefixed with __, infinite inheritance is assumed.\n" },
394 { "ImportVar", pbx_builtin_importvar,
395 "Set variable to value",
396 " ImportVar(#n=channel|variable): Sets variable n to variable as evaluated on\n"
397 "the specified channel (instead of current). If prefixed with _, single\n"
398 "inheritance assumed. If prefixed with __, infinite inheritance is assumed.\n" },
400 { "StripMSD", pbx_builtin_stripmsd,
401 "Strip leading digits",
402 " StripMSD(count): Strips the leading 'count' digits from the channel's\n"
403 "associated extension. For example, the number 5551212 when stripped with a\n"
404 "count of 3 would be changed to 1212. This app always returns 0, and the PBX\n"
405 "will continue processing at the next priority for the *new* extension.\n"
406 " So, for example, if priority 3 of 5551212 is StripMSD 3, the next step\n"
407 "executed will be priority 4 of 1212. If you switch into an extension which\n"
408 "has no first step, the PBX will treat it as though the user dialed an\n"
409 "invalid extension.\n"
412 { "Suffix", pbx_builtin_suffix,
413 "Append trailing digits",
414 " Suffix(digits): Appends the digit string specified by digits to the\n"
415 "channel's associated extension. For example, the number 555 when suffixed\n"
416 "with '1212' will become 5551212. This app always returns 0, and the PBX will\n"
417 "continue processing at the next priority for the *new* extension.\n"
418 " So, for example, if priority 3 of 555 is Suffix 1212, the next step\n"
419 "executed will be priority 4 of 5551212. If you switch into an extension\n"
420 "which has no first step, the PBX will treat it as though the user dialed an\n"
421 "invalid extension.\n"
424 { "Wait", pbx_builtin_wait,
425 "Waits for some time",
426 " Wait(seconds): Waits for a specified number of seconds, then returns 0.\n"
427 "seconds can be passed with fractions of a second. (eg: 1.5 = 1.5 seconds)\n"
430 { "WaitExten", pbx_builtin_waitexten,
431 "Waits for an extension to be entered",
432 " WaitExten([seconds]): Waits for the user to enter a new extension for the \n"
433 "specified number of seconds, then returns 0. Seconds can be passed with\n"
434 "fractions of a seconds (eg: 1.5 = 1.5 seconds) or if unspecified the\n"
435 "default extension timeout will be used.\n"
440 AST_MUTEX_DEFINE_STATIC(applock); /* Lock for the application list */
441 static struct ast_context *contexts = NULL;
442 AST_MUTEX_DEFINE_STATIC(conlock); /* Lock for the ast_context list */
443 static struct ast_app *apps = NULL;
445 AST_MUTEX_DEFINE_STATIC(switchlock); /* Lock for switches */
446 struct ast_switch *switches = NULL;
448 AST_MUTEX_DEFINE_STATIC(hintlock); /* Lock for extension state notifys */
449 static int stateid = 1;
450 struct ast_hint *hints = NULL;
451 struct ast_state_cb *statecbs = NULL;
453 int pbx_exec(struct ast_channel *c, /* Channel */
454 struct ast_app *app, /* Application */
455 void *data, /* Data for execution */
456 int newstack) /* Force stack increment */
458 /* This function is special. It saves the stack so that no matter
459 how many times it is called, it returns to the same place */
465 int (*execute)(struct ast_channel *chan, void *data) = app->execute;
469 ast_cdr_setapp(c->cdr, app->name, data);
471 /* save channel values */
472 saved_c_appl= c->appl;
473 saved_c_data= c->data;
477 res = execute(c, data);
478 /* restore channel values */
479 c->appl= saved_c_appl;
480 c->data= saved_c_data;
483 ast_log(LOG_WARNING, "You really didn't want to call this function with newstack set to 0\n");
488 /* Go no deeper than this through includes (not counting loops) */
489 #define AST_PBX_MAX_STACK 64
491 #define HELPER_EXISTS 0
492 #define HELPER_SPAWN 1
493 #define HELPER_EXEC 2
494 #define HELPER_CANMATCH 3
495 #define HELPER_MATCHMORE 4
496 #define HELPER_FINDLABEL 5
498 struct ast_app *pbx_findapp(const char *app)
502 if (ast_mutex_lock(&applock)) {
503 ast_log(LOG_WARNING, "Unable to obtain application lock\n");
508 if (!strcasecmp(tmp->name, app))
512 ast_mutex_unlock(&applock);
516 static struct ast_switch *pbx_findswitch(const char *sw)
518 struct ast_switch *asw;
520 if (ast_mutex_lock(&switchlock)) {
521 ast_log(LOG_WARNING, "Unable to obtain application lock\n");
526 if (!strcasecmp(asw->name, sw))
530 ast_mutex_unlock(&switchlock);
534 static inline int include_valid(struct ast_include *i)
539 return ast_check_timing(&(i->timing));
542 static void pbx_destroy(struct ast_pbx *p)
547 #define EXTENSION_MATCH_CORE(data,pattern,match) {\
548 /* All patterns begin with _ */\
549 if (pattern[0] != '_') \
551 /* Start optimistic */\
554 while(match && *data && *pattern && (*pattern != '/')) {\
555 while (*data == '-' && (*(data+1) != '\0')) data++;\
556 switch(toupper(*pattern)) {\
563 where=strchr(pattern,']');\
565 border=(int)(where-pattern);\
566 if (!where || border > strlen(pattern)) {\
567 ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");\
570 for (i=0; i<border; i++) {\
573 if (pattern[i+1]=='-') {\
574 if (*data >= pattern[i] && *data <= pattern[i+2]) {\
581 if (res==1 || *data==pattern[i]) {\
590 if ((*data < '2') || (*data > '9'))\
594 if ((*data < '0') || (*data > '9'))\
598 if ((*data < '1') || (*data > '9'))\
606 /* Ignore these characters */\
610 if (*data != *pattern)\
618 int ast_extension_match(const char *pattern, const char *data)
621 /* If they're the same return */
622 if (!strcmp(pattern, data))
624 EXTENSION_MATCH_CORE(data,pattern,match);
625 /* Must be at the end of both */
626 if (*data || (*pattern && (*pattern != '/')))
631 int ast_extension_close(const char *pattern, const char *data, int needmore)
634 /* If "data" is longer, it can'be a subset of pattern unless
635 pattern is a pattern match */
636 if ((strlen(pattern) < strlen(data)) && (pattern[0] != '_'))
639 if ((ast_strlen_zero((char *)data) || !strncasecmp(pattern, data, strlen(data))) &&
640 (!needmore || (strlen(pattern) > strlen(data)))) {
643 EXTENSION_MATCH_CORE(data,pattern,match);
644 /* If there's more or we don't care about more, return non-zero, otlherwise it's a miss */
645 if (!needmore || *pattern) {
651 struct ast_context *ast_context_find(const char *name)
653 struct ast_context *tmp;
654 ast_mutex_lock(&conlock);
658 if (!strcasecmp(name, tmp->name))
664 ast_mutex_unlock(&conlock);
668 #define STATUS_NO_CONTEXT 1
669 #define STATUS_NO_EXTENSION 2
670 #define STATUS_NO_PRIORITY 3
671 #define STATUS_NO_LABEL 4
672 #define STATUS_SUCCESS 5
674 static int matchcid(const char *cidpattern, const char *callerid)
678 /* If the Caller*ID pattern is empty, then we're matching NO Caller*ID, so
679 failing to get a number should count as a match, otherwise not */
682 if (!ast_strlen_zero(cidpattern))
690 return ast_extension_match(cidpattern, callerid);
693 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)
696 struct ast_context *tmp;
697 struct ast_exten *e, *eroot;
698 struct ast_include *i;
700 struct ast_switch *asw;
702 /* Initialize status if appropriate */
704 *status = STATUS_NO_CONTEXT;
708 /* Check for stack overflow */
709 if (*stacklen >= AST_PBX_MAX_STACK) {
710 ast_log(LOG_WARNING, "Maximum PBX stack exceeded\n");
713 /* Check first to see if we've already been checked */
714 for (x=0;x<*stacklen;x++) {
715 if (!strcasecmp(incstack[x], context))
724 if (bypass || !strcmp(tmp->name, context)) {
725 if (*status < STATUS_NO_EXTENSION)
726 *status = STATUS_NO_EXTENSION;
729 /* Match extension */
730 if ((((action != HELPER_MATCHMORE) && ast_extension_match(eroot->exten, exten)) ||
731 ((action == HELPER_CANMATCH) && (ast_extension_close(eroot->exten, exten, 0))) ||
732 ((action == HELPER_MATCHMORE) && (ast_extension_close(eroot->exten, exten, 1)))) &&
733 (!eroot->matchcid || matchcid(eroot->cidmatch, callerid))) {
735 if (*status < STATUS_NO_PRIORITY)
736 *status = STATUS_NO_PRIORITY;
739 if (action == HELPER_FINDLABEL) {
740 if (*status < STATUS_NO_LABEL)
741 *status = STATUS_NO_LABEL;
742 if (label && e->label && !strcmp(label, e->label)) {
743 *status = STATUS_SUCCESS;
744 *foundcontext = context;
747 } else if (e->priority == priority) {
748 *status = STATUS_SUCCESS;
749 *foundcontext = context;
757 /* Check alternative switches */
760 if ((asw = pbx_findswitch(sw->name))) {
761 if (action == HELPER_CANMATCH)
762 res = asw->canmatch ? asw->canmatch(chan, context, exten, priority, callerid, sw->data) : 0;
763 else if (action == HELPER_MATCHMORE)
764 res = asw->matchmore ? asw->matchmore(chan, context, exten, priority, callerid, sw->data) : 0;
766 res = asw->exists ? asw->exists(chan, context, exten, priority, callerid, sw->data) : 0;
771 *foundcontext = context;
775 ast_log(LOG_WARNING, "No such switch '%s'\n", sw->name);
779 /* Setup the stack */
780 incstack[*stacklen] = tmp->name;
782 /* Now try any includes we have in this context */
785 if (include_valid(i)) {
786 if ((e = pbx_find_extension(chan, bypass, i->rname, exten, priority, label, callerid, action, incstack, stacklen, status, swo, data, foundcontext)))
800 void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp)
803 char tmpvar[80] = "";
805 struct tm brokentime;
807 struct ast_var_t *variables;
812 /* Now we have the variable name on cp3 */
813 if (!strncasecmp(var,"LEN(",4)) {
816 if (strrchr(var,')')) {
818 strncpy(cp3, var, sizeof(cp3) - 1);
819 cp3[len-len_len-1]='\0';
820 sprintf(workspace,"%d",(int)strlen(cp3));
826 } else if ((first=strchr(var,':'))) {
827 strncpy(tmpvar, var, sizeof(tmpvar) - 1);
828 first = strchr(tmpvar, ':');
830 first = tmpvar + strlen(tmpvar);
832 pbx_retrieve_variable(c,tmpvar,ret,workspace,workspacelen - 1, headp);
834 offset=atoi(first+1);
835 if ((second=strchr(first+1,':'))) {
837 offset2=atoi(second+1);
839 offset2=strlen(*ret)-offset;
840 if (abs(offset)>strlen(*ret)) {
844 offset=-strlen(*ret);
846 if ((offset<0 && offset2>-offset) || (offset>=0 && offset+offset2>strlen(*ret))) {
848 offset2=strlen(*ret)-offset;
850 offset2=strlen(*ret)+offset;
855 *ret+=strlen(*ret)+offset;
856 (*ret)[offset2] = '\0';
857 } else if (c && !strcmp(var, "CALLERIDNUM")) {
858 if (c->cid.cid_num) {
859 strncpy(workspace, c->cid.cid_num, workspacelen - 1);
863 } else if (c && !strcmp(var, "CALLERANI")) {
864 if (c->cid.cid_ani) {
865 strncpy(workspace, c->cid.cid_ani, workspacelen - 1);
869 } else if (c && !strcmp(var, "CALLERIDNAME")) {
870 if (c->cid.cid_name) {
871 strncpy(workspace, c->cid.cid_name, workspacelen - 1);
875 } else if (c && !strcmp(var, "CALLERID")) {
876 if (c->cid.cid_num) {
877 if (c->cid.cid_name) {
878 snprintf(workspace, workspacelen, "\"%s\" <%s>", c->cid.cid_name, c->cid.cid_num);
880 strncpy(workspace, c->cid.cid_num, workspacelen - 1);
883 } else if (c->cid.cid_name) {
884 strncpy(workspace, c->cid.cid_name, workspacelen - 1);
888 } else if (c && !strcmp(var, "DNID")) {
889 if (c->cid.cid_dnid) {
890 strncpy(workspace, c->cid.cid_dnid, workspacelen - 1);
894 } else if (c && !strcmp(var, "HINT")) {
895 if (!ast_get_hint(workspace, workspacelen, c, c->context, c->exten))
899 } else if (c && !strcmp(var, "EXTEN")) {
900 strncpy(workspace, c->exten, workspacelen - 1);
902 } else if (c && !strcmp(var, "RDNIS")) {
903 if (c->cid.cid_rdnis) {
904 strncpy(workspace, c->cid.cid_rdnis, workspacelen - 1);
908 } else if (c && !strcmp(var, "CONTEXT")) {
909 strncpy(workspace, c->context, workspacelen - 1);
911 } else if (c && !strcmp(var, "PRIORITY")) {
912 snprintf(workspace, workspacelen, "%d", c->priority);
914 } else if (c && !strcmp(var, "CALLINGPRES")) {
915 snprintf(workspace, workspacelen, "%d", c->cid.cid_pres);
917 } else if (c && !strcmp(var, "CALLINGANI2")) {
918 snprintf(workspace, workspacelen, "%d", c->cid.cid_ani2);
920 } else if (c && !strcmp(var, "CALLINGTON")) {
921 snprintf(workspace, workspacelen, "%d", c->cid.cid_ton);
923 } else if (c && !strcmp(var, "CALLINGTNS")) {
924 snprintf(workspace, workspacelen, "%d", c->cid.cid_tns);
926 } else if (c && !strcmp(var, "CHANNEL")) {
927 strncpy(workspace, c->name, workspacelen - 1);
929 } else if (c && !strcmp(var, "EPOCH")) {
930 snprintf(workspace, workspacelen, "%u",(int)time(NULL));
932 } else if (c && !strcmp(var, "DATETIME")) {
934 localtime_r(&thistime, &brokentime);
935 snprintf(workspace, workspacelen, "%02d%02d%04d-%02d:%02d:%02d",
938 brokentime.tm_year+1900,
944 } else if (c && !strcmp(var, "TIMESTAMP")) {
946 localtime_r(&thistime, &brokentime);
947 /* 20031130-150612 */
948 snprintf(workspace, workspacelen, "%04d%02d%02d-%02d%02d%02d",
949 brokentime.tm_year+1900,
957 } else if (c && !strcmp(var, "UNIQUEID")) {
958 snprintf(workspace, workspacelen, "%s", c->uniqueid);
960 } else if (c && !strcmp(var, "HANGUPCAUSE")) {
961 snprintf(workspace, workspacelen, "%i", c->hangupcause);
963 } else if (c && !strcmp(var, "ACCOUNTCODE")) {
964 strncpy(workspace, c->accountcode, workspacelen - 1);
966 } else if (c && !strcmp(var, "LANGUAGE")) {
967 strncpy(workspace, c->language, workspacelen - 1);
971 AST_LIST_TRAVERSE(headp,variables,entries) {
973 ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",var,ast_var_name(variables));
975 if (strcasecmp(ast_var_name(variables),var)==0) {
976 *ret=ast_var_value(variables);
978 strncpy(workspace, *ret, workspacelen - 1);
987 AST_LIST_TRAVERSE(&globals,variables,entries) {
989 ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",var,ast_var_name(variables));
991 if (strcasecmp(ast_var_name(variables),var)==0) {
992 *ret=ast_var_value(variables);
994 strncpy(workspace, *ret, workspacelen - 1);
1001 int len=strlen(var);
1002 int len_env=strlen("ENV(");
1003 if (len > (len_env+1) && !strncasecmp(var,"ENV(",len_env) && !strcmp(var+len-1,")")) {
1005 strncpy(cp3, var, sizeof(cp3) - 1);
1007 *ret=getenv(cp3+len_env);
1009 strncpy(workspace, *ret, workspacelen - 1);
1017 static void pbx_substitute_variables_helper_full(struct ast_channel *c, const char *cp1, char *cp2, int count, struct varshead *headp)
1020 const char *tmp, *whereweare;
1022 char workspace[4096];
1023 char ltmp[4096], var[4096];
1024 char *nextvar, *nextexp;
1026 int pos, brackets, needsub, len;
1028 /* Substitutes variables into cp2, based on string cp1, and assuming cp2 to be
1031 while(!ast_strlen_zero(whereweare) && count) {
1032 /* Assume we're copying the whole remaining string */
1033 pos = strlen(whereweare);
1035 /* Look for a variable */
1036 nextvar = strstr(whereweare, "${");
1038 /* Look for an expression */
1039 nextexp = strstr(whereweare, "$[");
1041 /* Pick the first one only */
1042 if (nextvar && nextexp) {
1043 if (nextvar < nextexp)
1049 /* If there is one, we only go that far */
1051 pos = nextvar - whereweare;
1053 pos = nextexp - whereweare;
1055 /* Can't copy more than 'count' bytes */
1059 /* Copy that many bytes */
1060 memcpy(cp2, whereweare, pos);
1067 /* We have a variable. Find the start and end, and determine
1068 if we are going to have to recursively call ourselves on the
1070 vars = vare = nextvar + 2;
1074 /* Find the end of it */
1075 while(brackets && *vare) {
1076 if ((vare[0] == '$') && (vare[1] == '{')) {
1079 } else if (vare[0] == '}') {
1081 } else if ((vare[0] == '$') && (vare[1] == '['))
1086 ast_log(LOG_NOTICE, "Error in extension logic (missing '}')\n");
1087 len = vare - vars - 1;
1089 /* Skip totally over variable name */
1090 whereweare += ( len + 3);
1092 /* Store variable name (and truncate) */
1093 memset(var, 0, sizeof(var));
1094 strncpy(var, vars, sizeof(var) - 1);
1097 /* Substitute if necessary */
1099 memset(ltmp, 0, sizeof(ltmp));
1100 pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1);
1106 /* Retrieve variable value */
1107 workspace[0] = '\0';
1108 pbx_retrieve_variable(c,vars,&cp4, workspace, sizeof(workspace), headp);
1110 length = strlen(cp4);
1113 memcpy(cp2, cp4, length);
1118 } else if (nextexp) {
1119 /* We have an expression. Find the start and end, and determine
1120 if we are going to have to recursively call ourselves on the
1122 vars = vare = nextexp + 2;
1126 /* Find the end of it */
1127 while(brackets && *vare) {
1128 if ((vare[0] == '$') && (vare[1] == '[')) {
1132 } else if (vare[0] == '[') {
1134 } else if (vare[0] == ']') {
1136 } else if ((vare[0] == '$') && (vare[1] == '{')) {
1143 ast_log(LOG_NOTICE, "Error in extension logic (missing ']')\n");
1144 len = vare - vars - 1;
1146 /* Skip totally over variable name */
1147 whereweare += ( len + 3);
1149 /* Store variable name (and truncate) */
1150 memset(var, 0, sizeof(var));
1151 strncpy(var, vars, sizeof(var) - 1);
1154 /* Substitute if necessary */
1156 memset(ltmp, 0, sizeof(ltmp));
1157 pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1);
1163 /* Evaluate expression */
1164 cp4 = ast_expr(vars);
1166 ast_log(LOG_DEBUG, "Expression is '%s'\n", cp4);
1169 length = strlen(cp4);
1172 memcpy(cp2, cp4, length);
1183 void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
1185 pbx_substitute_variables_helper_full(c, cp1, cp2, count, NULL);
1188 void pbx_substitute_variables_varshead(struct varshead *headp, const char *cp1, char *cp2, int count)
1190 pbx_substitute_variables_helper_full(NULL, cp1, cp2, count, headp);
1193 static void pbx_substitute_variables(char *passdata, int datalen, struct ast_channel *c, struct ast_exten *e) {
1195 memset(passdata, 0, datalen);
1197 /* No variables or expressions in e->data, so why scan it? */
1198 if (!strstr(e->data,"${") && !strstr(e->data,"$[")) {
1199 strncpy(passdata, e->data, datalen - 1);
1200 passdata[datalen-1] = '\0';
1204 pbx_substitute_variables_helper(c, e->data, passdata, datalen - 1);
1207 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)
1209 struct ast_exten *e;
1210 struct ast_app *app;
1211 struct ast_switch *sw;
1213 const char *foundcontext=NULL;
1217 char *incstack[AST_PBX_MAX_STACK];
1218 char passdata[EXT_DATA_SIZE];
1222 char tmp3[EXT_DATA_SIZE];
1224 char atmp2[EXT_DATA_SIZE+100];
1226 if (ast_mutex_lock(&conlock)) {
1227 ast_log(LOG_WARNING, "Unable to obtain lock\n");
1228 if ((action == HELPER_EXISTS) || (action == HELPER_CANMATCH) || (action == HELPER_MATCHMORE))
1233 e = pbx_find_extension(c, con, context, exten, priority, label, callerid, action, incstack, &stacklen, &status, &sw, &data, &foundcontext);
1236 case HELPER_CANMATCH:
1237 ast_mutex_unlock(&conlock);
1240 ast_mutex_unlock(&conlock);
1242 case HELPER_FINDLABEL:
1244 ast_mutex_unlock(&conlock);
1246 case HELPER_MATCHMORE:
1247 ast_mutex_unlock(&conlock);
1253 app = pbx_findapp(e->app);
1254 ast_mutex_unlock(&conlock);
1256 if (c->context != context)
1257 strncpy(c->context, context, sizeof(c->context)-1);
1258 if (c->exten != exten)
1259 strncpy(c->exten, exten, sizeof(c->exten)-1);
1260 c->priority = priority;
1261 pbx_substitute_variables(passdata, sizeof(passdata), c, e);
1263 ast_log(LOG_DEBUG, "Launching '%s'\n", app->name);
1264 snprintf(atmp, 80, "STACK-%s-%s-%d", context, exten, priority);
1265 snprintf(atmp2, EXT_DATA_SIZE+100, "%s(\"%s\", \"%s\") %s", app->name, c->name, (!ast_strlen_zero(passdata) ? (char *)passdata : ""), (newstack ? "in new stack" : "in same stack"));
1266 pbx_builtin_setvar_helper(c, atmp, atmp2);
1268 if (option_verbose > 2)
1269 ast_verbose( VERBOSE_PREFIX_3 "Executing %s(\"%s\", \"%s\") %s\n",
1270 term_color(tmp, app->name, COLOR_BRCYAN, 0, sizeof(tmp)),
1271 term_color(tmp2, c->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
1272 term_color(tmp3, (!ast_strlen_zero(passdata) ? (char *)passdata : ""), COLOR_BRMAGENTA, 0, sizeof(tmp3)),
1273 (newstack ? "in new stack" : "in same stack"));
1274 manager_event(EVENT_FLAG_CALL, "Newexten",
1279 "Application: %s\r\n"
1282 c->name, c->context, c->exten, c->priority, app->name, passdata ? passdata : "(NULL)", c->uniqueid);
1283 res = pbx_exec(c, app, passdata, newstack);
1286 ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
1290 ast_log(LOG_WARNING, "Huh (%d)?\n", action); return -1;
1294 case HELPER_CANMATCH:
1295 ast_mutex_unlock(&conlock);
1298 ast_mutex_unlock(&conlock);
1300 case HELPER_MATCHMORE:
1301 ast_mutex_unlock(&conlock);
1303 case HELPER_FINDLABEL:
1304 ast_mutex_unlock(&conlock);
1310 ast_mutex_unlock(&conlock);
1312 res = sw->exec(c, foundcontext ? foundcontext : context, exten, priority, callerid, newstack, data);
1314 ast_log(LOG_WARNING, "No execution engine for switch %s\n", sw->name);
1319 ast_log(LOG_WARNING, "Huh (%d)?\n", action);
1323 ast_mutex_unlock(&conlock);
1325 case STATUS_NO_CONTEXT:
1326 if ((action != HELPER_EXISTS) && (action != HELPER_MATCHMORE))
1327 ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", context);
1329 case STATUS_NO_EXTENSION:
1330 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1331 ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, context);
1333 case STATUS_NO_PRIORITY:
1334 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1335 ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, context);
1337 case STATUS_NO_LABEL:
1339 ast_log(LOG_NOTICE, "No such label '%s' in extension '%s' in context '%s'\n", label, exten, context);
1342 ast_log(LOG_DEBUG, "Shouldn't happen!\n");
1345 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1353 static struct ast_exten *ast_hint_extension(struct ast_channel *c, const char *context, const char *exten)
1355 struct ast_exten *e;
1356 struct ast_switch *sw;
1358 const char *foundcontext = NULL;
1360 char *incstack[AST_PBX_MAX_STACK];
1363 if (ast_mutex_lock(&conlock)) {
1364 ast_log(LOG_WARNING, "Unable to obtain lock\n");
1367 e = pbx_find_extension(c, NULL, context, exten, PRIORITY_HINT, NULL, "", HELPER_EXISTS, incstack, &stacklen, &status, &sw, &data, &foundcontext);
1368 ast_mutex_unlock(&conlock);
1372 static int ast_extension_state2(struct ast_exten *e)
1374 char hint[AST_MAX_EXTENSION] = "";
1377 int allunavailable = 1, allbusy = 1, allfree = 1;
1380 strncpy(hint, ast_get_extension_app(e), sizeof(hint)-1);
1384 rest = strchr(cur, '&');
1390 res = ast_device_state(cur);
1392 case AST_DEVICE_NOT_INUSE:
1396 case AST_DEVICE_INUSE:
1397 return AST_EXTENSION_INUSE;
1398 case AST_DEVICE_BUSY:
1403 case AST_DEVICE_UNAVAILABLE:
1404 case AST_DEVICE_INVALID:
1417 return AST_EXTENSION_NOT_INUSE;
1419 return AST_EXTENSION_BUSY;
1421 return AST_EXTENSION_UNAVAILABLE;
1423 return AST_EXTENSION_INUSE;
1425 return AST_EXTENSION_NOT_INUSE;
1429 int ast_extension_state(struct ast_channel *c, char *context, char *exten)
1431 struct ast_exten *e;
1433 e = ast_hint_extension(c, context, exten);
1437 return ast_extension_state2(e);
1440 int ast_device_state_changed(const char *fmt, ...)
1442 struct ast_hint *list;
1443 struct ast_state_cb *cblist;
1444 struct ast_devstate_cb *devcb;
1445 char hint[AST_MAX_EXTENSION] = "";
1446 char device[AST_MAX_EXTENSION];
1453 vsnprintf(device, sizeof(device), fmt, ap);
1456 rest = strchr(device, '-');
1461 state = ast_device_state(device);
1463 ast_mutex_lock(&hintlock);
1467 if (devcb->callback)
1468 devcb->callback(device, state, devcb->data);
1469 devcb = devcb->next;
1475 strncpy(hint, ast_get_extension_app(list->exten), sizeof(hint) - 1);
1478 rest = strchr(cur, '&');
1484 if (!strcmp(cur, device)) {
1485 /* Found extension execute callbacks */
1486 state = ast_extension_state2(list->exten);
1487 if ((state != -1) && (state != list->laststate)) {
1488 /* For general callbacks */
1491 cblist->callback(list->exten->parent->name, list->exten->exten, state, cblist->data);
1492 cblist = cblist->next;
1495 /* For extension callbacks */
1496 cblist = list->callbacks;
1498 cblist->callback(list->exten->parent->name, list->exten->exten, state, cblist->data);
1499 cblist = cblist->next;
1502 list->laststate = state;
1510 ast_mutex_unlock(&hintlock);
1514 int ast_devstate_add(ast_devstate_cb_type callback, void *data)
1516 struct ast_devstate_cb *devcb;
1517 devcb = malloc(sizeof(struct ast_devstate_cb));
1519 memset(devcb, 0, sizeof(struct ast_devstate_cb));
1520 ast_mutex_lock(&hintlock);
1522 devcb->callback = callback;
1523 devcb->next = devcbs;
1525 ast_mutex_unlock(&hintlock);
1530 void ast_devstate_del(ast_devstate_cb_type callback, void *data)
1532 struct ast_devstate_cb *devcb, *prev = NULL, *next;
1533 ast_mutex_lock(&hintlock);
1537 if ((devcb->data == data) && (devcb->callback == callback)) {
1547 ast_mutex_unlock(&hintlock);
1550 int ast_extension_state_add(const char *context, const char *exten,
1551 ast_state_cb_type callback, void *data)
1553 struct ast_hint *list;
1554 struct ast_state_cb *cblist;
1555 struct ast_exten *e;
1557 /* No context and extension add callback to statecbs list */
1558 if (!context && !exten) {
1559 ast_mutex_lock(&hintlock);
1563 if (cblist->callback == callback) {
1564 cblist->data = data;
1565 ast_mutex_unlock(&hintlock);
1567 cblist = cblist->next;
1570 /* Now inserts the callback */
1571 cblist = malloc(sizeof(struct ast_state_cb));
1573 ast_mutex_unlock(&hintlock);
1576 memset(cblist, 0, sizeof(struct ast_state_cb));
1578 cblist->callback = callback;
1579 cblist->data = data;
1581 cblist->next = statecbs;
1584 ast_mutex_unlock(&hintlock);
1588 if (!context || !exten)
1591 /* This callback type is for only one hint */
1592 e = ast_hint_extension(NULL, context, exten);
1597 ast_mutex_lock(&hintlock);
1601 if (list->exten == e)
1607 ast_mutex_unlock(&hintlock);
1611 /* Now inserts the callback */
1612 cblist = malloc(sizeof(struct ast_state_cb));
1614 ast_mutex_unlock(&hintlock);
1617 memset(cblist, 0, sizeof(struct ast_state_cb));
1618 cblist->id = stateid++;
1619 cblist->callback = callback;
1620 cblist->data = data;
1622 cblist->next = list->callbacks;
1623 list->callbacks = cblist;
1625 ast_mutex_unlock(&hintlock);
1629 int ast_extension_state_del(int id, ast_state_cb_type callback)
1631 struct ast_hint *list;
1632 struct ast_state_cb *cblist, *cbprev;
1634 if (!id && !callback)
1637 ast_mutex_lock(&hintlock);
1639 /* id is zero is a callback without extension */
1644 if (cblist->callback == callback) {
1646 statecbs = cblist->next;
1648 cbprev->next = cblist->next;
1652 ast_mutex_unlock(&hintlock);
1656 cblist = cblist->next;
1659 ast_mutex_lock(&hintlock);
1663 /* id greater than zero is a callback with extension */
1666 cblist = list->callbacks;
1669 if (cblist->id==id) {
1671 list->callbacks = cblist->next;
1673 cbprev->next = cblist->next;
1677 ast_mutex_unlock(&hintlock);
1681 cblist = cblist->next;
1686 ast_mutex_unlock(&hintlock);
1690 static int ast_add_hint(struct ast_exten *e)
1692 struct ast_hint *list;
1697 ast_mutex_lock(&hintlock);
1700 /* Search if hint exists, do nothing */
1702 if (list->exten == e) {
1703 ast_mutex_unlock(&hintlock);
1709 list = malloc(sizeof(struct ast_hint));
1711 ast_mutex_unlock(&hintlock);
1714 /* Initialize and insert new item */
1715 memset(list, 0, sizeof(struct ast_hint));
1717 list->laststate = ast_extension_state2(e);
1721 ast_mutex_unlock(&hintlock);
1725 static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
1727 struct ast_hint *list;
1729 ast_mutex_lock(&hintlock);
1733 if (list->exten == oe) {
1735 ast_mutex_unlock(&hintlock);
1740 ast_mutex_unlock(&hintlock);
1745 static int ast_remove_hint(struct ast_exten *e)
1747 /* Cleanup the Notifys if hint is removed */
1748 struct ast_hint *list, *prev = NULL;
1749 struct ast_state_cb *cblist, *cbprev;
1754 ast_mutex_lock(&hintlock);
1758 if (list->exten==e) {
1760 cblist = list->callbacks;
1762 /* Notify with -1 and remove all callbacks */
1764 cblist = cblist->next;
1765 cbprev->callback(list->exten->parent->name, list->exten->exten, -1, cbprev->data);
1768 list->callbacks = NULL;
1773 prev->next = list->next;
1776 ast_mutex_unlock(&hintlock);
1784 ast_mutex_unlock(&hintlock);
1789 int ast_get_hint(char *hint, int hintsize, struct ast_channel *c, const char *context, const char *exten)
1791 struct ast_exten *e;
1792 e = ast_hint_extension(c, context, exten);
1794 strncpy(hint, ast_get_extension_app(e), hintsize - 1);
1800 int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
1802 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_EXISTS);
1805 int ast_findlabel_extension(struct ast_channel *c, const char *context, const char *exten, const char *label, const char *callerid)
1807 return pbx_extension_helper(c, NULL, context, exten, 0, label, callerid, HELPER_FINDLABEL);
1810 int ast_findlabel_extension2(struct ast_channel *c, struct ast_context *con, const char *exten, const char *label, const char *callerid)
1812 return pbx_extension_helper(c, con, NULL, exten, 0, label, callerid, HELPER_FINDLABEL);
1815 int ast_canmatch_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
1817 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_CANMATCH);
1820 int ast_matchmore_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
1822 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_MATCHMORE);
1825 int ast_spawn_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
1827 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_SPAWN);
1830 int ast_exec_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
1832 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_EXEC);
1835 int ast_pbx_run(struct ast_channel *c)
1844 /* A little initial setup here */
1846 ast_log(LOG_WARNING, "%s already has PBX structure??\n", c->name);
1847 c->pbx = malloc(sizeof(struct ast_pbx));
1849 ast_log(LOG_ERROR, "Out of memory\n");
1854 c->cdr = ast_cdr_alloc();
1856 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
1860 ast_cdr_init(c->cdr, c);
1863 memset(c->pbx, 0, sizeof(struct ast_pbx));
1864 /* Set reasonable defaults */
1865 c->pbx->rtimeout = 10;
1866 c->pbx->dtimeout = 5;
1868 /* Start by trying whatever the channel is set to */
1869 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
1870 /* JK02: If not successfull fall back to 's' */
1871 if (option_verbose > 1)
1872 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);
1873 strncpy(c->exten, "s", sizeof(c->exten)-1);
1874 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
1875 /* JK02: And finally back to default if everything else failed */
1876 if (option_verbose > 1)
1877 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);
1878 strncpy(c->context, "default", sizeof(c->context)-1);
1882 if (c->cdr && !c->cdr->start.tv_sec && !c->cdr->start.tv_usec)
1883 ast_cdr_start(c->cdr);
1887 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
1888 memset(exten, 0, sizeof(exten));
1889 if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
1890 /* Something bad happened, or a hangup has been requested. */
1891 if (((res >= '0') && (res <= '9')) || ((res >= 'A') && (res <= 'F')) ||
1892 (res == '*') || (res == '#')) {
1893 ast_log(LOG_DEBUG, "Oooh, got something to jump out with ('%c')!\n", res);
1894 memset(exten, 0, sizeof(exten));
1896 exten[pos++] = digit = res;
1900 case AST_PBX_KEEPALIVE:
1902 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
1903 else if (option_verbose > 1)
1904 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
1909 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
1910 else if (option_verbose > 1)
1911 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
1912 if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
1917 if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
1927 if ((c->_softhangup == AST_SOFTHANGUP_TIMEOUT) && (ast_exists_extension(c,c->context,"T",1,c->cid.cid_num))) {
1928 strncpy(c->exten,"T",sizeof(c->exten) - 1);
1929 /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
1930 c->whentohangup = 0;
1932 c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
1933 } else if (c->_softhangup) {
1934 ast_log(LOG_DEBUG, "Extension %s, priority %d returned normally even though call was hung up\n",
1935 c->exten, c->priority);
1941 if (!ast_exists_extension(c, c->context, c->exten, 1, c->cid.cid_num)) {
1942 /* It's not a valid extension anymore */
1943 if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
1944 if (option_verbose > 2)
1945 ast_verbose(VERBOSE_PREFIX_3 "Sent into invalid extension '%s' in context '%s' on %s\n", c->exten, c->context, c->name);
1946 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", c->exten);
1947 strncpy(c->exten, "i", sizeof(c->exten)-1);
1950 ast_log(LOG_WARNING, "Channel '%s' sent into invalid extension '%s' in context '%s', but no invalid handler\n",
1951 c->name, c->exten, c->context);
1954 } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
1955 /* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */
1958 /* Done, wait for an extension */
1961 waittime = c->pbx->dtimeout;
1962 else if (!autofallthrough)
1963 waittime = c->pbx->rtimeout;
1965 while (ast_matchmore_extension(c, c->context, exten, 1, c->cid.cid_num)) {
1966 /* As long as we're willing to wait, and as long as it's not defined,
1967 keep reading digits until we can't possibly get a right answer anymore. */
1968 digit = ast_waitfordigit(c, waittime * 1000);
1969 if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
1976 /* Error, maybe a hangup */
1978 exten[pos++] = digit;
1979 waittime = c->pbx->dtimeout;
1982 if (ast_exists_extension(c, c->context, exten, 1, c->cid.cid_num)) {
1983 /* Prepare the next cycle */
1984 strncpy(c->exten, exten, sizeof(c->exten)-1);
1987 /* No such extension */
1988 if (!ast_strlen_zero(exten)) {
1989 /* An invalid extension */
1990 if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
1991 if (option_verbose > 2)
1992 ast_verbose( VERBOSE_PREFIX_3 "Invalid extension '%s' in context '%s' on %s\n", exten, c->context, c->name);
1993 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", exten);
1994 strncpy(c->exten, "i", sizeof(c->exten)-1);
1997 ast_log(LOG_WARNING, "Invalid extension '%s', but no rule 'i' in context '%s'\n", exten, c->context);
2001 /* A simple timeout */
2002 if (ast_exists_extension(c, c->context, "t", 1, c->cid.cid_num)) {
2003 if (option_verbose > 2)
2004 ast_verbose( VERBOSE_PREFIX_3 "Timeout on %s\n", c->name);
2005 strncpy(c->exten, "t", sizeof(c->exten)-1);
2008 ast_log(LOG_WARNING, "Timeout, but no rule 't' in context '%s'\n", c->context);
2014 if (option_verbose > 2)
2015 ast_verbose(VERBOSE_PREFIX_2 "CDR updated on %s\n",c->name);
2019 if (option_verbose > 0) {
2021 status = pbx_builtin_getvar_helper(c, "DIALSTATUS");
2024 if (option_verbose > 2)
2025 ast_verbose(VERBOSE_PREFIX_2 "Auto fallthrough, channel '%s' status is '%s'\n", c->name, status);
2026 if (!strcasecmp(status, "CONGESTION"))
2027 res = pbx_builtin_congestion(c, "10");
2028 else if (!strcasecmp(status, "CHANUNAVAIL"))
2029 res = pbx_builtin_congestion(c, "10");
2030 else if (!strcasecmp(status, "BUSY"))
2031 res = pbx_builtin_busy(c, "10");
2038 ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", c->name);
2040 if ((res != AST_PBX_KEEPALIVE) && ast_exists_extension(c, c->context, "h", 1, c->cid.cid_num)) {
2044 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2045 if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
2046 /* Something bad happened, or a hangup has been requested. */
2048 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2049 else if (option_verbose > 1)
2050 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2057 pbx_destroy(c->pbx);
2059 if (res != AST_PBX_KEEPALIVE)
2064 static void *pbx_thread(void *data)
2066 /* Oh joyeous kernel, we're a new thread, with nothing to do but
2067 answer this channel and get it going. The setjmp stuff is fairly
2068 confusing, but necessary to get smooth transitions between
2069 the execution of different applications (without the use of
2070 additional threads) */
2071 struct ast_channel *c = data;
2077 int ast_pbx_start(struct ast_channel *c)
2080 pthread_attr_t attr;
2082 ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
2086 /* Start a new thread, and get something handling this channel. */
2087 pthread_attr_init(&attr);
2088 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
2089 if (ast_pthread_create(&t, &attr, pbx_thread, c)) {
2090 ast_log(LOG_WARNING, "Failed to create new channel thread\n");
2096 int pbx_set_autofallthrough(int newval)
2099 oldval = autofallthrough;
2100 if (oldval != newval)
2101 autofallthrough = newval;
2106 * This function locks contexts list by &conlist, search for the right context
2107 * structure, leave context list locked and call ast_context_remove_include2
2108 * which removes include, unlock contexts list and return ...
2110 int ast_context_remove_include(const char *context, const char *include, const char *registrar)
2112 struct ast_context *c;
2114 if (ast_lock_contexts()) return -1;
2116 /* walk contexts and search for the right one ...*/
2117 c = ast_walk_contexts(NULL);
2119 /* we found one ... */
2120 if (!strcmp(ast_get_context_name(c), context)) {
2122 /* remove include from this context ... */
2123 ret = ast_context_remove_include2(c, include, registrar);
2125 ast_unlock_contexts();
2127 /* ... return results */
2130 c = ast_walk_contexts(c);
2133 /* we can't find the right one context */
2134 ast_unlock_contexts();
2139 * When we call this function, &conlock lock must be locked, because when
2140 * we giving *con argument, some process can remove/change this context
2141 * and after that there can be segfault.
2143 * This function locks given context, removes include, unlock context and
2146 int ast_context_remove_include2(struct ast_context *con, const char *include, const char *registrar)
2148 struct ast_include *i, *pi = NULL;
2150 if (ast_mutex_lock(&con->lock)) return -1;
2155 /* find our include */
2156 if (!strcmp(i->name, include) &&
2157 (!registrar || !strcmp(i->registrar, registrar))) {
2158 /* remove from list */
2162 con->includes = i->next;
2163 /* free include and return */
2165 ast_mutex_unlock(&con->lock);
2172 /* we can't find the right include */
2173 ast_mutex_unlock(&con->lock);
2178 * This function locks contexts list by &conlist, search for the rigt context
2179 * structure, leave context list locked and call ast_context_remove_switch2
2180 * which removes switch, unlock contexts list and return ...
2182 int ast_context_remove_switch(const char *context, const char *sw, const char *data, const char *registrar)
2184 struct ast_context *c;
2186 if (ast_lock_contexts()) return -1;
2188 /* walk contexts and search for the right one ...*/
2189 c = ast_walk_contexts(NULL);
2191 /* we found one ... */
2192 if (!strcmp(ast_get_context_name(c), context)) {
2194 /* remove switch from this context ... */
2195 ret = ast_context_remove_switch2(c, sw, data, registrar);
2197 ast_unlock_contexts();
2199 /* ... return results */
2202 c = ast_walk_contexts(c);
2205 /* we can't find the right one context */
2206 ast_unlock_contexts();
2211 * When we call this function, &conlock lock must be locked, because when
2212 * we giving *con argument, some process can remove/change this context
2213 * and after that there can be segfault.
2215 * This function locks given context, removes switch, unlock context and
2218 int ast_context_remove_switch2(struct ast_context *con, const char *sw, const char *data, const char *registrar)
2220 struct ast_sw *i, *pi = NULL;
2222 if (ast_mutex_lock(&con->lock)) return -1;
2227 /* find our switch */
2228 if (!strcmp(i->name, sw) && !strcmp(i->data, data) &&
2229 (!registrar || !strcmp(i->registrar, registrar))) {
2230 /* remove from list */
2234 con->alts = i->next;
2235 /* free switch and return */
2237 ast_mutex_unlock(&con->lock);
2244 /* we can't find the right switch */
2245 ast_mutex_unlock(&con->lock);
2250 * This functions lock contexts list, search for the right context,
2251 * call ast_context_remove_extension2, unlock contexts list and return.
2252 * In this function we are using
2254 int ast_context_remove_extension(const char *context, const char *extension, int priority, const char *registrar)
2256 struct ast_context *c;
2258 if (ast_lock_contexts()) return -1;
2260 /* walk contexts ... */
2261 c = ast_walk_contexts(NULL);
2263 /* ... search for the right one ... */
2264 if (!strcmp(ast_get_context_name(c), context)) {
2265 /* ... remove extension ... */
2266 int ret = ast_context_remove_extension2(c, extension, priority,
2268 /* ... unlock contexts list and return */
2269 ast_unlock_contexts();
2272 c = ast_walk_contexts(c);
2275 /* we can't find the right context */
2276 ast_unlock_contexts();
2281 * When do you want to call this function, make sure that &conlock is locked,
2282 * because some process can handle with your *con context before you lock
2285 * This functionc locks given context, search for the right extension and
2286 * fires out all peer in this extensions with given priority. If priority
2287 * is set to 0, all peers are removed. After that, unlock context and
2290 int ast_context_remove_extension2(struct ast_context *con, const char *extension, int priority, const char *registrar)
2292 struct ast_exten *exten, *prev_exten = NULL;
2294 if (ast_mutex_lock(&con->lock)) return -1;
2296 /* go through all extensions in context and search the right one ... */
2300 /* look for right extension */
2301 if (!strcmp(exten->exten, extension) &&
2302 (!registrar || !strcmp(exten->registrar, registrar))) {
2303 struct ast_exten *peer;
2305 /* should we free all peers in this extension? (priority == 0)? */
2306 if (priority == 0) {
2307 /* remove this extension from context list */
2309 prev_exten->next = exten->next;
2311 con->root = exten->next;
2313 /* fire out all peers */
2318 if (!peer->priority==PRIORITY_HINT)
2319 ast_remove_hint(peer);
2321 peer->datad(peer->data);
2327 ast_mutex_unlock(&con->lock);
2330 /* remove only extension with exten->priority == priority */
2331 struct ast_exten *previous_peer = NULL;
2335 /* is this our extension? */
2336 if (peer->priority == priority &&
2337 (!registrar || !strcmp(peer->registrar, registrar) )) {
2338 /* we are first priority extension? */
2339 if (!previous_peer) {
2340 /* exists previous extension here? */
2342 /* yes, so we must change next pointer in
2343 * previous connection to next peer
2346 prev_exten->next = peer->peer;
2347 peer->peer->next = exten->next;
2349 prev_exten->next = exten->next;
2351 /* no previous extension, we are first
2352 * extension, so change con->root ...
2355 con->root = peer->peer;
2357 con->root = exten->next;
2360 /* we are not first priority in extension */
2361 previous_peer->peer = peer->peer;
2364 /* now, free whole priority extension */
2365 if (peer->priority==PRIORITY_HINT)
2366 ast_remove_hint(peer);
2367 peer->datad(peer->data);
2370 ast_mutex_unlock(&con->lock);
2373 /* this is not right extension, skip to next peer */
2374 previous_peer = peer;
2379 ast_mutex_unlock(&con->lock);
2385 exten = exten->next;
2388 /* we can't find right extension */
2389 ast_mutex_unlock(&con->lock);
2394 int ast_register_application(const char *app, int (*execute)(struct ast_channel *, void *), const char *synopsis, const char *description)
2396 struct ast_app *tmp, *prev, *cur;
2399 length = sizeof(struct ast_app);
2400 length += strlen(app) + 1;
2401 if (ast_mutex_lock(&applock)) {
2402 ast_log(LOG_ERROR, "Unable to lock application list\n");
2407 if (!strcasecmp(app, tmp->name)) {
2408 ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
2409 ast_mutex_unlock(&applock);
2414 tmp = malloc(length);
2416 memset(tmp, 0, length);
2417 strcpy(tmp->name, app);
2418 tmp->execute = execute;
2419 tmp->synopsis = synopsis;
2420 tmp->description = description;
2421 /* Store in alphabetical order */
2425 if (strcasecmp(tmp->name, cur->name) < 0)
2431 tmp->next = prev->next;
2438 ast_log(LOG_ERROR, "Out of memory\n");
2439 ast_mutex_unlock(&applock);
2442 if (option_verbose > 1)
2443 ast_verbose( VERBOSE_PREFIX_2 "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
2444 ast_mutex_unlock(&applock);
2448 int ast_register_switch(struct ast_switch *sw)
2450 struct ast_switch *tmp, *prev=NULL;
2451 if (ast_mutex_lock(&switchlock)) {
2452 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
2457 if (!strcasecmp(tmp->name, sw->name))
2463 ast_mutex_unlock(&switchlock);
2464 ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name);
2472 ast_mutex_unlock(&switchlock);
2476 void ast_unregister_switch(struct ast_switch *sw)
2478 struct ast_switch *tmp, *prev=NULL;
2479 if (ast_mutex_lock(&switchlock)) {
2480 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
2487 prev->next = tmp->next;
2489 switches = tmp->next;
2496 ast_mutex_unlock(&switchlock);
2500 * Help for CLI commands ...
2502 static char show_application_help[] =
2503 "Usage: show application <application> [<application> [<application> [...]]]\n"
2504 " Describes a particular application.\n";
2506 static char show_applications_help[] =
2507 "Usage: show applications [{like|describing} <text>]\n"
2508 " List applications which are currently available.\n"
2509 " If 'like', <text> will be a substring of the app name\n"
2510 " If 'describing', <text> will be a substring of the description\n";
2512 static char show_dialplan_help[] =
2513 "Usage: show dialplan [exten@][context]\n"
2516 static char show_switches_help[] =
2517 "Usage: show switches\n"
2518 " Show registered switches\n";
2521 * IMPLEMENTATION OF CLI FUNCTIONS IS IN THE SAME ORDER AS COMMANDS HELPS
2526 * 'show application' CLI command implementation functions ...
2530 * There is a possibility to show informations about more than one
2531 * application at one time. You can type 'show application Dial Echo' and
2532 * you will see informations about these two applications ...
2534 static char *complete_show_application(char *line, char *word,
2540 /* try to lock applications list ... */
2541 if (ast_mutex_lock(&applock)) {
2542 ast_log(LOG_ERROR, "Unable to lock application list\n");
2546 /* ... walk all applications ... */
2549 /* ... check if word matches this application ... */
2550 if (!strncasecmp(word, a->name, strlen(word))) {
2551 /* ... if this is right app serve it ... */
2552 if (++which > state) {
2553 char *ret = strdup(a->name);
2554 ast_mutex_unlock(&applock);
2561 /* no application match */
2562 ast_mutex_unlock(&applock);
2566 static int handle_show_application(int fd, int argc, char *argv[])
2569 int app, no_registered_app = 1;
2571 if (argc < 3) return RESULT_SHOWUSAGE;
2573 /* try to lock applications list ... */
2574 if (ast_mutex_lock(&applock)) {
2575 ast_log(LOG_ERROR, "Unable to lock application list\n");
2579 /* ... go through all applications ... */
2582 /* ... compare this application name with all arguments given
2583 * to 'show application' command ... */
2584 for (app = 2; app < argc; app++) {
2585 if (!strcasecmp(a->name, argv[app])) {
2586 /* Maximum number of characters added by terminal coloring is 22 */
2587 char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
2588 char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
2589 int synopsis_size, description_size;
2591 no_registered_app = 0;
2594 synopsis_size = strlen(a->synopsis) + 23;
2596 synopsis_size = strlen("Not available") + 23;
2597 synopsis = alloca(synopsis_size);
2600 description_size = strlen(a->description) + 23;
2602 description_size = strlen("Not available") + 23;
2603 description = alloca(description_size);
2605 if (synopsis && description) {
2606 snprintf(info, 64 + AST_MAX_APP, "\n -= Info about application '%s' =- \n\n", a->name);
2607 term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
2608 term_color(syntitle, "[Synopsis]:\n", COLOR_MAGENTA, 0, 40);
2609 term_color(destitle, "[Description]:\n", COLOR_MAGENTA, 0, 40);
2610 term_color(synopsis,
2611 a->synopsis ? a->synopsis : "Not available",
2612 COLOR_CYAN, 0, synopsis_size);
2613 term_color(description,
2614 a->description ? a->description : "Not available",
2615 COLOR_CYAN, 0, description_size);
2617 ast_cli(fd,"%s%s%s\n\n%s%s\n", infotitle, syntitle, synopsis, destitle, description);
2619 /* ... one of our applications, show info ...*/
2620 ast_cli(fd,"\n -= Info about application '%s' =- \n\n"
2621 "[Synopsis]:\n %s\n\n"
2622 "[Description]:\n%s\n",
2624 a->synopsis ? a->synopsis : "Not available",
2625 a->description ? a->description : "Not available");
2632 ast_mutex_unlock(&applock);
2634 /* we found at least one app? no? */
2635 if (no_registered_app) {
2636 ast_cli(fd, "Your application(s) is (are) not registered\n");
2637 return RESULT_FAILURE;
2640 return RESULT_SUCCESS;
2643 static int handle_show_switches(int fd, int argc, char *argv[])
2645 struct ast_switch *sw;
2647 ast_cli(fd, "There are no registered alternative switches\n");
2648 return RESULT_SUCCESS;
2650 /* ... we have applications ... */
2651 ast_cli(fd, "\n -= Registered Asterisk Alternative Switches =-\n");
2652 if (ast_mutex_lock(&switchlock)) {
2653 ast_log(LOG_ERROR, "Unable to lock switches\n");
2658 ast_cli(fd, "%s: %s\n", sw->name, sw->description);
2661 ast_mutex_unlock(&switchlock);
2662 return RESULT_SUCCESS;
2666 * 'show applications' CLI command implementation functions ...
2668 static int handle_show_applications(int fd, int argc, char *argv[])
2671 int like=0, describing=0;
2672 int total_match = 0; /* Number of matches in like clause */
2673 int total_apps = 0; /* Number of apps registered */
2675 /* try to lock applications list ... */
2676 if (ast_mutex_lock(&applock)) {
2677 ast_log(LOG_ERROR, "Unable to lock application list\n");
2681 /* ... have we got at least one application (first)? no? */
2683 ast_cli(fd, "There are no registered applications\n");
2684 ast_mutex_unlock(&applock);
2688 /* show applications like <keyword> */
2689 if ((argc == 4) && (!strcmp(argv[2], "like"))) {
2691 } else if ((argc > 3) && (!strcmp(argv[2], "describing"))) {
2695 /* show applications describing <keyword1> [<keyword2>] [...] */
2696 if ((!like) && (!describing)) {
2697 ast_cli(fd, " -= Registered Asterisk Applications =-\n");
2699 ast_cli(fd, " -= Matching Asterisk Applications =-\n");
2702 /* ... go through all applications ... */
2703 for (a = apps; a; a = a->next) {
2704 /* ... show informations about applications ... */
2708 if (ast_strcasestr(a->name, argv[3])) {
2712 } else if (describing) {
2713 if (a->description) {
2714 /* Match all words on command line */
2717 for (i=3;i<argc;i++) {
2718 if (! ast_strcasestr(a->description, argv[i])) {
2730 ast_cli(fd," %20s: %s\n", a->name, a->synopsis ? a->synopsis : "<Synopsis not available>");
2733 if ((!like) && (!describing)) {
2734 ast_cli(fd, " -= %d Applications Registered =-\n",total_apps);
2736 ast_cli(fd, " -= %d Applications Matching =-\n",total_match);
2739 /* ... unlock and return */
2740 ast_mutex_unlock(&applock);
2742 return RESULT_SUCCESS;
2745 static char *complete_show_applications(char *line, char *word, int pos, int state)
2748 if (ast_strlen_zero(word)) {
2751 return strdup("like");
2753 return strdup("describing");
2757 } else if (! strncasecmp(word, "like", strlen(word))) {
2759 return strdup("like");
2763 } else if (! strncasecmp(word, "describing", strlen(word))) {
2765 return strdup("describing");
2775 * 'show dialplan' CLI command implementation functions ...
2777 static char *complete_show_dialplan_context(char *line, char *word, int pos,
2780 struct ast_context *c;
2783 /* we are do completion of [exten@]context on second position only */
2784 if (pos != 2) return NULL;
2786 /* try to lock contexts list ... */
2787 if (ast_lock_contexts()) {
2788 ast_log(LOG_ERROR, "Unable to lock context list\n");
2792 /* ... walk through all contexts ... */
2793 c = ast_walk_contexts(NULL);
2795 /* ... word matches context name? yes? ... */
2796 if (!strncasecmp(word, ast_get_context_name(c), strlen(word))) {
2797 /* ... for serve? ... */
2798 if (++which > state) {
2799 /* ... yes, serve this context name ... */
2800 char *ret = strdup(ast_get_context_name(c));
2801 ast_unlock_contexts();
2805 c = ast_walk_contexts(c);
2808 /* ... unlock and return */
2809 ast_unlock_contexts();
2813 static int handle_show_dialplan(int fd, int argc, char *argv[])
2815 struct ast_context *c;
2816 char *exten = NULL, *context = NULL;
2817 int context_existence = 0, extension_existence = 0;
2818 /* Variables used for different counters */
2819 int total_context = 0, total_exten = 0, total_prio = 0;
2821 if (argc != 3 && argc != 2) return -1;
2823 /* we obtain [exten@]context? if yes, split them ... */
2825 char *splitter = argv[2];
2826 /* is there a '@' character? */
2827 if (strchr(argv[2], '@')) {
2828 /* yes, split into exten & context ... */
2829 exten = strsep(&splitter, "@");
2832 /* check for length and change to NULL if ast_strlen_zero() */
2833 if (ast_strlen_zero(exten)) exten = NULL;
2834 if (ast_strlen_zero(context)) context = NULL;
2837 /* no '@' char, only context given */
2839 if (ast_strlen_zero(context)) context = NULL;
2843 /* try to lock contexts */
2844 if (ast_lock_contexts()) {
2845 ast_log(LOG_WARNING, "Failed to lock contexts list\n");
2846 return RESULT_FAILURE;
2849 /* walk all contexts ... */
2850 c = ast_walk_contexts(NULL);
2852 /* show this context? */
2854 !strcmp(ast_get_context_name(c), context)) {
2855 context_existence = 1;
2857 /* try to lock context before walking in ... */
2858 if (!ast_lock_context(c)) {
2859 struct ast_exten *e;
2860 struct ast_include *i;
2861 struct ast_ignorepat *ip;
2863 char buf[256], buf2[256];
2864 int context_info_printed = 0;
2866 /* are we looking for exten too? if yes, we print context
2867 * if we our extension only
2871 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
2872 ast_get_context_name(c), ast_get_context_registrar(c));
2873 context_info_printed = 1;
2876 /* walk extensions ... */
2877 e = ast_walk_context_extensions(c, NULL);
2879 struct ast_exten *p;
2882 /* looking for extension? is this our extension? */
2884 strcmp(ast_get_extension_name(e), exten))
2886 /* we are looking for extension and it's not our
2887 * extension, so skip to next extension */
2888 e = ast_walk_context_extensions(c, e);
2892 extension_existence = 1;
2894 /* may we print context info? */
2895 if (!context_info_printed) {
2897 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
2898 ast_get_context_name(c),
2899 ast_get_context_registrar(c));
2900 context_info_printed = 1;
2904 /* write extension name and first peer */
2905 bzero(buf, sizeof(buf));
2906 snprintf(buf, sizeof(buf), "'%s' =>",
2907 ast_get_extension_name(e));
2909 prio = ast_get_extension_priority(e);
2910 if (prio == PRIORITY_HINT) {
2911 snprintf(buf2, sizeof(buf2),
2913 ast_get_extension_app(e));
2915 snprintf(buf2, sizeof(buf2),
2918 ast_get_extension_app(e),
2919 (char *)ast_get_extension_app_data(e));
2922 ast_cli(fd, " %-17s %-45s [%s]\n", buf, buf2,
2923 ast_get_extension_registrar(e));
2926 /* walk next extension peers */
2927 p = ast_walk_extension_priorities(e, e);
2930 bzero((void *)buf2, sizeof(buf2));
2931 bzero((void *)buf, sizeof(buf));
2932 if (ast_get_extension_label(p))
2933 snprintf(buf, sizeof(buf), " [%s]", ast_get_extension_label(p));
2934 prio = ast_get_extension_priority(p);
2935 if (prio == PRIORITY_HINT) {
2936 snprintf(buf2, sizeof(buf2),
2938 ast_get_extension_app(p));
2940 snprintf(buf2, sizeof(buf2),
2943 ast_get_extension_app(p),
2944 (char *)ast_get_extension_app_data(p));
2947 ast_cli(fd," %-17s %-45s [%s]\n",
2949 ast_get_extension_registrar(p));
2951 p = ast_walk_extension_priorities(e, p);
2953 e = ast_walk_context_extensions(c, e);
2956 /* include & ignorepat we all printing if we are not
2957 * looking for exact extension
2960 if (ast_walk_context_extensions(c, NULL))
2963 /* walk included and write info ... */
2964 i = ast_walk_context_includes(c, NULL);
2966 bzero(buf, sizeof(buf));
2967 snprintf(buf, sizeof(buf), "'%s'",
2968 ast_get_include_name(i));
2969 ast_cli(fd, " Include => %-45s [%s]\n",
2970 buf, ast_get_include_registrar(i));
2971 i = ast_walk_context_includes(c, i);
2974 /* walk ignore patterns and write info ... */
2975 ip = ast_walk_context_ignorepats(c, NULL);
2977 bzero(buf, sizeof(buf));
2978 snprintf(buf, sizeof(buf), "'%s'",
2979 ast_get_ignorepat_name(ip));
2980 ast_cli(fd, " Ignore pattern => %-45s [%s]\n",
2981 buf, ast_get_ignorepat_registrar(ip));
2982 ip = ast_walk_context_ignorepats(c, ip);
2984 sw = ast_walk_context_switches(c, NULL);
2986 bzero(buf, sizeof(buf));
2987 snprintf(buf, sizeof(buf), "'%s/%s'",
2988 ast_get_switch_name(sw),
2989 ast_get_switch_data(sw));
2990 ast_cli(fd, " Alt. Switch => %-45s [%s]\n",
2991 buf, ast_get_switch_registrar(sw));
2992 sw = ast_walk_context_switches(c, sw);
2996 ast_unlock_context(c);
2998 /* if we print something in context, make an empty line */
2999 if (context_info_printed) ast_cli(fd, "\n");
3002 c = ast_walk_contexts(c);
3004 ast_unlock_contexts();
3006 /* check for input failure and throw some error messages */
3007 if (context && !context_existence) {
3008 ast_cli(fd, "There is no existence of '%s' context\n",
3010 return RESULT_FAILURE;
3013 if (exten && !extension_existence) {
3015 ast_cli(fd, "There is no existence of %s@%s extension\n",
3019 "There is no existence of '%s' extension in all contexts\n",
3021 return RESULT_FAILURE;
3023 ast_cli(fd,"-= %d extensions (%d priorities) in %d contexts. =-\n",total_exten, total_prio, total_context);
3026 return RESULT_SUCCESS;
3030 * CLI entries for upper commands ...
3032 static struct ast_cli_entry show_applications_cli =
3033 { { "show", "applications", NULL },
3034 handle_show_applications, "Shows registered applications",
3035 show_applications_help, complete_show_applications };
3037 static struct ast_cli_entry show_application_cli =
3038 { { "show", "application", NULL },
3039 handle_show_application, "Describe a specific application",
3040 show_application_help, complete_show_application };
3042 static struct ast_cli_entry show_dialplan_cli =
3043 { { "show", "dialplan", NULL },
3044 handle_show_dialplan, "Show dialplan",
3045 show_dialplan_help, complete_show_dialplan_context };
3047 static struct ast_cli_entry show_switches_cli =
3048 { { "show", "switches", NULL },
3049 handle_show_switches, "Show alternative switches",
3050 show_switches_help, NULL };
3052 int ast_unregister_application(const char *app) {
3053 struct ast_app *tmp, *tmpl = NULL;
3054 if (ast_mutex_lock(&applock)) {
3055 ast_log(LOG_ERROR, "Unable to lock application list\n");
3060 if (!strcasecmp(app, tmp->name)) {
3062 tmpl->next = tmp->next;
3065 if (option_verbose > 1)
3066 ast_verbose( VERBOSE_PREFIX_2 "Unregistered application '%s'\n", tmp->name);
3068 ast_mutex_unlock(&applock);
3074 ast_mutex_unlock(&applock);
3078 struct ast_context *ast_context_create(struct ast_context **extcontexts, const char *name, const char *registrar)
3080 struct ast_context *tmp, **local_contexts;
3082 length = sizeof(struct ast_context);
3083 length += strlen(name) + 1;
3085 local_contexts = &contexts;
3086 ast_mutex_lock(&conlock);
3088 local_contexts = extcontexts;
3090 tmp = *local_contexts;
3092 if (!strcasecmp(tmp->name, name)) {
3093 ast_mutex_unlock(&conlock);
3094 ast_log(LOG_WARNING, "Tried to register context '%s', already in use\n", name);
3096 ast_mutex_unlock(&conlock);
3101 tmp = malloc(length);
3103 memset(tmp, 0, length);
3104 ast_mutex_init(&tmp->lock);
3105 strcpy(tmp->name, name);
3107 tmp->registrar = registrar;
3108 tmp->next = *local_contexts;
3109 tmp->includes = NULL;
3110 tmp->ignorepats = NULL;
3111 *local_contexts = tmp;
3113 ast_log(LOG_DEBUG, "Registered context '%s'\n", tmp->name);
3114 else if (option_verbose > 2)
3115 ast_verbose( VERBOSE_PREFIX_3 "Registered extension context '%s'\n", tmp->name);
3117 ast_log(LOG_ERROR, "Out of memory\n");
3120 ast_mutex_unlock(&conlock);
3124 void __ast_context_destroy(struct ast_context *con, const char *registrar);
3126 void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char *registrar) {
3127 struct ast_context *tmp, *lasttmp = NULL;
3129 ast_mutex_lock(&conlock);
3131 __ast_context_destroy(NULL,registrar);
3138 __ast_context_destroy(tmp,tmp->registrar);
3144 lasttmp->next = contexts;
3145 contexts = *extcontexts;
3146 *extcontexts = NULL;
3148 ast_log(LOG_WARNING, "Requested contexts didn't get merged\n");
3149 ast_mutex_unlock(&conlock);
3155 * EBUSY - can't lock
3156 * ENOENT - no existence of context
3158 int ast_context_add_include(const char *context, const char *include, const char *registrar)
3160 struct ast_context *c;
3162 if (ast_lock_contexts()) {
3167 /* walk contexts ... */
3168 c = ast_walk_contexts(NULL);
3170 /* ... search for the right one ... */
3171 if (!strcmp(ast_get_context_name(c), context)) {
3172 int ret = ast_context_add_include2(c, include, registrar);
3173 /* ... unlock contexts list and return */
3174 ast_unlock_contexts();
3177 c = ast_walk_contexts(c);
3180 /* we can't find the right context */
3181 ast_unlock_contexts();
3189 while(*c && (*c != '|')) c++; \
3190 if (*c) { *c = '\0'; c++; } else c = NULL; \
3193 static void get_timerange(struct ast_timing *i, char *times)
3201 /* start disabling all times, fill the fields with 0's, as they may contain garbage */
3202 memset(i->minmask, 0, sizeof(i->minmask));
3204 /* Star is all times */
3205 if (ast_strlen_zero(times) || !strcmp(times, "*")) {
3207 i->minmask[x] = (1 << 30) - 1;
3210 /* Otherwise expect a range */
3211 e = strchr(times, '-');
3213 ast_log(LOG_WARNING, "Time range is not valid. Assuming no restrictions based on time.\n");
3218 while(*e && !isdigit(*e)) e++;
3220 ast_log(LOG_WARNING, "Invalid time range. Assuming no restrictions based on time.\n");
3223 if (sscanf(times, "%d:%d", &s1, &s2) != 2) {
3224 ast_log(LOG_WARNING, "%s isn't a time. Assuming no restrictions based on time.\n", times);
3227 if (sscanf(e, "%d:%d", &e1, &e2) != 2) {
3228 ast_log(LOG_WARNING, "%s isn't a time. Assuming no restrictions based on time.\n", e);
3233 s1 = s1 * 30 + s2/2;
3234 if ((s1 < 0) || (s1 >= 24*30)) {
3235 ast_log(LOG_WARNING, "%s isn't a valid start time. Assuming no time.\n", times);
3238 e1 = e1 * 30 + e2/2;
3239 if ((e1 < 0) || (e1 >= 24*30)) {
3240 ast_log(LOG_WARNING, "%s isn't a valid end time. Assuming no time.\n", e);
3243 /* Go through the time and enable each appropriate bit */
3244 for (x=s1;x != e1;x = (x + 1) % (24 * 30)) {
3245 i->minmask[x/30] |= (1 << (x % 30));
3247 /* Do the last one */
3248 i->minmask[x/30] |= (1 << (x % 30));
3250 for (cth=0;cth<24;cth++) {
3251 /* Initialize masks to blank */
3252 i->minmask[cth] = 0;
3253 for (ctm=0;ctm<30;ctm++) {
3255 /* First hour with more than one hour */
3256 (((cth == s1) && (ctm >= s2)) &&
3259 || (((cth == s1) && (ctm >= s2)) &&
3260 ((cth == e1) && (ctm <= e2)))
3261 /* In between first and last hours (more than 2 hours) */
3264 /* Last hour with more than one hour */
3266 ((cth == e1) && (ctm <= e2)))
3268 i->minmask[cth] |= (1 << (ctm / 2));
3276 static char *days[] =
3287 static unsigned int get_dow(char *dow)
3290 /* The following line is coincidence, really! */
3294 /* Check for all days */
3295 if (ast_strlen_zero(dow) || !strcmp(dow, "*"))
3296 return (1 << 7) - 1;
3297 /* Get start and ending days */
3298 c = strchr(dow, '-');
3304 /* Find the start */
3306 while((s < 7) && strcasecmp(dow, days[s])) s++;
3308 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", dow);
3313 while((e < 7) && strcasecmp(c, days[e])) e++;
3315 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
3321 for (x=s; x != e; x = (x + 1) % 7) {
3329 static unsigned int get_day(char *day)
3332 /* The following line is coincidence, really! */
3336 /* Check for all days */
3337 if (ast_strlen_zero(day) || !strcmp(day, "*")) {
3338 mask = (1 << 30) + ((1 << 30) - 1);
3341 /* Get start and ending days */
3342 c = strchr(day, '-');
3347 /* Find the start */
3348 if (sscanf(day, "%d", &s) != 1) {
3349 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", day);
3352 if ((s < 1) || (s > 31)) {
3353 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", day);
3358 if (sscanf(c, "%d", &e) != 1) {
3359 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
3362 if ((e < 1) || (e > 31)) {
3363 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
3370 for (x=s;x!=e;x = (x + 1) % 31) {
3377 static char *months[] =
3393 static unsigned int get_month(char *mon)
3396 /* The following line is coincidence, really! */
3400 /* Check for all days */
3401 if (ast_strlen_zero(mon) || !strcmp(mon, "*"))
3402 return (1 << 12) - 1;
3403 /* Get start and ending days */
3404 c = strchr(mon, '-');
3409 /* Find the start */
3411 while((s < 12) && strcasecmp(mon, months[s])) s++;
3413 ast_log(LOG_WARNING, "Invalid month '%s', assuming none\n", mon);
3418 while((e < 12) && strcasecmp(mon, months[e])) e++;
3420 ast_log(LOG_WARNING, "Invalid month '%s', assuming none\n", c);
3426 for (x=s; x!=e; x = (x + 1) % 12) {
3434 int ast_build_timing(struct ast_timing *i, char *info_in)
3436 char info_save[256];
3440 /* Check for empty just in case */
3441 if (ast_strlen_zero(info_in))
3443 /* make a copy just in case we were passed a static string */
3444 strncpy(info_save, info_in, sizeof(info_save));