various doxygen fixes
[asterisk-bristuff.git] / pbx.c
blob437fc658ca71ca83d6f5ab19be568bd09987fcdb
1 /*
2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2006, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
19 /*! \file
21 * \brief Core PBX routines.
23 * \author Mark Spencer <markster@digium.com>
26 #include <sys/types.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <ctype.h>
32 #include <errno.h>
33 #include <time.h>
34 #include <sys/time.h>
36 #include "asterisk.h"
38 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
40 #include "asterisk/lock.h"
41 #include "asterisk/cli.h"
42 #include "asterisk/pbx.h"
43 #include "asterisk/channel.h"
44 #include "asterisk/options.h"
45 #include "asterisk/logger.h"
46 #include "asterisk/file.h"
47 #include "asterisk/callerid.h"
48 #include "asterisk/cdr.h"
49 #include "asterisk/config.h"
50 #include "asterisk/term.h"
51 #include "asterisk/manager.h"
52 #include "asterisk/ast_expr.h"
53 #include "asterisk/linkedlists.h"
54 #define SAY_STUBS /* generate declarations and stubs for say methods */
55 #include "asterisk/say.h"
56 #include "asterisk/utils.h"
57 #include "asterisk/causes.h"
58 #include "asterisk/musiconhold.h"
59 #include "asterisk/app.h"
60 #include "asterisk/devicestate.h"
61 #include "asterisk/compat.h"
62 #include "asterisk/stringfields.h"
64 /*!
65 * \note I M P O R T A N T :
67 * The speed of extension handling will likely be among the most important
68 * aspects of this PBX. The switching scheme as it exists right now isn't
69 * terribly bad (it's O(N+M), where N is the # of extensions and M is the avg #
70 * of priorities, but a constant search time here would be great ;-)
74 #ifdef LOW_MEMORY
75 #define EXT_DATA_SIZE 256
76 #else
77 #define EXT_DATA_SIZE 8192
78 #endif
80 #define SWITCH_DATA_LENGTH 256
82 #define VAR_BUF_SIZE 4096
84 #define VAR_NORMAL 1
85 #define VAR_SOFTTRAN 2
86 #define VAR_HARDTRAN 3
88 #define BACKGROUND_SKIP (1 << 0)
89 #define BACKGROUND_NOANSWER (1 << 1)
90 #define BACKGROUND_MATCHEXTEN (1 << 2)
91 #define BACKGROUND_PLAYBACK (1 << 3)
93 AST_APP_OPTIONS(background_opts, {
94 AST_APP_OPTION('s', BACKGROUND_SKIP),
95 AST_APP_OPTION('n', BACKGROUND_NOANSWER),
96 AST_APP_OPTION('m', BACKGROUND_MATCHEXTEN),
97 AST_APP_OPTION('p', BACKGROUND_PLAYBACK),
98 });
100 #define WAITEXTEN_MOH (1 << 0)
102 AST_APP_OPTIONS(waitexten_opts, {
103 AST_APP_OPTION_ARG('m', WAITEXTEN_MOH, 1),
106 struct ast_context;
109 \brief ast_exten: An extension
110 The dialplan is saved as a linked list with each context
111 having it's own linked list of extensions - one item per
112 priority.
114 struct ast_exten {
115 char *exten; /*!< Extension name */
116 int matchcid; /*!< Match caller id ? */
117 const char *cidmatch; /*!< Caller id to match for this extension */
118 int priority; /*!< Priority */
119 const char *label; /*!< Label */
120 struct ast_context *parent; /*!< The context this extension belongs to */
121 const char *app; /*!< Application to execute */
122 void *data; /*!< Data to use (arguments) */
123 void (*datad)(void *); /*!< Data destructor */
124 struct ast_exten *peer; /*!< Next higher priority with our extension */
125 const char *registrar; /*!< Registrar */
126 struct ast_exten *next; /*!< Extension with a greater ID */
127 char stuff[0];
130 /*! \brief ast_include: include= support in extensions.conf */
131 struct ast_include {
132 const char *name;
133 const char *rname; /*!< Context to include */
134 const char *registrar; /*!< Registrar */
135 int hastime; /*!< If time construct exists */
136 struct ast_timing timing; /*!< time construct */
137 struct ast_include *next; /*!< Link them together */
138 char stuff[0];
141 /*! \brief ast_sw: Switch statement in extensions.conf */
142 struct ast_sw {
143 char *name;
144 const char *registrar; /*!< Registrar */
145 char *data; /*!< Data load */
146 int eval;
147 AST_LIST_ENTRY(ast_sw) list;
148 char *tmpdata;
149 char stuff[0];
152 /*! \brief ast_ignorepat: Ignore patterns in dial plan */
153 struct ast_ignorepat {
154 const char *registrar;
155 struct ast_ignorepat *next;
156 const char pattern[0];
159 /*! \brief ast_context: An extension context */
160 struct ast_context {
161 ast_mutex_t lock; /*!< A lock to prevent multiple threads from clobbering the context */
162 struct ast_exten *root; /*!< The root of the list of extensions */
163 struct ast_context *next; /*!< Link them together */
164 struct ast_include *includes; /*!< Include other contexts */
165 struct ast_ignorepat *ignorepats; /*!< Patterns for which to continue playing dialtone */
166 const char *registrar; /*!< Registrar */
167 AST_LIST_HEAD_NOLOCK(, ast_sw) alts; /*!< Alternative switches */
168 char name[0]; /*!< Name of the context */
172 /*! \brief ast_app: A registered application */
173 struct ast_app {
174 int (*execute)(struct ast_channel *chan, void *data);
175 const char *synopsis; /*!< Synopsis text for 'show applications' */
176 const char *description; /*!< Description (help text) for 'show application &lt;name&gt;' */
177 AST_LIST_ENTRY(ast_app) list; /*!< Next app in list */
178 struct module *module; /*!< Module this app belongs to */
179 char name[0]; /*!< Name of the application */
182 /*! \brief ast_state_cb: An extension state notify register item */
183 struct ast_state_cb {
184 int id;
185 void *data;
186 ast_state_cb_type callback;
187 struct ast_state_cb *next;
190 /*! \brief Structure for dial plan hints
192 Hints are pointers from an extension in the dialplan to one or
193 more devices (tech/name) */
194 struct ast_hint {
195 struct ast_exten *exten; /*!< Extension */
196 int laststate; /*!< Last known state */
197 struct ast_state_cb *callbacks; /*!< Callback list for this extension */
198 AST_LIST_ENTRY(ast_hint) list; /*!< Pointer to next hint in list */
201 static const struct cfextension_states {
202 int extension_state;
203 const char * const text;
204 } extension_states[] = {
205 { AST_EXTENSION_NOT_INUSE, "Idle" },
206 { AST_EXTENSION_INUSE, "InUse" },
207 { AST_EXTENSION_BUSY, "Busy" },
208 { AST_EXTENSION_UNAVAILABLE, "Unavailable" },
209 { AST_EXTENSION_RINGING, "Ringing" },
210 { AST_EXTENSION_INUSE | AST_EXTENSION_RINGING, "InUse&Ringing" }
213 int ast_pbx_outgoing_cdr_failed(void);
215 static int pbx_builtin_answer(struct ast_channel *, void *);
216 static int pbx_builtin_goto(struct ast_channel *, void *);
217 static int pbx_builtin_hangup(struct ast_channel *, void *);
218 static int pbx_builtin_background(struct ast_channel *, void *);
219 static int pbx_builtin_wait(struct ast_channel *, void *);
220 static int pbx_builtin_waitexten(struct ast_channel *, void *);
221 static int pbx_builtin_resetcdr(struct ast_channel *, void *);
222 static int pbx_builtin_setamaflags(struct ast_channel *, void *);
223 static int pbx_builtin_ringing(struct ast_channel *, void *);
224 static int pbx_builtin_progress(struct ast_channel *, void *);
225 static int pbx_builtin_congestion(struct ast_channel *, void *);
226 static int pbx_builtin_busy(struct ast_channel *, void *);
227 static int pbx_builtin_setglobalvar(struct ast_channel *, void *);
228 static int pbx_builtin_noop(struct ast_channel *, void *);
229 static int pbx_builtin_gotoif(struct ast_channel *, void *);
230 static int pbx_builtin_gotoiftime(struct ast_channel *, void *);
231 static int pbx_builtin_execiftime(struct ast_channel *, void *);
232 static int pbx_builtin_saynumber(struct ast_channel *, void *);
233 static int pbx_builtin_saydigits(struct ast_channel *, void *);
234 static int pbx_builtin_saycharacters(struct ast_channel *, void *);
235 static int pbx_builtin_sayphonetic(struct ast_channel *, void *);
236 int pbx_builtin_setvar(struct ast_channel *, void *);
237 static int pbx_builtin_importvar(struct ast_channel *, void *);
239 AST_MUTEX_DEFINE_STATIC(globalslock);
240 static struct varshead globals;
242 static int autofallthrough = 0;
244 AST_MUTEX_DEFINE_STATIC(maxcalllock);
245 static int countcalls = 0;
247 static AST_LIST_HEAD_STATIC(acf_root, ast_custom_function);
249 /*! \brief Declaration of builtin applications */
250 static struct pbx_builtin {
251 char name[AST_MAX_APP];
252 int (*execute)(struct ast_channel *chan, void *data);
253 char *synopsis;
254 char *description;
255 } builtins[] =
257 /* These applications are built into the PBX core and do not
258 need separate modules */
260 { "Answer", pbx_builtin_answer,
261 "Answer a channel if ringing",
262 " Answer([delay]): If the call has not been answered, this application will\n"
263 "answer it. Otherwise, it has no effect on the call. If a delay is specified,\n"
264 "Asterisk will wait this number of milliseconds before answering the call.\n"
267 { "BackGround", pbx_builtin_background,
268 "Play a file while awaiting extension",
269 " Background(filename1[&filename2...][|options[|langoverride][|context]]):\n"
270 "This application will play the given list of files while waiting for an\n"
271 "extension to be dialed by the calling channel. To continue waiting for digits\n"
272 "after this application has finished playing files, the WaitExten application\n"
273 "should be used. The 'langoverride' option explicity specifies which language\n"
274 "to attempt to use for the requested sound files. If a 'context' is specified,\n"
275 "this is the dialplan context that this application will use when exiting to a\n"
276 "dialed extension."
277 " If one of the requested sound files does not exist, call processing will be\n"
278 "terminated.\n"
279 " Options:\n"
280 " s - causes the playback of the message to be skipped\n"
281 " if the channel is not in the 'up' state (i.e. it\n"
282 " hasn't been answered yet.) If this happens, the\n"
283 " application will return immediately.\n"
284 " n - don't answer the channel before playing the files\n"
285 " m - only break if a digit hit matches a one digit\n"
286 " extension in the destination context\n"
289 { "Busy", pbx_builtin_busy,
290 "Indicate the Busy condition",
291 " Busy([timeout]): This application will indicate the busy condition to\n"
292 "the calling channel. If the optional timeout is specified, the calling channel\n"
293 "will be hung up after the specified number of seconds. Otherwise, this\n"
294 "application will wait until the calling channel hangs up.\n"
297 { "Congestion", pbx_builtin_congestion,
298 "Indicate the Congestion condition",
299 " Congestion([timeout]): This application will indicate the congenstion\n"
300 "condition to the calling channel. If the optional timeout is specified, the\n"
301 "calling channel will be hung up after the specified number of seconds.\n"
302 "Otherwise, this application will wait until the calling channel hangs up.\n"
305 { "Goto", pbx_builtin_goto,
306 "Jump to a particular priority, extension, or context",
307 " Goto([[context|]extension|]priority): This application will cause the\n"
308 "calling channel to continue dialplan execution at the specified priority.\n"
309 "If no specific extension, or extension and context, are specified, then this\n"
310 "application will jump to the specified priority of the current extension.\n"
311 " If the attempt to jump to another location in the dialplan is not successful,\n"
312 "then the channel will continue at the next priority of the current extension.\n"
315 { "GotoIf", pbx_builtin_gotoif,
316 "Conditional goto",
317 " GotoIf(condition?[labeliftrue]:[labeliffalse]): This application will cause\n"
318 "the calling channel to jump to the specified location in the dialplan based on\n"
319 "the evaluation of the given condition. The channel will continue at\n"
320 "'labeliftrue' if the condition is true, or 'labeliffalse' if the condition is\n"
321 "false. The labels are specified with the same syntax as used within the Goto\n"
322 "application. If the label chosen by the condition is omitted, no jump is\n"
323 "performed, but execution continues with the next priority in the dialplan.\n"
326 { "GotoIfTime", pbx_builtin_gotoiftime,
327 "Conditional Goto based on the current time",
328 " GotoIfTime(<times>|<weekdays>|<mdays>|<months>?[[context|]exten|]priority):\n"
329 "This application will have the calling channel jump to the speicified location\n"
330 "int the dialplan if the current time matches the given time specification.\n"
331 "Further information on the time specification can be found in examples\n"
332 "illustrating how to do time-based context includes in the dialplan.\n"
335 { "ExecIfTime", pbx_builtin_execiftime,
336 "Conditional application execution based on the current time",
337 " ExecIfTime(<times>|<weekdays>|<mdays>|<months>?appname[|appargs]):\n"
338 "This application will execute the specified dialplan application, with optional\n"
339 "arguments, if the current time matches the given time specification. Further\n"
340 "information on the time speicification can be found in examples illustrating\n"
341 "how to do time-based context includes in the dialplan.\n"
344 { "Hangup", pbx_builtin_hangup,
345 "Hang up the calling channel",
346 " Hangup(): This application will hang up the calling channel.\n"
349 { "NoOp", pbx_builtin_noop,
350 "Do Nothing",
351 " NoOp(): This applicatiion does nothing. However, it is useful for debugging\n"
352 "purposes. Any text that is provided as arguments to this application can be\n"
353 "viewed at the Asterisk CLI. This method can be used to see the evaluations of\n"
354 "variables or functions without having any effect."
357 { "Progress", pbx_builtin_progress,
358 "Indicate progress",
359 " Progress(): This application will request that in-band progress information\n"
360 "be provided to the calling channel.\n"
363 { "ResetCDR", pbx_builtin_resetcdr,
364 "Resets the Call Data Record",
365 " ResetCDR([options]): This application causes the Call Data Record to be\n"
366 "reset.\n"
367 " Options:\n"
368 " w -- Store the current CDR record before resetting it.\n"
369 " a -- Store any stacked records.\n"
370 " v -- Save CDR variables.\n"
373 { "Ringing", pbx_builtin_ringing,
374 "Indicate ringing tone",
375 " Ringing(): This application will request that the channel indicate a ringing\n"
376 "tone to the user.\n"
379 { "SayNumber", pbx_builtin_saynumber,
380 "Say Number",
381 " SayNumber(digits[,gender]): This application will play the sounds that\n"
382 "correspond to the given number. Optionally, a gender may be specified.\n"
383 "This will use the language that is currently set for the channel. See the\n"
384 "LANGUAGE function for more information on setting the language for the channel.\n"
387 { "SayDigits", pbx_builtin_saydigits,
388 "Say Digits",
389 " SayDigits(digits): This application will play the sounds that correspond\n"
390 "to the digits of the given number. This will use the language that is currently\n"
391 "set for the channel. See the LANGUAGE function for more information on setting\n"
392 "the language for the channel.\n"
395 { "SayAlpha", pbx_builtin_saycharacters,
396 "Say Alpha",
397 " SayAlpha(string): This application will play the sounds that correspond to\n"
398 "the letters of the given string.\n"
401 { "SayPhonetic", pbx_builtin_sayphonetic,
402 "Say Phonetic",
403 " SayPhonetic(string): This application will play the sounds from the phonetic\n"
404 "alphabet that correspond to the letters in the given string.\n"
407 { "SetAMAFlags", pbx_builtin_setamaflags,
408 "Set the AMA Flags",
409 " SetAMAFlags([flag]): This channel will set the channel's AMA Flags for billing\n"
410 "purposes.\n"
413 { "SetGlobalVar", pbx_builtin_setglobalvar,
414 "Set a global variable to a given value",
415 " SetGlobalVar(variable=value): This application sets a given global variable to\n"
416 "the specified value.\n"
419 { "Set", pbx_builtin_setvar,
420 "Set channel variable(s) or function value(s)",
421 " Set(name1=value1|name2=value2|..[|options])\n"
422 "This function can be used to set the value of channel variables or dialplan\n"
423 "functions. It will accept up to 24 name/value pairs. When setting variables,\n"
424 "if the variable name is prefixed with _, the variable will be inherited into\n"
425 "channels created from the current channel. If the variable name is prefixed\n"
426 "with __, the variable will be inherited into channels created from the current\n"
427 "channel and all children channels.\n"
428 " Options:\n"
429 " g - Set variable globally instead of on the channel\n"
430 " (applies only to variables, not functions)\n"
433 { "ImportVar", pbx_builtin_importvar,
434 "Import a variable from a channel into a new variable",
435 " ImportVar(newvar=channelname|variable): This application imports a variable\n"
436 "from the specified channel (as opposed to the current one) and stores it as\n"
437 "a variable in the current channel (the channel that is calling this\n"
438 "application). Variables created by this application have the same inheritance\n"
439 "properties as those created with the Set application. See the documentation for\n"
440 "Set for more information.\n"
443 { "Wait", pbx_builtin_wait,
444 "Waits for some time",
445 " Wait(seconds): This application waits for a specified number of seconds.\n"
446 "Then, dialplan execution will continue at the next priority.\n"
447 " Note that the seconds can be passed with fractions of a second. For example,\n"
448 "'1.5' will ask the application to wait for 1.5 seconds.\n"
451 { "WaitExten", pbx_builtin_waitexten,
452 "Waits for an extension to be entered",
453 " WaitExten([seconds][|options]): This application waits for the user to enter\n"
454 "a new extension for a specified number of seconds.\n"
455 " Note that the seconds can be passed with fractions of a second. For example,\n"
456 "'1.5' will ask the application to wait for 1.5 seconds.\n"
457 " Options:\n"
458 " m[(x)] - Provide music on hold to the caller while waiting for an extension.\n"
459 " Optionally, specify the class for music on hold within parenthesis.\n"
464 static struct ast_context *contexts = NULL;
465 AST_MUTEX_DEFINE_STATIC(conlock); /*!< Lock for the ast_context list */
467 static AST_LIST_HEAD_STATIC(apps, ast_app);
469 static AST_LIST_HEAD_STATIC(switches, ast_switch);
471 static int stateid = 1;
472 /* WARNING:
473 When holding this list's lock, do _not_ do anything that will cause conlock
474 to be taken, unless you _already_ hold it. The ast_merge_contexts_and_delete
475 function will take the locks in conlock/hints order, so any other
476 paths that require both locks must also take them in that order.
478 static AST_LIST_HEAD_STATIC(hints, ast_hint);
479 struct ast_state_cb *statecbs = NULL;
482 \note This function is special. It saves the stack so that no matter
483 how many times it is called, it returns to the same place */
484 int pbx_exec(struct ast_channel *c, /*!< Channel */
485 struct ast_app *app, /*!< Application */
486 void *data) /*!< Data for execution */
488 int res;
490 const char *saved_c_appl;
491 const char *saved_c_data;
493 if (c->cdr)
494 ast_cdr_setapp(c->cdr, app->name, data);
496 /* save channel values */
497 saved_c_appl= c->appl;
498 saved_c_data= c->data;
500 c->appl = app->name;
501 c->data = data;
502 /* XXX remember what to to when we have linked apps to modules */
503 if (app->module) {
504 /* XXX LOCAL_USER_ADD(app->module) */
506 res = app->execute(c, data);
507 if (app->module) {
508 /* XXX LOCAL_USER_REMOVE(app->module) */
510 /* restore channel values */
511 c->appl = saved_c_appl;
512 c->data = saved_c_data;
513 return res;
517 /*! Go no deeper than this through includes (not counting loops) */
518 #define AST_PBX_MAX_STACK 128
520 /*! \brief Find application handle in linked list
522 struct ast_app *pbx_findapp(const char *app)
524 struct ast_app *tmp;
526 AST_LIST_LOCK(&apps);
527 AST_LIST_TRAVERSE(&apps, tmp, list) {
528 if (!strcasecmp(tmp->name, app))
529 break;
531 AST_LIST_UNLOCK(&apps);
533 return tmp;
536 static struct ast_switch *pbx_findswitch(const char *sw)
538 struct ast_switch *asw;
540 AST_LIST_LOCK(&switches);
541 AST_LIST_TRAVERSE(&switches, asw, list) {
542 if (!strcasecmp(asw->name, sw))
543 break;
545 AST_LIST_UNLOCK(&switches);
547 return asw;
550 static inline int include_valid(struct ast_include *i)
552 if (!i->hastime)
553 return 1;
555 return ast_check_timing(&(i->timing));
558 static void pbx_destroy(struct ast_pbx *p)
560 free(p);
564 * When looking up extensions, we can have different requests
565 * identified by the 'action' argument, as follows.
566 * Note that the coding is such that the low 4 bits are the
567 * third argument to extension_match_core.
569 enum ext_match_t {
570 E_MATCHMORE = 0x00, /* extension can match but only with more 'digits' */
571 E_CANMATCH = 0x01, /* extension can match with or without more 'digits' */
572 E_MATCH = 0x02, /* extension is an exact match */
573 E_MATCH_MASK = 0x03, /* mask for the argument to extension_match_core() */
574 E_SPAWN = 0x12, /* want to spawn an extension. Requires exact match */
575 E_FINDLABEL = 0x22 /* returns the priority for a given label. Requires exact match */
579 * Internal function for ast_extension_{match|close}
580 * return 0 on no-match, 1 on match, 2 on early match.
581 * mode is as follows:
582 * E_MATCH success only on exact match
583 * E_MATCHMORE success only on partial match (i.e. leftover digits in pattern)
584 * E_CANMATCH either of the above.
586 static int _extension_match_core(const char *pattern, const char *data, enum ext_match_t mode)
588 mode &= E_MATCH_MASK; /* only consider the relevant bits */
590 if (pattern[0] != '_') { /* not a pattern, try exact or partial match */
591 int ld = strlen(data), lp = strlen(pattern);
593 if (lp < ld) /* pattern too short, cannot match */
594 return 0;
595 /* depending on the mode, accept full or partial match or both */
596 if (mode == E_MATCH)
597 return !strcmp(pattern, data); /* 1 on match, 0 on fail */
598 if (ld == 0 || !strncasecmp(pattern, data, ld)) /* partial or full match */
599 return (mode == E_MATCHMORE) ? lp > ld : 1; /* XXX should consider '!' and '/' ? */
600 else
601 return 0;
603 pattern++; /* skip leading _ */
604 while (*data && *pattern && *pattern != '/') {
605 const char *end;
607 if (*data == '-') { /* skip '-' in data (just a separator) */
608 data++;
609 continue;
611 switch (toupper(*pattern)) {
612 case '[': /* a range */
613 end = strchr(pattern+1, ']'); /* XXX should deal with escapes ? */
614 if (end == NULL) {
615 ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");
616 return 0; /* unconditional failure */
618 for (pattern++; pattern != end; pattern++) {
619 if (pattern+2 < end && pattern[1] == '-') { /* this is a range */
620 if (*data >= pattern[0] && *data <= pattern[2])
621 break; /* match found */
622 else {
623 pattern += 2; /* skip a total of 3 chars */
624 continue;
626 } else if (*data == pattern[0])
627 break; /* match found */
629 if (pattern == end)
630 return 0;
631 pattern = end; /* skip and continue */
632 break;
633 case 'N':
634 if (*data < '2' || *data > '9')
635 return 0;
636 break;
637 case 'X':
638 if (*data < '0' || *data > '9')
639 return 0;
640 break;
641 case 'Z':
642 if (*data < '1' || *data > '9')
643 return 0;
644 break;
645 case '.': /* Must match, even with more digits */
646 return 1;
647 case '!': /* Early match */
648 return 2;
649 case ' ':
650 case '-': /* Ignore these in patterns */
651 data--; /* compensate the final data++ */
652 break;
653 default:
654 if (*data != *pattern)
655 return 0;
657 data++;
658 pattern++;
660 if (*data) /* data longer than pattern, no match */
661 return 0;
663 * match so far, but ran off the end of the data.
664 * Depending on what is next, determine match or not.
666 if (*pattern == '\0' || *pattern == '/') /* exact match */
667 return (mode == E_MATCHMORE) ? 0 : 1; /* this is a failure for E_MATCHMORE */
668 else if (*pattern == '!') /* early match */
669 return 2;
670 else /* partial match */
671 return (mode == E_MATCH) ? 0 : 1; /* this is a failure for E_MATCH */
675 * Wrapper around _extension_match_core() to do performance measurement
676 * using the profiling code.
678 static int extension_match_core(const char *pattern, const char *data, enum ext_match_t mode)
680 int i;
681 static int prof_id = -2; /* marker for 'unallocated' id */
682 if (prof_id == -2)
683 prof_id = ast_add_profile("ext_match", 0);
684 ast_mark(prof_id, 1);
685 i = _extension_match_core(pattern, data, mode);
686 ast_mark(prof_id, 0);
687 return i;
690 int ast_extension_match(const char *pattern, const char *data)
692 return extension_match_core(pattern, data, E_MATCH);
695 int ast_extension_close(const char *pattern, const char *data, int needmore)
697 if (needmore != E_MATCHMORE && needmore != E_CANMATCH)
698 ast_log(LOG_WARNING, "invalid argument %d\n", needmore);
699 return extension_match_core(pattern, data, needmore);
702 struct ast_context *ast_context_find(const char *name)
704 struct ast_context *tmp = NULL;
705 ast_mutex_lock(&conlock);
706 while ( (tmp = ast_walk_contexts(tmp)) ) {
707 if (!name || !strcasecmp(name, tmp->name))
708 break;
710 ast_mutex_unlock(&conlock);
711 return tmp;
714 #define STATUS_NO_CONTEXT 1
715 #define STATUS_NO_EXTENSION 2
716 #define STATUS_NO_PRIORITY 3
717 #define STATUS_NO_LABEL 4
718 #define STATUS_SUCCESS 5
720 static int matchcid(const char *cidpattern, const char *callerid)
722 /* If the Caller*ID pattern is empty, then we're matching NO Caller*ID, so
723 failing to get a number should count as a match, otherwise not */
725 if (ast_strlen_zero(callerid))
726 return ast_strlen_zero(cidpattern) ? 1 : 0;
728 return ast_extension_match(cidpattern, callerid);
731 /* request and result for pbx_find_extension */
732 struct pbx_find_info {
733 #if 0
734 const char *context;
735 const char *exten;
736 int priority;
737 #endif
739 char *incstack[AST_PBX_MAX_STACK]; /* filled during the search */
740 int stacklen; /* modified during the search */
741 int status; /* set on return */
742 struct ast_switch *swo; /* set on return */
743 const char *data; /* set on return */
744 const char *foundcontext; /* set on return */
747 static struct ast_exten *pbx_find_extension(struct ast_channel *chan,
748 struct ast_context *bypass, struct pbx_find_info *q,
749 const char *context, const char *exten, int priority,
750 const char *label, const char *callerid, enum ext_match_t action)
752 int x, res;
753 struct ast_context *tmp;
754 struct ast_exten *e, *eroot;
755 struct ast_include *i;
756 struct ast_sw *sw;
758 struct ast_exten *earlymatch = NULL;
760 /* Initialize status if appropriate */
761 if (q->stacklen == 0) {
762 q->status = STATUS_NO_CONTEXT;
763 q->swo = NULL;
764 q->data = NULL;
765 q->foundcontext = NULL;
767 /* Check for stack overflow */
768 if (q->stacklen >= AST_PBX_MAX_STACK) {
769 ast_log(LOG_WARNING, "Maximum PBX stack exceeded\n");
770 return NULL;
772 /* Check first to see if we've already been checked */
773 for (x = 0; x < q->stacklen; x++) {
774 if (!strcasecmp(q->incstack[x], context))
775 return NULL;
777 if (bypass) /* bypass means we only look there */
778 tmp = bypass;
779 else { /* look in contexts */
780 tmp = NULL;
781 while ((tmp = ast_walk_contexts(tmp)) ) {
782 if (!strcmp(tmp->name, context))
783 break;
785 if (!tmp)
786 return NULL;
788 if (q->status < STATUS_NO_EXTENSION)
789 q->status = STATUS_NO_EXTENSION;
790 for (eroot = tmp->root; eroot; eroot = eroot->next) {
791 int match;
792 /* Match extension */
793 if ( (match = extension_match_core(eroot->exten, exten, action)) &&
794 (!eroot->matchcid || matchcid(eroot->cidmatch, callerid))) {
796 if (action == E_MATCHMORE && match == 2 && !earlymatch) {
797 /* XXX not sure the logic is correct here.
798 * we should go in irrespective of earlymatch
800 /* It matched an extension ending in a '!' wildcard
801 So ignore it for now, unless there's a better match */
802 earlymatch = eroot;
803 } else {
804 if (q->status < STATUS_NO_PRIORITY)
805 q->status = STATUS_NO_PRIORITY;
806 for (e = eroot; e; e = e->peer) {
807 /* Match priority */
808 if (action == E_FINDLABEL) {
809 if (q->status < STATUS_NO_LABEL)
810 q->status = STATUS_NO_LABEL;
811 if (label && e->label && !strcmp(label, e->label)) {
812 q->status = STATUS_SUCCESS;
813 q->foundcontext = context;
814 return e;
816 } else if (e->priority == priority) {
817 q->status = STATUS_SUCCESS;
818 q->foundcontext = context;
819 return e;
825 if (earlymatch) {
826 /* Bizarre logic for E_MATCHMORE. We return zero to break out
827 of the loop waiting for more digits, and _then_ match (normally)
828 the extension we ended up with. We got an early-matching wildcard
829 pattern, so return NULL to break out of the loop. */
830 return NULL;
832 /* Check alternative switches */
833 AST_LIST_TRAVERSE(&tmp->alts, sw, list) {
834 struct ast_switch *asw = pbx_findswitch(sw->name);
835 ast_switch_f *aswf = NULL;
836 char *datap;
838 if (!asw) {
839 ast_log(LOG_WARNING, "No such switch '%s'\n", sw->name);
840 continue;
842 /* Substitute variables now */
843 if (sw->eval)
844 pbx_substitute_variables_helper(chan, sw->data, sw->tmpdata, SWITCH_DATA_LENGTH - 1);
846 /* equivalent of extension_match_core() at the switch level */
847 if (action == E_CANMATCH)
848 aswf = asw->canmatch;
849 else if (action == E_MATCHMORE)
850 aswf = asw->matchmore;
851 else
852 aswf = asw->exists;
853 datap = sw->eval ? sw->tmpdata : sw->data;
854 res = !aswf ? 0 : aswf(chan, context, exten, priority, callerid, datap);
855 if (res) { /* Got a match */
856 q->swo = asw;
857 q->data = datap;
858 q->foundcontext = context;
859 /* XXX keep status = STATUS_NO_CONTEXT ? */
860 return NULL;
863 q->incstack[q->stacklen++] = tmp->name; /* Setup the stack */
864 /* Now try any includes we have in this context */
865 for (i = tmp->includes; i; i = i->next) {
866 if (include_valid(i)) {
867 if ((e = pbx_find_extension(chan, bypass, q, i->rname, exten, priority, label, callerid, action)))
868 return e;
869 if (q->swo)
870 return NULL;
873 return NULL;
876 /* Note that it's negative -- that's important later. */
877 #define DONT_HAVE_LENGTH 0x80000000
879 /*! \brief extract offset:length from variable name.
880 * Returns 1 if there is a offset:length part, which is
881 * trimmed off (values go into variables)
883 static int parse_variable_name(char *var, int *offset, int *length, int *isfunc)
885 int parens=0;
887 *offset = 0;
888 *length = DONT_HAVE_LENGTH;
889 *isfunc = 0;
890 for (; *var; var++) {
891 if (*var == '(') {
892 (*isfunc)++;
893 parens++;
894 } else if (*var == ')') {
895 parens--;
896 } else if (*var == ':' && parens == 0) {
897 *var++ = '\0';
898 sscanf(var, "%d:%d", offset, length);
899 return 1; /* offset:length valid */
902 return 0;
905 /*! \brief takes a substring. It is ok to call with value == workspace.
907 * offset < 0 means start from the end of the string and set the beginning
908 * to be that many characters back.
909 * length is the length of the substring, -1 means unlimited
910 * (we take any negative value).
911 * Always return a copy in workspace.
913 static char *substring(const char *value, int offset, int length, char *workspace, size_t workspace_len)
915 char *ret = workspace;
916 int lr; /* length of the input string after the copy */
918 ast_copy_string(workspace, value, workspace_len); /* always make a copy */
920 /* Quick check if no need to do anything */
921 if (offset == 0 && length < 0) /* take the whole string */
922 return ret;
924 lr = strlen(ret); /* compute length after copy, so we never go out of the workspace */
926 if (offset < 0) { /* translate negative offset into positive ones */
927 offset = lr + offset;
928 if (offset < 0) /* If the negative offset was greater than the length of the string, just start at the beginning */
929 offset = 0;
932 /* too large offset result in empty string so we know what to return */
933 if (offset >= lr)
934 return ret + lr; /* the final '\0' */
936 ret += offset; /* move to the start position */
937 if (length >= 0 && length < lr - offset) /* truncate if necessary */
938 ret[length] = '\0';
940 return ret;
943 /*! \brief pbx_retrieve_variable: Support for Asterisk built-in variables and
944 functions in the dialplan
945 ---*/
946 void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp)
948 const char not_found = '\0';
949 char *tmpvar;
950 const char *s; /* the result */
951 int offset, length;
952 int i, need_substring;
953 struct varshead *places[2] = { headp, &globals }; /* list of places where we may look */
955 if (c) {
956 places[0] = &c->varshead;
959 * Make a copy of var because parse_variable_name() modifies the string.
960 * Then if called directly, we might need to run substring() on the result;
961 * remember this for later in 'need_substring', 'offset' and 'length'
963 tmpvar = ast_strdupa(var); /* parse_variable_name modifies the string */
964 need_substring = parse_variable_name(tmpvar, &offset, &length, &i /* ignored */);
967 * Look first into predefined variables, then into variable lists.
968 * Variable 's' points to the result, according to the following rules:
969 * s == &not_found (set at the beginning) means that we did not find a
970 * matching variable and need to look into more places.
971 * If s != &not_found, s is a valid result string as follows:
972 * s = NULL if the variable does not have a value;
973 * you typically do this when looking for an unset predefined variable.
974 * s = workspace if the result has been assembled there;
975 * typically done when the result is built e.g. with an snprintf(),
976 * so we don't need to do an additional copy.
977 * s != workspace in case we have a string, that needs to be copied
978 * (the ast_copy_string is done once for all at the end).
979 * Typically done when the result is already available in some string.
981 s = &not_found; /* default value */
982 if (c) { /* This group requires a valid channel */
983 /* Names with common parts are looked up a piece at a time using strncmp. */
984 if (!strncmp(var, "CALL", 4)) {
985 if (!strncmp(var + 4, "ING", 3)) {
986 if (!strcmp(var + 7, "PRES")) { /* CALLINGPRES */
987 snprintf(workspace, workspacelen, "%d", c->cid.cid_pres);
988 s = workspace;
989 } else if (!strcmp(var + 7, "ANI2")) { /* CALLINGANI2 */
990 snprintf(workspace, workspacelen, "%d", c->cid.cid_ani2);
991 s = workspace;
992 } else if (!strcmp(var + 7, "TON")) { /* CALLINGTON */
993 snprintf(workspace, workspacelen, "%d", c->cid.cid_ton);
994 s = workspace;
995 } else if (!strcmp(var + 7, "TNS")) { /* CALLINGTNS */
996 snprintf(workspace, workspacelen, "%d", c->cid.cid_tns);
997 s = workspace;
1000 } else if (!strcmp(var, "HINT")) {
1001 s = ast_get_hint(workspace, workspacelen, NULL, 0, c, c->context, c->exten) ? workspace : NULL;
1002 } else if (!strcmp(var, "HINTNAME")) {
1003 s = ast_get_hint(NULL, 0, workspace, workspacelen, c, c->context, c->exten) ? workspace : NULL;
1004 } else if (!strcmp(var, "EXTEN")) {
1005 s = c->exten;
1006 } else if (!strcmp(var, "CONTEXT")) {
1007 s = c->context;
1008 } else if (!strcmp(var, "PRIORITY")) {
1009 snprintf(workspace, workspacelen, "%d", c->priority);
1010 s = workspace;
1011 } else if (!strcmp(var, "CHANNEL")) {
1012 s = c->name;
1013 } else if (!strcmp(var, "UNIQUEID")) {
1014 s = c->uniqueid;
1015 } else if (!strcmp(var, "HANGUPCAUSE")) {
1016 snprintf(workspace, workspacelen, "%d", c->hangupcause);
1017 s = workspace;
1020 if (s == &not_found) { /* look for more */
1021 if (!strcmp(var, "EPOCH")) {
1022 snprintf(workspace, workspacelen, "%u",(int)time(NULL));
1023 s = workspace;
1024 } else if (!strcmp(var, "SYSTEMNAME")) {
1025 s = ast_config_AST_SYSTEM_NAME;
1028 /* if not found, look into chanvars or global vars */
1029 for (i = 0; s == &not_found && i < (sizeof(places) / sizeof(places[0])); i++) {
1030 struct ast_var_t *variables;
1031 if (!places[i])
1032 continue;
1033 if (places[i] == &globals)
1034 ast_mutex_lock(&globalslock);
1035 AST_LIST_TRAVERSE(places[i], variables, entries) {
1036 if (strcasecmp(ast_var_name(variables), var)==0) {
1037 s = ast_var_value(variables);
1038 break;
1041 if (places[i] == &globals)
1042 ast_mutex_unlock(&globalslock);
1044 if (s == &not_found || s == NULL)
1045 *ret = NULL;
1046 else {
1047 if (s != workspace)
1048 ast_copy_string(workspace, s, workspacelen);
1049 *ret = workspace;
1050 if (need_substring)
1051 *ret = substring(*ret, offset, length, workspace, workspacelen);
1055 /*! \brief CLI function to show installed custom functions
1056 \addtogroup CLI_functions
1058 static int handle_show_functions(int fd, int argc, char *argv[])
1060 struct ast_custom_function *acf;
1061 int count_acf = 0;
1062 int like = 0;
1064 if (argc == 4 && (!strcmp(argv[2], "like")) ) {
1065 like = 1;
1066 } else if (argc != 2) {
1067 return RESULT_SHOWUSAGE;
1070 ast_cli(fd, "%s Custom Functions:\n--------------------------------------------------------------------------------\n", like ? "Matching" : "Installed");
1072 AST_LIST_LOCK(&acf_root);
1073 AST_LIST_TRAVERSE(&acf_root, acf, acflist) {
1074 if (!like || strstr(acf->name, argv[3])) {
1075 count_acf++;
1076 ast_cli(fd, "%-20.20s %-35.35s %s\n", acf->name, acf->syntax, acf->synopsis);
1079 AST_LIST_UNLOCK(&acf_root);
1081 ast_cli(fd, "%d %scustom functions installed.\n", count_acf, like ? "matching " : "");
1083 return RESULT_SUCCESS;
1086 static int handle_show_function(int fd, int argc, char *argv[])
1088 struct ast_custom_function *acf;
1089 /* Maximum number of characters added by terminal coloring is 22 */
1090 char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
1091 char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
1092 char stxtitle[40], *syntax = NULL;
1093 int synopsis_size, description_size, syntax_size;
1095 if (argc < 3)
1096 return RESULT_SHOWUSAGE;
1098 if (!(acf = ast_custom_function_find(argv[2]))) {
1099 ast_cli(fd, "No function by that name registered.\n");
1100 return RESULT_FAILURE;
1104 if (acf->synopsis)
1105 synopsis_size = strlen(acf->synopsis) + 23;
1106 else
1107 synopsis_size = strlen("Not available") + 23;
1108 synopsis = alloca(synopsis_size);
1110 if (acf->desc)
1111 description_size = strlen(acf->desc) + 23;
1112 else
1113 description_size = strlen("Not available") + 23;
1114 description = alloca(description_size);
1116 if (acf->syntax)
1117 syntax_size = strlen(acf->syntax) + 23;
1118 else
1119 syntax_size = strlen("Not available") + 23;
1120 syntax = alloca(syntax_size);
1122 snprintf(info, 64 + AST_MAX_APP, "\n -= Info about function '%s' =- \n\n", acf->name);
1123 term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
1124 term_color(stxtitle, "[Syntax]\n", COLOR_MAGENTA, 0, 40);
1125 term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
1126 term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
1127 term_color(syntax,
1128 acf->syntax ? acf->syntax : "Not available",
1129 COLOR_CYAN, 0, syntax_size);
1130 term_color(synopsis,
1131 acf->synopsis ? acf->synopsis : "Not available",
1132 COLOR_CYAN, 0, synopsis_size);
1133 term_color(description,
1134 acf->desc ? acf->desc : "Not available",
1135 COLOR_CYAN, 0, description_size);
1137 ast_cli(fd,"%s%s%s\n\n%s%s\n\n%s%s\n", infotitle, stxtitle, syntax, syntitle, synopsis, destitle, description);
1139 return RESULT_SUCCESS;
1142 static char *complete_show_function(const char *line, const char *word, int pos, int state)
1144 struct ast_custom_function *acf;
1145 char *ret = NULL;
1146 int which = 0;
1147 int wordlen = strlen(word);
1149 /* case-insensitive for convenience in this 'complete' function */
1150 AST_LIST_LOCK(&acf_root);
1151 AST_LIST_TRAVERSE(&acf_root, acf, acflist) {
1152 if (!strncasecmp(word, acf->name, wordlen) && ++which > state) {
1153 ret = strdup(acf->name);
1154 break;
1157 AST_LIST_UNLOCK(&acf_root);
1159 return ret;
1162 struct ast_custom_function *ast_custom_function_find(const char *name)
1164 struct ast_custom_function *acf = NULL;
1166 AST_LIST_LOCK(&acf_root);
1167 AST_LIST_TRAVERSE(&acf_root, acf, acflist) {
1168 if (!strcmp(name, acf->name))
1169 break;
1171 AST_LIST_UNLOCK(&acf_root);
1173 return acf;
1176 int ast_custom_function_unregister(struct ast_custom_function *acf)
1178 struct ast_custom_function *cur;
1180 if (!acf)
1181 return -1;
1183 AST_LIST_LOCK(&acf_root);
1184 AST_LIST_TRAVERSE_SAFE_BEGIN(&acf_root, cur, acflist) {
1185 if (cur == acf) {
1186 AST_LIST_REMOVE_CURRENT(&acf_root, acflist);
1187 if (option_verbose > 1)
1188 ast_verbose(VERBOSE_PREFIX_2 "Unregistered custom function %s\n", acf->name);
1189 break;
1192 AST_LIST_TRAVERSE_SAFE_END
1193 AST_LIST_UNLOCK(&acf_root);
1195 return acf ? 0 : -1;
1198 int ast_custom_function_register(struct ast_custom_function *acf)
1200 struct ast_custom_function *cur;
1202 if (!acf)
1203 return -1;
1205 AST_LIST_LOCK(&acf_root);
1207 if (ast_custom_function_find(acf->name)) {
1208 ast_log(LOG_ERROR, "Function %s already registered.\n", acf->name);
1209 AST_LIST_UNLOCK(&acf_root);
1210 return -1;
1213 /* Store in alphabetical order */
1214 AST_LIST_TRAVERSE_SAFE_BEGIN(&acf_root, cur, acflist) {
1215 if (strcasecmp(acf->name, cur->name) < 0) {
1216 AST_LIST_INSERT_BEFORE_CURRENT(&acf_root, acf, acflist);
1217 break;
1220 AST_LIST_TRAVERSE_SAFE_END
1221 if (!cur)
1222 AST_LIST_INSERT_TAIL(&acf_root, acf, acflist);
1224 AST_LIST_UNLOCK(&acf_root);
1226 if (option_verbose > 1)
1227 ast_verbose(VERBOSE_PREFIX_2 "Registered custom function %s\n", acf->name);
1229 return 0;
1232 /*! \brief return a pointer to the arguments of the function,
1233 * and terminates the function name with '\\0'
1235 static char *func_args(char *function)
1237 char *args = strchr(function, '(');
1239 if (!args)
1240 ast_log(LOG_WARNING, "Function doesn't contain parentheses. Assuming null argument.\n");
1241 else {
1242 char *p;
1243 *args++ = '\0';
1244 if ((p = strrchr(args, ')')) )
1245 *p = '\0';
1246 else
1247 ast_log(LOG_WARNING, "Can't find trailing parenthesis?\n");
1249 return args;
1252 int ast_func_read(struct ast_channel *chan, char *function, char *workspace, size_t len)
1254 char *args = func_args(function);
1255 struct ast_custom_function *acfptr = ast_custom_function_find(function);
1257 if (acfptr == NULL)
1258 ast_log(LOG_ERROR, "Function %s not registered\n", function);
1259 else if (!acfptr->read)
1260 ast_log(LOG_ERROR, "Function %s cannot be read\n", function);
1261 else
1262 return acfptr->read(chan, function, args, workspace, len);
1263 return -1;
1266 int ast_func_write(struct ast_channel *chan, char *function, const char *value)
1268 char *args = func_args(function);
1269 struct ast_custom_function *acfptr = ast_custom_function_find(function);
1271 if (acfptr == NULL)
1272 ast_log(LOG_ERROR, "Function %s not registered\n", function);
1273 else if (!acfptr->write)
1274 ast_log(LOG_ERROR, "Function %s cannot be written to\n", function);
1275 else
1276 return acfptr->write(chan, function, args, value);
1278 return -1;
1281 static void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int count)
1283 /* Substitutes variables into cp2, based on string cp1, and assuming cp2 to be
1284 zero-filled */
1285 char *cp4;
1286 const char *tmp, *whereweare;
1287 int length, offset, offset2, isfunction;
1288 char *workspace = NULL;
1289 char *ltmp = NULL, *var = NULL;
1290 char *nextvar, *nextexp, *nextthing;
1291 char *vars, *vare;
1292 int pos, brackets, needsub, len;
1294 whereweare=tmp=cp1;
1295 while (!ast_strlen_zero(whereweare) && count) {
1296 /* Assume we're copying the whole remaining string */
1297 pos = strlen(whereweare);
1298 nextvar = NULL;
1299 nextexp = NULL;
1300 nextthing = strchr(whereweare, '$');
1301 if (nextthing) {
1302 switch(nextthing[1]) {
1303 case '{':
1304 nextvar = nextthing;
1305 pos = nextvar - whereweare;
1306 break;
1307 case '[':
1308 nextexp = nextthing;
1309 pos = nextexp - whereweare;
1310 break;
1314 if (pos) {
1315 /* Can't copy more than 'count' bytes */
1316 if (pos > count)
1317 pos = count;
1319 /* Copy that many bytes */
1320 memcpy(cp2, whereweare, pos);
1322 count -= pos;
1323 cp2 += pos;
1324 whereweare += pos;
1327 if (nextvar) {
1328 /* We have a variable. Find the start and end, and determine
1329 if we are going to have to recursively call ourselves on the
1330 contents */
1331 vars = vare = nextvar + 2;
1332 brackets = 1;
1333 needsub = 0;
1335 /* Find the end of it */
1336 while (brackets && *vare) {
1337 if ((vare[0] == '$') && (vare[1] == '{')) {
1338 needsub++;
1339 } else if (vare[0] == '{') {
1340 brackets++;
1341 } else if (vare[0] == '}') {
1342 brackets--;
1343 } else if ((vare[0] == '$') && (vare[1] == '['))
1344 needsub++;
1345 vare++;
1347 if (brackets)
1348 ast_log(LOG_NOTICE, "Error in extension logic (missing '}')\n");
1349 len = vare - vars - 1;
1351 /* Skip totally over variable string */
1352 whereweare += (len + 3);
1354 if (!var)
1355 var = alloca(VAR_BUF_SIZE);
1357 /* Store variable name (and truncate) */
1358 ast_copy_string(var, vars, len + 1);
1360 /* Substitute if necessary */
1361 if (needsub) {
1362 if (!ltmp)
1363 ltmp = alloca(VAR_BUF_SIZE);
1365 memset(ltmp, 0, VAR_BUF_SIZE);
1366 pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1);
1367 vars = ltmp;
1368 } else {
1369 vars = var;
1372 if (!workspace)
1373 workspace = alloca(VAR_BUF_SIZE);
1375 workspace[0] = '\0';
1377 parse_variable_name(vars, &offset, &offset2, &isfunction);
1378 if (isfunction) {
1379 /* Evaluate function */
1380 cp4 = ast_func_read(c, vars, workspace, VAR_BUF_SIZE) ? NULL : workspace;
1382 ast_log(LOG_DEBUG, "Function result is '%s'\n", cp4 ? cp4 : "(null)");
1383 } else {
1384 /* Retrieve variable value */
1385 pbx_retrieve_variable(c, vars, &cp4, workspace, VAR_BUF_SIZE, headp);
1387 if (cp4) {
1388 cp4 = substring(cp4, offset, offset2, workspace, VAR_BUF_SIZE);
1390 length = strlen(cp4);
1391 if (length > count)
1392 length = count;
1393 memcpy(cp2, cp4, length);
1394 count -= length;
1395 cp2 += length;
1397 } else if (nextexp) {
1398 /* We have an expression. Find the start and end, and determine
1399 if we are going to have to recursively call ourselves on the
1400 contents */
1401 vars = vare = nextexp + 2;
1402 brackets = 1;
1403 needsub = 0;
1405 /* Find the end of it */
1406 while(brackets && *vare) {
1407 if ((vare[0] == '$') && (vare[1] == '[')) {
1408 needsub++;
1409 brackets++;
1410 vare++;
1411 } else if (vare[0] == '[') {
1412 brackets++;
1413 } else if (vare[0] == ']') {
1414 brackets--;
1415 } else if ((vare[0] == '$') && (vare[1] == '{')) {
1416 needsub++;
1417 vare++;
1419 vare++;
1421 if (brackets)
1422 ast_log(LOG_NOTICE, "Error in extension logic (missing ']')\n");
1423 len = vare - vars - 1;
1425 /* Skip totally over expression */
1426 whereweare += (len + 3);
1428 if (!var)
1429 var = alloca(VAR_BUF_SIZE);
1431 /* Store variable name (and truncate) */
1432 ast_copy_string(var, vars, len + 1);
1434 /* Substitute if necessary */
1435 if (needsub) {
1436 if (!ltmp)
1437 ltmp = alloca(VAR_BUF_SIZE);
1439 memset(ltmp, 0, VAR_BUF_SIZE);
1440 pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1);
1441 vars = ltmp;
1442 } else {
1443 vars = var;
1446 length = ast_expr(vars, cp2, count);
1448 if (length) {
1449 ast_log(LOG_DEBUG, "Expression result is '%s'\n", cp2);
1450 count -= length;
1451 cp2 += length;
1453 } else
1454 break;
1458 void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
1460 pbx_substitute_variables_helper_full(c, (c) ? &c->varshead : NULL, cp1, cp2, count);
1463 void pbx_substitute_variables_varshead(struct varshead *headp, const char *cp1, char *cp2, int count)
1465 pbx_substitute_variables_helper_full(NULL, headp, cp1, cp2, count);
1468 static void pbx_substitute_variables(char *passdata, int datalen, struct ast_channel *c, struct ast_exten *e)
1470 memset(passdata, 0, datalen);
1472 /* No variables or expressions in e->data, so why scan it? */
1473 if (!strchr(e->data, '$') && !strstr(e->data,"${") && !strstr(e->data,"$[") && !strstr(e->data,"$(")) {
1474 ast_copy_string(passdata, e->data, datalen);
1475 return;
1478 pbx_substitute_variables_helper(c, e->data, passdata, datalen - 1);
1481 /*! \brief The return value depends on the action:
1483 * E_MATCH, E_CANMATCH, E_MATCHMORE require a real match,
1484 * and return 0 on failure, -1 on match;
1485 * E_FINDLABEL maps the label to a priority, and returns
1486 * the priority on success, ... XXX
1487 * E_SPAWN, spawn an application,
1488 * and return 0 on success, -1 on failure.
1490 static int pbx_extension_helper(struct ast_channel *c, struct ast_context *con,
1491 const char *context, const char *exten, int priority,
1492 const char *label, const char *callerid, enum ext_match_t action)
1494 struct ast_exten *e;
1495 struct ast_app *app;
1496 int res;
1497 struct pbx_find_info q = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */
1498 char passdata[EXT_DATA_SIZE];
1500 int matching_action = (action == E_MATCH || action == E_CANMATCH || action == E_MATCHMORE);
1502 ast_mutex_lock(&conlock);
1503 e = pbx_find_extension(c, con, &q, context, exten, priority, label, callerid, action);
1504 if (e) {
1505 if (matching_action) {
1506 ast_mutex_unlock(&conlock);
1507 return -1; /* success, we found it */
1508 } else if (action == E_FINDLABEL) { /* map the label to a priority */
1509 res = e->priority;
1510 ast_mutex_unlock(&conlock);
1511 return res; /* the priority we were looking for */
1512 } else { /* spawn */
1513 app = pbx_findapp(e->app);
1514 ast_mutex_unlock(&conlock);
1515 if (!app) {
1516 ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
1517 return -1;
1519 if (c->context != context)
1520 ast_copy_string(c->context, context, sizeof(c->context));
1521 if (c->exten != exten)
1522 ast_copy_string(c->exten, exten, sizeof(c->exten));
1523 c->priority = priority;
1524 pbx_substitute_variables(passdata, sizeof(passdata), c, e);
1525 if (option_debug) {
1526 char atmp[80];
1527 char atmp2[EXT_DATA_SIZE+100];
1528 ast_log(LOG_DEBUG, "Launching '%s'\n", app->name);
1529 snprintf(atmp, sizeof(atmp), "STACK-%s-%s-%d", context, exten, priority);
1530 snprintf(atmp2, sizeof(atmp2), "%s(\"%s\", \"%s\") %s",
1531 app->name, c->name, passdata, "in new stack");
1532 pbx_builtin_setvar_helper(c, atmp, atmp2);
1534 if (option_verbose > 2) {
1535 char tmp[80], tmp2[80], tmp3[EXT_DATA_SIZE];
1536 ast_verbose( VERBOSE_PREFIX_3 "Executing [%s:%d] %s(\"%s\", \"%s\") %s\n",
1537 context, priority,
1538 term_color(tmp, app->name, COLOR_BRCYAN, 0, sizeof(tmp)),
1539 term_color(tmp2, c->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
1540 term_color(tmp3, passdata, COLOR_BRMAGENTA, 0, sizeof(tmp3)),
1541 "in new stack");
1543 manager_event(EVENT_FLAG_CALL, "Newexten",
1544 "Channel: %s\r\n"
1545 "Context: %s\r\n"
1546 "Extension: %s\r\n"
1547 "Priority: %d\r\n"
1548 "Application: %s\r\n"
1549 "AppData: %s\r\n"
1550 "Uniqueid: %s\r\n",
1551 c->name, c->context, c->exten, c->priority, app->name, passdata, c->uniqueid);
1552 return pbx_exec(c, app, passdata); /* 0 on success, -1 on failure */
1554 } else if (q.swo) { /* not found here, but in another switch */
1555 ast_mutex_unlock(&conlock);
1556 if (matching_action)
1557 return -1;
1558 else {
1559 if (!q.swo->exec) {
1560 ast_log(LOG_WARNING, "No execution engine for switch %s\n", q.swo->name);
1561 res = -1;
1563 return q.swo->exec(c, q.foundcontext ? q.foundcontext : context, exten, priority, callerid, q.data);
1565 } else { /* not found anywhere, see what happened */
1566 ast_mutex_unlock(&conlock);
1567 switch (q.status) {
1568 case STATUS_NO_CONTEXT:
1569 if (!matching_action)
1570 ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", context);
1571 break;
1572 case STATUS_NO_EXTENSION:
1573 if (!matching_action)
1574 ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, context);
1575 break;
1576 case STATUS_NO_PRIORITY:
1577 if (!matching_action)
1578 ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, context);
1579 break;
1580 case STATUS_NO_LABEL:
1581 if (context)
1582 ast_log(LOG_NOTICE, "No such label '%s' in extension '%s' in context '%s'\n", label, exten, context);
1583 break;
1584 default:
1585 ast_log(LOG_DEBUG, "Shouldn't happen!\n");
1588 return (matching_action) ? 0 : -1;
1592 /*! \brief ast_hint_extension: Find hint for given extension in context */
1593 static struct ast_exten *ast_hint_extension(struct ast_channel *c, const char *context, const char *exten)
1595 struct ast_exten *e;
1596 struct pbx_find_info q = { .stacklen = 0 }; /* the rest is set in pbx_find_context */
1598 ast_mutex_lock(&conlock);
1599 e = pbx_find_extension(c, NULL, &q, context, exten, PRIORITY_HINT, NULL, "", E_MATCH);
1600 ast_mutex_unlock(&conlock);
1602 return e;
1605 /*! \brief ast_extensions_state2: Check state of extension by using hints */
1606 static int ast_extension_state2(struct ast_exten *e)
1608 char hint[AST_MAX_EXTENSION];
1609 char *cur, *rest;
1610 int allunavailable = 1, allbusy = 1, allfree = 1;
1611 int busy = 0, inuse = 0, ring = 0;
1613 if (!e)
1614 return -1;
1616 ast_copy_string(hint, ast_get_extension_app(e), sizeof(hint));
1618 rest = hint; /* One or more devices separated with a & character */
1619 while ( (cur = strsep(&rest, "&")) ) {
1620 int res = ast_device_state(cur);
1621 switch (res) {
1622 case AST_DEVICE_NOT_INUSE:
1623 allunavailable = 0;
1624 allbusy = 0;
1625 break;
1626 case AST_DEVICE_INUSE:
1627 inuse = 1;
1628 allunavailable = 0;
1629 allfree = 0;
1630 break;
1631 case AST_DEVICE_RINGING:
1632 ring = 1;
1633 allunavailable = 0;
1634 allfree = 0;
1635 break;
1636 case AST_DEVICE_BUSY:
1637 allunavailable = 0;
1638 allfree = 0;
1639 busy = 1;
1640 break;
1641 case AST_DEVICE_UNAVAILABLE:
1642 case AST_DEVICE_INVALID:
1643 allbusy = 0;
1644 allfree = 0;
1645 break;
1646 default:
1647 allunavailable = 0;
1648 allbusy = 0;
1649 allfree = 0;
1653 if (!inuse && ring)
1654 return AST_EXTENSION_RINGING;
1655 if (inuse && ring)
1656 return (AST_EXTENSION_INUSE | AST_EXTENSION_RINGING);
1657 if (inuse)
1658 return AST_EXTENSION_INUSE;
1659 if (allfree)
1660 return AST_EXTENSION_NOT_INUSE;
1661 if (allbusy)
1662 return AST_EXTENSION_BUSY;
1663 if (allunavailable)
1664 return AST_EXTENSION_UNAVAILABLE;
1665 if (busy)
1666 return AST_EXTENSION_INUSE;
1668 return AST_EXTENSION_NOT_INUSE;
1671 /*! \brief ast_extension_state2str: Return extension_state as string */
1672 const char *ast_extension_state2str(int extension_state)
1674 int i;
1676 for (i = 0; (i < (sizeof(extension_states) / sizeof(extension_states[0]))); i++) {
1677 if (extension_states[i].extension_state == extension_state)
1678 return extension_states[i].text;
1680 return "Unknown";
1683 /*! \brief ast_extension_state: Check extension state for an extension by using hint */
1684 int ast_extension_state(struct ast_channel *c, const char *context, const char *exten)
1686 struct ast_exten *e;
1688 e = ast_hint_extension(c, context, exten); /* Do we have a hint for this extension ? */
1689 if (!e)
1690 return -1; /* No hint, return -1 */
1692 return ast_extension_state2(e); /* Check all devices in the hint */
1695 void ast_hint_state_changed(const char *device)
1697 struct ast_hint *hint;
1699 AST_LIST_LOCK(&hints);
1701 AST_LIST_TRAVERSE(&hints, hint, list) {
1702 struct ast_state_cb *cblist;
1703 char buf[AST_MAX_EXTENSION];
1704 char *parse = buf;
1705 char *cur;
1706 int state;
1708 ast_copy_string(buf, ast_get_extension_app(hint->exten), sizeof(buf));
1709 while ( (cur = strsep(&parse, "&")) ) {
1710 if (!strcasecmp(cur, device))
1711 break;
1713 if (!cur)
1714 continue;
1716 /* Get device state for this hint */
1717 state = ast_extension_state2(hint->exten);
1719 if ((state == -1) || (state == hint->laststate))
1720 continue;
1722 /* Device state changed since last check - notify the watchers */
1724 /* For general callbacks */
1725 for (cblist = statecbs; cblist; cblist = cblist->next)
1726 cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data);
1728 /* For extension callbacks */
1729 for (cblist = hint->callbacks; cblist; cblist = cblist->next)
1730 cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data);
1732 hint->laststate = state; /* record we saw the change */
1735 AST_LIST_UNLOCK(&hints);
1738 /*! \brief ast_extension_state_add: Add watcher for extension states */
1739 int ast_extension_state_add(const char *context, const char *exten,
1740 ast_state_cb_type callback, void *data)
1742 struct ast_hint *hint;
1743 struct ast_state_cb *cblist;
1744 struct ast_exten *e;
1746 /* If there's no context and extension: add callback to statecbs list */
1747 if (!context && !exten) {
1748 AST_LIST_LOCK(&hints);
1750 for (cblist = statecbs; cblist; cblist = cblist->next) {
1751 if (cblist->callback == callback) {
1752 cblist->data = data;
1753 AST_LIST_UNLOCK(&hints);
1754 return 0;
1758 /* Now insert the callback */
1759 if (!(cblist = ast_calloc(1, sizeof(*cblist)))) {
1760 AST_LIST_UNLOCK(&hints);
1761 return -1;
1763 cblist->id = 0;
1764 cblist->callback = callback;
1765 cblist->data = data;
1767 cblist->next = statecbs;
1768 statecbs = cblist;
1770 AST_LIST_UNLOCK(&hints);
1771 return 0;
1774 if (!context || !exten)
1775 return -1;
1777 /* This callback type is for only one hint, so get the hint */
1778 e = ast_hint_extension(NULL, context, exten);
1779 if (!e) {
1780 return -1;
1783 /* Find the hint in the list of hints */
1784 AST_LIST_LOCK(&hints);
1786 AST_LIST_TRAVERSE(&hints, hint, list) {
1787 if (hint->exten == e)
1788 break;
1791 if (!hint) {
1792 /* We have no hint, sorry */
1793 AST_LIST_UNLOCK(&hints);
1794 return -1;
1797 /* Now insert the callback in the callback list */
1798 if (!(cblist = ast_calloc(1, sizeof(*cblist)))) {
1799 AST_LIST_UNLOCK(&hints);
1800 return -1;
1802 cblist->id = stateid++; /* Unique ID for this callback */
1803 cblist->callback = callback; /* Pointer to callback routine */
1804 cblist->data = data; /* Data for the callback */
1806 cblist->next = hint->callbacks;
1807 hint->callbacks = cblist;
1809 AST_LIST_UNLOCK(&hints);
1810 return cblist->id;
1813 /*! \brief ast_extension_state_del: Remove a watcher from the callback list */
1814 int ast_extension_state_del(int id, ast_state_cb_type callback)
1816 struct ast_state_cb **p_cur = NULL; /* address of pointer to us */
1817 int ret = -1;
1819 if (!id && !callback)
1820 return -1;
1822 AST_LIST_LOCK(&hints);
1824 if (!id) { /* id == 0 is a callback without extension */
1825 for (p_cur = &statecbs; *p_cur; p_cur = &(*p_cur)->next) {
1826 if ((*p_cur)->callback == callback)
1827 break;
1829 } else { /* callback with extension, find the callback based on ID */
1830 struct ast_hint *hint;
1831 AST_LIST_TRAVERSE(&hints, hint, list) {
1832 for (p_cur = &hint->callbacks; *p_cur; p_cur = &(*p_cur)->next) {
1833 if ((*p_cur)->id == id)
1834 break;
1836 if (*p_cur) /* found in the inner loop */
1837 break;
1840 if (p_cur && *p_cur) {
1841 struct ast_state_cb *cur = *p_cur;
1842 *p_cur = cur->next;
1843 free(cur);
1844 ret = 0;
1846 AST_LIST_UNLOCK(&hints);
1847 return ret;
1850 /*! \brief ast_add_hint: Add hint to hint list, check initial extension state */
1851 static int ast_add_hint(struct ast_exten *e)
1853 struct ast_hint *hint;
1855 if (!e)
1856 return -1;
1858 AST_LIST_LOCK(&hints);
1860 /* Search if hint exists, do nothing */
1861 AST_LIST_TRAVERSE(&hints, hint, list) {
1862 if (hint->exten == e) {
1863 AST_LIST_UNLOCK(&hints);
1864 if (option_debug > 1)
1865 ast_log(LOG_DEBUG, "HINTS: Not re-adding existing hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
1866 return -1;
1870 if (option_debug > 1)
1871 ast_log(LOG_DEBUG, "HINTS: Adding hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
1873 if (!(hint = ast_calloc(1, sizeof(*hint)))) {
1874 AST_LIST_UNLOCK(&hints);
1875 return -1;
1877 /* Initialize and insert new item at the top */
1878 hint->exten = e;
1879 hint->laststate = ast_extension_state2(e);
1880 AST_LIST_INSERT_HEAD(&hints, hint, list);
1882 AST_LIST_UNLOCK(&hints);
1883 return 0;
1886 /*! \brief ast_change_hint: Change hint for an extension */
1887 static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
1889 struct ast_hint *hint;
1890 int res = -1;
1892 AST_LIST_LOCK(&hints);
1893 AST_LIST_TRAVERSE(&hints, hint, list) {
1894 if (hint->exten == oe) {
1895 hint->exten = ne;
1896 res = 0;
1897 break;
1900 AST_LIST_UNLOCK(&hints);
1902 return res;
1905 /*! \brief ast_remove_hint: Remove hint from extension */
1906 static int ast_remove_hint(struct ast_exten *e)
1908 /* Cleanup the Notifys if hint is removed */
1909 struct ast_hint *hint;
1910 struct ast_state_cb *cblist, *cbprev;
1911 int res = -1;
1913 if (!e)
1914 return -1;
1916 AST_LIST_LOCK(&hints);
1917 AST_LIST_TRAVERSE_SAFE_BEGIN(&hints, hint, list) {
1918 if (hint->exten == e) {
1919 cbprev = NULL;
1920 cblist = hint->callbacks;
1921 while (cblist) {
1922 /* Notify with -1 and remove all callbacks */
1923 cbprev = cblist;
1924 cblist = cblist->next;
1925 cbprev->callback(hint->exten->parent->name, hint->exten->exten, AST_EXTENSION_DEACTIVATED, cbprev->data);
1926 free(cbprev);
1928 hint->callbacks = NULL;
1929 AST_LIST_REMOVE_CURRENT(&hints, list);
1930 free(hint);
1931 res = 0;
1932 break;
1935 AST_LIST_TRAVERSE_SAFE_END
1936 AST_LIST_UNLOCK(&hints);
1938 return res;
1942 /*! \brief ast_get_hint: Get hint for channel */
1943 int ast_get_hint(char *hint, int hintsize, char *name, int namesize, struct ast_channel *c, const char *context, const char *exten)
1945 struct ast_exten *e = ast_hint_extension(c, context, exten);
1947 if (e) {
1948 if (hint)
1949 ast_copy_string(hint, ast_get_extension_app(e), hintsize);
1950 if (name) {
1951 const char *tmp = ast_get_extension_app_data(e);
1952 if (tmp)
1953 ast_copy_string(name, tmp, namesize);
1955 return -1;
1957 return 0;
1960 int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
1962 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_MATCH);
1965 int ast_findlabel_extension(struct ast_channel *c, const char *context, const char *exten, const char *label, const char *callerid)
1967 return pbx_extension_helper(c, NULL, context, exten, 0, label, callerid, E_FINDLABEL);
1970 int ast_findlabel_extension2(struct ast_channel *c, struct ast_context *con, const char *exten, const char *label, const char *callerid)
1972 return pbx_extension_helper(c, con, NULL, exten, 0, label, callerid, E_FINDLABEL);
1975 int ast_canmatch_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
1977 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_CANMATCH);
1980 int ast_matchmore_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
1982 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_MATCHMORE);
1985 int ast_spawn_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
1987 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_SPAWN);
1990 /* helper function to set extension and priority */
1991 static void set_ext_pri(struct ast_channel *c, const char *exten, int pri)
1993 ast_copy_string(c->exten, exten, sizeof(c->exten));
1994 c->priority = pri;
1998 * \brief collect digits from the channel into the buffer,
1999 * return -1 on error, 0 on timeout or done.
2001 static int collect_digits(struct ast_channel *c, int waittime, char *buf, int buflen, int pos)
2003 int digit;
2005 buf[pos] = '\0'; /* make sure it is properly terminated */
2006 while (ast_matchmore_extension(c, c->context, buf, 1, c->cid.cid_num)) {
2007 /* As long as we're willing to wait, and as long as it's not defined,
2008 keep reading digits until we can't possibly get a right answer anymore. */
2009 digit = ast_waitfordigit(c, waittime * 1000);
2010 if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
2011 c->_softhangup = 0;
2012 } else {
2013 if (!digit) /* No entry */
2014 break;
2015 if (digit < 0) /* Error, maybe a hangup */
2016 return -1;
2017 if (pos < buflen - 1) { /* XXX maybe error otherwise ? */
2018 buf[pos++] = digit;
2019 buf[pos] = '\0';
2021 waittime = c->pbx->dtimeout;
2024 return 0;
2027 static int __ast_pbx_run(struct ast_channel *c)
2029 int found = 0; /* set if we find at least one match */
2030 int res = 0;
2031 int autoloopflag;
2032 int error = 0; /* set an error conditions */
2034 /* A little initial setup here */
2035 if (c->pbx) {
2036 ast_log(LOG_WARNING, "%s already has PBX structure??\n", c->name);
2037 /* XXX and now what ? */
2038 free(c->pbx);
2040 if (!(c->pbx = ast_calloc(1, sizeof(*c->pbx))))
2041 return -1;
2042 if (c->amaflags) {
2043 if (!c->cdr) {
2044 c->cdr = ast_cdr_alloc();
2045 if (!c->cdr) {
2046 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
2047 free(c->pbx);
2048 return -1;
2050 ast_cdr_init(c->cdr, c);
2053 /* Set reasonable defaults */
2054 c->pbx->rtimeout = 10;
2055 c->pbx->dtimeout = 5;
2057 autoloopflag = ast_test_flag(c, AST_FLAG_IN_AUTOLOOP); /* save value to restore at the end */
2058 ast_set_flag(c, AST_FLAG_IN_AUTOLOOP);
2060 /* Start by trying whatever the channel is set to */
2061 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2062 /* If not successful fall back to 's' */
2063 if (option_verbose > 1)
2064 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);
2065 /* XXX the original code used the existing priority in the call to
2066 * ast_exists_extension(), and reset it to 1 afterwards.
2067 * I believe the correct thing is to set it to 1 immediately.
2069 set_ext_pri(c, "s", 1);
2070 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2071 /* JK02: And finally back to default if everything else failed */
2072 if (option_verbose > 1)
2073 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);
2074 ast_copy_string(c->context, "default", sizeof(c->context));
2077 if (c->cdr && ast_tvzero(c->cdr->start))
2078 ast_cdr_start(c->cdr);
2079 for (;;) {
2080 char dst_exten[256]; /* buffer to accumulate digits */
2081 int pos = 0; /* XXX should check bounds */
2082 int digit = 0;
2084 /* loop on priorities in this context/exten */
2085 while (ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2086 found = 1;
2087 if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
2088 /* Something bad happened, or a hangup has been requested. */
2089 if (strchr("0123456789ABCDEF*#", res)) {
2090 ast_log(LOG_DEBUG, "Oooh, got something to jump out with ('%c')!\n", res);
2091 pos = 0;
2092 dst_exten[pos++] = digit = res;
2093 dst_exten[pos] = '\0';
2094 break;
2096 if (res == AST_PBX_KEEPALIVE) {
2097 if (option_debug)
2098 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
2099 else if (option_verbose > 1)
2100 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
2101 error = 1;
2102 break;
2104 if (option_debug)
2105 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2106 else if (option_verbose > 1)
2107 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2108 if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
2109 c->_softhangup =0;
2110 } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
2111 /* atimeout, nothing bad */
2112 } else {
2113 if (c->cdr)
2114 ast_cdr_update(c);
2115 error = 1;
2116 break;
2119 if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT && ast_exists_extension(c,c->context,"T",1,c->cid.cid_num)) {
2120 set_ext_pri(c, "T", 0); /* 0 will become 1 with the c->priority++; at the end */
2121 /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
2122 c->whentohangup = 0;
2123 c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
2124 } else if (c->_softhangup) {
2125 ast_log(LOG_DEBUG, "Extension %s, priority %d returned normally even though call was hung up\n",
2126 c->exten, c->priority);
2127 error = 1;
2128 break;
2130 c->priority++;
2131 } /* end while - from here on we can use 'break' to go out */
2132 if (error)
2133 break;
2135 /* XXX we get here on non-existing extension or a keypress or hangup ? */
2137 if (!ast_exists_extension(c, c->context, c->exten, 1, c->cid.cid_num)) {
2138 /* If there is no match at priority 1, it is not a valid extension anymore.
2139 * Try to continue at "i", 1 or exit if the latter does not exist.
2141 if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
2142 if (option_verbose > 2)
2143 ast_verbose(VERBOSE_PREFIX_3 "Sent into invalid extension '%s' in context '%s' on %s\n", c->exten, c->context, c->name);
2144 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", c->exten);
2145 set_ext_pri(c, "i", 1);
2146 } else {
2147 ast_log(LOG_WARNING, "Channel '%s' sent into invalid extension '%s' in context '%s', but no invalid handler\n",
2148 c->name, c->exten, c->context);
2149 error = 1; /* we know what to do with it */
2150 break;
2152 } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
2153 /* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */
2154 c->_softhangup = 0;
2155 } else { /* keypress received, get more digits for a full extension */
2156 int waittime = 0;
2157 if (digit)
2158 waittime = c->pbx->dtimeout;
2159 else if (!autofallthrough)
2160 waittime = c->pbx->rtimeout;
2161 if (!waittime) {
2162 const char *status = pbx_builtin_getvar_helper(c, "DIALSTATUS");
2163 if (!status)
2164 status = "UNKNOWN";
2165 if (option_verbose > 2)
2166 ast_verbose(VERBOSE_PREFIX_2 "Auto fallthrough, channel '%s' status is '%s'\n", c->name, status);
2167 if (!strcasecmp(status, "CONGESTION"))
2168 res = pbx_builtin_congestion(c, "10");
2169 else if (!strcasecmp(status, "CHANUNAVAIL"))
2170 res = pbx_builtin_congestion(c, "10");
2171 else if (!strcasecmp(status, "BUSY"))
2172 res = pbx_builtin_busy(c, "10");
2173 error = 1; /* XXX disable message */
2174 break; /* exit from the 'for' loop */
2177 if (collect_digits(c, waittime, dst_exten, sizeof(dst_exten), pos))
2178 break;
2179 if (ast_exists_extension(c, c->context, dst_exten, 1, c->cid.cid_num)) /* Prepare the next cycle */
2180 set_ext_pri(c, dst_exten, 1);
2181 else {
2182 /* No such extension */
2183 if (!ast_strlen_zero(dst_exten)) {
2184 /* An invalid extension */
2185 if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
2186 if (option_verbose > 2)
2187 ast_verbose( VERBOSE_PREFIX_3 "Invalid extension '%s' in context '%s' on %s\n", dst_exten, c->context, c->name);
2188 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", dst_exten);
2189 set_ext_pri(c, "i", 1);
2190 } else {
2191 ast_log(LOG_WARNING, "Invalid extension '%s', but no rule 'i' in context '%s'\n", dst_exten, c->context);
2192 found = 1; /* XXX disable message */
2193 break;
2195 } else {
2196 /* A simple timeout */
2197 if (ast_exists_extension(c, c->context, "t", 1, c->cid.cid_num)) {
2198 if (option_verbose > 2)
2199 ast_verbose( VERBOSE_PREFIX_3 "Timeout on %s\n", c->name);
2200 set_ext_pri(c, "t", 1);
2201 } else {
2202 ast_log(LOG_WARNING, "Timeout, but no rule 't' in context '%s'\n", c->context);
2203 found = 1; /* XXX disable message */
2204 break;
2208 if (c->cdr) {
2209 if (option_verbose > 2)
2210 ast_verbose(VERBOSE_PREFIX_2 "CDR updated on %s\n",c->name);
2211 ast_cdr_update(c);
2215 if (!found && !error)
2216 ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", c->name);
2217 if ((res != AST_PBX_KEEPALIVE) && ast_exists_extension(c, c->context, "h", 1, c->cid.cid_num)) {
2218 if (c->cdr && ast_opt_end_cdr_before_h_exten)
2219 ast_cdr_end(c->cdr);
2220 set_ext_pri(c, "h", 1);
2221 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2222 if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
2223 /* Something bad happened, or a hangup has been requested. */
2224 if (option_debug)
2225 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2226 else if (option_verbose > 1)
2227 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2228 break;
2230 c->priority++;
2233 ast_set2_flag(c, autoloopflag, AST_FLAG_IN_AUTOLOOP);
2235 pbx_destroy(c->pbx);
2236 c->pbx = NULL;
2237 if (res != AST_PBX_KEEPALIVE)
2238 ast_hangup(c);
2239 return 0;
2242 /* Returns 0 on success, non-zero if call limit was reached */
2243 static int increase_call_count(const struct ast_channel *c)
2245 int failed = 0;
2246 double curloadavg;
2247 ast_mutex_lock(&maxcalllock);
2248 if (option_maxcalls) {
2249 if (countcalls >= option_maxcalls) {
2250 ast_log(LOG_NOTICE, "Maximum call limit of %d calls exceeded by '%s'!\n", option_maxcalls, c->name);
2251 failed = -1;
2254 if (option_maxload) {
2255 getloadavg(&curloadavg, 1);
2256 if (curloadavg >= option_maxload) {
2257 ast_log(LOG_NOTICE, "Maximum loadavg limit of %f load exceeded by '%s' (currently %f)!\n", option_maxload, c->name, curloadavg);
2258 failed = -1;
2261 if (!failed)
2262 countcalls++;
2263 ast_mutex_unlock(&maxcalllock);
2265 return failed;
2268 static void decrease_call_count(void)
2270 ast_mutex_lock(&maxcalllock);
2271 if (countcalls > 0)
2272 countcalls--;
2273 ast_mutex_unlock(&maxcalllock);
2276 static void destroy_exten(struct ast_exten *e)
2278 if (e->priority == PRIORITY_HINT)
2279 ast_remove_hint(e);
2281 if (e->datad)
2282 e->datad(e->data);
2283 free(e);
2286 static void *pbx_thread(void *data)
2288 /* Oh joyeous kernel, we're a new thread, with nothing to do but
2289 answer this channel and get it going.
2291 /* NOTE:
2292 The launcher of this function _MUST_ increment 'countcalls'
2293 before invoking the function; it will be decremented when the
2294 PBX has finished running on the channel
2296 struct ast_channel *c = data;
2298 __ast_pbx_run(c);
2299 decrease_call_count();
2301 pthread_exit(NULL);
2303 return NULL;
2306 enum ast_pbx_result ast_pbx_start(struct ast_channel *c)
2308 pthread_t t;
2309 pthread_attr_t attr;
2311 if (!c) {
2312 ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
2313 return AST_PBX_FAILED;
2316 if (increase_call_count(c))
2317 return AST_PBX_CALL_LIMIT;
2319 /* Start a new thread, and get something handling this channel. */
2320 pthread_attr_init(&attr);
2321 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
2322 if (ast_pthread_create(&t, &attr, pbx_thread, c)) {
2323 ast_log(LOG_WARNING, "Failed to create new channel thread\n");
2324 return AST_PBX_FAILED;
2327 return AST_PBX_SUCCESS;
2330 enum ast_pbx_result ast_pbx_run(struct ast_channel *c)
2332 enum ast_pbx_result res = AST_PBX_SUCCESS;
2334 if (increase_call_count(c))
2335 return AST_PBX_CALL_LIMIT;
2337 res = __ast_pbx_run(c);
2338 decrease_call_count();
2340 return res;
2343 int ast_active_calls(void)
2345 return countcalls;
2348 int pbx_set_autofallthrough(int newval)
2350 int oldval = autofallthrough;
2351 autofallthrough = newval;
2352 return oldval;
2355 /* lookup for a context with a given name,
2356 * return with conlock held if found, NULL if not found
2358 static struct ast_context *find_context_locked(const char *context)
2360 struct ast_context *c = NULL;
2362 ast_lock_contexts();
2363 while ( (c = ast_walk_contexts(c)) ) {
2364 if (!strcmp(ast_get_context_name(c), context))
2365 return c;
2367 ast_unlock_contexts();
2369 return NULL;
2373 * This function locks contexts list by &conlist, search for the right context
2374 * structure, leave context list locked and call ast_context_remove_include2
2375 * which removes include, unlock contexts list and return ...
2377 int ast_context_remove_include(const char *context, const char *include, const char *registrar)
2379 int ret = -1;
2380 struct ast_context *c = find_context_locked(context);
2382 if (c) {
2383 /* found, remove include from this context ... */
2384 ret = ast_context_remove_include2(c, include, registrar);
2385 ast_unlock_contexts();
2387 return ret;
2391 * When we call this function, &conlock lock must be locked, because when
2392 * we giving *con argument, some process can remove/change this context
2393 * and after that there can be segfault.
2395 * This function locks given context, removes include, unlock context and
2396 * return.
2398 int ast_context_remove_include2(struct ast_context *con, const char *include, const char *registrar)
2400 struct ast_include *i, *pi = NULL;
2401 int ret = -1;
2403 ast_mutex_lock(&con->lock);
2405 /* find our include */
2406 for (i = con->includes; i; pi = i, i = i->next) {
2407 if (!strcmp(i->name, include) &&
2408 (!registrar || !strcmp(i->registrar, registrar))) {
2409 /* remove from list */
2410 if (pi)
2411 pi->next = i->next;
2412 else
2413 con->includes = i->next;
2414 /* free include and return */
2415 free(i);
2416 ret = 0;
2417 break;
2421 ast_mutex_unlock(&con->lock);
2422 return ret;
2426 * \note This function locks contexts list by &conlist, search for the rigt context
2427 * structure, leave context list locked and call ast_context_remove_switch2
2428 * which removes switch, unlock contexts list and return ...
2430 int ast_context_remove_switch(const char *context, const char *sw, const char *data, const char *registrar)
2432 int ret = -1; /* default error return */
2433 struct ast_context *c = find_context_locked(context);
2435 if (c) {
2436 /* remove switch from this context ... */
2437 ret = ast_context_remove_switch2(c, sw, data, registrar);
2438 ast_unlock_contexts();
2440 return ret;
2444 * \brief This function locks given context, removes switch, unlock context and
2445 * return.
2446 * \note When we call this function, &conlock lock must be locked, because when
2447 * we giving *con argument, some process can remove/change this context
2448 * and after that there can be segfault.
2451 int ast_context_remove_switch2(struct ast_context *con, const char *sw, const char *data, const char *registrar)
2453 struct ast_sw *i;
2454 int ret = -1;
2456 ast_mutex_lock(&con->lock);
2458 /* walk switches */
2459 AST_LIST_TRAVERSE_SAFE_BEGIN(&con->alts, i, list) {
2460 if (!strcmp(i->name, sw) && !strcmp(i->data, data) &&
2461 (!registrar || !strcmp(i->registrar, registrar))) {
2462 /* found, remove from list */
2463 AST_LIST_REMOVE_CURRENT(&con->alts, list);
2464 free(i); /* free switch and return */
2465 ret = 0;
2466 break;
2469 AST_LIST_TRAVERSE_SAFE_END
2471 ast_mutex_unlock(&con->lock);
2473 return ret;
2477 * \note This functions lock contexts list, search for the right context,
2478 * call ast_context_remove_extension2, unlock contexts list and return.
2479 * In this function we are using
2481 int ast_context_remove_extension(const char *context, const char *extension, int priority, const char *registrar)
2483 int ret = -1; /* default error return */
2484 struct ast_context *c = find_context_locked(context);
2486 if (c) { /* ... remove extension ... */
2487 ret = ast_context_remove_extension2(c, extension, priority, registrar);
2488 ast_unlock_contexts();
2490 return ret;
2494 * \brief This functionc locks given context, search for the right extension and
2495 * fires out all peer in this extensions with given priority. If priority
2496 * is set to 0, all peers are removed. After that, unlock context and
2497 * return.
2498 * \note When do you want to call this function, make sure that &conlock is locked,
2499 * because some process can handle with your *con context before you lock
2500 * it.
2503 int ast_context_remove_extension2(struct ast_context *con, const char *extension, int priority, const char *registrar)
2505 struct ast_exten *exten, *prev_exten = NULL;
2506 struct ast_exten *peer;
2508 ast_mutex_lock(&con->lock);
2510 /* scan the extension list to find matching extension-registrar */
2511 for (exten = con->root; exten; prev_exten = exten, exten = exten->next) {
2512 if (!strcmp(exten->exten, extension) &&
2513 (!registrar || !strcmp(exten->registrar, registrar)))
2514 break;
2516 if (!exten) {
2517 /* we can't find right extension */
2518 ast_mutex_unlock(&con->lock);
2519 return -1;
2522 /* should we free all peers in this extension? (priority == 0)? */
2523 if (priority == 0) {
2524 /* remove this extension from context list */
2525 if (prev_exten)
2526 prev_exten->next = exten->next;
2527 else
2528 con->root = exten->next;
2530 /* fire out all peers */
2531 while ( (peer = exten) ) {
2532 exten = peer->peer; /* prepare for next entry */
2533 destroy_exten(peer);
2535 } else {
2536 /* scan the priority list to remove extension with exten->priority == priority */
2537 struct ast_exten *previous_peer = NULL;
2539 for (peer = exten; peer; previous_peer = peer, peer = peer->peer) {
2540 if (peer->priority == priority &&
2541 (!registrar || !strcmp(peer->registrar, registrar) ))
2542 break; /* found our priority */
2544 if (!peer) { /* not found */
2545 ast_mutex_unlock(&con->lock);
2546 return -1;
2548 /* we are first priority extension? */
2549 if (!previous_peer) {
2551 * We are first in the priority chain, so must update the extension chain.
2552 * The next node is either the next priority or the next extension
2554 struct ast_exten *next_node = peer->peer ? peer->peer : peer->next;
2556 if (!prev_exten) /* change the root... */
2557 con->root = next_node;
2558 else
2559 prev_exten->next = next_node; /* unlink */
2560 if (peer->peer) /* XXX update the new head of the pri list */
2561 peer->peer->next = peer->next;
2562 } else { /* easy, we are not first priority in extension */
2563 previous_peer->peer = peer->peer;
2566 /* now, free whole priority extension */
2567 destroy_exten(peer);
2568 /* XXX should we return -1 ? */
2570 ast_mutex_unlock(&con->lock);
2571 return 0;
2575 /*! \brief Dynamically register a new dial plan application */
2576 int ast_register_application(const char *app, int (*execute)(struct ast_channel *, void *), const char *synopsis, const char *description)
2578 struct ast_app *tmp, *cur = NULL;
2579 char tmps[80];
2580 int length;
2582 AST_LIST_LOCK(&apps);
2583 AST_LIST_TRAVERSE(&apps, tmp, list) {
2584 if (!strcasecmp(app, tmp->name)) {
2585 ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
2586 AST_LIST_UNLOCK(&apps);
2587 return -1;
2591 length = sizeof(*tmp) + strlen(app) + 1;
2593 if (!(tmp = ast_calloc(1, length))) {
2594 AST_LIST_UNLOCK(&apps);
2595 return -1;
2598 strcpy(tmp->name, app);
2599 tmp->execute = execute;
2600 tmp->synopsis = synopsis;
2601 tmp->description = description;
2603 /* Store in alphabetical order */
2604 AST_LIST_TRAVERSE_SAFE_BEGIN(&apps, cur, list) {
2605 if (strcasecmp(tmp->name, cur->name) < 0) {
2606 AST_LIST_INSERT_BEFORE_CURRENT(&apps, tmp, list);
2607 break;
2610 AST_LIST_TRAVERSE_SAFE_END
2611 if (!cur)
2612 AST_LIST_INSERT_TAIL(&apps, tmp, list);
2614 if (option_verbose > 1)
2615 ast_verbose( VERBOSE_PREFIX_2 "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
2617 AST_LIST_UNLOCK(&apps);
2619 return 0;
2623 * Append to the list. We don't have a tail pointer because we need
2624 * to scan the list anyways to check for duplicates during insertion.
2626 int ast_register_switch(struct ast_switch *sw)
2628 struct ast_switch *tmp;
2630 AST_LIST_LOCK(&switches);
2631 AST_LIST_TRAVERSE(&switches, tmp, list) {
2632 if (!strcasecmp(tmp->name, sw->name)) {
2633 AST_LIST_UNLOCK(&switches);
2634 ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name);
2635 return -1;
2638 AST_LIST_INSERT_TAIL(&switches, sw, list);
2639 AST_LIST_UNLOCK(&switches);
2641 return 0;
2644 void ast_unregister_switch(struct ast_switch *sw)
2646 AST_LIST_LOCK(&switches);
2647 AST_LIST_REMOVE(&switches, sw, list);
2648 AST_LIST_UNLOCK(&switches);
2652 * Help for CLI commands ...
2654 static char show_application_help[] =
2655 "Usage: show application <application> [<application> [<application> [...]]]\n"
2656 " Describes a particular application.\n";
2658 static char show_functions_help[] =
2659 "Usage: show functions [like <text>]\n"
2660 " List builtin functions, optionally only those matching a given string\n";
2662 static char show_function_help[] =
2663 "Usage: show function <function>\n"
2664 " Describe a particular dialplan function.\n";
2666 static char show_applications_help[] =
2667 "Usage: show applications [{like|describing} <text>]\n"
2668 " List applications which are currently available.\n"
2669 " If 'like', <text> will be a substring of the app name\n"
2670 " If 'describing', <text> will be a substring of the description\n";
2672 static char show_dialplan_help[] =
2673 "Usage: show dialplan [exten@][context]\n"
2674 " Show dialplan\n";
2676 static char show_switches_help[] =
2677 "Usage: show switches\n"
2678 " Show registered switches\n";
2680 static char show_hints_help[] =
2681 "Usage: show hints\n"
2682 " Show registered hints\n";
2684 static char show_globals_help[] =
2685 "Usage: show globals\n"
2686 " Show current global dialplan variables and their values\n";
2688 static char set_global_help[] =
2689 "Usage: set global <name> <value>\n"
2690 " Set global dialplan variable <name> to <value>\n";
2694 * IMPLEMENTATION OF CLI FUNCTIONS IS IN THE SAME ORDER AS COMMANDS HELPS
2699 * \brief 'show application' CLI command implementation functions ...
2703 * There is a possibility to show informations about more than one
2704 * application at one time. You can type 'show application Dial Echo' and
2705 * you will see informations about these two applications ...
2707 static char *complete_show_application(const char *line, const char *word, int pos, int state)
2709 struct ast_app *a;
2710 char *ret = NULL;
2711 int which = 0;
2712 int wordlen = strlen(word);
2714 /* return the n-th [partial] matching entry */
2715 AST_LIST_LOCK(&apps);
2716 AST_LIST_TRAVERSE(&apps, a, list) {
2717 if (!strncasecmp(word, a->name, wordlen) && ++which > state)
2718 ret = strdup(a->name);
2720 AST_LIST_UNLOCK(&apps);
2722 return ret;
2725 static int handle_show_application(int fd, int argc, char *argv[])
2727 struct ast_app *a;
2728 int app, no_registered_app = 1;
2730 if (argc < 3)
2731 return RESULT_SHOWUSAGE;
2733 /* ... go through all applications ... */
2734 AST_LIST_LOCK(&apps);
2735 AST_LIST_TRAVERSE(&apps, a, list) {
2736 /* ... compare this application name with all arguments given
2737 * to 'show application' command ... */
2738 for (app = 2; app < argc; app++) {
2739 if (!strcasecmp(a->name, argv[app])) {
2740 /* Maximum number of characters added by terminal coloring is 22 */
2741 char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
2742 char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
2743 int synopsis_size, description_size;
2745 no_registered_app = 0;
2747 if (a->synopsis)
2748 synopsis_size = strlen(a->synopsis) + 23;
2749 else
2750 synopsis_size = strlen("Not available") + 23;
2751 synopsis = alloca(synopsis_size);
2753 if (a->description)
2754 description_size = strlen(a->description) + 23;
2755 else
2756 description_size = strlen("Not available") + 23;
2757 description = alloca(description_size);
2759 if (synopsis && description) {
2760 snprintf(info, 64 + AST_MAX_APP, "\n -= Info about application '%s' =- \n\n", a->name);
2761 term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
2762 term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
2763 term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
2764 term_color(synopsis,
2765 a->synopsis ? a->synopsis : "Not available",
2766 COLOR_CYAN, 0, synopsis_size);
2767 term_color(description,
2768 a->description ? a->description : "Not available",
2769 COLOR_CYAN, 0, description_size);
2771 ast_cli(fd,"%s%s%s\n\n%s%s\n", infotitle, syntitle, synopsis, destitle, description);
2772 } else {
2773 /* ... one of our applications, show info ...*/
2774 ast_cli(fd,"\n -= Info about application '%s' =- \n\n"
2775 "[Synopsis]\n %s\n\n"
2776 "[Description]\n%s\n",
2777 a->name,
2778 a->synopsis ? a->synopsis : "Not available",
2779 a->description ? a->description : "Not available");
2784 AST_LIST_UNLOCK(&apps);
2786 /* we found at least one app? no? */
2787 if (no_registered_app) {
2788 ast_cli(fd, "Your application(s) is (are) not registered\n");
2789 return RESULT_FAILURE;
2792 return RESULT_SUCCESS;
2795 /*! \brief handle_show_hints: CLI support for listing registred dial plan hints */
2796 static int handle_show_hints(int fd, int argc, char *argv[])
2798 struct ast_hint *hint;
2799 int num = 0;
2800 int watchers;
2801 struct ast_state_cb *watcher;
2803 if (AST_LIST_EMPTY(&hints)) {
2804 ast_cli(fd, "There are no registered dialplan hints\n");
2805 return RESULT_SUCCESS;
2807 /* ... we have hints ... */
2808 ast_cli(fd, "\n -= Registered Asterisk Dial Plan Hints =-\n");
2809 AST_LIST_LOCK(&hints);
2810 AST_LIST_TRAVERSE(&hints, hint, list) {
2811 watchers = 0;
2812 for (watcher = hint->callbacks; watcher; watcher = watcher->next)
2813 watchers++;
2814 ast_cli(fd, " %20s@%-20.20s: %-20.20s State:%-15.15s Watchers %2d\n",
2815 ast_get_extension_name(hint->exten),
2816 ast_get_context_name(ast_get_extension_context(hint->exten)),
2817 ast_get_extension_app(hint->exten),
2818 ast_extension_state2str(hint->laststate), watchers);
2819 num++;
2821 ast_cli(fd, "----------------\n");
2822 ast_cli(fd, "- %d hints registered\n", num);
2823 AST_LIST_UNLOCK(&hints);
2824 return RESULT_SUCCESS;
2827 /*! \brief handle_show_switches: CLI support for listing registred dial plan switches */
2828 static int handle_show_switches(int fd, int argc, char *argv[])
2830 struct ast_switch *sw;
2832 AST_LIST_LOCK(&switches);
2834 if (AST_LIST_EMPTY(&switches)) {
2835 AST_LIST_UNLOCK(&switches);
2836 ast_cli(fd, "There are no registered alternative switches\n");
2837 return RESULT_SUCCESS;
2840 ast_cli(fd, "\n -= Registered Asterisk Alternative Switches =-\n");
2841 AST_LIST_TRAVERSE(&switches, sw, list)
2842 ast_cli(fd, "%s: %s\n", sw->name, sw->description);
2844 AST_LIST_UNLOCK(&switches);
2846 return RESULT_SUCCESS;
2850 * 'show applications' CLI command implementation functions ...
2852 static int handle_show_applications(int fd, int argc, char *argv[])
2854 struct ast_app *a;
2855 int like = 0, describing = 0;
2856 int total_match = 0; /* Number of matches in like clause */
2857 int total_apps = 0; /* Number of apps registered */
2859 AST_LIST_LOCK(&apps);
2861 if (AST_LIST_EMPTY(&apps)) {
2862 ast_cli(fd, "There are no registered applications\n");
2863 AST_LIST_UNLOCK(&apps);
2864 return -1;
2867 /* show applications like <keyword> */
2868 if ((argc == 4) && (!strcmp(argv[2], "like"))) {
2869 like = 1;
2870 } else if ((argc > 3) && (!strcmp(argv[2], "describing"))) {
2871 describing = 1;
2874 /* show applications describing <keyword1> [<keyword2>] [...] */
2875 if ((!like) && (!describing)) {
2876 ast_cli(fd, " -= Registered Asterisk Applications =-\n");
2877 } else {
2878 ast_cli(fd, " -= Matching Asterisk Applications =-\n");
2881 AST_LIST_TRAVERSE(&apps, a, list) {
2882 int printapp = 0;
2883 total_apps++;
2884 if (like) {
2885 if (strcasestr(a->name, argv[3])) {
2886 printapp = 1;
2887 total_match++;
2889 } else if (describing) {
2890 if (a->description) {
2891 /* Match all words on command line */
2892 int i;
2893 printapp = 1;
2894 for (i = 3; i < argc; i++) {
2895 if (!strcasestr(a->description, argv[i])) {
2896 printapp = 0;
2897 } else {
2898 total_match++;
2902 } else {
2903 printapp = 1;
2906 if (printapp) {
2907 ast_cli(fd," %20s: %s\n", a->name, a->synopsis ? a->synopsis : "<Synopsis not available>");
2910 if ((!like) && (!describing)) {
2911 ast_cli(fd, " -= %d Applications Registered =-\n",total_apps);
2912 } else {
2913 ast_cli(fd, " -= %d Applications Matching =-\n",total_match);
2916 AST_LIST_UNLOCK(&apps);
2918 return RESULT_SUCCESS;
2921 static char *complete_show_applications(const char *line, const char *word, int pos, int state)
2923 static char* choices[] = { "like", "describing", NULL };
2925 return (pos != 2) ? NULL : ast_cli_complete(word, choices, state);
2929 * 'show dialplan' CLI command implementation functions ...
2931 static char *complete_show_dialplan_context(const char *line, const char *word, int pos,
2932 int state)
2934 struct ast_context *c = NULL;
2935 char *ret = NULL;
2936 int which = 0;
2937 int wordlen;
2939 /* we are do completion of [exten@]context on second position only */
2940 if (pos != 2)
2941 return NULL;
2943 ast_lock_contexts();
2945 wordlen = strlen(word);
2947 /* walk through all contexts and return the n-th match */
2948 while ( (c = ast_walk_contexts(c)) ) {
2949 if (!strncasecmp(word, ast_get_context_name(c), wordlen) && ++which > state) {
2950 ret = ast_strdup(ast_get_context_name(c));
2951 break;
2955 ast_unlock_contexts();
2957 return ret;
2960 struct dialplan_counters {
2961 int total_context;
2962 int total_exten;
2963 int total_prio;
2964 int context_existence;
2965 int extension_existence;
2968 /*! \brief helper function to print an extension */
2969 static void print_ext(struct ast_exten *e, char * buf, int buflen)
2971 int prio = ast_get_extension_priority(e);
2972 if (prio == PRIORITY_HINT) {
2973 snprintf(buf, buflen, "hint: %s",
2974 ast_get_extension_app(e));
2975 } else {
2976 snprintf(buf, buflen, "%d. %s(%s)",
2977 prio, ast_get_extension_app(e),
2978 (char *)ast_get_extension_app_data(e));
2982 /* XXX not verified */
2983 static int show_dialplan_helper(int fd, const char *context, const char *exten, struct dialplan_counters *dpc, struct ast_include *rinclude, int includecount, const char *includes[])
2985 struct ast_context *c = NULL;
2986 int res = 0, old_total_exten = dpc->total_exten;
2988 ast_lock_contexts();
2990 /* walk all contexts ... */
2991 while ( (c = ast_walk_contexts(c)) ) {
2992 struct ast_exten *e;
2993 struct ast_include *i;
2994 struct ast_ignorepat *ip;
2995 char buf[256], buf2[256];
2996 int context_info_printed = 0;
2998 if (context && strcmp(ast_get_context_name(c), context))
2999 continue; /* skip this one, name doesn't match */
3001 dpc->context_existence = 1;
3003 ast_lock_context(c);
3005 /* are we looking for exten too? if yes, we print context
3006 * only if we find our extension.
3007 * Otherwise print context even if empty ?
3008 * XXX i am not sure how the rinclude is handled.
3009 * I think it ought to go inside.
3011 if (!exten) {
3012 dpc->total_context++;
3013 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
3014 ast_get_context_name(c), ast_get_context_registrar(c));
3015 context_info_printed = 1;
3018 /* walk extensions ... */
3019 e = NULL;
3020 while ( (e = ast_walk_context_extensions(c, e)) ) {
3021 struct ast_exten *p;
3023 if (exten && !ast_extension_match(ast_get_extension_name(e), exten))
3024 continue; /* skip, extension match failed */
3026 dpc->extension_existence = 1;
3028 /* may we print context info? */
3029 if (!context_info_printed) {
3030 dpc->total_context++;
3031 if (rinclude) { /* TODO Print more info about rinclude */
3032 ast_cli(fd, "[ Included context '%s' created by '%s' ]\n",
3033 ast_get_context_name(c), ast_get_context_registrar(c));
3034 } else {
3035 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
3036 ast_get_context_name(c), ast_get_context_registrar(c));
3038 context_info_printed = 1;
3040 dpc->total_prio++;
3042 /* write extension name and first peer */
3043 snprintf(buf, sizeof(buf), "'%s' =>", ast_get_extension_name(e));
3045 print_ext(e, buf2, sizeof(buf2));
3047 ast_cli(fd, " %-17s %-45s [%s]\n", buf, buf2,
3048 ast_get_extension_registrar(e));
3050 dpc->total_exten++;
3051 /* walk next extension peers */
3052 p = e; /* skip the first one, we already got it */
3053 while ( (p = ast_walk_extension_priorities(e, p)) ) {
3054 const char *el = ast_get_extension_label(p);
3055 dpc->total_prio++;
3056 if (el)
3057 snprintf(buf, sizeof(buf), " [%s]", el);
3058 else
3059 buf[0] = '\0';
3060 print_ext(p, buf2, sizeof(buf2));
3062 ast_cli(fd," %-17s %-45s [%s]\n", buf, buf2,
3063 ast_get_extension_registrar(p));
3067 /* walk included and write info ... */
3068 i = NULL;
3069 while ( (i = ast_walk_context_includes(c, i)) ) {
3070 snprintf(buf, sizeof(buf), "'%s'", ast_get_include_name(i));
3071 if (exten) {
3072 /* Check all includes for the requested extension */
3073 if (includecount >= AST_PBX_MAX_STACK) {
3074 ast_log(LOG_NOTICE, "Maximum include depth exceeded!\n");
3075 } else {
3076 int dupe=0;
3077 int x;
3078 for (x=0;x<includecount;x++) {
3079 if (!strcasecmp(includes[x], ast_get_include_name(i))) {
3080 dupe++;
3081 break;
3084 if (!dupe) {
3085 includes[includecount] = ast_get_include_name(i);
3086 show_dialplan_helper(fd, ast_get_include_name(i), exten, dpc, i, includecount + 1, includes);
3087 } else {
3088 ast_log(LOG_WARNING, "Avoiding circular include of %s within %s\n", ast_get_include_name(i), context);
3091 } else {
3092 ast_cli(fd, " Include => %-45s [%s]\n",
3093 buf, ast_get_include_registrar(i));
3097 /* walk ignore patterns and write info ... */
3098 ip = NULL;
3099 while ( (ip = ast_walk_context_ignorepats(c, ip)) ) {
3100 const char *ipname = ast_get_ignorepat_name(ip);
3101 char ignorepat[AST_MAX_EXTENSION];
3102 snprintf(buf, sizeof(buf), "'%s'", ipname);
3103 snprintf(ignorepat, sizeof(ignorepat), "_%s.", ipname);
3104 if (!exten || ast_extension_match(ignorepat, exten)) {
3105 ast_cli(fd, " Ignore pattern => %-45s [%s]\n",
3106 buf, ast_get_ignorepat_registrar(ip));
3109 if (!rinclude) {
3110 struct ast_sw *sw = NULL;
3111 while ( (sw = ast_walk_context_switches(c, sw)) ) {
3112 snprintf(buf, sizeof(buf), "'%s/%s'",
3113 ast_get_switch_name(sw),
3114 ast_get_switch_data(sw));
3115 ast_cli(fd, " Alt. Switch => %-45s [%s]\n",
3116 buf, ast_get_switch_registrar(sw));
3120 ast_unlock_context(c);
3122 /* if we print something in context, make an empty line */
3123 if (context_info_printed)
3124 ast_cli(fd, "\r\n");
3126 ast_unlock_contexts();
3128 return (dpc->total_exten == old_total_exten) ? -1 : res;
3131 static int handle_show_dialplan(int fd, int argc, char *argv[])
3133 char *exten = NULL, *context = NULL;
3134 /* Variables used for different counters */
3135 struct dialplan_counters counters;
3137 const char *incstack[AST_PBX_MAX_STACK];
3138 memset(&counters, 0, sizeof(counters));
3140 if (argc != 2 && argc != 3)
3141 return RESULT_SHOWUSAGE;
3143 /* we obtain [exten@]context? if yes, split them ... */
3144 if (argc == 3) {
3145 if (strchr(argv[2], '@')) { /* split into exten & context */
3146 context = ast_strdupa(argv[2]);
3147 exten = strsep(&context, "@");
3148 /* change empty strings to NULL */
3149 if (ast_strlen_zero(exten))
3150 exten = NULL;
3151 } else { /* no '@' char, only context given */
3152 context = argv[2];
3154 if (ast_strlen_zero(context))
3155 context = NULL;
3157 /* else Show complete dial plan, context and exten are NULL */
3158 show_dialplan_helper(fd, context, exten, &counters, NULL, 0, incstack);
3160 /* check for input failure and throw some error messages */
3161 if (context && !counters.context_existence) {
3162 ast_cli(fd, "There is no existence of '%s' context\n", context);
3163 return RESULT_FAILURE;
3166 if (exten && !counters.extension_existence) {
3167 if (context)
3168 ast_cli(fd, "There is no existence of %s@%s extension\n",
3169 exten, context);
3170 else
3171 ast_cli(fd,
3172 "There is no existence of '%s' extension in all contexts\n",
3173 exten);
3174 return RESULT_FAILURE;
3177 ast_cli(fd,"-= %d %s (%d %s) in %d %s. =-\n",
3178 counters.total_exten, counters.total_exten == 1 ? "extension" : "extensions",
3179 counters.total_prio, counters.total_prio == 1 ? "priority" : "priorities",
3180 counters.total_context, counters.total_context == 1 ? "context" : "contexts");
3182 /* everything ok */
3183 return RESULT_SUCCESS;
3186 /*! \brief CLI support for listing global variables in a parseable way */
3187 static int handle_show_globals(int fd, int argc, char *argv[])
3189 int i = 0;
3190 struct ast_var_t *newvariable;
3192 ast_mutex_lock(&globalslock);
3193 AST_LIST_TRAVERSE (&globals, newvariable, entries) {
3194 i++;
3195 ast_cli(fd, " %s=%s\n", ast_var_name(newvariable), ast_var_value(newvariable));
3197 ast_mutex_unlock(&globalslock);
3198 ast_cli(fd, "\n -- %d variables\n", i);
3200 return RESULT_SUCCESS;
3203 /*! \brief CLI support for setting global variables */
3204 static int handle_set_global(int fd, int argc, char *argv[])
3206 if (argc != 4)
3207 return RESULT_SHOWUSAGE;
3209 pbx_builtin_setvar_helper(NULL, argv[2], argv[3]);
3210 ast_cli(fd, "\n -- Global variable %s set to %s\n", argv[2], argv[3]);
3212 return RESULT_SUCCESS;
3218 * CLI entries for upper commands ...
3220 static struct ast_cli_entry pbx_cli[] = {
3221 { { "show", "applications", NULL }, handle_show_applications,
3222 "Shows registered dialplan applications", show_applications_help, complete_show_applications },
3223 { { "show", "functions", NULL }, handle_show_functions,
3224 "Shows registered dialplan functions", show_functions_help },
3225 { { "show" , "function", NULL }, handle_show_function,
3226 "Describe a specific dialplan function", show_function_help, complete_show_function },
3227 { { "show", "application", NULL }, handle_show_application,
3228 "Describe a specific dialplan application", show_application_help, complete_show_application },
3229 { { "show", "dialplan", NULL }, handle_show_dialplan,
3230 "Show dialplan", show_dialplan_help, complete_show_dialplan_context },
3231 { { "show", "switches", NULL }, handle_show_switches,
3232 "Show alternative switches", show_switches_help },
3233 { { "show", "hints", NULL }, handle_show_hints,
3234 "Show dialplan hints", show_hints_help },
3235 { { "show", "globals", NULL }, handle_show_globals,
3236 "Show global dialplan variables", show_globals_help },
3237 { { "set", "global", NULL }, handle_set_global,
3238 "Set global dialplan variable", set_global_help },
3241 int ast_unregister_application(const char *app)
3243 struct ast_app *tmp;
3245 AST_LIST_LOCK(&apps);
3246 AST_LIST_TRAVERSE_SAFE_BEGIN(&apps, tmp, list) {
3247 if (!strcasecmp(app, tmp->name)) {
3248 AST_LIST_REMOVE_CURRENT(&apps, list);
3249 if (option_verbose > 1)
3250 ast_verbose( VERBOSE_PREFIX_2 "Unregistered application '%s'\n", tmp->name);
3251 free(tmp);
3252 break;
3255 AST_LIST_TRAVERSE_SAFE_END
3256 AST_LIST_UNLOCK(&apps);
3258 return tmp ? 0 : -1;
3261 struct ast_context *ast_context_create(struct ast_context **extcontexts, const char *name, const char *registrar)
3263 struct ast_context *tmp, **local_contexts;
3264 int length;
3265 length = sizeof(struct ast_context);
3266 length += strlen(name) + 1;
3267 if (!extcontexts) {
3268 local_contexts = &contexts;
3269 ast_mutex_lock(&conlock);
3270 } else
3271 local_contexts = extcontexts;
3273 for (tmp = *local_contexts; tmp; tmp = tmp->next) {
3274 if (!strcasecmp(tmp->name, name)) {
3275 ast_mutex_unlock(&conlock);
3276 ast_log(LOG_WARNING, "Tried to register context '%s', already in use\n", name);
3277 if (!extcontexts)
3278 ast_mutex_unlock(&conlock);
3279 return NULL;
3282 if ((tmp = ast_calloc(1, length))) {
3283 ast_mutex_init(&tmp->lock);
3284 strcpy(tmp->name, name);
3285 tmp->root = NULL;
3286 tmp->registrar = registrar;
3287 tmp->next = *local_contexts;
3288 tmp->includes = NULL;
3289 tmp->ignorepats = NULL;
3290 *local_contexts = tmp;
3291 if (option_debug)
3292 ast_log(LOG_DEBUG, "Registered context '%s'\n", tmp->name);
3293 else if (option_verbose > 2)
3294 ast_verbose( VERBOSE_PREFIX_3 "Registered extension context '%s'\n", tmp->name);
3297 if (!extcontexts)
3298 ast_mutex_unlock(&conlock);
3299 return tmp;
3302 void __ast_context_destroy(struct ast_context *con, const char *registrar);
3304 struct store_hint {
3305 char *context;
3306 char *exten;
3307 struct ast_state_cb *callbacks;
3308 int laststate;
3309 AST_LIST_ENTRY(store_hint) list;
3310 char data[1];
3313 AST_LIST_HEAD(store_hints, store_hint);
3315 /* XXX this does not check that multiple contexts are merged */
3316 void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char *registrar)
3318 struct ast_context *tmp, *lasttmp = NULL;
3319 struct store_hints store;
3320 struct store_hint *this;
3321 struct ast_hint *hint;
3322 struct ast_exten *exten;
3323 int length;
3324 struct ast_state_cb *thiscb, *prevcb;
3326 AST_LIST_HEAD_INIT(&store);
3328 /* it is very important that this function hold the hint list lock _and_ the conlock
3329 during its operation; not only do we need to ensure that the list of contexts
3330 and extensions does not change, but also that no hint callbacks (watchers) are
3331 added or removed during the merge/delete process
3333 in addition, the locks _must_ be taken in this order, because there are already
3334 other code paths that use this order
3336 ast_mutex_lock(&conlock);
3337 AST_LIST_LOCK(&hints);
3339 /* preserve all watchers for hints associated with this registrar */
3340 AST_LIST_TRAVERSE(&hints, hint, list) {
3341 if (hint->callbacks && !strcmp(registrar, hint->exten->parent->registrar)) {
3342 length = strlen(hint->exten->exten) + strlen(hint->exten->parent->name) + 2 + sizeof(*this);
3343 if (!(this = ast_calloc(1, length)))
3344 continue;
3345 this->callbacks = hint->callbacks;
3346 hint->callbacks = NULL;
3347 this->laststate = hint->laststate;
3348 this->context = this->data;
3349 strcpy(this->data, hint->exten->parent->name);
3350 this->exten = this->data + strlen(this->context) + 1;
3351 strcpy(this->exten, hint->exten->exten);
3352 AST_LIST_INSERT_HEAD(&store, this, list);
3356 tmp = *extcontexts;
3357 if (registrar) {
3358 /* XXX remove previous contexts from same registrar */
3359 ast_log(LOG_DEBUG, "must remove any reg %s\n", registrar);
3360 __ast_context_destroy(NULL,registrar);
3361 while (tmp) {
3362 lasttmp = tmp;
3363 tmp = tmp->next;
3365 } else {
3366 /* XXX remove contexts with the same name */
3367 while (tmp) {
3368 ast_log(LOG_WARNING, "must remove %s reg %s\n", tmp->name, tmp->registrar);
3369 __ast_context_destroy(tmp,tmp->registrar);
3370 lasttmp = tmp;
3371 tmp = tmp->next;
3374 if (lasttmp) {
3375 lasttmp->next = contexts;
3376 contexts = *extcontexts;
3377 *extcontexts = NULL;
3378 } else
3379 ast_log(LOG_WARNING, "Requested contexts didn't get merged\n");
3381 /* restore the watchers for hints that can be found; notify those that
3382 cannot be restored
3384 while ((this = AST_LIST_REMOVE_HEAD(&store, list))) {
3385 exten = ast_hint_extension(NULL, this->context, this->exten);
3386 /* Find the hint in the list of hints */
3387 AST_LIST_TRAVERSE(&hints, hint, list) {
3388 if (hint->exten == exten)
3389 break;
3391 if (!exten || !hint) {
3392 /* this hint has been removed, notify the watchers */
3393 prevcb = NULL;
3394 thiscb = this->callbacks;
3395 while (thiscb) {
3396 prevcb = thiscb;
3397 thiscb = thiscb->next;
3398 prevcb->callback(this->context, this->exten, AST_EXTENSION_REMOVED, prevcb->data);
3399 free(prevcb);
3401 } else {
3402 thiscb = this->callbacks;
3403 while (thiscb->next)
3404 thiscb = thiscb->next;
3405 thiscb->next = hint->callbacks;
3406 hint->callbacks = this->callbacks;
3407 hint->laststate = this->laststate;
3409 free(this);
3412 AST_LIST_UNLOCK(&hints);
3413 ast_mutex_unlock(&conlock);
3415 return;
3419 * errno values
3420 * EBUSY - can't lock
3421 * ENOENT - no existence of context
3423 int ast_context_add_include(const char *context, const char *include, const char *registrar)
3425 int ret = -1;
3426 struct ast_context *c = find_context_locked(context);
3428 if (c) {
3429 ret = ast_context_add_include2(c, include, registrar);
3430 ast_unlock_contexts();
3432 return ret;
3435 /*! \brief Helper for get_range.
3436 * return the index of the matching entry, starting from 1.
3437 * If names is not supplied, try numeric values.
3439 static int lookup_name(const char *s, char *const names[], int max)
3441 int i;
3443 if (names) {
3444 for (i = 0; names[i]; i++) {
3445 if (!strcasecmp(s, names[i]))
3446 return i+1;
3448 } else if (sscanf(s, "%d", &i) == 1 && i >= 1 && i <= max) {
3449 return i;
3451 return 0; /* error return */
3454 /*! \brief helper function to return a range up to max (7, 12, 31 respectively).
3455 * names, if supplied, is an array of names that should be mapped to numbers.
3457 static unsigned get_range(char *src, int max, char *const names[], const char *msg)
3459 int s, e; /* start and ending position */
3460 unsigned int mask = 0;
3462 /* Check for whole range */
3463 if (ast_strlen_zero(src) || !strcmp(src, "*")) {
3464 s = 0;
3465 e = max - 1;
3466 } else {
3467 /* Get start and ending position */
3468 char *c = strchr(src, '-');
3469 if (c)
3470 *c++ = '\0';
3471 /* Find the start */
3472 s = lookup_name(src, names, max);
3473 if (!s) {
3474 ast_log(LOG_WARNING, "Invalid %s '%s', assuming none\n", msg, src);
3475 return 0;
3477 s--;
3478 if (c) { /* find end of range */
3479 e = lookup_name(c, names, max);
3480 if (!e) {
3481 ast_log(LOG_WARNING, "Invalid end %s '%s', assuming none\n", msg, c);
3482 return 0;
3484 e--;
3485 } else
3486 e = s;
3488 /* Fill the mask. Remember that ranges are cyclic */
3489 mask = 1 << e; /* initialize with last element */
3490 while (s != e) {
3491 if (s >= max) {
3492 s = 0;
3493 mask |= (1 << s);
3494 } else {
3495 mask |= (1 << s);
3496 s++;
3499 return mask;
3502 /*! \brief store a bitmask of valid times, one bit each 2 minute */
3503 static void get_timerange(struct ast_timing *i, char *times)
3505 char *e;
3506 int x;
3507 int s1, s2;
3508 int e1, e2;
3509 /* int cth, ctm; */
3511 /* start disabling all times, fill the fields with 0's, as they may contain garbage */
3512 memset(i->minmask, 0, sizeof(i->minmask));
3514 /* 2-minutes per bit, since the mask has only 32 bits :( */
3515 /* Star is all times */
3516 if (ast_strlen_zero(times) || !strcmp(times, "*")) {
3517 for (x=0; x<24; x++)
3518 i->minmask[x] = 0x3fffffff; /* 30 bits */
3519 return;
3521 /* Otherwise expect a range */
3522 e = strchr(times, '-');
3523 if (!e) {
3524 ast_log(LOG_WARNING, "Time range is not valid. Assuming no restrictions based on time.\n");
3525 return;
3527 *e++ = '\0';
3528 /* XXX why skip non digits ? */
3529 while (*e && !isdigit(*e))
3530 e++;
3531 if (!*e) {
3532 ast_log(LOG_WARNING, "Invalid time range. Assuming no restrictions based on time.\n");
3533 return;
3535 if (sscanf(times, "%d:%d", &s1, &s2) != 2) {
3536 ast_log(LOG_WARNING, "%s isn't a time. Assuming no restrictions based on time.\n", times);
3537 return;
3539 if (sscanf(e, "%d:%d", &e1, &e2) != 2) {
3540 ast_log(LOG_WARNING, "%s isn't a time. Assuming no restrictions based on time.\n", e);
3541 return;
3543 /* XXX this needs to be optimized */
3544 #if 1
3545 s1 = s1 * 30 + s2/2;
3546 if ((s1 < 0) || (s1 >= 24*30)) {
3547 ast_log(LOG_WARNING, "%s isn't a valid start time. Assuming no time.\n", times);
3548 return;
3550 e1 = e1 * 30 + e2/2;
3551 if ((e1 < 0) || (e1 >= 24*30)) {
3552 ast_log(LOG_WARNING, "%s isn't a valid end time. Assuming no time.\n", e);
3553 return;
3555 /* Go through the time and enable each appropriate bit */
3556 for (x=s1;x != e1;x = (x + 1) % (24 * 30)) {
3557 i->minmask[x/30] |= (1 << (x % 30));
3559 /* Do the last one */
3560 i->minmask[x/30] |= (1 << (x % 30));
3561 #else
3562 for (cth=0; cth<24; cth++) {
3563 /* Initialize masks to blank */
3564 i->minmask[cth] = 0;
3565 for (ctm=0; ctm<30; ctm++) {
3566 if (
3567 /* First hour with more than one hour */
3568 (((cth == s1) && (ctm >= s2)) &&
3569 ((cth < e1)))
3570 /* Only one hour */
3571 || (((cth == s1) && (ctm >= s2)) &&
3572 ((cth == e1) && (ctm <= e2)))
3573 /* In between first and last hours (more than 2 hours) */
3574 || ((cth > s1) &&
3575 (cth < e1))
3576 /* Last hour with more than one hour */
3577 || ((cth > s1) &&
3578 ((cth == e1) && (ctm <= e2)))
3580 i->minmask[cth] |= (1 << (ctm / 2));
3583 #endif
3584 /* All done */
3585 return;
3588 static char *days[] =
3590 "sun",
3591 "mon",
3592 "tue",
3593 "wed",
3594 "thu",
3595 "fri",
3596 "sat",
3597 NULL,
3600 static char *months[] =
3602 "jan",
3603 "feb",
3604 "mar",
3605 "apr",
3606 "may",
3607 "jun",
3608 "jul",
3609 "aug",
3610 "sep",
3611 "oct",
3612 "nov",
3613 "dec",
3614 NULL,
3617 int ast_build_timing(struct ast_timing *i, const char *info_in)
3619 char info_save[256];
3620 char *info;
3622 /* Check for empty just in case */
3623 if (ast_strlen_zero(info_in))
3624 return 0;
3625 /* make a copy just in case we were passed a static string */
3626 ast_copy_string(info_save, info_in, sizeof(info_save));
3627 info = info_save;
3628 /* Assume everything except time */
3629 i->monthmask = 0xfff; /* 12 bits */
3630 i->daymask = 0x7fffffffU; /* 31 bits */
3631 i->dowmask = 0x7f; /* 7 bits */
3632 /* on each call, use strsep() to move info to the next argument */
3633 get_timerange(i, strsep(&info, "|"));
3634 if (info)
3635 i->dowmask = get_range(strsep(&info, "|"), 7, days, "day of week");
3636 if (info)
3637 i->daymask = get_range(strsep(&info, "|"), 31, NULL, "day");
3638 if (info)
3639 i->monthmask = get_range(strsep(&info, "|"), 12, months, "month");
3640 return 1;
3643 int ast_check_timing(const struct ast_timing *i)
3645 struct tm tm;
3646 time_t t = time(NULL);
3648 localtime_r(&t,&tm);
3650 /* If it's not the right month, return */
3651 if (!(i->monthmask & (1 << tm.tm_mon)))
3652 return 0;
3654 /* If it's not that time of the month.... */
3655 /* Warning, tm_mday has range 1..31! */
3656 if (!(i->daymask & (1 << (tm.tm_mday-1))))
3657 return 0;
3659 /* If it's not the right day of the week */
3660 if (!(i->dowmask & (1 << tm.tm_wday)))
3661 return 0;
3663 /* Sanity check the hour just to be safe */
3664 if ((tm.tm_hour < 0) || (tm.tm_hour > 23)) {
3665 ast_log(LOG_WARNING, "Insane time...\n");
3666 return 0;
3669 /* Now the tough part, we calculate if it fits
3670 in the right time based on min/hour */
3671 if (!(i->minmask[tm.tm_hour] & (1 << (tm.tm_min / 2))))
3672 return 0;
3674 /* If we got this far, then we're good */
3675 return 1;
3679 * errno values
3680 * ENOMEM - out of memory
3681 * EBUSY - can't lock
3682 * EEXIST - already included
3683 * EINVAL - there is no existence of context for inclusion
3685 int ast_context_add_include2(struct ast_context *con, const char *value,
3686 const char *registrar)
3688 struct ast_include *new_include;
3689 char *c;
3690 struct ast_include *i, *il = NULL; /* include, include_last */
3691 int length;
3692 char *p;
3694 length = sizeof(struct ast_include);
3695 length += 2 * (strlen(value) + 1);
3697 /* allocate new include structure ... */
3698 if (!(new_include = ast_calloc(1, length)))
3699 return -1;
3700 /* Fill in this structure. Use 'p' for assignments, as the fields
3701 * in the structure are 'const char *'
3703 p = new_include->stuff;
3704 new_include->name = p;
3705 strcpy(p, value);
3706 p += strlen(value) + 1;
3707 new_include->rname = p;
3708 strcpy(p, value);
3709 /* Strip off timing info, and process if it is there */
3710 if ( (c = strchr(p, '|')) ) {
3711 *c++ = '\0';
3712 new_include->hastime = ast_build_timing(&(new_include->timing), c);
3714 new_include->next = NULL;
3715 new_include->registrar = registrar;
3717 ast_mutex_lock(&con->lock);
3719 /* ... go to last include and check if context is already included too... */
3720 for (i = con->includes; i; i = i->next) {
3721 if (!strcasecmp(i->name, new_include->name)) {
3722 free(new_include);
3723 ast_mutex_unlock(&con->lock);
3724 errno = EEXIST;
3725 return -1;
3727 il = i;
3730 /* ... include new context into context list, unlock, return */
3731 if (il)
3732 il->next = new_include;
3733 else
3734 con->includes = new_include;
3735 if (option_verbose > 2)
3736 ast_verbose(VERBOSE_PREFIX_3 "Including context '%s' in context '%s'\n", new_include->name, ast_get_context_name(con));
3737 ast_mutex_unlock(&con->lock);
3739 return 0;
3743 * errno values
3744 * EBUSY - can't lock
3745 * ENOENT - no existence of context
3747 int ast_context_add_switch(const char *context, const char *sw, const char *data, int eval, const char *registrar)
3749 int ret = -1;
3750 struct ast_context *c = find_context_locked(context);
3752 if (c) { /* found, add switch to this context */
3753 ret = ast_context_add_switch2(c, sw, data, eval, registrar);
3754 ast_unlock_contexts();
3756 return ret;
3760 * errno values
3761 * ENOMEM - out of memory
3762 * EBUSY - can't lock
3763 * EEXIST - already included
3764 * EINVAL - there is no existence of context for inclusion
3766 int ast_context_add_switch2(struct ast_context *con, const char *value,
3767 const char *data, int eval, const char *registrar)
3769 struct ast_sw *new_sw;
3770 struct ast_sw *i;
3771 int length;
3772 char *p;
3774 length = sizeof(struct ast_sw);
3775 length += strlen(value) + 1;
3776 if (data)
3777 length += strlen(data);
3778 length++;
3779 if (eval) {
3780 /* Create buffer for evaluation of variables */
3781 length += SWITCH_DATA_LENGTH;
3782 length++;
3785 /* allocate new sw structure ... */
3786 if (!(new_sw = ast_calloc(1, length)))
3787 return -1;
3788 /* ... fill in this structure ... */
3789 p = new_sw->stuff;
3790 new_sw->name = p;
3791 strcpy(new_sw->name, value);
3792 p += strlen(value) + 1;
3793 new_sw->data = p;
3794 if (data) {
3795 strcpy(new_sw->data, data);
3796 p += strlen(data) + 1;
3797 } else {
3798 strcpy(new_sw->data, "");
3799 p++;
3801 if (eval)
3802 new_sw->tmpdata = p;
3803 new_sw->eval = eval;
3804 new_sw->registrar = registrar;
3806 /* ... try to lock this context ... */
3807 ast_mutex_lock(&con->lock);
3809 /* ... go to last sw and check if context is already swd too... */
3810 AST_LIST_TRAVERSE(&con->alts, i, list) {
3811 if (!strcasecmp(i->name, new_sw->name) && !strcasecmp(i->data, new_sw->data)) {
3812 free(new_sw);
3813 ast_mutex_unlock(&con->lock);
3814 errno = EEXIST;
3815 return -1;
3819 /* ... sw new context into context list, unlock, return */
3820 AST_LIST_INSERT_TAIL(&con->alts, new_sw, list);
3822 if (option_verbose > 2)
3823 ast_verbose(VERBOSE_PREFIX_3 "Including switch '%s/%s' in context '%s'\n", new_sw->name, new_sw->data, ast_get_context_name(con));
3825 ast_mutex_unlock(&con->lock);
3827 return 0;
3831 * EBUSY - can't lock
3832 * ENOENT - there is not context existence
3834 int ast_context_remove_ignorepat(const char *context, const char *ignorepat, const char *registrar)
3836 int ret = -1;
3837 struct ast_context *c = find_context_locked(context);
3839 if (c) {
3840 ret = ast_context_remove_ignorepat2(c, ignorepat, registrar);
3841 ast_unlock_contexts();
3843 return ret;
3846 int ast_context_remove_ignorepat2(struct ast_context *con, const char *ignorepat, const char *registrar)
3848 struct ast_ignorepat *ip, *ipl = NULL;
3850 ast_mutex_lock(&con->lock);
3852 for (ip = con->ignorepats; ip; ip = ip->next) {
3853 if (!strcmp(ip->pattern, ignorepat) &&
3854 (!registrar || (registrar == ip->registrar))) {
3855 if (ipl) {
3856 ipl->next = ip->next;
3857 free(ip);
3858 } else {
3859 con->ignorepats = ip->next;
3860 free(ip);
3862 ast_mutex_unlock(&con->lock);
3863 return 0;
3865 ipl = ip;
3868 ast_mutex_unlock(&con->lock);
3869 errno = EINVAL;
3870 return -1;
3874 * EBUSY - can't lock
3875 * ENOENT - there is no existence of context
3877 int ast_context_add_ignorepat(const char *context, const char *value, const char *registrar)
3879 int ret = -1;
3880 struct ast_context *c = find_context_locked(context);
3882 if (c) {
3883 ret = ast_context_add_ignorepat2(c, value, registrar);
3884 ast_unlock_contexts();
3886 return ret;
3889 int ast_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar)
3891 struct ast_ignorepat *ignorepat, *ignorepatc, *ignorepatl = NULL;
3892 int length;
3893 length = sizeof(struct ast_ignorepat);
3894 length += strlen(value) + 1;
3895 if (!(ignorepat = ast_calloc(1, length)))
3896 return -1;
3897 /* The cast to char * is because we need to write the initial value.
3898 * The field is not supposed to be modified otherwise
3900 strcpy((char *)ignorepat->pattern, value);
3901 ignorepat->next = NULL;
3902 ignorepat->registrar = registrar;
3903 ast_mutex_lock(&con->lock);
3904 for (ignorepatc = con->ignorepats; ignorepatc; ignorepatc = ignorepatc->next) {
3905 ignorepatl = ignorepatc;
3906 if (!strcasecmp(ignorepatc->pattern, value)) {
3907 /* Already there */
3908 ast_mutex_unlock(&con->lock);
3909 errno = EEXIST;
3910 return -1;
3913 if (ignorepatl)
3914 ignorepatl->next = ignorepat;
3915 else
3916 con->ignorepats = ignorepat;
3917 ast_mutex_unlock(&con->lock);
3918 return 0;
3922 int ast_ignore_pattern(const char *context, const char *pattern)
3924 struct ast_context *con = ast_context_find(context);
3925 if (con) {
3926 struct ast_ignorepat *pat;
3927 for (pat = con->ignorepats; pat; pat = pat->next) {
3928 if (ast_extension_match(pat->pattern, pattern))
3929 return 1;
3933 return 0;
3937 * EBUSY - can't lock
3938 * ENOENT - no existence of context
3941 int ast_add_extension(const char *context, int replace, const char *extension,
3942 int priority, const char *label, const char *callerid,
3943 const char *application, void *data, void (*datad)(void *), const char *registrar)
3945 int ret = -1;
3946 struct ast_context *c = find_context_locked(context);
3948 if (c) {
3949 ret = ast_add_extension2(c, replace, extension, priority, label, callerid,
3950 application, data, datad, registrar);
3951 ast_unlock_contexts();
3953 return ret;
3956 int ast_explicit_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
3958 if (!chan)
3959 return -1;
3961 if (!ast_strlen_zero(context))
3962 ast_copy_string(chan->context, context, sizeof(chan->context));
3963 if (!ast_strlen_zero(exten))
3964 ast_copy_string(chan->exten, exten, sizeof(chan->exten));
3965 if (priority > -1) {
3966 chan->priority = priority;
3967 /* see flag description in channel.h for explanation */
3968 if (ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP))
3969 chan->priority--;
3972 return 0;
3975 int ast_async_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
3977 int res = 0;
3979 ast_channel_lock(chan);
3981 if (chan->pbx) { /* This channel is currently in the PBX */
3982 ast_explicit_goto(chan, context, exten, priority);
3983 ast_softhangup_nolock(chan, AST_SOFTHANGUP_ASYNCGOTO);
3984 } else {
3985 /* In order to do it when the channel doesn't really exist within
3986 the PBX, we have to make a new channel, masquerade, and start the PBX
3987 at the new location */
3988 struct ast_channel *tmpchan = ast_channel_alloc(0);
3989 if (!tmpchan)
3990 res = -1;
3991 else {
3992 ast_string_field_build(tmpchan, name, "AsyncGoto/%s", chan->name);
3993 ast_setstate(tmpchan, chan->_state);
3994 /* Make formats okay */
3995 tmpchan->readformat = chan->readformat;
3996 tmpchan->writeformat = chan->writeformat;
3997 /* Setup proper location */
3998 ast_explicit_goto(tmpchan,
3999 S_OR(context, chan->context), S_OR(exten, chan->exten), priority);
4001 /* Masquerade into temp channel */
4002 ast_channel_masquerade(tmpchan, chan);
4004 /* Grab the locks and get going */
4005 ast_channel_lock(tmpchan);
4006 ast_do_masquerade(tmpchan);
4007 ast_channel_unlock(tmpchan);
4008 /* Start the PBX going on our stolen channel */
4009 if (ast_pbx_start(tmpchan)) {
4010 ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmpchan->name);
4011 ast_hangup(tmpchan);
4012 res = -1;
4016 ast_channel_unlock(chan);
4017 return res;
4020 int ast_async_goto_by_name(const char *channame, const char *context, const char *exten, int priority)
4022 struct ast_channel *chan;
4023 int res = -1;
4025 chan = ast_get_channel_by_name_locked(channame);
4026 if (chan) {
4027 res = ast_async_goto(chan, context, exten, priority);
4028 ast_channel_unlock(chan);
4030 return res;
4033 /*! \brief copy a string skipping whitespace */
4034 static int ext_strncpy(char *dst, const char *src, int len)
4036 int count=0;
4038 while (*src && (count < len - 1)) {
4039 switch(*src) {
4040 case ' ':
4041 /* otherwise exten => [a-b],1,... doesn't work */
4042 /* case '-': */
4043 /* Ignore */
4044 break;
4045 default:
4046 *dst = *src;
4047 dst++;
4049 src++;
4050 count++;
4052 *dst = '\0';
4054 return count;
4057 static void null_datad(void *foo)
4061 /*! \brief add the extension in the priority chain */
4062 static int add_pri(struct ast_context *con, struct ast_exten *tmp,
4063 struct ast_exten *el, struct ast_exten *e, int replace)
4065 struct ast_exten *ep;
4067 for (ep = NULL; e ; ep = e, e = e->peer) {
4068 if (e->priority >= tmp->priority)
4069 break;
4071 if (!e) { /* go at the end, and ep is surely set because the list is not empty */
4072 ep->peer = tmp;
4073 return 0; /* success */
4075 if (e->priority == tmp->priority) {
4076 /* Can't have something exactly the same. Is this a
4077 replacement? If so, replace, otherwise, bonk. */
4078 if (!replace) {
4079 ast_log(LOG_WARNING, "Unable to register extension '%s', priority %d in '%s', already in use\n", tmp->exten, tmp->priority, con->name);
4080 tmp->datad(tmp->data);
4081 free(tmp);
4082 return -1;
4084 /* we are replacing e, so copy the link fields and then update
4085 * whoever pointed to e to point to us
4087 tmp->next = e->next; /* not meaningful if we are not first in the peer list */
4088 tmp->peer = e->peer; /* always meaningful */
4089 if (ep) /* We're in the peer list, just insert ourselves */
4090 ep->peer = tmp;
4091 else if (el) /* We're the first extension. Take over e's functions */
4092 el->next = tmp;
4093 else /* We're the very first extension. */
4094 con->root = tmp;
4095 if (tmp->priority == PRIORITY_HINT)
4096 ast_change_hint(e,tmp);
4097 /* Destroy the old one */
4098 e->datad(e->data);
4099 free(e);
4100 } else { /* Slip ourselves in just before e */
4101 tmp->peer = e;
4102 tmp->next = e->next; /* extension chain, or NULL if e is not the first extension */
4103 if (ep) /* Easy enough, we're just in the peer list */
4104 ep->peer = tmp;
4105 else { /* we are the first in some peer list, so link in the ext list */
4106 if (el)
4107 el->next = tmp; /* in the middle... */
4108 else
4109 con->root = tmp; /* ... or at the head */
4110 e->next = NULL; /* e is no more at the head, so e->next must be reset */
4112 /* And immediately return success. */
4113 if (tmp->priority == PRIORITY_HINT)
4114 ast_add_hint(tmp);
4116 return 0;
4119 /*! \brief
4120 * Main interface to add extensions to the list for out context.
4122 * We sort extensions in order of matching preference, so that we can
4123 * stop the search as soon as we find a suitable match.
4124 * This ordering also takes care of wildcards such as '.' (meaning
4125 * "one or more of any character") and '!' (which is 'earlymatch',
4126 * meaning "zero or more of any character" but also impacts the
4127 * return value from CANMATCH and EARLYMATCH.
4129 * The extension match rules defined in the devmeeting 2006.05.05 are
4130 * quite simple: WE SELECT THE LONGEST MATCH.
4131 * In detail, "longest" means the number of matched characters in
4132 * the extension. In case of ties (e.g. _XXX and 333) in the length
4133 * of a pattern, we give priority to entries with the smallest cardinality
4134 * (e.g, [5-9] comes before [2-8] before the former has only 5 elements,
4135 * while the latter has 7, etc.
4136 * In case of same cardinality, the first element in the range counts.
4137 * If we still have a tie, any final '!' will make this as a possibly
4138 * less specific pattern.
4140 * EBUSY - can't lock
4141 * EEXIST - extension with the same priority exist and no replace is set
4144 int ast_add_extension2(struct ast_context *con,
4145 int replace, const char *extension, int priority, const char *label, const char *callerid,
4146 const char *application, void *data, void (*datad)(void *),
4147 const char *registrar)
4150 #define LOG do { if (option_debug) {\
4151 if (tmp->matchcid) { \
4152 ast_log(LOG_DEBUG, "Added extension '%s' priority %d (CID match '%s') to %s\n", tmp->exten, tmp->priority, tmp->cidmatch, con->name); \
4153 } else { \
4154 ast_log(LOG_DEBUG, "Added extension '%s' priority %d to %s\n", tmp->exten, tmp->priority, con->name); \
4156 } else if (option_verbose > 2) { \
4157 if (tmp->matchcid) { \
4158 ast_verbose( VERBOSE_PREFIX_3 "Added extension '%s' priority %d (CID match '%s')to %s\n", tmp->exten, tmp->priority, tmp->cidmatch, con->name); \
4159 } else { \
4160 ast_verbose( VERBOSE_PREFIX_3 "Added extension '%s' priority %d to %s\n", tmp->exten, tmp->priority, con->name); \
4162 } } while(0)
4165 * This is a fairly complex routine. Different extensions are kept
4166 * in order by the extension number. Then, extensions of different
4167 * priorities (same extension) are kept in a list, according to the
4168 * peer pointer.
4170 struct ast_exten *tmp, *e, *el = NULL;
4171 int res;
4172 int length;
4173 char *p;
4174 char expand_buf[VAR_BUF_SIZE] = { 0, };
4176 /* if we are adding a hint, and there are global variables, and the hint
4177 contains variable references, then expand them
4179 ast_mutex_lock(&globalslock);
4180 if ((priority == PRIORITY_HINT) && AST_LIST_FIRST(&globals) && strstr(application, "${")) {
4181 pbx_substitute_variables_varshead(&globals, application, expand_buf, sizeof(expand_buf));
4182 application = expand_buf;
4184 ast_mutex_unlock(&globalslock);
4186 length = sizeof(struct ast_exten);
4187 length += strlen(extension) + 1;
4188 length += strlen(application) + 1;
4189 if (label)
4190 length += strlen(label) + 1;
4191 if (callerid)
4192 length += strlen(callerid) + 1;
4193 else
4194 length ++; /* just the '\0' */
4196 /* Be optimistic: Build the extension structure first */
4197 if (datad == NULL)
4198 datad = null_datad;
4199 if (!(tmp = ast_calloc(1, length)))
4200 return -1;
4202 /* use p as dst in assignments, as the fields are const char * */
4203 p = tmp->stuff;
4204 if (label) {
4205 tmp->label = p;
4206 strcpy(p, label);
4207 p += strlen(label) + 1;
4209 tmp->exten = p;
4210 p += ext_strncpy(p, extension, strlen(extension) + 1) + 1;
4211 tmp->priority = priority;
4212 tmp->cidmatch = p; /* but use p for assignments below */
4213 if (callerid) {
4214 p += ext_strncpy(p, callerid, strlen(callerid) + 1) + 1;
4215 tmp->matchcid = 1;
4216 } else {
4217 *p++ = '\0';
4218 tmp->matchcid = 0;
4220 tmp->app = p;
4221 strcpy(p, application);
4222 tmp->parent = con;
4223 tmp->data = data;
4224 tmp->datad = datad;
4225 tmp->registrar = registrar;
4227 ast_mutex_lock(&con->lock);
4228 for (e = con->root; e; el = e, e = e->next) { /* scan the extension list */
4229 /* XXX should use ext_cmp() to sort patterns correctly */
4230 /* almost strcmp, but make sure patterns are always last! */
4231 if (e->exten[0] != '_' && extension[0] == '_')
4232 res = -1;
4233 else if (e->exten[0] == '_' && extension[0] != '_')
4234 res = 1;
4235 else
4236 res= strcmp(e->exten, extension);
4237 if (res == 0) { /* extension match, now look at cidmatch */
4238 if (!e->matchcid && !tmp->matchcid)
4239 res = 0;
4240 else if (tmp->matchcid && !e->matchcid)
4241 res = 1;
4242 else if (e->matchcid && !tmp->matchcid)
4243 res = -1;
4244 else
4245 res = strcasecmp(e->cidmatch, tmp->cidmatch);
4247 if (res >= 0)
4248 break;
4250 if (e && res == 0) { /* exact match, insert in the pri chain */
4251 int ret = add_pri(con, tmp, el, e, replace);
4252 ast_mutex_unlock(&con->lock);
4253 if (ret < 0)
4254 errno = EEXIST;
4255 else {
4256 LOG;
4258 return ret;
4260 /* ok found the insertion place, right before 'e' (if any) */
4261 tmp->next = e;
4262 if (el)
4263 el->next = tmp;
4264 else
4265 con->root = tmp;
4266 ast_mutex_unlock(&con->lock);
4267 if (tmp->priority == PRIORITY_HINT)
4268 ast_add_hint(tmp);
4269 LOG;
4270 return 0;
4273 struct async_stat {
4274 pthread_t p;
4275 struct ast_channel *chan;
4276 char context[AST_MAX_CONTEXT];
4277 char exten[AST_MAX_EXTENSION];
4278 int priority;
4279 int timeout;
4280 char app[AST_MAX_EXTENSION];
4281 char appdata[1024];
4284 static void *async_wait(void *data)
4286 struct async_stat *as = data;
4287 struct ast_channel *chan = as->chan;
4288 int timeout = as->timeout;
4289 int res;
4290 struct ast_frame *f;
4291 struct ast_app *app;
4293 while (timeout && (chan->_state != AST_STATE_UP)) {
4294 res = ast_waitfor(chan, timeout);
4295 if (res < 1)
4296 break;
4297 if (timeout > -1)
4298 timeout = res;
4299 f = ast_read(chan);
4300 if (!f)
4301 break;
4302 if (f->frametype == AST_FRAME_CONTROL) {
4303 if ((f->subclass == AST_CONTROL_BUSY) ||
4304 (f->subclass == AST_CONTROL_CONGESTION) )
4305 break;
4307 ast_frfree(f);
4309 if (chan->_state == AST_STATE_UP) {
4310 if (!ast_strlen_zero(as->app)) {
4311 app = pbx_findapp(as->app);
4312 if (app) {
4313 if (option_verbose > 2)
4314 ast_verbose(VERBOSE_PREFIX_3 "Launching %s(%s) on %s\n", as->app, as->appdata, chan->name);
4315 pbx_exec(chan, app, as->appdata);
4316 } else
4317 ast_log(LOG_WARNING, "No such application '%s'\n", as->app);
4318 } else {
4319 if (!ast_strlen_zero(as->context))
4320 ast_copy_string(chan->context, as->context, sizeof(chan->context));
4321 if (!ast_strlen_zero(as->exten))
4322 ast_copy_string(chan->exten, as->exten, sizeof(chan->exten));
4323 if (as->priority > 0)
4324 chan->priority = as->priority;
4325 /* Run the PBX */
4326 if (ast_pbx_run(chan)) {
4327 ast_log(LOG_ERROR, "Failed to start PBX on %s\n", chan->name);
4328 } else {
4329 /* PBX will have taken care of this */
4330 chan = NULL;
4334 free(as);
4335 if (chan)
4336 ast_hangup(chan);
4337 return NULL;
4340 /*! Function to post an empty cdr after a spool call fails.
4342 * This function posts an empty cdr for a failed spool call
4345 int ast_pbx_outgoing_cdr_failed(void)
4347 /* allocate a channel */
4348 struct ast_channel *chan = ast_channel_alloc(0);
4350 if (!chan)
4351 return -1; /* failure */
4353 chan->cdr = ast_cdr_alloc(); /* allocate a cdr for the channel */
4355 if (!chan->cdr) {
4356 /* allocation of the cdr failed */
4357 ast_channel_free(chan); /* free the channel */
4358 return -1; /* return failure */
4361 /* allocation of the cdr was successful */
4362 ast_cdr_init(chan->cdr, chan); /* initilize our channel's cdr */
4363 ast_cdr_start(chan->cdr); /* record the start and stop time */
4364 ast_cdr_end(chan->cdr);
4365 ast_cdr_failed(chan->cdr); /* set the status to failed */
4366 ast_cdr_detach(chan->cdr); /* post and free the record */
4367 ast_channel_free(chan); /* free the channel */
4369 return 0; /* success */
4372 int ast_pbx_outgoing_exten(const char *type, int format, void *data, int timeout, const char *context, const char *exten, int priority, int *reason, int sync, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **channel)
4374 struct ast_channel *chan;
4375 struct async_stat *as;
4376 int res = -1, cdr_res = -1;
4377 struct outgoing_helper oh;
4378 pthread_attr_t attr;
4380 if (sync) {
4381 LOAD_OH(oh);
4382 chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
4383 if (channel) {
4384 *channel = chan;
4385 if (chan)
4386 ast_channel_lock(chan);
4388 if (chan) {
4389 if (chan->cdr) { /* check if the channel already has a cdr record, if not give it one */
4390 ast_log(LOG_WARNING, "%s already has a call record??\n", chan->name);
4391 } else {
4392 chan->cdr = ast_cdr_alloc(); /* allocate a cdr for the channel */
4393 if (!chan->cdr) {
4394 /* allocation of the cdr failed */
4395 free(chan->pbx);
4396 res = -1;
4397 goto outgoing_exten_cleanup;
4399 /* allocation of the cdr was successful */
4400 ast_cdr_init(chan->cdr, chan); /* initilize our channel's cdr */
4401 ast_cdr_start(chan->cdr);
4403 if (chan->_state == AST_STATE_UP) {
4404 res = 0;
4405 if (option_verbose > 3)
4406 ast_verbose(VERBOSE_PREFIX_4 "Channel %s was answered.\n", chan->name);
4408 if (sync > 1) {
4409 if (channel)
4410 ast_channel_unlock(chan);
4411 if (ast_pbx_run(chan)) {
4412 ast_log(LOG_ERROR, "Unable to run PBX on %s\n", chan->name);
4413 if (channel)
4414 *channel = NULL;
4415 ast_hangup(chan);
4416 res = -1;
4418 } else {
4419 if (ast_pbx_start(chan)) {
4420 ast_log(LOG_ERROR, "Unable to start PBX on %s\n", chan->name);
4421 if (channel) {
4422 *channel = NULL;
4423 ast_channel_unlock(chan);
4425 ast_hangup(chan);
4426 res = -1;
4429 } else {
4430 if (option_verbose > 3)
4431 ast_verbose(VERBOSE_PREFIX_4 "Channel %s was never answered.\n", chan->name);
4433 if(chan->cdr) { /* update the cdr */
4434 /* here we update the status of the call, which sould be busy.
4435 * if that fails then we set the status to failed */
4436 if (ast_cdr_disposition(chan->cdr, chan->hangupcause))
4437 ast_cdr_failed(chan->cdr);
4440 if (channel) {
4441 *channel = NULL;
4442 ast_channel_unlock(chan);
4444 ast_hangup(chan);
4448 if (res < 0) { /* the call failed for some reason */
4449 if (*reason == 0) { /* if the call failed (not busy or no answer)
4450 * update the cdr with the failed message */
4451 cdr_res = ast_pbx_outgoing_cdr_failed();
4452 if (cdr_res != 0) {
4453 res = cdr_res;
4454 goto outgoing_exten_cleanup;
4458 /* create a fake channel and execute the "failed" extension (if it exists) within the requested context */
4459 /* check if "failed" exists */
4460 if (ast_exists_extension(chan, context, "failed", 1, NULL)) {
4461 chan = ast_channel_alloc(0);
4462 if (chan) {
4463 ast_string_field_set(chan, name, "OutgoingSpoolFailed");
4464 if (!ast_strlen_zero(context))
4465 ast_copy_string(chan->context, context, sizeof(chan->context));
4466 set_ext_pri(chan, "failed", 1);
4467 ast_set_variables(chan, vars);
4468 if (account)
4469 ast_cdr_setaccount(chan, account);
4470 ast_pbx_run(chan);
4474 } else {
4475 if (!(as = ast_calloc(1, sizeof(*as)))) {
4476 res = -1;
4477 goto outgoing_exten_cleanup;
4479 chan = ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name);
4480 if (channel) {
4481 *channel = chan;
4482 if (chan)
4483 ast_channel_lock(chan);
4485 if (!chan) {
4486 free(as);
4487 res = -1;
4488 goto outgoing_exten_cleanup;
4490 as->chan = chan;
4491 ast_copy_string(as->context, context, sizeof(as->context));
4492 set_ext_pri(as->chan, exten, priority);
4493 as->timeout = timeout;
4494 ast_set_variables(chan, vars);
4495 if (account)
4496 ast_cdr_setaccount(chan, account);
4497 pthread_attr_init(&attr);
4498 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
4499 if (ast_pthread_create(&as->p, &attr, async_wait, as)) {
4500 ast_log(LOG_WARNING, "Failed to start async wait\n");
4501 free(as);
4502 if (channel) {
4503 *channel = NULL;
4504 ast_channel_unlock(chan);
4506 ast_hangup(chan);
4507 res = -1;
4508 goto outgoing_exten_cleanup;
4510 res = 0;
4512 outgoing_exten_cleanup:
4513 ast_variables_destroy(vars);
4514 return res;
4517 struct app_tmp {
4518 char app[256];
4519 char data[256];
4520 struct ast_channel *chan;
4521 pthread_t t;
4524 /*! \brief run the application and free the descriptor once done */
4525 static void *ast_pbx_run_app(void *data)
4527 struct app_tmp *tmp = data;
4528 struct ast_app *app;
4529 app = pbx_findapp(tmp->app);
4530 if (app) {
4531 if (option_verbose > 3)
4532 ast_verbose(VERBOSE_PREFIX_4 "Launching %s(%s) on %s\n", tmp->app, tmp->data, tmp->chan->name);
4533 pbx_exec(tmp->chan, app, tmp->data);
4534 } else
4535 ast_log(LOG_WARNING, "No such application '%s'\n", tmp->app);
4536 ast_hangup(tmp->chan);
4537 free(tmp);
4538 return NULL;
4541 int ast_pbx_outgoing_app(const char *type, int format, void *data, int timeout, const char *app, const char *appdata, int *reason, int sync, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **locked_channel)
4543 struct ast_channel *chan;
4544 struct app_tmp *tmp;
4545 int res = -1, cdr_res = -1;
4546 struct outgoing_helper oh;
4547 pthread_attr_t attr;
4549 memset(&oh, 0, sizeof(oh));
4550 oh.vars = vars;
4551 oh.account = account;
4553 if (locked_channel)
4554 *locked_channel = NULL;
4555 if (ast_strlen_zero(app)) {
4556 res = -1;
4557 goto outgoing_app_cleanup;
4559 if (sync) {
4560 chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
4561 if (chan) {
4562 if (chan->cdr) { /* check if the channel already has a cdr record, if not give it one */
4563 ast_log(LOG_WARNING, "%s already has a call record??\n", chan->name);
4564 } else {
4565 chan->cdr = ast_cdr_alloc(); /* allocate a cdr for the channel */
4566 if(!chan->cdr) {
4567 /* allocation of the cdr failed */
4568 free(chan->pbx);
4569 res = -1;
4570 goto outgoing_app_cleanup;
4572 /* allocation of the cdr was successful */
4573 ast_cdr_init(chan->cdr, chan); /* initilize our channel's cdr */
4574 ast_cdr_start(chan->cdr);
4576 ast_set_variables(chan, vars);
4577 if (account)
4578 ast_cdr_setaccount(chan, account);
4579 if (chan->_state == AST_STATE_UP) {
4580 res = 0;
4581 if (option_verbose > 3)
4582 ast_verbose(VERBOSE_PREFIX_4 "Channel %s was answered.\n", chan->name);
4583 tmp = ast_calloc(1, sizeof(*tmp));
4584 if (!tmp)
4585 res = -1;
4586 else {
4587 ast_copy_string(tmp->app, app, sizeof(tmp->app));
4588 if (appdata)
4589 ast_copy_string(tmp->data, appdata, sizeof(tmp->data));
4590 tmp->chan = chan;
4591 if (sync > 1) {
4592 if (locked_channel)
4593 ast_channel_unlock(chan);
4594 ast_pbx_run_app(tmp);
4595 } else {
4596 pthread_attr_init(&attr);
4597 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
4598 if (locked_channel)
4599 ast_channel_lock(chan);
4600 if (ast_pthread_create(&tmp->t, &attr, ast_pbx_run_app, tmp)) {
4601 ast_log(LOG_WARNING, "Unable to spawn execute thread on %s: %s\n", chan->name, strerror(errno));
4602 free(tmp);
4603 if (locked_channel)
4604 ast_channel_unlock(chan);
4605 ast_hangup(chan);
4606 res = -1;
4607 } else {
4608 if (locked_channel)
4609 *locked_channel = chan;
4613 } else {
4614 if (option_verbose > 3)
4615 ast_verbose(VERBOSE_PREFIX_4 "Channel %s was never answered.\n", chan->name);
4616 if (chan->cdr) { /* update the cdr */
4617 /* here we update the status of the call, which sould be busy.
4618 * if that fails then we set the status to failed */
4619 if (ast_cdr_disposition(chan->cdr, chan->hangupcause))
4620 ast_cdr_failed(chan->cdr);
4622 ast_hangup(chan);
4626 if (res < 0) { /* the call failed for some reason */
4627 if (*reason == 0) { /* if the call failed (not busy or no answer)
4628 * update the cdr with the failed message */
4629 cdr_res = ast_pbx_outgoing_cdr_failed();
4630 if (cdr_res != 0) {
4631 res = cdr_res;
4632 goto outgoing_app_cleanup;
4637 } else {
4638 struct async_stat *as;
4639 if (!(as = ast_calloc(1, sizeof(*as)))) {
4640 res = -1;
4641 goto outgoing_app_cleanup;
4643 chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
4644 if (!chan) {
4645 free(as);
4646 res = -1;
4647 goto outgoing_app_cleanup;
4649 as->chan = chan;
4650 ast_copy_string(as->app, app, sizeof(as->app));
4651 if (appdata)
4652 ast_copy_string(as->appdata, appdata, sizeof(as->appdata));
4653 as->timeout = timeout;
4654 ast_set_variables(chan, vars);
4655 if (account)
4656 ast_cdr_setaccount(chan, account);
4657 /* Start a new thread, and get something handling this channel. */
4658 pthread_attr_init(&attr);
4659 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
4660 if (locked_channel)
4661 ast_channel_lock(chan);
4662 if (ast_pthread_create(&as->p, &attr, async_wait, as)) {
4663 ast_log(LOG_WARNING, "Failed to start async wait\n");
4664 free(as);
4665 if (locked_channel)
4666 ast_channel_unlock(chan);
4667 ast_hangup(chan);
4668 res = -1;
4669 goto outgoing_app_cleanup;
4670 } else {
4671 if (locked_channel)
4672 *locked_channel = chan;
4674 res = 0;
4676 outgoing_app_cleanup:
4677 ast_variables_destroy(vars);
4678 return res;
4681 void __ast_context_destroy(struct ast_context *con, const char *registrar)
4683 struct ast_context *tmp, *tmpl=NULL;
4684 struct ast_include *tmpi;
4685 struct ast_sw *sw;
4686 struct ast_exten *e, *el, *en;
4687 struct ast_ignorepat *ipi;
4689 ast_mutex_lock(&conlock);
4690 for (tmp = contexts; tmp; ) {
4691 struct ast_context *next; /* next starting point */
4692 for (; tmp; tmpl = tmp, tmp = tmp->next) {
4693 ast_log(LOG_DEBUG, "check ctx %s %s\n", tmp->name, tmp->registrar);
4694 if ( (!registrar || !strcasecmp(registrar, tmp->registrar)) &&
4695 (!con || !strcasecmp(tmp->name, con->name)) )
4696 break; /* found it */
4698 if (!tmp) /* not found, we are done */
4699 break;
4700 ast_mutex_lock(&tmp->lock);
4701 ast_log(LOG_DEBUG, "delete ctx %s %s\n", tmp->name, tmp->registrar);
4702 next = tmp->next;
4703 if (tmpl)
4704 tmpl->next = next;
4705 else
4706 contexts = next;
4707 /* Okay, now we're safe to let it go -- in a sense, we were
4708 ready to let it go as soon as we locked it. */
4709 ast_mutex_unlock(&tmp->lock);
4710 for (tmpi = tmp->includes; tmpi; ) { /* Free includes */
4711 struct ast_include *tmpil = tmpi;
4712 tmpi = tmpi->next;
4713 free(tmpil);
4715 for (ipi = tmp->ignorepats; ipi; ) { /* Free ignorepats */
4716 struct ast_ignorepat *ipl = ipi;
4717 ipi = ipi->next;
4718 free(ipl);
4720 while ((sw = AST_LIST_REMOVE_HEAD(&tmp->alts, list)))
4721 free(sw);
4722 for (e = tmp->root; e;) {
4723 for (en = e->peer; en;) {
4724 el = en;
4725 en = en->peer;
4726 destroy_exten(el);
4728 el = e;
4729 e = e->next;
4730 destroy_exten(el);
4732 ast_mutex_destroy(&tmp->lock);
4733 free(tmp);
4734 /* if we have a specific match, we are done, otherwise continue */
4735 tmp = con ? NULL : next;
4737 ast_mutex_unlock(&conlock);
4740 void ast_context_destroy(struct ast_context *con, const char *registrar)
4742 __ast_context_destroy(con,registrar);
4745 static void wait_for_hangup(struct ast_channel *chan, void *data)
4747 int res;
4748 struct ast_frame *f;
4749 int waittime;
4751 if (ast_strlen_zero(data) || (sscanf(data, "%d", &waittime) != 1) || (waittime < 0))
4752 waittime = -1;
4753 if (waittime > -1) {
4754 ast_safe_sleep(chan, waittime * 1000);
4755 } else do {
4756 res = ast_waitfor(chan, -1);
4757 if (res < 0)
4758 return;
4759 f = ast_read(chan);
4760 if (f)
4761 ast_frfree(f);
4762 } while(f);
4766 * \ingroup applications
4768 static int pbx_builtin_progress(struct ast_channel *chan, void *data)
4770 ast_indicate(chan, AST_CONTROL_PROGRESS);
4771 return 0;
4775 * \ingroup applications
4777 static int pbx_builtin_ringing(struct ast_channel *chan, void *data)
4779 ast_indicate(chan, AST_CONTROL_RINGING);
4780 return 0;
4784 * \ingroup applications
4786 static int pbx_builtin_busy(struct ast_channel *chan, void *data)
4788 ast_indicate(chan, AST_CONTROL_BUSY);
4789 ast_setstate(chan, AST_STATE_BUSY);
4790 wait_for_hangup(chan, data);
4791 return -1;
4795 * \ingroup applications
4797 static int pbx_builtin_congestion(struct ast_channel *chan, void *data)
4799 ast_indicate(chan, AST_CONTROL_CONGESTION);
4800 ast_setstate(chan, AST_STATE_BUSY);
4801 wait_for_hangup(chan, data);
4802 return -1;
4806 * \ingroup applications
4808 static int pbx_builtin_answer(struct ast_channel *chan, void *data)
4810 int delay = 0;
4811 int res;
4813 if (chan->_state == AST_STATE_UP)
4814 delay = 0;
4815 else if (!ast_strlen_zero(data))
4816 delay = atoi(data);
4818 res = ast_answer(chan);
4819 if (res)
4820 return res;
4822 if (delay)
4823 res = ast_safe_sleep(chan, delay);
4825 return res;
4828 AST_APP_OPTIONS(resetcdr_opts, {
4829 AST_APP_OPTION('w', AST_CDR_FLAG_POSTED),
4830 AST_APP_OPTION('a', AST_CDR_FLAG_LOCKED),
4831 AST_APP_OPTION('v', AST_CDR_FLAG_KEEP_VARS),
4835 * \ingroup applications
4837 static int pbx_builtin_resetcdr(struct ast_channel *chan, void *data)
4839 char *args;
4840 struct ast_flags flags = { 0 };
4842 if (!ast_strlen_zero(data)) {
4843 if (!(args = ast_strdupa(data)))
4844 return -1;
4845 ast_app_parse_options(resetcdr_opts, &flags, NULL, args);
4848 ast_cdr_reset(chan->cdr, &flags);
4850 return 0;
4854 * \ingroup applications
4856 static int pbx_builtin_setamaflags(struct ast_channel *chan, void *data)
4858 /* Copy the AMA Flags as specified */
4859 ast_cdr_setamaflags(chan, data ? data : "");
4860 return 0;
4864 * \ingroup applications
4866 static int pbx_builtin_hangup(struct ast_channel *chan, void *data)
4868 /* Just return non-zero and it will hang up */
4869 if (!chan->hangupcause)
4870 chan->hangupcause = AST_CAUSE_NORMAL_CLEARING;
4871 return -1;
4875 * \ingroup applications
4877 static int pbx_builtin_gotoiftime(struct ast_channel *chan, void *data)
4879 int res=0;
4880 char *s, *ts;
4881 struct ast_timing timing;
4883 if (ast_strlen_zero(data)) {
4884 ast_log(LOG_WARNING, "GotoIfTime requires an argument:\n <time range>|<days of week>|<days of month>|<months>?[[context|]extension|]priority\n");
4885 return -1;
4888 if ((s = ast_strdupa(data))) {
4889 ts = s;
4891 /* Separate the Goto path */
4892 strsep(&ts,"?");
4894 /* struct ast_include include contained garbage here, fixed by zeroing it on get_timerange */
4895 if (ast_build_timing(&timing, s) && ast_check_timing(&timing))
4896 res = pbx_builtin_goto(chan, (void *)ts);
4898 return res;
4902 * \ingroup applications
4904 static int pbx_builtin_execiftime(struct ast_channel *chan, void *data)
4906 char *s, *appname;
4907 struct ast_timing timing;
4908 struct ast_app *app;
4909 static const char *usage = "ExecIfTime requires an argument:\n <time range>|<days of week>|<days of month>|<months>?<appname>[|<appargs>]";
4911 if (ast_strlen_zero(data)) {
4912 ast_log(LOG_WARNING, "%s\n", usage);
4913 return -1;
4916 if (!(appname = ast_strdupa(data)))
4917 return -1;
4919 s = strsep(&appname,"?"); /* Separate the timerange and application name/data */
4920 if (!appname) { /* missing application */
4921 ast_log(LOG_WARNING, "%s\n", usage);
4922 return -1;
4925 if (!ast_build_timing(&timing, s)) {
4926 ast_log(LOG_WARNING, "Invalid Time Spec: %s\nCorrect usage: %s\n", s, usage);
4927 return -1;
4930 if (!ast_check_timing(&timing)) /* outside the valid time window, just return */
4931 return 0;
4933 /* now split appname|appargs */
4934 if ((s = strchr(appname, '|')))
4935 *s++ = '\0';
4937 if ((app = pbx_findapp(appname))) {
4938 return pbx_exec(chan, app, S_OR(s, ""));
4939 } else {
4940 ast_log(LOG_WARNING, "Cannot locate application %s\n", appname);
4941 return -1;
4946 * \ingroup applications
4948 static int pbx_builtin_wait(struct ast_channel *chan, void *data)
4950 int ms;
4952 /* Wait for "n" seconds */
4953 if (data && (ms = atof(data)) > 0) {
4954 ms *= 1000;
4955 return ast_safe_sleep(chan, ms);
4957 return 0;
4961 * \ingroup applications
4963 static int pbx_builtin_waitexten(struct ast_channel *chan, void *data)
4965 int ms, res;
4966 struct ast_flags flags = {0};
4967 char *opts[1] = { NULL };
4968 char *parse;
4969 AST_DECLARE_APP_ARGS(args,
4970 AST_APP_ARG(timeout);
4971 AST_APP_ARG(options);
4974 if (!ast_strlen_zero(data)) {
4975 if (!(parse = ast_strdupa(data)))
4976 return -1;
4977 AST_STANDARD_APP_ARGS(args, parse);
4978 } else
4979 memset(&args, 0, sizeof(args));
4981 if (args.options)
4982 ast_app_parse_options(waitexten_opts, &flags, opts, args.options);
4984 if (ast_test_flag(&flags, WAITEXTEN_MOH))
4985 ast_moh_start(chan, opts[0]);
4987 /* Wait for "n" seconds */
4988 if (args.timeout && (ms = atof(args.timeout)) > 0)
4989 ms *= 1000;
4990 else if (chan->pbx)
4991 ms = chan->pbx->rtimeout * 1000;
4992 else
4993 ms = 10000;
4994 res = ast_waitfordigit(chan, ms);
4995 if (!res) {
4996 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 1, chan->cid.cid_num)) {
4997 if (option_verbose > 2)
4998 ast_verbose(VERBOSE_PREFIX_3 "Timeout on %s, continuing...\n", chan->name);
4999 } else if (ast_exists_extension(chan, chan->context, "t", 1, chan->cid.cid_num)) {
5000 if (option_verbose > 2)
5001 ast_verbose(VERBOSE_PREFIX_3 "Timeout on %s, going to 't'\n", chan->name);
5002 set_ext_pri(chan, "t", 0); /* XXX is the 0 correct ? */
5003 } else {
5004 ast_log(LOG_WARNING, "Timeout but no rule 't' in context '%s'\n", chan->context);
5005 res = -1;
5009 if (ast_test_flag(&flags, WAITEXTEN_MOH))
5010 ast_moh_stop(chan);
5012 return res;
5016 * \ingroup applications
5018 static int pbx_builtin_background(struct ast_channel *chan, void *data)
5020 int res = 0;
5021 struct ast_flags flags = {0};
5022 char *parse;
5023 AST_DECLARE_APP_ARGS(args,
5024 AST_APP_ARG(filename);
5025 AST_APP_ARG(options);
5026 AST_APP_ARG(lang);
5027 AST_APP_ARG(context);
5030 if (ast_strlen_zero(data))
5031 ast_log(LOG_WARNING, "Background requires an argument (filename)\n");
5033 if (!(parse = ast_strdupa(data)))
5034 return -1;
5036 AST_STANDARD_APP_ARGS(args, parse);
5038 if (!args.lang)
5039 args.lang = (char *)chan->language; /* XXX this is const */
5041 if (!args.context)
5042 args.context = chan->context;
5044 if (args.options) {
5045 if (!strcasecmp(args.options, "skip"))
5046 flags.flags = BACKGROUND_SKIP;
5047 else if (!strcasecmp(args.options, "noanswer"))
5048 flags.flags = BACKGROUND_NOANSWER;
5049 else
5050 ast_app_parse_options(background_opts, &flags, NULL, args.options);
5053 /* Answer if need be */
5054 if (chan->_state != AST_STATE_UP) {
5055 if (ast_test_flag(&flags, BACKGROUND_SKIP)) {
5056 return 0;
5057 } else if (!ast_test_flag(&flags, BACKGROUND_NOANSWER)) {
5058 res = ast_answer(chan);
5062 if (!res) {
5063 char *back = args.filename;
5064 char *front;
5065 ast_stopstream(chan); /* Stop anything playing */
5066 /* Stream the list of files */
5067 while (!res && (front = strsep(&back, "&")) ) {
5068 if ( (res = ast_streamfile(chan, front, args.lang)) ) {
5069 ast_log(LOG_WARNING, "ast_streamfile failed on %s for %s\n", chan->name, (char*)data);
5070 res = 0;
5071 break;
5073 if (ast_test_flag(&flags, BACKGROUND_PLAYBACK)) {
5074 res = ast_waitstream(chan, "");
5075 } else if (ast_test_flag(&flags, BACKGROUND_MATCHEXTEN)) {
5076 res = ast_waitstream_exten(chan, args.context);
5077 } else {
5078 res = ast_waitstream(chan, AST_DIGIT_ANY);
5080 ast_stopstream(chan);
5083 if (args.context != chan->context && res) {
5084 snprintf(chan->exten, sizeof(chan->exten), "%c", res);
5085 ast_copy_string(chan->context, args.context, sizeof(chan->context));
5086 chan->priority = 0;
5087 res = 0;
5089 return res;
5092 /*! Goto
5093 * \ingroup applications
5095 static int pbx_builtin_goto(struct ast_channel *chan, void *data)
5097 int res = ast_parseable_goto(chan, data);
5098 if (!res && (option_verbose > 2))
5099 ast_verbose( VERBOSE_PREFIX_3 "Goto (%s,%s,%d)\n", chan->context,chan->exten, chan->priority+1);
5100 return res;
5104 int pbx_builtin_serialize_variables(struct ast_channel *chan, char *buf, size_t size)
5106 struct ast_var_t *variables;
5107 const char *var, *val;
5108 int total = 0;
5110 if (!chan)
5111 return 0;
5113 memset(buf, 0, size);
5115 AST_LIST_TRAVERSE(&chan->varshead, variables, entries) {
5116 if(variables &&
5117 (var=ast_var_name(variables)) && (val=ast_var_value(variables)) &&
5118 !ast_strlen_zero(var) && !ast_strlen_zero(val)) {
5119 if (ast_build_string(&buf, &size, "%s=%s\n", var, val)) {
5120 ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
5121 break;
5122 } else
5123 total++;
5124 } else
5125 break;
5128 return total;
5131 const char *pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
5133 struct ast_var_t *variables;
5134 const char *ret = NULL;
5135 int i;
5136 struct varshead *places[2] = { NULL, &globals };
5138 if (!name)
5139 return NULL;
5140 if (chan)
5141 places[0] = &chan->varshead;
5143 for (i = 0; i < 2; i++) {
5144 if (!places[i])
5145 continue;
5146 if (places[i] == &globals)
5147 ast_mutex_lock(&globalslock);
5148 AST_LIST_TRAVERSE(places[i], variables, entries) {
5149 if (!strcmp(name, ast_var_name(variables))) {
5150 ret = ast_var_value(variables);
5151 break;
5154 if (places[i] == &globals)
5155 ast_mutex_unlock(&globalslock);
5156 if (ret)
5157 break;
5160 return ret;
5163 void pbx_builtin_pushvar_helper(struct ast_channel *chan, const char *name, const char *value)
5165 struct ast_var_t *newvariable;
5166 struct varshead *headp;
5168 if (name[strlen(name)-1] == ')') {
5169 char *function = ast_strdupa(name);
5171 ast_log(LOG_WARNING, "Cannot push a value onto a function\n");
5172 ast_func_write(chan, function, value);
5173 return;
5176 headp = (chan) ? &chan->varshead : &globals;
5178 if (value) {
5179 if ((option_verbose > 1) && (headp == &globals))
5180 ast_verbose(VERBOSE_PREFIX_2 "Setting global variable '%s' to '%s'\n", name, value);
5181 newvariable = ast_var_assign(name, value);
5182 if (headp == &globals)
5183 ast_mutex_lock(&globalslock);
5184 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
5185 if (headp == &globals)
5186 ast_mutex_unlock(&globalslock);
5190 void pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
5192 struct ast_var_t *newvariable;
5193 struct varshead *headp;
5194 const char *nametail = name;
5196 /* XXX may need locking on the channel ? */
5197 if (name[strlen(name)-1] == ')') {
5198 char *function = ast_strdupa(name);
5200 ast_func_write(chan, function, value);
5201 return;
5204 headp = (chan) ? &chan->varshead : &globals;
5206 /* For comparison purposes, we have to strip leading underscores */
5207 if (*nametail == '_') {
5208 nametail++;
5209 if (*nametail == '_')
5210 nametail++;
5213 if (headp == &globals)
5214 ast_mutex_lock(&globalslock);
5215 AST_LIST_TRAVERSE (headp, newvariable, entries) {
5216 if (strcasecmp(ast_var_name(newvariable), nametail) == 0) {
5217 /* there is already such a variable, delete it */
5218 AST_LIST_REMOVE(headp, newvariable, entries);
5219 ast_var_delete(newvariable);
5220 break;
5224 if (value) {
5225 if ((option_verbose > 1) && (headp == &globals))
5226 ast_verbose(VERBOSE_PREFIX_2 "Setting global variable '%s' to '%s'\n", name, value);
5227 newvariable = ast_var_assign(name, value);
5228 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
5231 if (headp == &globals)
5232 ast_mutex_unlock(&globalslock);
5235 int pbx_builtin_setvar(struct ast_channel *chan, void *data)
5237 char *name, *value, *mydata;
5238 int argc;
5239 char *argv[24]; /* this will only support a maximum of 24 variables being set in a single operation */
5240 int global = 0;
5241 int x;
5243 if (ast_strlen_zero(data)) {
5244 ast_log(LOG_WARNING, "Set requires at least one variable name/value pair.\n");
5245 return 0;
5248 mydata = ast_strdupa(data);
5249 argc = ast_app_separate_args(mydata, '|', argv, sizeof(argv) / sizeof(argv[0]));
5251 /* check for a trailing flags argument */
5252 if ((argc > 1) && !strchr(argv[argc-1], '=')) {
5253 argc--;
5254 if (strchr(argv[argc], 'g'))
5255 global = 1;
5258 for (x = 0; x < argc; x++) {
5259 name = argv[x];
5260 if ((value = strchr(name, '='))) {
5261 *value++ = '\0';
5262 pbx_builtin_setvar_helper((global) ? NULL : chan, name, value);
5263 } else
5264 ast_log(LOG_WARNING, "Ignoring entry '%s' with no = (and not last 'options' entry)\n", name);
5267 return(0);
5270 int pbx_builtin_importvar(struct ast_channel *chan, void *data)
5272 char *name;
5273 char *value;
5274 char *channel;
5275 char tmp[VAR_BUF_SIZE]="";
5277 if (ast_strlen_zero(data)) {
5278 ast_log(LOG_WARNING, "Ignoring, since there is no variable to set\n");
5279 return 0;
5282 value = ast_strdupa(data);
5283 name = strsep(&value,"=");
5284 channel = strsep(&value,"|");
5285 if (channel && value && name) { /*! \todo XXX should do !ast_strlen_zero(..) of the args ? */
5286 struct ast_channel *chan2 = ast_get_channel_by_name_locked(channel);
5287 if (chan2) {
5288 char *s = alloca(strlen(value) + 4);
5289 if (s) {
5290 sprintf(s, "${%s}", value);
5291 pbx_substitute_variables_helper(chan2, s, tmp, sizeof(tmp) - 1);
5293 ast_channel_unlock(chan2);
5295 pbx_builtin_setvar_helper(chan, name, tmp);
5298 return(0);
5301 /*! \todo XXX overwrites data ? */
5302 static int pbx_builtin_setglobalvar(struct ast_channel *chan, void *data)
5304 char *name;
5305 char *stringp = data;
5307 if (ast_strlen_zero(data)) {
5308 ast_log(LOG_WARNING, "Ignoring, since there is no variable to set\n");
5309 return 0;
5312 name = strsep(&stringp, "=");
5313 /*! \todo XXX watch out, leading whitespace ? */
5314 pbx_builtin_setvar_helper(NULL, name, stringp);
5316 return(0);
5319 static int pbx_builtin_noop(struct ast_channel *chan, void *data)
5321 return 0;
5324 void pbx_builtin_clear_globals(void)
5326 struct ast_var_t *vardata;
5328 ast_mutex_lock(&globalslock);
5329 while ((vardata = AST_LIST_REMOVE_HEAD(&globals, entries)))
5330 ast_var_delete(vardata);
5331 ast_mutex_unlock(&globalslock);
5334 int pbx_checkcondition(const char *condition)
5336 if (ast_strlen_zero(condition)) /* NULL or empty strings are false */
5337 return 0;
5338 else if (*condition >= '0' && *condition <= '9') /* Numbers are evaluated for truth */
5339 return atoi(condition);
5340 else /* Strings are true */
5341 return 1;
5344 static int pbx_builtin_gotoif(struct ast_channel *chan, void *data)
5346 char *condition, *branch1, *branch2, *branch;
5347 int rc;
5348 char *stringp;
5350 if (ast_strlen_zero(data)) {
5351 ast_log(LOG_WARNING, "Ignoring, since there is no variable to check\n");
5352 return 0;
5355 stringp = ast_strdupa(data);
5356 condition = strsep(&stringp,"?");
5357 branch1 = strsep(&stringp,":");
5358 branch2 = strsep(&stringp,"");
5359 branch = pbx_checkcondition(condition) ? branch1 : branch2;
5361 if (ast_strlen_zero(branch)) {
5362 ast_log(LOG_DEBUG, "Not taking any branch\n");
5363 return 0;
5366 rc = pbx_builtin_goto(chan, branch);
5368 return rc;
5371 static int pbx_builtin_saynumber(struct ast_channel *chan, void *data)
5373 char tmp[256];
5374 char *number = tmp;
5375 char *options;
5377 if (ast_strlen_zero(data)) {
5378 ast_log(LOG_WARNING, "SayNumber requires an argument (number)\n");
5379 return -1;
5381 ast_copy_string(tmp, data, sizeof(tmp));
5382 strsep(&number, "|");
5383 options = strsep(&number, "|");
5384 if (options) {
5385 if ( strcasecmp(options, "f") && strcasecmp(options,"m") &&
5386 strcasecmp(options, "c") && strcasecmp(options, "n") ) {
5387 ast_log(LOG_WARNING, "SayNumber gender option is either 'f', 'm', 'c' or 'n'\n");
5388 return -1;
5391 return ast_say_number(chan, atoi(tmp), "", chan->language, options);
5394 static int pbx_builtin_saydigits(struct ast_channel *chan, void *data)
5396 int res = 0;
5398 if (data)
5399 res = ast_say_digit_str(chan, data, "", chan->language);
5400 return res;
5403 static int pbx_builtin_saycharacters(struct ast_channel *chan, void *data)
5405 int res = 0;
5407 if (data)
5408 res = ast_say_character_str(chan, data, "", chan->language);
5409 return res;
5412 static int pbx_builtin_sayphonetic(struct ast_channel *chan, void *data)
5414 int res = 0;
5416 if (data)
5417 res = ast_say_phonetic_str(chan, data, "", chan->language);
5418 return res;
5421 int load_pbx(void)
5423 int x;
5425 /* Initialize the PBX */
5426 if (option_verbose) {
5427 ast_verbose( "Asterisk PBX Core Initializing\n");
5428 ast_verbose( "Registering builtin applications:\n");
5430 AST_LIST_HEAD_INIT_NOLOCK(&globals);
5431 ast_cli_register_multiple(pbx_cli, sizeof(pbx_cli) / sizeof(pbx_cli[0]));
5433 /* Register builtin applications */
5434 for (x=0; x<sizeof(builtins) / sizeof(struct pbx_builtin); x++) {
5435 if (option_verbose)
5436 ast_verbose( VERBOSE_PREFIX_1 "[%s]\n", builtins[x].name);
5437 if (ast_register_application(builtins[x].name, builtins[x].execute, builtins[x].synopsis, builtins[x].description)) {
5438 ast_log(LOG_ERROR, "Unable to register builtin application '%s'\n", builtins[x].name);
5439 return -1;
5442 return 0;
5446 * Lock context list functions ...
5448 int ast_lock_contexts()
5450 return ast_mutex_lock(&conlock);
5453 int ast_unlock_contexts()
5455 return ast_mutex_unlock(&conlock);
5459 * Lock context ...
5461 int ast_lock_context(struct ast_context *con)
5463 return ast_mutex_lock(&con->lock);
5466 int ast_unlock_context(struct ast_context *con)
5468 return ast_mutex_unlock(&con->lock);
5472 * Name functions ...
5474 const char *ast_get_context_name(struct ast_context *con)
5476 return con ? con->name : NULL;
5479 struct ast_context *ast_get_extension_context(struct ast_exten *exten)
5481 return exten ? exten->parent : NULL;
5484 const char *ast_get_extension_name(struct ast_exten *exten)
5486 return exten ? exten->exten : NULL;
5489 const char *ast_get_extension_label(struct ast_exten *exten)
5491 return exten ? exten->label : NULL;
5494 const char *ast_get_include_name(struct ast_include *inc)
5496 return inc ? inc->name : NULL;
5499 const char *ast_get_ignorepat_name(struct ast_ignorepat *ip)
5501 return ip ? ip->pattern : NULL;
5504 int ast_get_extension_priority(struct ast_exten *exten)
5506 return exten ? exten->priority : -1;
5510 * Registrar info functions ...
5512 const char *ast_get_context_registrar(struct ast_context *c)
5514 return c ? c->registrar : NULL;
5517 const char *ast_get_extension_registrar(struct ast_exten *e)
5519 return e ? e->registrar : NULL;
5522 const char *ast_get_include_registrar(struct ast_include *i)
5524 return i ? i->registrar : NULL;
5527 const char *ast_get_ignorepat_registrar(struct ast_ignorepat *ip)
5529 return ip ? ip->registrar : NULL;
5532 int ast_get_extension_matchcid(struct ast_exten *e)
5534 return e ? e->matchcid : 0;
5537 const char *ast_get_extension_cidmatch(struct ast_exten *e)
5539 return e ? e->cidmatch : NULL;
5542 const char *ast_get_extension_app(struct ast_exten *e)
5544 return e ? e->app : NULL;
5547 void *ast_get_extension_app_data(struct ast_exten *e)
5549 return e ? e->data : NULL;
5552 const char *ast_get_switch_name(struct ast_sw *sw)
5554 return sw ? sw->name : NULL;
5557 const char *ast_get_switch_data(struct ast_sw *sw)
5559 return sw ? sw->data : NULL;
5562 const char *ast_get_switch_registrar(struct ast_sw *sw)
5564 return sw ? sw->registrar : NULL;
5568 * Walking functions ...
5570 struct ast_context *ast_walk_contexts(struct ast_context *con)
5572 return con ? con->next : contexts;
5575 struct ast_exten *ast_walk_context_extensions(struct ast_context *con,
5576 struct ast_exten *exten)
5578 if (!exten)
5579 return con ? con->root : NULL;
5580 else
5581 return exten->next;
5584 struct ast_sw *ast_walk_context_switches(struct ast_context *con,
5585 struct ast_sw *sw)
5587 if (!sw)
5588 return con ? AST_LIST_FIRST(&con->alts) : NULL;
5589 else
5590 return AST_LIST_NEXT(sw, list);
5593 struct ast_exten *ast_walk_extension_priorities(struct ast_exten *exten,
5594 struct ast_exten *priority)
5596 return priority ? priority->peer : exten;
5599 struct ast_include *ast_walk_context_includes(struct ast_context *con,
5600 struct ast_include *inc)
5602 if (!inc)
5603 return con ? con->includes : NULL;
5604 else
5605 return inc->next;
5608 struct ast_ignorepat *ast_walk_context_ignorepats(struct ast_context *con,
5609 struct ast_ignorepat *ip)
5611 if (!ip)
5612 return con ? con->ignorepats : NULL;
5613 else
5614 return ip->next;
5617 int ast_context_verify_includes(struct ast_context *con)
5619 struct ast_include *inc = NULL;
5620 int res = 0;
5622 while ( (inc = ast_walk_context_includes(con, inc)) )
5623 if (!ast_context_find(inc->rname)) {
5624 res = -1;
5625 ast_log(LOG_WARNING, "Context '%s' tries includes nonexistent context '%s'\n",
5626 ast_get_context_name(con), inc->rname);
5628 return res;
5632 static int __ast_goto_if_exists(struct ast_channel *chan, const char *context, const char *exten, int priority, int async)
5634 int (*goto_func)(struct ast_channel *chan, const char *context, const char *exten, int priority);
5636 if (!chan)
5637 return -2;
5639 if (context == NULL)
5640 context = chan->context;
5641 if (exten == NULL)
5642 exten = chan->exten;
5644 goto_func = (async) ? ast_async_goto : ast_explicit_goto;
5645 if (ast_exists_extension(chan, context, exten, priority, chan->cid.cid_num))
5646 return goto_func(chan, context, exten, priority);
5647 else
5648 return -3;
5651 int ast_goto_if_exists(struct ast_channel *chan, const char* context, const char *exten, int priority)
5653 return __ast_goto_if_exists(chan, context, exten, priority, 0);
5656 int ast_async_goto_if_exists(struct ast_channel *chan, const char * context, const char *exten, int priority)
5658 return __ast_goto_if_exists(chan, context, exten, priority, 1);
5661 int ast_parseable_goto(struct ast_channel *chan, const char *goto_string)
5663 char *exten, *pri, *context;
5664 char *stringp;
5665 int ipri;
5666 int mode = 0;
5668 if (ast_strlen_zero(goto_string)) {
5669 ast_log(LOG_WARNING, "Goto requires an argument (optional context|optional extension|priority)\n");
5670 return -1;
5672 stringp = ast_strdupa(goto_string);
5673 context = strsep(&stringp, "|"); /* guaranteed non-null */
5674 exten = strsep(&stringp, "|");
5675 pri = strsep(&stringp, "|");
5676 if (!exten) { /* Only a priority in this one */
5677 pri = context;
5678 exten = NULL;
5679 context = NULL;
5680 } else if (!pri) { /* Only an extension and priority in this one */
5681 pri = exten;
5682 exten = context;
5683 context = NULL;
5685 if (*pri == '+') {
5686 mode = 1;
5687 pri++;
5688 } else if (*pri == '-') {
5689 mode = -1;
5690 pri++;
5692 if (sscanf(pri, "%d", &ipri) != 1) {
5693 if ((ipri = ast_findlabel_extension(chan, context ? context : chan->context, exten ? exten : chan->exten,
5694 pri, chan->cid.cid_num)) < 1) {
5695 ast_log(LOG_WARNING, "Priority '%s' must be a number > 0, or valid label\n", pri);
5696 return -1;
5697 } else
5698 mode = 0;
5700 /* At this point we have a priority and maybe an extension and a context */
5702 if (mode)
5703 ipri = chan->priority + (ipri * mode);
5705 ast_explicit_goto(chan, context, exten, ipri);
5706 ast_cdr_update(chan);
5707 return 0;