officially deprecate the 'roundrobin' queue strategy in favor of 'rrmemory'
[asterisk-bristuff.git] / pbx.c
blobd2f0c6e5c413b1418f81414eb32df1ffbcf05974
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 an audio file while waiting for digits of an extension to go to.\n",
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 explicitly 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 congestion\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 specified location\n"
330 "in the dialplan if the current time matches the given time specification.\n"
333 { "ExecIfTime", pbx_builtin_execiftime,
334 "Conditional application execution based on the current time",
335 " ExecIfTime(<times>|<weekdays>|<mdays>|<months>?appname[|appargs]):\n"
336 "This application will execute the specified dialplan application, with optional\n"
337 "arguments, if the current time matches the given time specification.\n"
340 { "Hangup", pbx_builtin_hangup,
341 "Hang up the calling channel",
342 " Hangup([causecode]): This application will hang up the calling channel.\n"
343 "If a causecode is given the channel's hangup cause will be set to the given\n"
344 "value.\n"
347 { "NoOp", pbx_builtin_noop,
348 "Do Nothing",
349 " NoOp(): This applicatiion does nothing. However, it is useful for debugging\n"
350 "purposes. Any text that is provided as arguments to this application can be\n"
351 "viewed at the Asterisk CLI. This method can be used to see the evaluations of\n"
352 "variables or functions without having any effect."
355 { "Progress", pbx_builtin_progress,
356 "Indicate progress",
357 " Progress(): This application will request that in-band progress information\n"
358 "be provided to the calling channel.\n"
361 { "ResetCDR", pbx_builtin_resetcdr,
362 "Resets the Call Data Record",
363 " ResetCDR([options]): This application causes the Call Data Record to be\n"
364 "reset.\n"
365 " Options:\n"
366 " w -- Store the current CDR record before resetting it.\n"
367 " a -- Store any stacked records.\n"
368 " v -- Save CDR variables.\n"
371 { "Ringing", pbx_builtin_ringing,
372 "Indicate ringing tone",
373 " Ringing(): This application will request that the channel indicate a ringing\n"
374 "tone to the user.\n"
377 { "SayNumber", pbx_builtin_saynumber,
378 "Say Number",
379 " SayNumber(digits[,gender]): This application will play the sounds that\n"
380 "correspond to the given number. Optionally, a gender may be specified.\n"
381 "This will use the language that is currently set for the channel. See the\n"
382 "LANGUAGE function for more information on setting the language for the channel.\n"
385 { "SayDigits", pbx_builtin_saydigits,
386 "Say Digits",
387 " SayDigits(digits): This application will play the sounds that correspond\n"
388 "to the digits of the given number. This will use the language that is currently\n"
389 "set for the channel. See the LANGUAGE function for more information on setting\n"
390 "the language for the channel.\n"
393 { "SayAlpha", pbx_builtin_saycharacters,
394 "Say Alpha",
395 " SayAlpha(string): This application will play the sounds that correspond to\n"
396 "the letters of the given string.\n"
399 { "SayPhonetic", pbx_builtin_sayphonetic,
400 "Say Phonetic",
401 " SayPhonetic(string): This application will play the sounds from the phonetic\n"
402 "alphabet that correspond to the letters in the given string.\n"
405 { "SetAMAFlags", pbx_builtin_setamaflags,
406 "Set the AMA Flags",
407 " SetAMAFlags([flag]): This application will set the channel's AMA Flags for\n"
408 " billing purposes.\n"
411 { "SetGlobalVar", pbx_builtin_setglobalvar,
412 "Set a global variable to a given value",
413 " SetGlobalVar(variable=value): This application sets a given global variable to\n"
414 "the specified value.\n"
417 { "Set", pbx_builtin_setvar,
418 "Set channel variable(s) or function value(s)",
419 " Set(name1=value1|name2=value2|..[|options])\n"
420 "This function can be used to set the value of channel variables or dialplan\n"
421 "functions. It will accept up to 24 name/value pairs. When setting variables,\n"
422 "if the variable name is prefixed with _, the variable will be inherited into\n"
423 "channels created from the current channel. If the variable name is prefixed\n"
424 "with __, the variable will be inherited into channels created from the current\n"
425 "channel and all children channels.\n"
426 " Options:\n"
427 " g - Set variable globally instead of on the channel\n"
428 " (applies only to variables, not functions)\n"
431 { "ImportVar", pbx_builtin_importvar,
432 "Import a variable from a channel into a new variable",
433 " ImportVar(newvar=channelname|variable): This application imports a variable\n"
434 "from the specified channel (as opposed to the current one) and stores it as\n"
435 "a variable in the current channel (the channel that is calling this\n"
436 "application). Variables created by this application have the same inheritance\n"
437 "properties as those created with the Set application. See the documentation for\n"
438 "Set for more information.\n"
441 { "Wait", pbx_builtin_wait,
442 "Waits for some time",
443 " Wait(seconds): This application waits for a specified number of seconds.\n"
444 "Then, dialplan execution will continue at the next priority.\n"
445 " Note that the seconds can be passed with fractions of a second. For example,\n"
446 "'1.5' will ask the application to wait for 1.5 seconds.\n"
449 { "WaitExten", pbx_builtin_waitexten,
450 "Waits for an extension to be entered",
451 " WaitExten([seconds][|options]): This application waits for the user to enter\n"
452 "a new extension for a specified number of seconds.\n"
453 " Note that the seconds can be passed with fractions of a second. For example,\n"
454 "'1.5' will ask the application to wait for 1.5 seconds.\n"
455 " Options:\n"
456 " m[(x)] - Provide music on hold to the caller while waiting for an extension.\n"
457 " Optionally, specify the class for music on hold within parenthesis.\n"
462 static struct ast_context *contexts = NULL;
463 AST_MUTEX_DEFINE_STATIC(conlock); /*!< Lock for the ast_context list */
465 static AST_LIST_HEAD_STATIC(apps, ast_app);
467 static AST_LIST_HEAD_STATIC(switches, ast_switch);
469 static int stateid = 1;
470 /* WARNING:
471 When holding this list's lock, do _not_ do anything that will cause conlock
472 to be taken, unless you _already_ hold it. The ast_merge_contexts_and_delete
473 function will take the locks in conlock/hints order, so any other
474 paths that require both locks must also take them in that order.
476 static AST_LIST_HEAD_STATIC(hints, ast_hint);
477 struct ast_state_cb *statecbs = NULL;
480 \note This function is special. It saves the stack so that no matter
481 how many times it is called, it returns to the same place */
482 int pbx_exec(struct ast_channel *c, /*!< Channel */
483 struct ast_app *app, /*!< Application */
484 void *data) /*!< Data for execution */
486 int res;
488 const char *saved_c_appl;
489 const char *saved_c_data;
491 if (c->cdr)
492 ast_cdr_setapp(c->cdr, app->name, data);
494 /* save channel values */
495 saved_c_appl= c->appl;
496 saved_c_data= c->data;
498 c->appl = app->name;
499 c->data = data;
500 /* XXX remember what to to when we have linked apps to modules */
501 if (app->module) {
502 /* XXX LOCAL_USER_ADD(app->module) */
504 res = app->execute(c, data);
505 if (app->module) {
506 /* XXX LOCAL_USER_REMOVE(app->module) */
508 /* restore channel values */
509 c->appl = saved_c_appl;
510 c->data = saved_c_data;
511 return res;
515 /*! Go no deeper than this through includes (not counting loops) */
516 #define AST_PBX_MAX_STACK 128
518 /*! \brief Find application handle in linked list
520 struct ast_app *pbx_findapp(const char *app)
522 struct ast_app *tmp;
524 AST_LIST_LOCK(&apps);
525 AST_LIST_TRAVERSE(&apps, tmp, list) {
526 if (!strcasecmp(tmp->name, app))
527 break;
529 AST_LIST_UNLOCK(&apps);
531 return tmp;
534 static struct ast_switch *pbx_findswitch(const char *sw)
536 struct ast_switch *asw;
538 AST_LIST_LOCK(&switches);
539 AST_LIST_TRAVERSE(&switches, asw, list) {
540 if (!strcasecmp(asw->name, sw))
541 break;
543 AST_LIST_UNLOCK(&switches);
545 return asw;
548 static inline int include_valid(struct ast_include *i)
550 if (!i->hastime)
551 return 1;
553 return ast_check_timing(&(i->timing));
556 static void pbx_destroy(struct ast_pbx *p)
558 free(p);
562 * Special characters used in patterns:
563 * '_' underscore is the leading character of a pattern.
564 * In other position it is treated as a regular char.
565 * ' ' '-' space and '-' are separator and ignored.
566 * . one or more of any character. Only allowed at the end of
567 * a pattern.
568 * ! zero or more of anything. Also impacts the result of CANMATCH
569 * and MATCHMORE. Only allowed at the end of a pattern.
570 * In the core routine, ! causes a match with a return code of 2.
571 * In turn, depending on the search mode: (XXX check if it is implemented)
572 * - E_MATCH retuns 1 (does match)
573 * - E_MATCHMORE returns 0 (no match)
574 * - E_CANMATCH returns 1 (does match)
576 * / should not appear as it is considered the separator of the CID info.
577 * XXX at the moment we may stop on this char.
579 * X Z N match ranges 0-9, 1-9, 2-9 respectively.
580 * [ denotes the start of a set of character. Everything inside
581 * is considered literally. We can have ranges a-d and individual
582 * characters. A '[' and '-' can be considered literally if they
583 * are just before ']'.
584 * XXX currently there is no way to specify ']' in a range, nor \ is
585 * considered specially.
587 * When we compare a pattern with a specific extension, all characters in the extension
588 * itself are considered literally with the only exception of '-' which is considered
589 * as a separator and thus ignored.
590 * XXX do we want to consider space as a separator as well ?
591 * XXX do we want to consider the separators in non-patterns as well ?
595 * \brief helper functions to sort extensions and patterns in the desired way,
596 * so that more specific patterns appear first.
598 * ext_cmp1 compares individual characters (or sets of), returning
599 * an int where bits 0-7 are the ASCII code of the first char in the set,
600 * while bit 8-15 are the cardinality of the set minus 1.
601 * This way more specific patterns (smaller cardinality) appear first.
602 * Wildcards have a special value, so that we can directly compare them to
603 * sets by subtracting the two values. In particular:
604 * 0x000xx one character, xx
605 * 0x0yyxx yy character set starting with xx
606 * 0x10000 '.' (one or more of anything)
607 * 0x20000 '!' (zero or more of anything)
608 * 0x30000 NUL (end of string)
609 * 0x40000 error in set.
610 * The pointer to the string is advanced according to needs.
611 * NOTES:
612 * 1. the empty set is equivalent to NUL.
613 * 2. given that a full set has always 0 as the first element,
614 * we could encode the special cases as 0xffXX where XX
615 * is 1, 2, 3, 4 as used above.
617 static int ext_cmp1(const char **p)
619 uint32_t chars[8];
620 int c, cmin = 0xff, count = 0;
621 const char *end;
623 /* load, sign extend and advance pointer until we find
624 * a valid character.
626 while ( (c = *(*p)++) && (c == ' ' || c == '-') )
627 ; /* ignore some characters */
629 /* always return unless we have a set of chars */
630 switch (c) {
631 default: /* ordinary character */
632 return 0x0000 | (c & 0xff);
634 case 'N': /* 2..9 */
635 return 0x0700 | '2' ;
637 case 'X': /* 0..9 */
638 return 0x0900 | '0';
640 case 'Z': /* 1..9 */
641 return 0x0800 | '1';
643 case '.': /* wildcard */
644 return 0x10000;
646 case '!': /* earlymatch */
647 return 0x20000; /* less specific than NULL */
649 case '\0': /* empty string */
650 *p = NULL;
651 return 0x30000;
653 case '[': /* pattern */
654 break;
656 /* locate end of set */
657 end = strchr(*p, ']');
659 if (end == NULL) {
660 ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");
661 return 0x40000; /* XXX make this entry go last... */
664 bzero(chars, sizeof(chars)); /* clear all chars in the set */
665 for (; *p < end ; (*p)++) {
666 unsigned char c1, c2; /* first-last char in range */
667 c1 = (unsigned char)((*p)[0]);
668 if (*p + 2 < end && (*p)[1] == '-') { /* this is a range */
669 c2 = (unsigned char)((*p)[2]);
670 *p += 2; /* skip a total of 3 chars */
671 } else /* individual character */
672 c2 = c1;
673 if (c1 < cmin)
674 cmin = c1;
675 for (; c1 <= c2; c1++) {
676 uint32_t mask = 1 << (c1 % 32);
677 if ( (chars[ c1 / 32 ] & mask) == 0)
678 count += 0x100;
679 chars[ c1 / 32 ] |= mask;
682 (*p)++;
683 return count == 0 ? 0x30000 : (count | cmin);
687 * \brief the full routine to compare extensions in rules.
689 static int ext_cmp(const char *a, const char *b)
691 /* make sure non-patterns come first.
692 * If a is not a pattern, it either comes first or
693 * we use strcmp to compare the strings.
695 int ret = 0;
697 if (a[0] != '_')
698 return (b[0] == '_') ? -1 : strcmp(a, b);
700 /* Now we know a is a pattern; if b is not, a comes first */
701 if (b[0] != '_')
702 return 1;
703 #if 0 /* old mode for ext matching */
704 return strcmp(a, b);
705 #endif
706 /* ok we need full pattern sorting routine */
707 while (!ret && a && b)
708 ret = ext_cmp1(&a) - ext_cmp1(&b);
709 if (ret == 0)
710 return 0;
711 else
712 return (ret > 0) ? 1 : -1;
716 * When looking up extensions, we can have different requests
717 * identified by the 'action' argument, as follows.
718 * Note that the coding is such that the low 4 bits are the
719 * third argument to extension_match_core.
721 enum ext_match_t {
722 E_MATCHMORE = 0x00, /* extension can match but only with more 'digits' */
723 E_CANMATCH = 0x01, /* extension can match with or without more 'digits' */
724 E_MATCH = 0x02, /* extension is an exact match */
725 E_MATCH_MASK = 0x03, /* mask for the argument to extension_match_core() */
726 E_SPAWN = 0x12, /* want to spawn an extension. Requires exact match */
727 E_FINDLABEL = 0x22 /* returns the priority for a given label. Requires exact match */
731 * Internal function for ast_extension_{match|close}
732 * return 0 on no-match, 1 on match, 2 on early match.
733 * mode is as follows:
734 * E_MATCH success only on exact match
735 * E_MATCHMORE success only on partial match (i.e. leftover digits in pattern)
736 * E_CANMATCH either of the above.
738 static int _extension_match_core(const char *pattern, const char *data, enum ext_match_t mode)
740 mode &= E_MATCH_MASK; /* only consider the relevant bits */
742 if (pattern[0] != '_') { /* not a pattern, try exact or partial match */
743 int ld = strlen(data), lp = strlen(pattern);
745 if (lp < ld) /* pattern too short, cannot match */
746 return 0;
747 /* depending on the mode, accept full or partial match or both */
748 if (mode == E_MATCH)
749 return !strcmp(pattern, data); /* 1 on match, 0 on fail */
750 if (ld == 0 || !strncasecmp(pattern, data, ld)) /* partial or full match */
751 return (mode == E_MATCHMORE) ? lp > ld : 1; /* XXX should consider '!' and '/' ? */
752 else
753 return 0;
755 pattern++; /* skip leading _ */
757 * XXX below we stop at '/' which is a separator for the CID info. However we should
758 * not store '/' in the pattern at all. When we insure it, we can remove the checks.
760 while (*data && *pattern && *pattern != '/') {
761 const char *end;
763 if (*data == '-') { /* skip '-' in data (just a separator) */
764 data++;
765 continue;
767 switch (toupper(*pattern)) {
768 case '[': /* a range */
769 end = strchr(pattern+1, ']'); /* XXX should deal with escapes ? */
770 if (end == NULL) {
771 ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");
772 return 0; /* unconditional failure */
774 for (pattern++; pattern != end; pattern++) {
775 if (pattern+2 < end && pattern[1] == '-') { /* this is a range */
776 if (*data >= pattern[0] && *data <= pattern[2])
777 break; /* match found */
778 else {
779 pattern += 2; /* skip a total of 3 chars */
780 continue;
782 } else if (*data == pattern[0])
783 break; /* match found */
785 if (pattern == end)
786 return 0;
787 pattern = end; /* skip and continue */
788 break;
789 case 'N':
790 if (*data < '2' || *data > '9')
791 return 0;
792 break;
793 case 'X':
794 if (*data < '0' || *data > '9')
795 return 0;
796 break;
797 case 'Z':
798 if (*data < '1' || *data > '9')
799 return 0;
800 break;
801 case '.': /* Must match, even with more digits */
802 return 1;
803 case '!': /* Early match */
804 return 2;
805 case ' ':
806 case '-': /* Ignore these in patterns */
807 data--; /* compensate the final data++ */
808 break;
809 default:
810 if (*data != *pattern)
811 return 0;
813 data++;
814 pattern++;
816 if (*data) /* data longer than pattern, no match */
817 return 0;
819 * match so far, but ran off the end of the data.
820 * Depending on what is next, determine match or not.
822 if (*pattern == '\0' || *pattern == '/') /* exact match */
823 return (mode == E_MATCHMORE) ? 0 : 1; /* this is a failure for E_MATCHMORE */
824 else if (*pattern == '!') /* early match */
825 return 2;
826 else /* partial match */
827 return (mode == E_MATCH) ? 0 : 1; /* this is a failure for E_MATCH */
831 * Wrapper around _extension_match_core() to do performance measurement
832 * using the profiling code.
834 static int extension_match_core(const char *pattern, const char *data, enum ext_match_t mode)
836 int i;
837 static int prof_id = -2; /* marker for 'unallocated' id */
838 if (prof_id == -2)
839 prof_id = ast_add_profile("ext_match", 0);
840 ast_mark(prof_id, 1);
841 i = _extension_match_core(pattern, data, mode);
842 ast_mark(prof_id, 0);
843 return i;
846 int ast_extension_match(const char *pattern, const char *data)
848 return extension_match_core(pattern, data, E_MATCH);
851 int ast_extension_close(const char *pattern, const char *data, int needmore)
853 if (needmore != E_MATCHMORE && needmore != E_CANMATCH)
854 ast_log(LOG_WARNING, "invalid argument %d\n", needmore);
855 return extension_match_core(pattern, data, needmore);
858 struct ast_context *ast_context_find(const char *name)
860 struct ast_context *tmp = NULL;
861 ast_mutex_lock(&conlock);
862 while ( (tmp = ast_walk_contexts(tmp)) ) {
863 if (!name || !strcasecmp(name, tmp->name))
864 break;
866 ast_mutex_unlock(&conlock);
867 return tmp;
870 #define STATUS_NO_CONTEXT 1
871 #define STATUS_NO_EXTENSION 2
872 #define STATUS_NO_PRIORITY 3
873 #define STATUS_NO_LABEL 4
874 #define STATUS_SUCCESS 5
876 static int matchcid(const char *cidpattern, const char *callerid)
878 /* If the Caller*ID pattern is empty, then we're matching NO Caller*ID, so
879 failing to get a number should count as a match, otherwise not */
881 if (ast_strlen_zero(callerid))
882 return ast_strlen_zero(cidpattern) ? 1 : 0;
884 return ast_extension_match(cidpattern, callerid);
887 /* request and result for pbx_find_extension */
888 struct pbx_find_info {
889 #if 0
890 const char *context;
891 const char *exten;
892 int priority;
893 #endif
895 char *incstack[AST_PBX_MAX_STACK]; /* filled during the search */
896 int stacklen; /* modified during the search */
897 int status; /* set on return */
898 struct ast_switch *swo; /* set on return */
899 const char *data; /* set on return */
900 const char *foundcontext; /* set on return */
903 static struct ast_exten *pbx_find_extension(struct ast_channel *chan,
904 struct ast_context *bypass, struct pbx_find_info *q,
905 const char *context, const char *exten, int priority,
906 const char *label, const char *callerid, enum ext_match_t action)
908 int x, res;
909 struct ast_context *tmp;
910 struct ast_exten *e, *eroot;
911 struct ast_include *i;
912 struct ast_sw *sw;
914 /* Initialize status if appropriate */
915 if (q->stacklen == 0) {
916 q->status = STATUS_NO_CONTEXT;
917 q->swo = NULL;
918 q->data = NULL;
919 q->foundcontext = NULL;
921 /* Check for stack overflow */
922 if (q->stacklen >= AST_PBX_MAX_STACK) {
923 ast_log(LOG_WARNING, "Maximum PBX stack exceeded\n");
924 return NULL;
926 /* Check first to see if we've already been checked */
927 for (x = 0; x < q->stacklen; x++) {
928 if (!strcasecmp(q->incstack[x], context))
929 return NULL;
931 if (bypass) /* bypass means we only look there */
932 tmp = bypass;
933 else { /* look in contexts */
934 tmp = NULL;
935 while ((tmp = ast_walk_contexts(tmp)) ) {
936 if (!strcmp(tmp->name, context))
937 break;
939 if (!tmp)
940 return NULL;
942 if (q->status < STATUS_NO_EXTENSION)
943 q->status = STATUS_NO_EXTENSION;
945 /* scan the list trying to match extension and CID */
946 eroot = NULL;
947 while ( (eroot = ast_walk_context_extensions(tmp, eroot)) ) {
948 int match = extension_match_core(eroot->exten, exten, action);
949 /* 0 on fail, 1 on match, 2 on earlymatch */
951 if (!match || (eroot->matchcid && !matchcid(eroot->cidmatch, callerid)))
952 continue; /* keep trying */
953 if (match == 2 && action == E_MATCHMORE) {
954 /* We match an extension ending in '!'.
955 * The decision in this case is final and is NULL (no match).
957 return NULL;
959 /* found entry, now look for the right priority */
960 if (q->status < STATUS_NO_PRIORITY)
961 q->status = STATUS_NO_PRIORITY;
962 e = NULL;
963 while ( (e = ast_walk_extension_priorities(eroot, e)) ) {
964 /* Match label or priority */
965 if (action == E_FINDLABEL) {
966 if (q->status < STATUS_NO_LABEL)
967 q->status = STATUS_NO_LABEL;
968 if (label && e->label && !strcmp(label, e->label))
969 break; /* found it */
970 } else if (e->priority == priority) {
971 break; /* found it */
972 } /* else keep searching */
974 if (e) { /* found a valid match */
975 q->status = STATUS_SUCCESS;
976 q->foundcontext = context;
977 return e;
980 /* Check alternative switches */
981 AST_LIST_TRAVERSE(&tmp->alts, sw, list) {
982 struct ast_switch *asw = pbx_findswitch(sw->name);
983 ast_switch_f *aswf = NULL;
984 char *datap;
986 if (!asw) {
987 ast_log(LOG_WARNING, "No such switch '%s'\n", sw->name);
988 continue;
990 /* Substitute variables now */
991 if (sw->eval)
992 pbx_substitute_variables_helper(chan, sw->data, sw->tmpdata, SWITCH_DATA_LENGTH - 1);
994 /* equivalent of extension_match_core() at the switch level */
995 if (action == E_CANMATCH)
996 aswf = asw->canmatch;
997 else if (action == E_MATCHMORE)
998 aswf = asw->matchmore;
999 else /* action == E_MATCH */
1000 aswf = asw->exists;
1001 datap = sw->eval ? sw->tmpdata : sw->data;
1002 res = !aswf ? 0 : aswf(chan, context, exten, priority, callerid, datap);
1003 if (res) { /* Got a match */
1004 q->swo = asw;
1005 q->data = datap;
1006 q->foundcontext = context;
1007 /* XXX keep status = STATUS_NO_CONTEXT ? */
1008 return NULL;
1011 q->incstack[q->stacklen++] = tmp->name; /* Setup the stack */
1012 /* Now try any includes we have in this context */
1013 for (i = tmp->includes; i; i = i->next) {
1014 if (include_valid(i)) {
1015 if ((e = pbx_find_extension(chan, bypass, q, i->rname, exten, priority, label, callerid, action)))
1016 return e;
1017 if (q->swo)
1018 return NULL;
1021 return NULL;
1024 /* Note that it's negative -- that's important later. */
1025 #define DONT_HAVE_LENGTH 0x80000000
1027 /*! \brief extract offset:length from variable name.
1028 * Returns 1 if there is a offset:length part, which is
1029 * trimmed off (values go into variables)
1031 static int parse_variable_name(char *var, int *offset, int *length, int *isfunc)
1033 int parens=0;
1035 *offset = 0;
1036 *length = DONT_HAVE_LENGTH;
1037 *isfunc = 0;
1038 for (; *var; var++) {
1039 if (*var == '(') {
1040 (*isfunc)++;
1041 parens++;
1042 } else if (*var == ')') {
1043 parens--;
1044 } else if (*var == ':' && parens == 0) {
1045 *var++ = '\0';
1046 sscanf(var, "%d:%d", offset, length);
1047 return 1; /* offset:length valid */
1050 return 0;
1053 /*! \brief takes a substring. It is ok to call with value == workspace.
1055 * offset < 0 means start from the end of the string and set the beginning
1056 * to be that many characters back.
1057 * length is the length of the substring, -1 means unlimited
1058 * (we take any negative value).
1059 * Always return a copy in workspace.
1061 static char *substring(const char *value, int offset, int length, char *workspace, size_t workspace_len)
1063 char *ret = workspace;
1064 int lr; /* length of the input string after the copy */
1066 ast_copy_string(workspace, value, workspace_len); /* always make a copy */
1068 /* Quick check if no need to do anything */
1069 if (offset == 0 && length < 0) /* take the whole string */
1070 return ret;
1072 lr = strlen(ret); /* compute length after copy, so we never go out of the workspace */
1074 if (offset < 0) { /* translate negative offset into positive ones */
1075 offset = lr + offset;
1076 if (offset < 0) /* If the negative offset was greater than the length of the string, just start at the beginning */
1077 offset = 0;
1080 /* too large offset result in empty string so we know what to return */
1081 if (offset >= lr)
1082 return ret + lr; /* the final '\0' */
1084 ret += offset; /* move to the start position */
1085 if (length >= 0 && length < lr - offset) /* truncate if necessary */
1086 ret[length] = '\0';
1088 return ret;
1091 /*! \brief pbx_retrieve_variable: Support for Asterisk built-in variables and
1092 functions in the dialplan
1093 ---*/
1094 void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp)
1096 const char not_found = '\0';
1097 char *tmpvar;
1098 const char *s; /* the result */
1099 int offset, length;
1100 int i, need_substring;
1101 struct varshead *places[2] = { headp, &globals }; /* list of places where we may look */
1103 if (c) {
1104 places[0] = &c->varshead;
1107 * Make a copy of var because parse_variable_name() modifies the string.
1108 * Then if called directly, we might need to run substring() on the result;
1109 * remember this for later in 'need_substring', 'offset' and 'length'
1111 tmpvar = ast_strdupa(var); /* parse_variable_name modifies the string */
1112 need_substring = parse_variable_name(tmpvar, &offset, &length, &i /* ignored */);
1115 * Look first into predefined variables, then into variable lists.
1116 * Variable 's' points to the result, according to the following rules:
1117 * s == &not_found (set at the beginning) means that we did not find a
1118 * matching variable and need to look into more places.
1119 * If s != &not_found, s is a valid result string as follows:
1120 * s = NULL if the variable does not have a value;
1121 * you typically do this when looking for an unset predefined variable.
1122 * s = workspace if the result has been assembled there;
1123 * typically done when the result is built e.g. with an snprintf(),
1124 * so we don't need to do an additional copy.
1125 * s != workspace in case we have a string, that needs to be copied
1126 * (the ast_copy_string is done once for all at the end).
1127 * Typically done when the result is already available in some string.
1129 s = &not_found; /* default value */
1130 if (c) { /* This group requires a valid channel */
1131 /* Names with common parts are looked up a piece at a time using strncmp. */
1132 if (!strncmp(var, "CALL", 4)) {
1133 if (!strncmp(var + 4, "ING", 3)) {
1134 if (!strcmp(var + 7, "PRES")) { /* CALLINGPRES */
1135 snprintf(workspace, workspacelen, "%d", c->cid.cid_pres);
1136 s = workspace;
1137 } else if (!strcmp(var + 7, "ANI2")) { /* CALLINGANI2 */
1138 snprintf(workspace, workspacelen, "%d", c->cid.cid_ani2);
1139 s = workspace;
1140 } else if (!strcmp(var + 7, "TON")) { /* CALLINGTON */
1141 snprintf(workspace, workspacelen, "%d", c->cid.cid_ton);
1142 s = workspace;
1143 } else if (!strcmp(var + 7, "TNS")) { /* CALLINGTNS */
1144 snprintf(workspace, workspacelen, "%d", c->cid.cid_tns);
1145 s = workspace;
1148 } else if (!strcmp(var, "HINT")) {
1149 s = ast_get_hint(workspace, workspacelen, NULL, 0, c, c->context, c->exten) ? workspace : NULL;
1150 } else if (!strcmp(var, "HINTNAME")) {
1151 s = ast_get_hint(NULL, 0, workspace, workspacelen, c, c->context, c->exten) ? workspace : NULL;
1152 } else if (!strcmp(var, "EXTEN")) {
1153 s = c->exten;
1154 } else if (!strcmp(var, "CONTEXT")) {
1155 s = c->context;
1156 } else if (!strcmp(var, "PRIORITY")) {
1157 snprintf(workspace, workspacelen, "%d", c->priority);
1158 s = workspace;
1159 } else if (!strcmp(var, "CHANNEL")) {
1160 s = c->name;
1161 } else if (!strcmp(var, "UNIQUEID")) {
1162 s = c->uniqueid;
1163 } else if (!strcmp(var, "HANGUPCAUSE")) {
1164 snprintf(workspace, workspacelen, "%d", c->hangupcause);
1165 s = workspace;
1168 if (s == &not_found) { /* look for more */
1169 if (!strcmp(var, "EPOCH")) {
1170 snprintf(workspace, workspacelen, "%u",(int)time(NULL));
1171 s = workspace;
1172 } else if (!strcmp(var, "SYSTEMNAME")) {
1173 s = ast_config_AST_SYSTEM_NAME;
1176 /* if not found, look into chanvars or global vars */
1177 for (i = 0; s == &not_found && i < (sizeof(places) / sizeof(places[0])); i++) {
1178 struct ast_var_t *variables;
1179 if (!places[i])
1180 continue;
1181 if (places[i] == &globals)
1182 ast_mutex_lock(&globalslock);
1183 AST_LIST_TRAVERSE(places[i], variables, entries) {
1184 if (strcasecmp(ast_var_name(variables), var)==0) {
1185 s = ast_var_value(variables);
1186 break;
1189 if (places[i] == &globals)
1190 ast_mutex_unlock(&globalslock);
1192 if (s == &not_found || s == NULL)
1193 *ret = NULL;
1194 else {
1195 if (s != workspace)
1196 ast_copy_string(workspace, s, workspacelen);
1197 *ret = workspace;
1198 if (need_substring)
1199 *ret = substring(*ret, offset, length, workspace, workspacelen);
1203 /*! \brief CLI function to show installed custom functions
1204 \addtogroup CLI_functions
1206 static int handle_show_functions(int fd, int argc, char *argv[])
1208 struct ast_custom_function *acf;
1209 int count_acf = 0;
1210 int like = 0;
1212 if (argc == 4 && (!strcmp(argv[2], "like")) ) {
1213 like = 1;
1214 } else if (argc != 2) {
1215 return RESULT_SHOWUSAGE;
1218 ast_cli(fd, "%s Custom Functions:\n--------------------------------------------------------------------------------\n", like ? "Matching" : "Installed");
1220 AST_LIST_LOCK(&acf_root);
1221 AST_LIST_TRAVERSE(&acf_root, acf, acflist) {
1222 if (!like || strstr(acf->name, argv[3])) {
1223 count_acf++;
1224 ast_cli(fd, "%-20.20s %-35.35s %s\n", acf->name, acf->syntax, acf->synopsis);
1227 AST_LIST_UNLOCK(&acf_root);
1229 ast_cli(fd, "%d %scustom functions installed.\n", count_acf, like ? "matching " : "");
1231 return RESULT_SUCCESS;
1234 static int handle_show_function(int fd, int argc, char *argv[])
1236 struct ast_custom_function *acf;
1237 /* Maximum number of characters added by terminal coloring is 22 */
1238 char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
1239 char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
1240 char stxtitle[40], *syntax = NULL;
1241 int synopsis_size, description_size, syntax_size;
1243 if (argc < 3)
1244 return RESULT_SHOWUSAGE;
1246 if (!(acf = ast_custom_function_find(argv[2]))) {
1247 ast_cli(fd, "No function by that name registered.\n");
1248 return RESULT_FAILURE;
1252 if (acf->synopsis)
1253 synopsis_size = strlen(acf->synopsis) + 23;
1254 else
1255 synopsis_size = strlen("Not available") + 23;
1256 synopsis = alloca(synopsis_size);
1258 if (acf->desc)
1259 description_size = strlen(acf->desc) + 23;
1260 else
1261 description_size = strlen("Not available") + 23;
1262 description = alloca(description_size);
1264 if (acf->syntax)
1265 syntax_size = strlen(acf->syntax) + 23;
1266 else
1267 syntax_size = strlen("Not available") + 23;
1268 syntax = alloca(syntax_size);
1270 snprintf(info, 64 + AST_MAX_APP, "\n -= Info about function '%s' =- \n\n", acf->name);
1271 term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
1272 term_color(stxtitle, "[Syntax]\n", COLOR_MAGENTA, 0, 40);
1273 term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
1274 term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
1275 term_color(syntax,
1276 acf->syntax ? acf->syntax : "Not available",
1277 COLOR_CYAN, 0, syntax_size);
1278 term_color(synopsis,
1279 acf->synopsis ? acf->synopsis : "Not available",
1280 COLOR_CYAN, 0, synopsis_size);
1281 term_color(description,
1282 acf->desc ? acf->desc : "Not available",
1283 COLOR_CYAN, 0, description_size);
1285 ast_cli(fd,"%s%s%s\n\n%s%s\n\n%s%s\n", infotitle, stxtitle, syntax, syntitle, synopsis, destitle, description);
1287 return RESULT_SUCCESS;
1290 static char *complete_show_function(const char *line, const char *word, int pos, int state)
1292 struct ast_custom_function *acf;
1293 char *ret = NULL;
1294 int which = 0;
1295 int wordlen = strlen(word);
1297 /* case-insensitive for convenience in this 'complete' function */
1298 AST_LIST_LOCK(&acf_root);
1299 AST_LIST_TRAVERSE(&acf_root, acf, acflist) {
1300 if (!strncasecmp(word, acf->name, wordlen) && ++which > state) {
1301 ret = strdup(acf->name);
1302 break;
1305 AST_LIST_UNLOCK(&acf_root);
1307 return ret;
1310 struct ast_custom_function *ast_custom_function_find(const char *name)
1312 struct ast_custom_function *acf = NULL;
1314 AST_LIST_LOCK(&acf_root);
1315 AST_LIST_TRAVERSE(&acf_root, acf, acflist) {
1316 if (!strcmp(name, acf->name))
1317 break;
1319 AST_LIST_UNLOCK(&acf_root);
1321 return acf;
1324 int ast_custom_function_unregister(struct ast_custom_function *acf)
1326 struct ast_custom_function *cur;
1328 if (!acf)
1329 return -1;
1331 AST_LIST_LOCK(&acf_root);
1332 AST_LIST_TRAVERSE_SAFE_BEGIN(&acf_root, cur, acflist) {
1333 if (cur == acf) {
1334 AST_LIST_REMOVE_CURRENT(&acf_root, acflist);
1335 if (option_verbose > 1)
1336 ast_verbose(VERBOSE_PREFIX_2 "Unregistered custom function %s\n", acf->name);
1337 break;
1340 AST_LIST_TRAVERSE_SAFE_END
1341 AST_LIST_UNLOCK(&acf_root);
1343 return acf ? 0 : -1;
1346 int ast_custom_function_register(struct ast_custom_function *acf)
1348 struct ast_custom_function *cur;
1350 if (!acf)
1351 return -1;
1353 AST_LIST_LOCK(&acf_root);
1355 if (ast_custom_function_find(acf->name)) {
1356 ast_log(LOG_ERROR, "Function %s already registered.\n", acf->name);
1357 AST_LIST_UNLOCK(&acf_root);
1358 return -1;
1361 /* Store in alphabetical order */
1362 AST_LIST_TRAVERSE_SAFE_BEGIN(&acf_root, cur, acflist) {
1363 if (strcasecmp(acf->name, cur->name) < 0) {
1364 AST_LIST_INSERT_BEFORE_CURRENT(&acf_root, acf, acflist);
1365 break;
1368 AST_LIST_TRAVERSE_SAFE_END
1369 if (!cur)
1370 AST_LIST_INSERT_TAIL(&acf_root, acf, acflist);
1372 AST_LIST_UNLOCK(&acf_root);
1374 if (option_verbose > 1)
1375 ast_verbose(VERBOSE_PREFIX_2 "Registered custom function %s\n", acf->name);
1377 return 0;
1380 /*! \brief return a pointer to the arguments of the function,
1381 * and terminates the function name with '\\0'
1383 static char *func_args(char *function)
1385 char *args = strchr(function, '(');
1387 if (!args)
1388 ast_log(LOG_WARNING, "Function doesn't contain parentheses. Assuming null argument.\n");
1389 else {
1390 char *p;
1391 *args++ = '\0';
1392 if ((p = strrchr(args, ')')) )
1393 *p = '\0';
1394 else
1395 ast_log(LOG_WARNING, "Can't find trailing parenthesis?\n");
1397 return args;
1400 int ast_func_read(struct ast_channel *chan, char *function, char *workspace, size_t len)
1402 char *args = func_args(function);
1403 struct ast_custom_function *acfptr = ast_custom_function_find(function);
1405 if (acfptr == NULL)
1406 ast_log(LOG_ERROR, "Function %s not registered\n", function);
1407 else if (!acfptr->read)
1408 ast_log(LOG_ERROR, "Function %s cannot be read\n", function);
1409 else
1410 return acfptr->read(chan, function, args, workspace, len);
1411 return -1;
1414 int ast_func_write(struct ast_channel *chan, char *function, const char *value)
1416 char *args = func_args(function);
1417 struct ast_custom_function *acfptr = ast_custom_function_find(function);
1419 if (acfptr == NULL)
1420 ast_log(LOG_ERROR, "Function %s not registered\n", function);
1421 else if (!acfptr->write)
1422 ast_log(LOG_ERROR, "Function %s cannot be written to\n", function);
1423 else
1424 return acfptr->write(chan, function, args, value);
1426 return -1;
1429 static void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int count)
1431 /* Substitutes variables into cp2, based on string cp1, and assuming cp2 to be
1432 zero-filled */
1433 char *cp4;
1434 const char *tmp, *whereweare;
1435 int length, offset, offset2, isfunction;
1436 char *workspace = NULL;
1437 char *ltmp = NULL, *var = NULL;
1438 char *nextvar, *nextexp, *nextthing;
1439 char *vars, *vare;
1440 int pos, brackets, needsub, len;
1442 whereweare=tmp=cp1;
1443 while (!ast_strlen_zero(whereweare) && count) {
1444 /* Assume we're copying the whole remaining string */
1445 pos = strlen(whereweare);
1446 nextvar = NULL;
1447 nextexp = NULL;
1448 nextthing = strchr(whereweare, '$');
1449 if (nextthing) {
1450 switch(nextthing[1]) {
1451 case '{':
1452 nextvar = nextthing;
1453 pos = nextvar - whereweare;
1454 break;
1455 case '[':
1456 nextexp = nextthing;
1457 pos = nextexp - whereweare;
1458 break;
1462 if (pos) {
1463 /* Can't copy more than 'count' bytes */
1464 if (pos > count)
1465 pos = count;
1467 /* Copy that many bytes */
1468 memcpy(cp2, whereweare, pos);
1470 count -= pos;
1471 cp2 += pos;
1472 whereweare += pos;
1475 if (nextvar) {
1476 /* We have a variable. Find the start and end, and determine
1477 if we are going to have to recursively call ourselves on the
1478 contents */
1479 vars = vare = nextvar + 2;
1480 brackets = 1;
1481 needsub = 0;
1483 /* Find the end of it */
1484 while (brackets && *vare) {
1485 if ((vare[0] == '$') && (vare[1] == '{')) {
1486 needsub++;
1487 } else if (vare[0] == '{') {
1488 brackets++;
1489 } else if (vare[0] == '}') {
1490 brackets--;
1491 } else if ((vare[0] == '$') && (vare[1] == '['))
1492 needsub++;
1493 vare++;
1495 if (brackets)
1496 ast_log(LOG_NOTICE, "Error in extension logic (missing '}')\n");
1497 len = vare - vars - 1;
1499 /* Skip totally over variable string */
1500 whereweare += (len + 3);
1502 if (!var)
1503 var = alloca(VAR_BUF_SIZE);
1505 /* Store variable name (and truncate) */
1506 ast_copy_string(var, vars, len + 1);
1508 /* Substitute if necessary */
1509 if (needsub) {
1510 if (!ltmp)
1511 ltmp = alloca(VAR_BUF_SIZE);
1513 memset(ltmp, 0, VAR_BUF_SIZE);
1514 pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1);
1515 vars = ltmp;
1516 } else {
1517 vars = var;
1520 if (!workspace)
1521 workspace = alloca(VAR_BUF_SIZE);
1523 workspace[0] = '\0';
1525 parse_variable_name(vars, &offset, &offset2, &isfunction);
1526 if (isfunction) {
1527 /* Evaluate function */
1528 cp4 = ast_func_read(c, vars, workspace, VAR_BUF_SIZE) ? NULL : workspace;
1530 ast_log(LOG_DEBUG, "Function result is '%s'\n", cp4 ? cp4 : "(null)");
1531 } else {
1532 /* Retrieve variable value */
1533 pbx_retrieve_variable(c, vars, &cp4, workspace, VAR_BUF_SIZE, headp);
1535 if (cp4) {
1536 cp4 = substring(cp4, offset, offset2, workspace, VAR_BUF_SIZE);
1538 length = strlen(cp4);
1539 if (length > count)
1540 length = count;
1541 memcpy(cp2, cp4, length);
1542 count -= length;
1543 cp2 += length;
1545 } else if (nextexp) {
1546 /* We have an expression. Find the start and end, and determine
1547 if we are going to have to recursively call ourselves on the
1548 contents */
1549 vars = vare = nextexp + 2;
1550 brackets = 1;
1551 needsub = 0;
1553 /* Find the end of it */
1554 while(brackets && *vare) {
1555 if ((vare[0] == '$') && (vare[1] == '[')) {
1556 needsub++;
1557 brackets++;
1558 vare++;
1559 } else if (vare[0] == '[') {
1560 brackets++;
1561 } else if (vare[0] == ']') {
1562 brackets--;
1563 } else if ((vare[0] == '$') && (vare[1] == '{')) {
1564 needsub++;
1565 vare++;
1567 vare++;
1569 if (brackets)
1570 ast_log(LOG_NOTICE, "Error in extension logic (missing ']')\n");
1571 len = vare - vars - 1;
1573 /* Skip totally over expression */
1574 whereweare += (len + 3);
1576 if (!var)
1577 var = alloca(VAR_BUF_SIZE);
1579 /* Store variable name (and truncate) */
1580 ast_copy_string(var, vars, len + 1);
1582 /* Substitute if necessary */
1583 if (needsub) {
1584 if (!ltmp)
1585 ltmp = alloca(VAR_BUF_SIZE);
1587 memset(ltmp, 0, VAR_BUF_SIZE);
1588 pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1);
1589 vars = ltmp;
1590 } else {
1591 vars = var;
1594 length = ast_expr(vars, cp2, count);
1596 if (length) {
1597 ast_log(LOG_DEBUG, "Expression result is '%s'\n", cp2);
1598 count -= length;
1599 cp2 += length;
1601 } else
1602 break;
1606 void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
1608 pbx_substitute_variables_helper_full(c, (c) ? &c->varshead : NULL, cp1, cp2, count);
1611 void pbx_substitute_variables_varshead(struct varshead *headp, const char *cp1, char *cp2, int count)
1613 pbx_substitute_variables_helper_full(NULL, headp, cp1, cp2, count);
1616 static void pbx_substitute_variables(char *passdata, int datalen, struct ast_channel *c, struct ast_exten *e)
1618 memset(passdata, 0, datalen);
1620 /* No variables or expressions in e->data, so why scan it? */
1621 if (!strchr(e->data, '$') && !strstr(e->data,"${") && !strstr(e->data,"$[") && !strstr(e->data,"$(")) {
1622 ast_copy_string(passdata, e->data, datalen);
1623 return;
1626 pbx_substitute_variables_helper(c, e->data, passdata, datalen - 1);
1629 /*! \brief The return value depends on the action:
1631 * E_MATCH, E_CANMATCH, E_MATCHMORE require a real match,
1632 * and return 0 on failure, -1 on match;
1633 * E_FINDLABEL maps the label to a priority, and returns
1634 * the priority on success, ... XXX
1635 * E_SPAWN, spawn an application,
1636 * and return 0 on success, -1 on failure.
1638 static int pbx_extension_helper(struct ast_channel *c, struct ast_context *con,
1639 const char *context, const char *exten, int priority,
1640 const char *label, const char *callerid, enum ext_match_t action)
1642 struct ast_exten *e;
1643 struct ast_app *app;
1644 int res;
1645 struct pbx_find_info q = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */
1646 char passdata[EXT_DATA_SIZE];
1648 int matching_action = (action == E_MATCH || action == E_CANMATCH || action == E_MATCHMORE);
1650 ast_mutex_lock(&conlock);
1651 e = pbx_find_extension(c, con, &q, context, exten, priority, label, callerid, action);
1652 if (e) {
1653 if (matching_action) {
1654 ast_mutex_unlock(&conlock);
1655 return -1; /* success, we found it */
1656 } else if (action == E_FINDLABEL) { /* map the label to a priority */
1657 res = e->priority;
1658 ast_mutex_unlock(&conlock);
1659 return res; /* the priority we were looking for */
1660 } else { /* spawn */
1661 app = pbx_findapp(e->app);
1662 ast_mutex_unlock(&conlock);
1663 if (!app) {
1664 ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
1665 return -1;
1667 if (c->context != context)
1668 ast_copy_string(c->context, context, sizeof(c->context));
1669 if (c->exten != exten)
1670 ast_copy_string(c->exten, exten, sizeof(c->exten));
1671 c->priority = priority;
1672 pbx_substitute_variables(passdata, sizeof(passdata), c, e);
1673 if (option_debug) {
1674 char atmp[80];
1675 char atmp2[EXT_DATA_SIZE+100];
1676 ast_log(LOG_DEBUG, "Launching '%s'\n", app->name);
1677 snprintf(atmp, sizeof(atmp), "STACK-%s-%s-%d", context, exten, priority);
1678 snprintf(atmp2, sizeof(atmp2), "%s(\"%s\", \"%s\") %s",
1679 app->name, c->name, passdata, "in new stack");
1680 pbx_builtin_setvar_helper(c, atmp, atmp2);
1682 if (option_verbose > 2) {
1683 char tmp[80], tmp2[80], tmp3[EXT_DATA_SIZE];
1684 ast_verbose( VERBOSE_PREFIX_3 "Executing [%s:%d] %s(\"%s\", \"%s\") %s\n",
1685 context, priority,
1686 term_color(tmp, app->name, COLOR_BRCYAN, 0, sizeof(tmp)),
1687 term_color(tmp2, c->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
1688 term_color(tmp3, passdata, COLOR_BRMAGENTA, 0, sizeof(tmp3)),
1689 "in new stack");
1691 manager_event(EVENT_FLAG_CALL, "Newexten",
1692 "Channel: %s\r\n"
1693 "Context: %s\r\n"
1694 "Extension: %s\r\n"
1695 "Priority: %d\r\n"
1696 "Application: %s\r\n"
1697 "AppData: %s\r\n"
1698 "Uniqueid: %s\r\n",
1699 c->name, c->context, c->exten, c->priority, app->name, passdata, c->uniqueid);
1700 return pbx_exec(c, app, passdata); /* 0 on success, -1 on failure */
1702 } else if (q.swo) { /* not found here, but in another switch */
1703 ast_mutex_unlock(&conlock);
1704 if (matching_action)
1705 return -1;
1706 else {
1707 if (!q.swo->exec) {
1708 ast_log(LOG_WARNING, "No execution engine for switch %s\n", q.swo->name);
1709 res = -1;
1711 return q.swo->exec(c, q.foundcontext ? q.foundcontext : context, exten, priority, callerid, q.data);
1713 } else { /* not found anywhere, see what happened */
1714 ast_mutex_unlock(&conlock);
1715 switch (q.status) {
1716 case STATUS_NO_CONTEXT:
1717 if (!matching_action)
1718 ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", context);
1719 break;
1720 case STATUS_NO_EXTENSION:
1721 if (!matching_action)
1722 ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, context);
1723 break;
1724 case STATUS_NO_PRIORITY:
1725 if (!matching_action)
1726 ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, context);
1727 break;
1728 case STATUS_NO_LABEL:
1729 if (context)
1730 ast_log(LOG_NOTICE, "No such label '%s' in extension '%s' in context '%s'\n", label, exten, context);
1731 break;
1732 default:
1733 ast_log(LOG_DEBUG, "Shouldn't happen!\n");
1736 return (matching_action) ? 0 : -1;
1740 /*! \brief ast_hint_extension: Find hint for given extension in context */
1741 static struct ast_exten *ast_hint_extension(struct ast_channel *c, const char *context, const char *exten)
1743 struct ast_exten *e;
1744 struct pbx_find_info q = { .stacklen = 0 }; /* the rest is set in pbx_find_context */
1746 ast_mutex_lock(&conlock);
1747 e = pbx_find_extension(c, NULL, &q, context, exten, PRIORITY_HINT, NULL, "", E_MATCH);
1748 ast_mutex_unlock(&conlock);
1750 return e;
1753 /*! \brief ast_extensions_state2: Check state of extension by using hints */
1754 static int ast_extension_state2(struct ast_exten *e)
1756 char hint[AST_MAX_EXTENSION];
1757 char *cur, *rest;
1758 int allunavailable = 1, allbusy = 1, allfree = 1;
1759 int busy = 0, inuse = 0, ring = 0;
1761 if (!e)
1762 return -1;
1764 ast_copy_string(hint, ast_get_extension_app(e), sizeof(hint));
1766 rest = hint; /* One or more devices separated with a & character */
1767 while ( (cur = strsep(&rest, "&")) ) {
1768 int res = ast_device_state(cur);
1769 switch (res) {
1770 case AST_DEVICE_NOT_INUSE:
1771 allunavailable = 0;
1772 allbusy = 0;
1773 break;
1774 case AST_DEVICE_INUSE:
1775 inuse = 1;
1776 allunavailable = 0;
1777 allfree = 0;
1778 break;
1779 case AST_DEVICE_RINGING:
1780 ring = 1;
1781 allunavailable = 0;
1782 allfree = 0;
1783 break;
1784 case AST_DEVICE_RINGINUSE:
1785 inuse = 1;
1786 ring = 1;
1787 allunavailable = 0;
1788 allfree = 0;
1789 break;
1790 case AST_DEVICE_BUSY:
1791 allunavailable = 0;
1792 allfree = 0;
1793 busy = 1;
1794 break;
1795 case AST_DEVICE_UNAVAILABLE:
1796 case AST_DEVICE_INVALID:
1797 allbusy = 0;
1798 allfree = 0;
1799 break;
1800 default:
1801 allunavailable = 0;
1802 allbusy = 0;
1803 allfree = 0;
1807 if (!inuse && ring)
1808 return AST_EXTENSION_RINGING;
1809 if (inuse && ring)
1810 return (AST_EXTENSION_INUSE | AST_EXTENSION_RINGING);
1811 if (inuse)
1812 return AST_EXTENSION_INUSE;
1813 if (allfree)
1814 return AST_EXTENSION_NOT_INUSE;
1815 if (allbusy)
1816 return AST_EXTENSION_BUSY;
1817 if (allunavailable)
1818 return AST_EXTENSION_UNAVAILABLE;
1819 if (busy)
1820 return AST_EXTENSION_INUSE;
1822 return AST_EXTENSION_NOT_INUSE;
1825 /*! \brief ast_extension_state2str: Return extension_state as string */
1826 const char *ast_extension_state2str(int extension_state)
1828 int i;
1830 for (i = 0; (i < (sizeof(extension_states) / sizeof(extension_states[0]))); i++) {
1831 if (extension_states[i].extension_state == extension_state)
1832 return extension_states[i].text;
1834 return "Unknown";
1837 /*! \brief ast_extension_state: Check extension state for an extension by using hint */
1838 int ast_extension_state(struct ast_channel *c, const char *context, const char *exten)
1840 struct ast_exten *e;
1842 e = ast_hint_extension(c, context, exten); /* Do we have a hint for this extension ? */
1843 if (!e)
1844 return -1; /* No hint, return -1 */
1846 return ast_extension_state2(e); /* Check all devices in the hint */
1849 void ast_hint_state_changed(const char *device)
1851 struct ast_hint *hint;
1853 AST_LIST_LOCK(&hints);
1855 AST_LIST_TRAVERSE(&hints, hint, list) {
1856 struct ast_state_cb *cblist;
1857 char buf[AST_MAX_EXTENSION];
1858 char *parse = buf;
1859 char *cur;
1860 int state;
1862 ast_copy_string(buf, ast_get_extension_app(hint->exten), sizeof(buf));
1863 while ( (cur = strsep(&parse, "&")) ) {
1864 if (!strcasecmp(cur, device))
1865 break;
1867 if (!cur)
1868 continue;
1870 /* Get device state for this hint */
1871 state = ast_extension_state2(hint->exten);
1873 if ((state == -1) || (state == hint->laststate))
1874 continue;
1876 /* Device state changed since last check - notify the watchers */
1878 /* For general callbacks */
1879 for (cblist = statecbs; cblist; cblist = cblist->next)
1880 cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data);
1882 /* For extension callbacks */
1883 for (cblist = hint->callbacks; cblist; cblist = cblist->next)
1884 cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data);
1886 hint->laststate = state; /* record we saw the change */
1889 AST_LIST_UNLOCK(&hints);
1892 /*! \brief ast_extension_state_add: Add watcher for extension states */
1893 int ast_extension_state_add(const char *context, const char *exten,
1894 ast_state_cb_type callback, void *data)
1896 struct ast_hint *hint;
1897 struct ast_state_cb *cblist;
1898 struct ast_exten *e;
1900 /* If there's no context and extension: add callback to statecbs list */
1901 if (!context && !exten) {
1902 AST_LIST_LOCK(&hints);
1904 for (cblist = statecbs; cblist; cblist = cblist->next) {
1905 if (cblist->callback == callback) {
1906 cblist->data = data;
1907 AST_LIST_UNLOCK(&hints);
1908 return 0;
1912 /* Now insert the callback */
1913 if (!(cblist = ast_calloc(1, sizeof(*cblist)))) {
1914 AST_LIST_UNLOCK(&hints);
1915 return -1;
1917 cblist->id = 0;
1918 cblist->callback = callback;
1919 cblist->data = data;
1921 cblist->next = statecbs;
1922 statecbs = cblist;
1924 AST_LIST_UNLOCK(&hints);
1925 return 0;
1928 if (!context || !exten)
1929 return -1;
1931 /* This callback type is for only one hint, so get the hint */
1932 e = ast_hint_extension(NULL, context, exten);
1933 if (!e) {
1934 return -1;
1937 /* Find the hint in the list of hints */
1938 AST_LIST_LOCK(&hints);
1940 AST_LIST_TRAVERSE(&hints, hint, list) {
1941 if (hint->exten == e)
1942 break;
1945 if (!hint) {
1946 /* We have no hint, sorry */
1947 AST_LIST_UNLOCK(&hints);
1948 return -1;
1951 /* Now insert the callback in the callback list */
1952 if (!(cblist = ast_calloc(1, sizeof(*cblist)))) {
1953 AST_LIST_UNLOCK(&hints);
1954 return -1;
1956 cblist->id = stateid++; /* Unique ID for this callback */
1957 cblist->callback = callback; /* Pointer to callback routine */
1958 cblist->data = data; /* Data for the callback */
1960 cblist->next = hint->callbacks;
1961 hint->callbacks = cblist;
1963 AST_LIST_UNLOCK(&hints);
1964 return cblist->id;
1967 /*! \brief ast_extension_state_del: Remove a watcher from the callback list */
1968 int ast_extension_state_del(int id, ast_state_cb_type callback)
1970 struct ast_state_cb **p_cur = NULL; /* address of pointer to us */
1971 int ret = -1;
1973 if (!id && !callback)
1974 return -1;
1976 AST_LIST_LOCK(&hints);
1978 if (!id) { /* id == 0 is a callback without extension */
1979 for (p_cur = &statecbs; *p_cur; p_cur = &(*p_cur)->next) {
1980 if ((*p_cur)->callback == callback)
1981 break;
1983 } else { /* callback with extension, find the callback based on ID */
1984 struct ast_hint *hint;
1985 AST_LIST_TRAVERSE(&hints, hint, list) {
1986 for (p_cur = &hint->callbacks; *p_cur; p_cur = &(*p_cur)->next) {
1987 if ((*p_cur)->id == id)
1988 break;
1990 if (*p_cur) /* found in the inner loop */
1991 break;
1994 if (p_cur && *p_cur) {
1995 struct ast_state_cb *cur = *p_cur;
1996 *p_cur = cur->next;
1997 free(cur);
1998 ret = 0;
2000 AST_LIST_UNLOCK(&hints);
2001 return ret;
2004 /*! \brief ast_add_hint: Add hint to hint list, check initial extension state */
2005 static int ast_add_hint(struct ast_exten *e)
2007 struct ast_hint *hint;
2009 if (!e)
2010 return -1;
2012 AST_LIST_LOCK(&hints);
2014 /* Search if hint exists, do nothing */
2015 AST_LIST_TRAVERSE(&hints, hint, list) {
2016 if (hint->exten == e) {
2017 AST_LIST_UNLOCK(&hints);
2018 if (option_debug > 1)
2019 ast_log(LOG_DEBUG, "HINTS: Not re-adding existing hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
2020 return -1;
2024 if (option_debug > 1)
2025 ast_log(LOG_DEBUG, "HINTS: Adding hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
2027 if (!(hint = ast_calloc(1, sizeof(*hint)))) {
2028 AST_LIST_UNLOCK(&hints);
2029 return -1;
2031 /* Initialize and insert new item at the top */
2032 hint->exten = e;
2033 hint->laststate = ast_extension_state2(e);
2034 AST_LIST_INSERT_HEAD(&hints, hint, list);
2036 AST_LIST_UNLOCK(&hints);
2037 return 0;
2040 /*! \brief ast_change_hint: Change hint for an extension */
2041 static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
2043 struct ast_hint *hint;
2044 int res = -1;
2046 AST_LIST_LOCK(&hints);
2047 AST_LIST_TRAVERSE(&hints, hint, list) {
2048 if (hint->exten == oe) {
2049 hint->exten = ne;
2050 res = 0;
2051 break;
2054 AST_LIST_UNLOCK(&hints);
2056 return res;
2059 /*! \brief ast_remove_hint: Remove hint from extension */
2060 static int ast_remove_hint(struct ast_exten *e)
2062 /* Cleanup the Notifys if hint is removed */
2063 struct ast_hint *hint;
2064 struct ast_state_cb *cblist, *cbprev;
2065 int res = -1;
2067 if (!e)
2068 return -1;
2070 AST_LIST_LOCK(&hints);
2071 AST_LIST_TRAVERSE_SAFE_BEGIN(&hints, hint, list) {
2072 if (hint->exten == e) {
2073 cbprev = NULL;
2074 cblist = hint->callbacks;
2075 while (cblist) {
2076 /* Notify with -1 and remove all callbacks */
2077 cbprev = cblist;
2078 cblist = cblist->next;
2079 cbprev->callback(hint->exten->parent->name, hint->exten->exten, AST_EXTENSION_DEACTIVATED, cbprev->data);
2080 free(cbprev);
2082 hint->callbacks = NULL;
2083 AST_LIST_REMOVE_CURRENT(&hints, list);
2084 free(hint);
2085 res = 0;
2086 break;
2089 AST_LIST_TRAVERSE_SAFE_END
2090 AST_LIST_UNLOCK(&hints);
2092 return res;
2096 /*! \brief ast_get_hint: Get hint for channel */
2097 int ast_get_hint(char *hint, int hintsize, char *name, int namesize, struct ast_channel *c, const char *context, const char *exten)
2099 struct ast_exten *e = ast_hint_extension(c, context, exten);
2101 if (e) {
2102 if (hint)
2103 ast_copy_string(hint, ast_get_extension_app(e), hintsize);
2104 if (name) {
2105 const char *tmp = ast_get_extension_app_data(e);
2106 if (tmp)
2107 ast_copy_string(name, tmp, namesize);
2109 return -1;
2111 return 0;
2114 int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
2116 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_MATCH);
2119 int ast_findlabel_extension(struct ast_channel *c, const char *context, const char *exten, const char *label, const char *callerid)
2121 return pbx_extension_helper(c, NULL, context, exten, 0, label, callerid, E_FINDLABEL);
2124 int ast_findlabel_extension2(struct ast_channel *c, struct ast_context *con, const char *exten, const char *label, const char *callerid)
2126 return pbx_extension_helper(c, con, NULL, exten, 0, label, callerid, E_FINDLABEL);
2129 int ast_canmatch_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
2131 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_CANMATCH);
2134 int ast_matchmore_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
2136 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_MATCHMORE);
2139 int ast_spawn_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
2141 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_SPAWN);
2144 /* helper function to set extension and priority */
2145 static void set_ext_pri(struct ast_channel *c, const char *exten, int pri)
2147 ast_copy_string(c->exten, exten, sizeof(c->exten));
2148 c->priority = pri;
2152 * \brief collect digits from the channel into the buffer,
2153 * return -1 on error, 0 on timeout or done.
2155 static int collect_digits(struct ast_channel *c, int waittime, char *buf, int buflen, int pos)
2157 int digit;
2159 buf[pos] = '\0'; /* make sure it is properly terminated */
2160 while (ast_matchmore_extension(c, c->context, buf, 1, c->cid.cid_num)) {
2161 /* As long as we're willing to wait, and as long as it's not defined,
2162 keep reading digits until we can't possibly get a right answer anymore. */
2163 digit = ast_waitfordigit(c, waittime * 1000);
2164 if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
2165 c->_softhangup = 0;
2166 } else {
2167 if (!digit) /* No entry */
2168 break;
2169 if (digit < 0) /* Error, maybe a hangup */
2170 return -1;
2171 if (pos < buflen - 1) { /* XXX maybe error otherwise ? */
2172 buf[pos++] = digit;
2173 buf[pos] = '\0';
2175 waittime = c->pbx->dtimeout;
2178 return 0;
2181 static int __ast_pbx_run(struct ast_channel *c)
2183 int found = 0; /* set if we find at least one match */
2184 int res = 0;
2185 int autoloopflag;
2186 int error = 0; /* set an error conditions */
2188 /* A little initial setup here */
2189 if (c->pbx) {
2190 ast_log(LOG_WARNING, "%s already has PBX structure??\n", c->name);
2191 /* XXX and now what ? */
2192 free(c->pbx);
2194 if (!(c->pbx = ast_calloc(1, sizeof(*c->pbx))))
2195 return -1;
2196 if (c->amaflags) {
2197 if (!c->cdr) {
2198 c->cdr = ast_cdr_alloc();
2199 if (!c->cdr) {
2200 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
2201 free(c->pbx);
2202 return -1;
2204 ast_cdr_init(c->cdr, c);
2207 /* Set reasonable defaults */
2208 c->pbx->rtimeout = 10;
2209 c->pbx->dtimeout = 5;
2211 autoloopflag = ast_test_flag(c, AST_FLAG_IN_AUTOLOOP); /* save value to restore at the end */
2212 ast_set_flag(c, AST_FLAG_IN_AUTOLOOP);
2214 /* Start by trying whatever the channel is set to */
2215 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2216 /* If not successful fall back to 's' */
2217 if (option_verbose > 1)
2218 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);
2219 /* XXX the original code used the existing priority in the call to
2220 * ast_exists_extension(), and reset it to 1 afterwards.
2221 * I believe the correct thing is to set it to 1 immediately.
2223 set_ext_pri(c, "s", 1);
2224 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2225 /* JK02: And finally back to default if everything else failed */
2226 if (option_verbose > 1)
2227 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);
2228 ast_copy_string(c->context, "default", sizeof(c->context));
2231 if (c->cdr && ast_tvzero(c->cdr->start))
2232 ast_cdr_start(c->cdr);
2233 for (;;) {
2234 char dst_exten[256]; /* buffer to accumulate digits */
2235 int pos = 0; /* XXX should check bounds */
2236 int digit = 0;
2238 /* loop on priorities in this context/exten */
2239 while (ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2240 found = 1;
2241 if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
2242 /* Something bad happened, or a hangup has been requested. */
2243 if (strchr("0123456789ABCDEF*#", res)) {
2244 ast_log(LOG_DEBUG, "Oooh, got something to jump out with ('%c')!\n", res);
2245 pos = 0;
2246 dst_exten[pos++] = digit = res;
2247 dst_exten[pos] = '\0';
2248 break;
2250 if (res == AST_PBX_KEEPALIVE) {
2251 if (option_debug)
2252 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
2253 else if (option_verbose > 1)
2254 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
2255 error = 1;
2256 break;
2258 if (option_debug)
2259 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2260 else if (option_verbose > 1)
2261 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2262 if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
2263 c->_softhangup =0;
2264 } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
2265 /* atimeout, nothing bad */
2266 } else {
2267 if (c->cdr)
2268 ast_cdr_update(c);
2269 error = 1;
2270 break;
2273 if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT && ast_exists_extension(c,c->context,"T",1,c->cid.cid_num)) {
2274 set_ext_pri(c, "T", 0); /* 0 will become 1 with the c->priority++; at the end */
2275 /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
2276 c->whentohangup = 0;
2277 c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
2278 } else if (c->_softhangup) {
2279 ast_log(LOG_DEBUG, "Extension %s, priority %d returned normally even though call was hung up\n",
2280 c->exten, c->priority);
2281 error = 1;
2282 break;
2284 c->priority++;
2285 } /* end while - from here on we can use 'break' to go out */
2286 if (error)
2287 break;
2289 /* XXX we get here on non-existing extension or a keypress or hangup ? */
2291 if (!ast_exists_extension(c, c->context, c->exten, 1, c->cid.cid_num)) {
2292 /* If there is no match at priority 1, it is not a valid extension anymore.
2293 * Try to continue at "i", 1 or exit if the latter does not exist.
2295 if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
2296 if (option_verbose > 2)
2297 ast_verbose(VERBOSE_PREFIX_3 "Sent into invalid extension '%s' in context '%s' on %s\n", c->exten, c->context, c->name);
2298 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", c->exten);
2299 set_ext_pri(c, "i", 1);
2300 } else {
2301 ast_log(LOG_WARNING, "Channel '%s' sent into invalid extension '%s' in context '%s', but no invalid handler\n",
2302 c->name, c->exten, c->context);
2303 error = 1; /* we know what to do with it */
2304 break;
2306 } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
2307 /* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */
2308 c->_softhangup = 0;
2309 } else { /* keypress received, get more digits for a full extension */
2310 int waittime = 0;
2311 if (digit)
2312 waittime = c->pbx->dtimeout;
2313 else if (!autofallthrough)
2314 waittime = c->pbx->rtimeout;
2315 if (!waittime) {
2316 const char *status = pbx_builtin_getvar_helper(c, "DIALSTATUS");
2317 if (!status)
2318 status = "UNKNOWN";
2319 if (option_verbose > 2)
2320 ast_verbose(VERBOSE_PREFIX_2 "Auto fallthrough, channel '%s' status is '%s'\n", c->name, status);
2321 if (!strcasecmp(status, "CONGESTION"))
2322 res = pbx_builtin_congestion(c, "10");
2323 else if (!strcasecmp(status, "CHANUNAVAIL"))
2324 res = pbx_builtin_congestion(c, "10");
2325 else if (!strcasecmp(status, "BUSY"))
2326 res = pbx_builtin_busy(c, "10");
2327 error = 1; /* XXX disable message */
2328 break; /* exit from the 'for' loop */
2331 if (collect_digits(c, waittime, dst_exten, sizeof(dst_exten), pos))
2332 break;
2333 if (ast_exists_extension(c, c->context, dst_exten, 1, c->cid.cid_num)) /* Prepare the next cycle */
2334 set_ext_pri(c, dst_exten, 1);
2335 else {
2336 /* No such extension */
2337 if (!ast_strlen_zero(dst_exten)) {
2338 /* An invalid extension */
2339 if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
2340 if (option_verbose > 2)
2341 ast_verbose( VERBOSE_PREFIX_3 "Invalid extension '%s' in context '%s' on %s\n", dst_exten, c->context, c->name);
2342 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", dst_exten);
2343 set_ext_pri(c, "i", 1);
2344 } else {
2345 ast_log(LOG_WARNING, "Invalid extension '%s', but no rule 'i' in context '%s'\n", dst_exten, c->context);
2346 found = 1; /* XXX disable message */
2347 break;
2349 } else {
2350 /* A simple timeout */
2351 if (ast_exists_extension(c, c->context, "t", 1, c->cid.cid_num)) {
2352 if (option_verbose > 2)
2353 ast_verbose( VERBOSE_PREFIX_3 "Timeout on %s\n", c->name);
2354 set_ext_pri(c, "t", 1);
2355 } else {
2356 ast_log(LOG_WARNING, "Timeout, but no rule 't' in context '%s'\n", c->context);
2357 found = 1; /* XXX disable message */
2358 break;
2362 if (c->cdr) {
2363 if (option_verbose > 2)
2364 ast_verbose(VERBOSE_PREFIX_2 "CDR updated on %s\n",c->name);
2365 ast_cdr_update(c);
2369 if (!found && !error)
2370 ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", c->name);
2371 if ((res != AST_PBX_KEEPALIVE) && ast_exists_extension(c, c->context, "h", 1, c->cid.cid_num)) {
2372 if (c->cdr && ast_opt_end_cdr_before_h_exten)
2373 ast_cdr_end(c->cdr);
2374 set_ext_pri(c, "h", 1);
2375 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2376 if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
2377 /* Something bad happened, or a hangup has been requested. */
2378 if (option_debug)
2379 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2380 else if (option_verbose > 1)
2381 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2382 break;
2384 c->priority++;
2387 ast_set2_flag(c, autoloopflag, AST_FLAG_IN_AUTOLOOP);
2389 pbx_destroy(c->pbx);
2390 c->pbx = NULL;
2391 if (res != AST_PBX_KEEPALIVE)
2392 ast_hangup(c);
2393 return 0;
2396 /* Returns 0 on success, non-zero if call limit was reached */
2397 static int increase_call_count(const struct ast_channel *c)
2399 int failed = 0;
2400 double curloadavg;
2401 ast_mutex_lock(&maxcalllock);
2402 if (option_maxcalls) {
2403 if (countcalls >= option_maxcalls) {
2404 ast_log(LOG_NOTICE, "Maximum call limit of %d calls exceeded by '%s'!\n", option_maxcalls, c->name);
2405 failed = -1;
2408 if (option_maxload) {
2409 getloadavg(&curloadavg, 1);
2410 if (curloadavg >= option_maxload) {
2411 ast_log(LOG_NOTICE, "Maximum loadavg limit of %f load exceeded by '%s' (currently %f)!\n", option_maxload, c->name, curloadavg);
2412 failed = -1;
2415 if (!failed)
2416 countcalls++;
2417 ast_mutex_unlock(&maxcalllock);
2419 return failed;
2422 static void decrease_call_count(void)
2424 ast_mutex_lock(&maxcalllock);
2425 if (countcalls > 0)
2426 countcalls--;
2427 ast_mutex_unlock(&maxcalllock);
2430 static void destroy_exten(struct ast_exten *e)
2432 if (e->priority == PRIORITY_HINT)
2433 ast_remove_hint(e);
2435 if (e->datad)
2436 e->datad(e->data);
2437 free(e);
2440 static void *pbx_thread(void *data)
2442 /* Oh joyeous kernel, we're a new thread, with nothing to do but
2443 answer this channel and get it going.
2445 /* NOTE:
2446 The launcher of this function _MUST_ increment 'countcalls'
2447 before invoking the function; it will be decremented when the
2448 PBX has finished running on the channel
2450 struct ast_channel *c = data;
2452 __ast_pbx_run(c);
2453 decrease_call_count();
2455 pthread_exit(NULL);
2457 return NULL;
2460 enum ast_pbx_result ast_pbx_start(struct ast_channel *c)
2462 pthread_t t;
2463 pthread_attr_t attr;
2465 if (!c) {
2466 ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
2467 return AST_PBX_FAILED;
2470 if (increase_call_count(c))
2471 return AST_PBX_CALL_LIMIT;
2473 /* Start a new thread, and get something handling this channel. */
2474 pthread_attr_init(&attr);
2475 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
2476 if (ast_pthread_create(&t, &attr, pbx_thread, c)) {
2477 ast_log(LOG_WARNING, "Failed to create new channel thread\n");
2478 return AST_PBX_FAILED;
2481 return AST_PBX_SUCCESS;
2484 enum ast_pbx_result ast_pbx_run(struct ast_channel *c)
2486 enum ast_pbx_result res = AST_PBX_SUCCESS;
2488 if (increase_call_count(c))
2489 return AST_PBX_CALL_LIMIT;
2491 res = __ast_pbx_run(c);
2492 decrease_call_count();
2494 return res;
2497 int ast_active_calls(void)
2499 return countcalls;
2502 int pbx_set_autofallthrough(int newval)
2504 int oldval = autofallthrough;
2505 autofallthrough = newval;
2506 return oldval;
2509 /* lookup for a context with a given name,
2510 * return with conlock held if found, NULL if not found
2512 static struct ast_context *find_context_locked(const char *context)
2514 struct ast_context *c = NULL;
2516 ast_lock_contexts();
2517 while ( (c = ast_walk_contexts(c)) ) {
2518 if (!strcmp(ast_get_context_name(c), context))
2519 return c;
2521 ast_unlock_contexts();
2523 return NULL;
2527 * This function locks contexts list by &conlist, search for the right context
2528 * structure, leave context list locked and call ast_context_remove_include2
2529 * which removes include, unlock contexts list and return ...
2531 int ast_context_remove_include(const char *context, const char *include, const char *registrar)
2533 int ret = -1;
2534 struct ast_context *c = find_context_locked(context);
2536 if (c) {
2537 /* found, remove include from this context ... */
2538 ret = ast_context_remove_include2(c, include, registrar);
2539 ast_unlock_contexts();
2541 return ret;
2545 * When we call this function, &conlock lock must be locked, because when
2546 * we giving *con argument, some process can remove/change this context
2547 * and after that there can be segfault.
2549 * This function locks given context, removes include, unlock context and
2550 * return.
2552 int ast_context_remove_include2(struct ast_context *con, const char *include, const char *registrar)
2554 struct ast_include *i, *pi = NULL;
2555 int ret = -1;
2557 ast_mutex_lock(&con->lock);
2559 /* find our include */
2560 for (i = con->includes; i; pi = i, i = i->next) {
2561 if (!strcmp(i->name, include) &&
2562 (!registrar || !strcmp(i->registrar, registrar))) {
2563 /* remove from list */
2564 if (pi)
2565 pi->next = i->next;
2566 else
2567 con->includes = i->next;
2568 /* free include and return */
2569 free(i);
2570 ret = 0;
2571 break;
2575 ast_mutex_unlock(&con->lock);
2576 return ret;
2580 * \note This function locks contexts list by &conlist, search for the rigt context
2581 * structure, leave context list locked and call ast_context_remove_switch2
2582 * which removes switch, unlock contexts list and return ...
2584 int ast_context_remove_switch(const char *context, const char *sw, const char *data, const char *registrar)
2586 int ret = -1; /* default error return */
2587 struct ast_context *c = find_context_locked(context);
2589 if (c) {
2590 /* remove switch from this context ... */
2591 ret = ast_context_remove_switch2(c, sw, data, registrar);
2592 ast_unlock_contexts();
2594 return ret;
2598 * \brief This function locks given context, removes switch, unlock context and
2599 * return.
2600 * \note When we call this function, &conlock lock must be locked, because when
2601 * we giving *con argument, some process can remove/change this context
2602 * and after that there can be segfault.
2605 int ast_context_remove_switch2(struct ast_context *con, const char *sw, const char *data, const char *registrar)
2607 struct ast_sw *i;
2608 int ret = -1;
2610 ast_mutex_lock(&con->lock);
2612 /* walk switches */
2613 AST_LIST_TRAVERSE_SAFE_BEGIN(&con->alts, i, list) {
2614 if (!strcmp(i->name, sw) && !strcmp(i->data, data) &&
2615 (!registrar || !strcmp(i->registrar, registrar))) {
2616 /* found, remove from list */
2617 AST_LIST_REMOVE_CURRENT(&con->alts, list);
2618 free(i); /* free switch and return */
2619 ret = 0;
2620 break;
2623 AST_LIST_TRAVERSE_SAFE_END
2625 ast_mutex_unlock(&con->lock);
2627 return ret;
2631 * \note This functions lock contexts list, search for the right context,
2632 * call ast_context_remove_extension2, unlock contexts list and return.
2633 * In this function we are using
2635 int ast_context_remove_extension(const char *context, const char *extension, int priority, const char *registrar)
2637 int ret = -1; /* default error return */
2638 struct ast_context *c = find_context_locked(context);
2640 if (c) { /* ... remove extension ... */
2641 ret = ast_context_remove_extension2(c, extension, priority, registrar);
2642 ast_unlock_contexts();
2644 return ret;
2648 * \brief This functionc locks given context, search for the right extension and
2649 * fires out all peer in this extensions with given priority. If priority
2650 * is set to 0, all peers are removed. After that, unlock context and
2651 * return.
2652 * \note When do you want to call this function, make sure that &conlock is locked,
2653 * because some process can handle with your *con context before you lock
2654 * it.
2657 int ast_context_remove_extension2(struct ast_context *con, const char *extension, int priority, const char *registrar)
2659 struct ast_exten *exten, *prev_exten = NULL;
2660 struct ast_exten *peer;
2662 ast_mutex_lock(&con->lock);
2664 /* scan the extension list to find matching extension-registrar */
2665 for (exten = con->root; exten; prev_exten = exten, exten = exten->next) {
2666 if (!strcmp(exten->exten, extension) &&
2667 (!registrar || !strcmp(exten->registrar, registrar)))
2668 break;
2670 if (!exten) {
2671 /* we can't find right extension */
2672 ast_mutex_unlock(&con->lock);
2673 return -1;
2676 /* should we free all peers in this extension? (priority == 0)? */
2677 if (priority == 0) {
2678 /* remove this extension from context list */
2679 if (prev_exten)
2680 prev_exten->next = exten->next;
2681 else
2682 con->root = exten->next;
2684 /* fire out all peers */
2685 while ( (peer = exten) ) {
2686 exten = peer->peer; /* prepare for next entry */
2687 destroy_exten(peer);
2689 } else {
2690 /* scan the priority list to remove extension with exten->priority == priority */
2691 struct ast_exten *previous_peer = NULL;
2693 for (peer = exten; peer; previous_peer = peer, peer = peer->peer) {
2694 if (peer->priority == priority &&
2695 (!registrar || !strcmp(peer->registrar, registrar) ))
2696 break; /* found our priority */
2698 if (!peer) { /* not found */
2699 ast_mutex_unlock(&con->lock);
2700 return -1;
2702 /* we are first priority extension? */
2703 if (!previous_peer) {
2705 * We are first in the priority chain, so must update the extension chain.
2706 * The next node is either the next priority or the next extension
2708 struct ast_exten *next_node = peer->peer ? peer->peer : peer->next;
2710 if (!prev_exten) /* change the root... */
2711 con->root = next_node;
2712 else
2713 prev_exten->next = next_node; /* unlink */
2714 if (peer->peer) /* XXX update the new head of the pri list */
2715 peer->peer->next = peer->next;
2716 } else { /* easy, we are not first priority in extension */
2717 previous_peer->peer = peer->peer;
2720 /* now, free whole priority extension */
2721 destroy_exten(peer);
2722 /* XXX should we return -1 ? */
2724 ast_mutex_unlock(&con->lock);
2725 return 0;
2729 /*! \brief Dynamically register a new dial plan application */
2730 int ast_register_application(const char *app, int (*execute)(struct ast_channel *, void *), const char *synopsis, const char *description)
2732 struct ast_app *tmp, *cur = NULL;
2733 char tmps[80];
2734 int length;
2736 AST_LIST_LOCK(&apps);
2737 AST_LIST_TRAVERSE(&apps, tmp, list) {
2738 if (!strcasecmp(app, tmp->name)) {
2739 ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
2740 AST_LIST_UNLOCK(&apps);
2741 return -1;
2745 length = sizeof(*tmp) + strlen(app) + 1;
2747 if (!(tmp = ast_calloc(1, length))) {
2748 AST_LIST_UNLOCK(&apps);
2749 return -1;
2752 strcpy(tmp->name, app);
2753 tmp->execute = execute;
2754 tmp->synopsis = synopsis;
2755 tmp->description = description;
2757 /* Store in alphabetical order */
2758 AST_LIST_TRAVERSE_SAFE_BEGIN(&apps, cur, list) {
2759 if (strcasecmp(tmp->name, cur->name) < 0) {
2760 AST_LIST_INSERT_BEFORE_CURRENT(&apps, tmp, list);
2761 break;
2764 AST_LIST_TRAVERSE_SAFE_END
2765 if (!cur)
2766 AST_LIST_INSERT_TAIL(&apps, tmp, list);
2768 if (option_verbose > 1)
2769 ast_verbose( VERBOSE_PREFIX_2 "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
2771 AST_LIST_UNLOCK(&apps);
2773 return 0;
2777 * Append to the list. We don't have a tail pointer because we need
2778 * to scan the list anyways to check for duplicates during insertion.
2780 int ast_register_switch(struct ast_switch *sw)
2782 struct ast_switch *tmp;
2784 AST_LIST_LOCK(&switches);
2785 AST_LIST_TRAVERSE(&switches, tmp, list) {
2786 if (!strcasecmp(tmp->name, sw->name)) {
2787 AST_LIST_UNLOCK(&switches);
2788 ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name);
2789 return -1;
2792 AST_LIST_INSERT_TAIL(&switches, sw, list);
2793 AST_LIST_UNLOCK(&switches);
2795 return 0;
2798 void ast_unregister_switch(struct ast_switch *sw)
2800 AST_LIST_LOCK(&switches);
2801 AST_LIST_REMOVE(&switches, sw, list);
2802 AST_LIST_UNLOCK(&switches);
2806 * Help for CLI commands ...
2808 static char show_application_help[] =
2809 "Usage: show application <application> [<application> [<application> [...]]]\n"
2810 " Describes a particular application.\n";
2812 static char show_functions_help[] =
2813 "Usage: show functions [like <text>]\n"
2814 " List builtin functions, optionally only those matching a given string\n";
2816 static char show_function_help[] =
2817 "Usage: show function <function>\n"
2818 " Describe a particular dialplan function.\n";
2820 static char show_applications_help[] =
2821 "Usage: show applications [{like|describing} <text>]\n"
2822 " List applications which are currently available.\n"
2823 " If 'like', <text> will be a substring of the app name\n"
2824 " If 'describing', <text> will be a substring of the description\n";
2826 static char show_dialplan_help[] =
2827 "Usage: show dialplan [exten@][context]\n"
2828 " Show dialplan\n";
2830 static char show_switches_help[] =
2831 "Usage: show switches\n"
2832 " Show registered switches\n";
2834 static char show_hints_help[] =
2835 "Usage: show hints\n"
2836 " Show registered hints\n";
2838 static char show_globals_help[] =
2839 "Usage: show globals\n"
2840 " Show current global dialplan variables and their values\n";
2842 static char set_global_help[] =
2843 "Usage: set global <name> <value>\n"
2844 " Set global dialplan variable <name> to <value>\n";
2848 * IMPLEMENTATION OF CLI FUNCTIONS IS IN THE SAME ORDER AS COMMANDS HELPS
2853 * \brief 'show application' CLI command implementation functions ...
2857 * There is a possibility to show informations about more than one
2858 * application at one time. You can type 'show application Dial Echo' and
2859 * you will see informations about these two applications ...
2861 static char *complete_show_application(const char *line, const char *word, int pos, int state)
2863 struct ast_app *a;
2864 char *ret = NULL;
2865 int which = 0;
2866 int wordlen = strlen(word);
2868 /* return the n-th [partial] matching entry */
2869 AST_LIST_LOCK(&apps);
2870 AST_LIST_TRAVERSE(&apps, a, list) {
2871 if (!strncasecmp(word, a->name, wordlen) && ++which > state) {
2872 ret = strdup(a->name);
2873 break;
2876 AST_LIST_UNLOCK(&apps);
2878 return ret;
2881 static int handle_show_application(int fd, int argc, char *argv[])
2883 struct ast_app *a;
2884 int app, no_registered_app = 1;
2886 if (argc < 3)
2887 return RESULT_SHOWUSAGE;
2889 /* ... go through all applications ... */
2890 AST_LIST_LOCK(&apps);
2891 AST_LIST_TRAVERSE(&apps, a, list) {
2892 /* ... compare this application name with all arguments given
2893 * to 'show application' command ... */
2894 for (app = 2; app < argc; app++) {
2895 if (!strcasecmp(a->name, argv[app])) {
2896 /* Maximum number of characters added by terminal coloring is 22 */
2897 char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
2898 char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
2899 int synopsis_size, description_size;
2901 no_registered_app = 0;
2903 if (a->synopsis)
2904 synopsis_size = strlen(a->synopsis) + 23;
2905 else
2906 synopsis_size = strlen("Not available") + 23;
2907 synopsis = alloca(synopsis_size);
2909 if (a->description)
2910 description_size = strlen(a->description) + 23;
2911 else
2912 description_size = strlen("Not available") + 23;
2913 description = alloca(description_size);
2915 if (synopsis && description) {
2916 snprintf(info, 64 + AST_MAX_APP, "\n -= Info about application '%s' =- \n\n", a->name);
2917 term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
2918 term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
2919 term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
2920 term_color(synopsis,
2921 a->synopsis ? a->synopsis : "Not available",
2922 COLOR_CYAN, 0, synopsis_size);
2923 term_color(description,
2924 a->description ? a->description : "Not available",
2925 COLOR_CYAN, 0, description_size);
2927 ast_cli(fd,"%s%s%s\n\n%s%s\n", infotitle, syntitle, synopsis, destitle, description);
2928 } else {
2929 /* ... one of our applications, show info ...*/
2930 ast_cli(fd,"\n -= Info about application '%s' =- \n\n"
2931 "[Synopsis]\n %s\n\n"
2932 "[Description]\n%s\n",
2933 a->name,
2934 a->synopsis ? a->synopsis : "Not available",
2935 a->description ? a->description : "Not available");
2940 AST_LIST_UNLOCK(&apps);
2942 /* we found at least one app? no? */
2943 if (no_registered_app) {
2944 ast_cli(fd, "Your application(s) is (are) not registered\n");
2945 return RESULT_FAILURE;
2948 return RESULT_SUCCESS;
2951 /*! \brief handle_show_hints: CLI support for listing registred dial plan hints */
2952 static int handle_show_hints(int fd, int argc, char *argv[])
2954 struct ast_hint *hint;
2955 int num = 0;
2956 int watchers;
2957 struct ast_state_cb *watcher;
2959 if (AST_LIST_EMPTY(&hints)) {
2960 ast_cli(fd, "There are no registered dialplan hints\n");
2961 return RESULT_SUCCESS;
2963 /* ... we have hints ... */
2964 ast_cli(fd, "\n -= Registered Asterisk Dial Plan Hints =-\n");
2965 AST_LIST_LOCK(&hints);
2966 AST_LIST_TRAVERSE(&hints, hint, list) {
2967 watchers = 0;
2968 for (watcher = hint->callbacks; watcher; watcher = watcher->next)
2969 watchers++;
2970 ast_cli(fd, " %20s@%-20.20s: %-20.20s State:%-15.15s Watchers %2d\n",
2971 ast_get_extension_name(hint->exten),
2972 ast_get_context_name(ast_get_extension_context(hint->exten)),
2973 ast_get_extension_app(hint->exten),
2974 ast_extension_state2str(hint->laststate), watchers);
2975 num++;
2977 ast_cli(fd, "----------------\n");
2978 ast_cli(fd, "- %d hints registered\n", num);
2979 AST_LIST_UNLOCK(&hints);
2980 return RESULT_SUCCESS;
2983 /*! \brief handle_show_switches: CLI support for listing registred dial plan switches */
2984 static int handle_show_switches(int fd, int argc, char *argv[])
2986 struct ast_switch *sw;
2988 AST_LIST_LOCK(&switches);
2990 if (AST_LIST_EMPTY(&switches)) {
2991 AST_LIST_UNLOCK(&switches);
2992 ast_cli(fd, "There are no registered alternative switches\n");
2993 return RESULT_SUCCESS;
2996 ast_cli(fd, "\n -= Registered Asterisk Alternative Switches =-\n");
2997 AST_LIST_TRAVERSE(&switches, sw, list)
2998 ast_cli(fd, "%s: %s\n", sw->name, sw->description);
3000 AST_LIST_UNLOCK(&switches);
3002 return RESULT_SUCCESS;
3006 * 'show applications' CLI command implementation functions ...
3008 static int handle_show_applications(int fd, int argc, char *argv[])
3010 struct ast_app *a;
3011 int like = 0, describing = 0;
3012 int total_match = 0; /* Number of matches in like clause */
3013 int total_apps = 0; /* Number of apps registered */
3015 AST_LIST_LOCK(&apps);
3017 if (AST_LIST_EMPTY(&apps)) {
3018 ast_cli(fd, "There are no registered applications\n");
3019 AST_LIST_UNLOCK(&apps);
3020 return -1;
3023 /* show applications like <keyword> */
3024 if ((argc == 4) && (!strcmp(argv[2], "like"))) {
3025 like = 1;
3026 } else if ((argc > 3) && (!strcmp(argv[2], "describing"))) {
3027 describing = 1;
3030 /* show applications describing <keyword1> [<keyword2>] [...] */
3031 if ((!like) && (!describing)) {
3032 ast_cli(fd, " -= Registered Asterisk Applications =-\n");
3033 } else {
3034 ast_cli(fd, " -= Matching Asterisk Applications =-\n");
3037 AST_LIST_TRAVERSE(&apps, a, list) {
3038 int printapp = 0;
3039 total_apps++;
3040 if (like) {
3041 if (strcasestr(a->name, argv[3])) {
3042 printapp = 1;
3043 total_match++;
3045 } else if (describing) {
3046 if (a->description) {
3047 /* Match all words on command line */
3048 int i;
3049 printapp = 1;
3050 for (i = 3; i < argc; i++) {
3051 if (!strcasestr(a->description, argv[i])) {
3052 printapp = 0;
3053 } else {
3054 total_match++;
3058 } else {
3059 printapp = 1;
3062 if (printapp) {
3063 ast_cli(fd," %20s: %s\n", a->name, a->synopsis ? a->synopsis : "<Synopsis not available>");
3066 if ((!like) && (!describing)) {
3067 ast_cli(fd, " -= %d Applications Registered =-\n",total_apps);
3068 } else {
3069 ast_cli(fd, " -= %d Applications Matching =-\n",total_match);
3072 AST_LIST_UNLOCK(&apps);
3074 return RESULT_SUCCESS;
3077 static char *complete_show_applications(const char *line, const char *word, int pos, int state)
3079 static char* choices[] = { "like", "describing", NULL };
3081 return (pos != 2) ? NULL : ast_cli_complete(word, choices, state);
3085 * 'show dialplan' CLI command implementation functions ...
3087 static char *complete_show_dialplan_context(const char *line, const char *word, int pos,
3088 int state)
3090 struct ast_context *c = NULL;
3091 char *ret = NULL;
3092 int which = 0;
3093 int wordlen;
3095 /* we are do completion of [exten@]context on second position only */
3096 if (pos != 2)
3097 return NULL;
3099 ast_lock_contexts();
3101 wordlen = strlen(word);
3103 /* walk through all contexts and return the n-th match */
3104 while ( (c = ast_walk_contexts(c)) ) {
3105 if (!strncasecmp(word, ast_get_context_name(c), wordlen) && ++which > state) {
3106 ret = ast_strdup(ast_get_context_name(c));
3107 break;
3111 ast_unlock_contexts();
3113 return ret;
3116 struct dialplan_counters {
3117 int total_context;
3118 int total_exten;
3119 int total_prio;
3120 int context_existence;
3121 int extension_existence;
3124 /*! \brief helper function to print an extension */
3125 static void print_ext(struct ast_exten *e, char * buf, int buflen)
3127 int prio = ast_get_extension_priority(e);
3128 if (prio == PRIORITY_HINT) {
3129 snprintf(buf, buflen, "hint: %s",
3130 ast_get_extension_app(e));
3131 } else {
3132 snprintf(buf, buflen, "%d. %s(%s)",
3133 prio, ast_get_extension_app(e),
3134 (char *)ast_get_extension_app_data(e));
3138 /* XXX not verified */
3139 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[])
3141 struct ast_context *c = NULL;
3142 int res = 0, old_total_exten = dpc->total_exten;
3144 ast_lock_contexts();
3146 /* walk all contexts ... */
3147 while ( (c = ast_walk_contexts(c)) ) {
3148 struct ast_exten *e;
3149 struct ast_include *i;
3150 struct ast_ignorepat *ip;
3151 char buf[256], buf2[256];
3152 int context_info_printed = 0;
3154 if (context && strcmp(ast_get_context_name(c), context))
3155 continue; /* skip this one, name doesn't match */
3157 dpc->context_existence = 1;
3159 ast_lock_context(c);
3161 /* are we looking for exten too? if yes, we print context
3162 * only if we find our extension.
3163 * Otherwise print context even if empty ?
3164 * XXX i am not sure how the rinclude is handled.
3165 * I think it ought to go inside.
3167 if (!exten) {
3168 dpc->total_context++;
3169 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
3170 ast_get_context_name(c), ast_get_context_registrar(c));
3171 context_info_printed = 1;
3174 /* walk extensions ... */
3175 e = NULL;
3176 while ( (e = ast_walk_context_extensions(c, e)) ) {
3177 struct ast_exten *p;
3179 if (exten && !ast_extension_match(ast_get_extension_name(e), exten))
3180 continue; /* skip, extension match failed */
3182 dpc->extension_existence = 1;
3184 /* may we print context info? */
3185 if (!context_info_printed) {
3186 dpc->total_context++;
3187 if (rinclude) { /* TODO Print more info about rinclude */
3188 ast_cli(fd, "[ Included context '%s' created by '%s' ]\n",
3189 ast_get_context_name(c), ast_get_context_registrar(c));
3190 } else {
3191 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
3192 ast_get_context_name(c), ast_get_context_registrar(c));
3194 context_info_printed = 1;
3196 dpc->total_prio++;
3198 /* write extension name and first peer */
3199 snprintf(buf, sizeof(buf), "'%s' =>", ast_get_extension_name(e));
3201 print_ext(e, buf2, sizeof(buf2));
3203 ast_cli(fd, " %-17s %-45s [%s]\n", buf, buf2,
3204 ast_get_extension_registrar(e));
3206 dpc->total_exten++;
3207 /* walk next extension peers */
3208 p = e; /* skip the first one, we already got it */
3209 while ( (p = ast_walk_extension_priorities(e, p)) ) {
3210 const char *el = ast_get_extension_label(p);
3211 dpc->total_prio++;
3212 if (el)
3213 snprintf(buf, sizeof(buf), " [%s]", el);
3214 else
3215 buf[0] = '\0';
3216 print_ext(p, buf2, sizeof(buf2));
3218 ast_cli(fd," %-17s %-45s [%s]\n", buf, buf2,
3219 ast_get_extension_registrar(p));
3223 /* walk included and write info ... */
3224 i = NULL;
3225 while ( (i = ast_walk_context_includes(c, i)) ) {
3226 snprintf(buf, sizeof(buf), "'%s'", ast_get_include_name(i));
3227 if (exten) {
3228 /* Check all includes for the requested extension */
3229 if (includecount >= AST_PBX_MAX_STACK) {
3230 ast_log(LOG_NOTICE, "Maximum include depth exceeded!\n");
3231 } else {
3232 int dupe=0;
3233 int x;
3234 for (x=0;x<includecount;x++) {
3235 if (!strcasecmp(includes[x], ast_get_include_name(i))) {
3236 dupe++;
3237 break;
3240 if (!dupe) {
3241 includes[includecount] = ast_get_include_name(i);
3242 show_dialplan_helper(fd, ast_get_include_name(i), exten, dpc, i, includecount + 1, includes);
3243 } else {
3244 ast_log(LOG_WARNING, "Avoiding circular include of %s within %s\n", ast_get_include_name(i), context);
3247 } else {
3248 ast_cli(fd, " Include => %-45s [%s]\n",
3249 buf, ast_get_include_registrar(i));
3253 /* walk ignore patterns and write info ... */
3254 ip = NULL;
3255 while ( (ip = ast_walk_context_ignorepats(c, ip)) ) {
3256 const char *ipname = ast_get_ignorepat_name(ip);
3257 char ignorepat[AST_MAX_EXTENSION];
3258 snprintf(buf, sizeof(buf), "'%s'", ipname);
3259 snprintf(ignorepat, sizeof(ignorepat), "_%s.", ipname);
3260 if (!exten || ast_extension_match(ignorepat, exten)) {
3261 ast_cli(fd, " Ignore pattern => %-45s [%s]\n",
3262 buf, ast_get_ignorepat_registrar(ip));
3265 if (!rinclude) {
3266 struct ast_sw *sw = NULL;
3267 while ( (sw = ast_walk_context_switches(c, sw)) ) {
3268 snprintf(buf, sizeof(buf), "'%s/%s'",
3269 ast_get_switch_name(sw),
3270 ast_get_switch_data(sw));
3271 ast_cli(fd, " Alt. Switch => %-45s [%s]\n",
3272 buf, ast_get_switch_registrar(sw));
3276 ast_unlock_context(c);
3278 /* if we print something in context, make an empty line */
3279 if (context_info_printed)
3280 ast_cli(fd, "\r\n");
3282 ast_unlock_contexts();
3284 return (dpc->total_exten == old_total_exten) ? -1 : res;
3287 static int handle_show_dialplan(int fd, int argc, char *argv[])
3289 char *exten = NULL, *context = NULL;
3290 /* Variables used for different counters */
3291 struct dialplan_counters counters;
3293 const char *incstack[AST_PBX_MAX_STACK];
3294 memset(&counters, 0, sizeof(counters));
3296 if (argc != 2 && argc != 3)
3297 return RESULT_SHOWUSAGE;
3299 /* we obtain [exten@]context? if yes, split them ... */
3300 if (argc == 3) {
3301 if (strchr(argv[2], '@')) { /* split into exten & context */
3302 context = ast_strdupa(argv[2]);
3303 exten = strsep(&context, "@");
3304 /* change empty strings to NULL */
3305 if (ast_strlen_zero(exten))
3306 exten = NULL;
3307 } else { /* no '@' char, only context given */
3308 context = argv[2];
3310 if (ast_strlen_zero(context))
3311 context = NULL;
3313 /* else Show complete dial plan, context and exten are NULL */
3314 show_dialplan_helper(fd, context, exten, &counters, NULL, 0, incstack);
3316 /* check for input failure and throw some error messages */
3317 if (context && !counters.context_existence) {
3318 ast_cli(fd, "There is no existence of '%s' context\n", context);
3319 return RESULT_FAILURE;
3322 if (exten && !counters.extension_existence) {
3323 if (context)
3324 ast_cli(fd, "There is no existence of %s@%s extension\n",
3325 exten, context);
3326 else
3327 ast_cli(fd,
3328 "There is no existence of '%s' extension in all contexts\n",
3329 exten);
3330 return RESULT_FAILURE;
3333 ast_cli(fd,"-= %d %s (%d %s) in %d %s. =-\n",
3334 counters.total_exten, counters.total_exten == 1 ? "extension" : "extensions",
3335 counters.total_prio, counters.total_prio == 1 ? "priority" : "priorities",
3336 counters.total_context, counters.total_context == 1 ? "context" : "contexts");
3338 /* everything ok */
3339 return RESULT_SUCCESS;
3342 /*! \brief CLI support for listing global variables in a parseable way */
3343 static int handle_show_globals(int fd, int argc, char *argv[])
3345 int i = 0;
3346 struct ast_var_t *newvariable;
3348 ast_mutex_lock(&globalslock);
3349 AST_LIST_TRAVERSE (&globals, newvariable, entries) {
3350 i++;
3351 ast_cli(fd, " %s=%s\n", ast_var_name(newvariable), ast_var_value(newvariable));
3353 ast_mutex_unlock(&globalslock);
3354 ast_cli(fd, "\n -- %d variables\n", i);
3356 return RESULT_SUCCESS;
3359 /*! \brief CLI support for setting global variables */
3360 static int handle_set_global(int fd, int argc, char *argv[])
3362 if (argc != 4)
3363 return RESULT_SHOWUSAGE;
3365 pbx_builtin_setvar_helper(NULL, argv[2], argv[3]);
3366 ast_cli(fd, "\n -- Global variable %s set to %s\n", argv[2], argv[3]);
3368 return RESULT_SUCCESS;
3374 * CLI entries for upper commands ...
3376 static struct ast_cli_entry pbx_cli[] = {
3377 { { "show", "applications", NULL }, handle_show_applications,
3378 "Shows registered dialplan applications", show_applications_help, complete_show_applications },
3379 { { "show", "functions", NULL }, handle_show_functions,
3380 "Shows registered dialplan functions", show_functions_help },
3381 { { "show" , "function", NULL }, handle_show_function,
3382 "Describe a specific dialplan function", show_function_help, complete_show_function },
3383 { { "show", "application", NULL }, handle_show_application,
3384 "Describe a specific dialplan application", show_application_help, complete_show_application },
3385 { { "show", "dialplan", NULL }, handle_show_dialplan,
3386 "Show dialplan", show_dialplan_help, complete_show_dialplan_context },
3387 { { "show", "switches", NULL }, handle_show_switches,
3388 "Show alternative switches", show_switches_help },
3389 { { "show", "hints", NULL }, handle_show_hints,
3390 "Show dialplan hints", show_hints_help },
3391 { { "show", "globals", NULL }, handle_show_globals,
3392 "Show global dialplan variables", show_globals_help },
3393 { { "set", "global", NULL }, handle_set_global,
3394 "Set global dialplan variable", set_global_help },
3397 int ast_unregister_application(const char *app)
3399 struct ast_app *tmp;
3401 AST_LIST_LOCK(&apps);
3402 AST_LIST_TRAVERSE_SAFE_BEGIN(&apps, tmp, list) {
3403 if (!strcasecmp(app, tmp->name)) {
3404 AST_LIST_REMOVE_CURRENT(&apps, list);
3405 if (option_verbose > 1)
3406 ast_verbose( VERBOSE_PREFIX_2 "Unregistered application '%s'\n", tmp->name);
3407 free(tmp);
3408 break;
3411 AST_LIST_TRAVERSE_SAFE_END
3412 AST_LIST_UNLOCK(&apps);
3414 return tmp ? 0 : -1;
3417 struct ast_context *ast_context_create(struct ast_context **extcontexts, const char *name, const char *registrar)
3419 struct ast_context *tmp, **local_contexts;
3420 int length = sizeof(struct ast_context) + strlen(name) + 1;
3422 if (!extcontexts) {
3423 ast_mutex_lock(&conlock);
3424 local_contexts = &contexts;
3425 } else
3426 local_contexts = extcontexts;
3428 for (tmp = *local_contexts; tmp; tmp = tmp->next) {
3429 if (!strcasecmp(tmp->name, name)) {
3430 ast_mutex_unlock(&conlock);
3431 ast_log(LOG_WARNING, "Tried to register context '%s', already in use\n", name);
3432 if (!extcontexts)
3433 ast_mutex_unlock(&conlock);
3434 return NULL;
3437 if ((tmp = ast_calloc(1, length))) {
3438 ast_mutex_init(&tmp->lock);
3439 strcpy(tmp->name, name);
3440 tmp->root = NULL;
3441 tmp->registrar = registrar;
3442 tmp->next = *local_contexts;
3443 tmp->includes = NULL;
3444 tmp->ignorepats = NULL;
3445 *local_contexts = tmp;
3446 if (option_debug)
3447 ast_log(LOG_DEBUG, "Registered context '%s'\n", tmp->name);
3448 else if (option_verbose > 2)
3449 ast_verbose( VERBOSE_PREFIX_3 "Registered extension context '%s'\n", tmp->name);
3452 if (!extcontexts)
3453 ast_mutex_unlock(&conlock);
3454 return tmp;
3457 void __ast_context_destroy(struct ast_context *con, const char *registrar);
3459 struct store_hint {
3460 char *context;
3461 char *exten;
3462 struct ast_state_cb *callbacks;
3463 int laststate;
3464 AST_LIST_ENTRY(store_hint) list;
3465 char data[1];
3468 AST_LIST_HEAD(store_hints, store_hint);
3470 /* XXX this does not check that multiple contexts are merged */
3471 void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char *registrar)
3473 struct ast_context *tmp, *lasttmp = NULL;
3474 struct store_hints store = AST_LIST_HEAD_INIT_VALUE;
3475 struct store_hint *this;
3476 struct ast_hint *hint;
3477 struct ast_exten *exten;
3478 int length;
3479 struct ast_state_cb *thiscb, *prevcb;
3481 /* it is very important that this function hold the hint list lock _and_ the conlock
3482 during its operation; not only do we need to ensure that the list of contexts
3483 and extensions does not change, but also that no hint callbacks (watchers) are
3484 added or removed during the merge/delete process
3486 in addition, the locks _must_ be taken in this order, because there are already
3487 other code paths that use this order
3489 ast_mutex_lock(&conlock);
3490 AST_LIST_LOCK(&hints);
3492 /* preserve all watchers for hints associated with this registrar */
3493 AST_LIST_TRAVERSE(&hints, hint, list) {
3494 if (hint->callbacks && !strcmp(registrar, hint->exten->parent->registrar)) {
3495 length = strlen(hint->exten->exten) + strlen(hint->exten->parent->name) + 2 + sizeof(*this);
3496 if (!(this = ast_calloc(1, length)))
3497 continue;
3498 this->callbacks = hint->callbacks;
3499 hint->callbacks = NULL;
3500 this->laststate = hint->laststate;
3501 this->context = this->data;
3502 strcpy(this->data, hint->exten->parent->name);
3503 this->exten = this->data + strlen(this->context) + 1;
3504 strcpy(this->exten, hint->exten->exten);
3505 AST_LIST_INSERT_HEAD(&store, this, list);
3509 tmp = *extcontexts;
3510 if (registrar) {
3511 /* XXX remove previous contexts from same registrar */
3512 ast_log(LOG_DEBUG, "must remove any reg %s\n", registrar);
3513 __ast_context_destroy(NULL,registrar);
3514 while (tmp) {
3515 lasttmp = tmp;
3516 tmp = tmp->next;
3518 } else {
3519 /* XXX remove contexts with the same name */
3520 while (tmp) {
3521 ast_log(LOG_WARNING, "must remove %s reg %s\n", tmp->name, tmp->registrar);
3522 __ast_context_destroy(tmp,tmp->registrar);
3523 lasttmp = tmp;
3524 tmp = tmp->next;
3527 if (lasttmp) {
3528 lasttmp->next = contexts;
3529 contexts = *extcontexts;
3530 *extcontexts = NULL;
3531 } else
3532 ast_log(LOG_WARNING, "Requested contexts didn't get merged\n");
3534 /* restore the watchers for hints that can be found; notify those that
3535 cannot be restored
3537 while ((this = AST_LIST_REMOVE_HEAD(&store, list))) {
3538 exten = ast_hint_extension(NULL, this->context, this->exten);
3539 /* Find the hint in the list of hints */
3540 AST_LIST_TRAVERSE(&hints, hint, list) {
3541 if (hint->exten == exten)
3542 break;
3544 if (!exten || !hint) {
3545 /* this hint has been removed, notify the watchers */
3546 prevcb = NULL;
3547 thiscb = this->callbacks;
3548 while (thiscb) {
3549 prevcb = thiscb;
3550 thiscb = thiscb->next;
3551 prevcb->callback(this->context, this->exten, AST_EXTENSION_REMOVED, prevcb->data);
3552 free(prevcb);
3554 } else {
3555 thiscb = this->callbacks;
3556 while (thiscb->next)
3557 thiscb = thiscb->next;
3558 thiscb->next = hint->callbacks;
3559 hint->callbacks = this->callbacks;
3560 hint->laststate = this->laststate;
3562 free(this);
3565 AST_LIST_UNLOCK(&hints);
3566 ast_mutex_unlock(&conlock);
3568 return;
3572 * errno values
3573 * EBUSY - can't lock
3574 * ENOENT - no existence of context
3576 int ast_context_add_include(const char *context, const char *include, const char *registrar)
3578 int ret = -1;
3579 struct ast_context *c = find_context_locked(context);
3581 if (c) {
3582 ret = ast_context_add_include2(c, include, registrar);
3583 ast_unlock_contexts();
3585 return ret;
3588 /*! \brief Helper for get_range.
3589 * return the index of the matching entry, starting from 1.
3590 * If names is not supplied, try numeric values.
3592 static int lookup_name(const char *s, char *const names[], int max)
3594 int i;
3596 if (names) {
3597 for (i = 0; names[i]; i++) {
3598 if (!strcasecmp(s, names[i]))
3599 return i+1;
3601 } else if (sscanf(s, "%d", &i) == 1 && i >= 1 && i <= max) {
3602 return i;
3604 return 0; /* error return */
3607 /*! \brief helper function to return a range up to max (7, 12, 31 respectively).
3608 * names, if supplied, is an array of names that should be mapped to numbers.
3610 static unsigned get_range(char *src, int max, char *const names[], const char *msg)
3612 int s, e; /* start and ending position */
3613 unsigned int mask = 0;
3615 /* Check for whole range */
3616 if (ast_strlen_zero(src) || !strcmp(src, "*")) {
3617 s = 0;
3618 e = max - 1;
3619 } else {
3620 /* Get start and ending position */
3621 char *c = strchr(src, '-');
3622 if (c)
3623 *c++ = '\0';
3624 /* Find the start */
3625 s = lookup_name(src, names, max);
3626 if (!s) {
3627 ast_log(LOG_WARNING, "Invalid %s '%s', assuming none\n", msg, src);
3628 return 0;
3630 s--;
3631 if (c) { /* find end of range */
3632 e = lookup_name(c, names, max);
3633 if (!e) {
3634 ast_log(LOG_WARNING, "Invalid end %s '%s', assuming none\n", msg, c);
3635 return 0;
3637 e--;
3638 } else
3639 e = s;
3641 /* Fill the mask. Remember that ranges are cyclic */
3642 mask = 1 << e; /* initialize with last element */
3643 while (s != e) {
3644 if (s >= max) {
3645 s = 0;
3646 mask |= (1 << s);
3647 } else {
3648 mask |= (1 << s);
3649 s++;
3652 return mask;
3655 /*! \brief store a bitmask of valid times, one bit each 2 minute */
3656 static void get_timerange(struct ast_timing *i, char *times)
3658 char *e;
3659 int x;
3660 int s1, s2;
3661 int e1, e2;
3662 /* int cth, ctm; */
3664 /* start disabling all times, fill the fields with 0's, as they may contain garbage */
3665 memset(i->minmask, 0, sizeof(i->minmask));
3667 /* 2-minutes per bit, since the mask has only 32 bits :( */
3668 /* Star is all times */
3669 if (ast_strlen_zero(times) || !strcmp(times, "*")) {
3670 for (x=0; x<24; x++)
3671 i->minmask[x] = 0x3fffffff; /* 30 bits */
3672 return;
3674 /* Otherwise expect a range */
3675 e = strchr(times, '-');
3676 if (!e) {
3677 ast_log(LOG_WARNING, "Time range is not valid. Assuming no restrictions based on time.\n");
3678 return;
3680 *e++ = '\0';
3681 /* XXX why skip non digits ? */
3682 while (*e && !isdigit(*e))
3683 e++;
3684 if (!*e) {
3685 ast_log(LOG_WARNING, "Invalid time range. Assuming no restrictions based on time.\n");
3686 return;
3688 if (sscanf(times, "%d:%d", &s1, &s2) != 2) {
3689 ast_log(LOG_WARNING, "%s isn't a time. Assuming no restrictions based on time.\n", times);
3690 return;
3692 if (sscanf(e, "%d:%d", &e1, &e2) != 2) {
3693 ast_log(LOG_WARNING, "%s isn't a time. Assuming no restrictions based on time.\n", e);
3694 return;
3696 /* XXX this needs to be optimized */
3697 #if 1
3698 s1 = s1 * 30 + s2/2;
3699 if ((s1 < 0) || (s1 >= 24*30)) {
3700 ast_log(LOG_WARNING, "%s isn't a valid start time. Assuming no time.\n", times);
3701 return;
3703 e1 = e1 * 30 + e2/2;
3704 if ((e1 < 0) || (e1 >= 24*30)) {
3705 ast_log(LOG_WARNING, "%s isn't a valid end time. Assuming no time.\n", e);
3706 return;
3708 /* Go through the time and enable each appropriate bit */
3709 for (x=s1;x != e1;x = (x + 1) % (24 * 30)) {
3710 i->minmask[x/30] |= (1 << (x % 30));
3712 /* Do the last one */
3713 i->minmask[x/30] |= (1 << (x % 30));
3714 #else
3715 for (cth=0; cth<24; cth++) {
3716 /* Initialize masks to blank */
3717 i->minmask[cth] = 0;
3718 for (ctm=0; ctm<30; ctm++) {
3719 if (
3720 /* First hour with more than one hour */
3721 (((cth == s1) && (ctm >= s2)) &&
3722 ((cth < e1)))
3723 /* Only one hour */
3724 || (((cth == s1) && (ctm >= s2)) &&
3725 ((cth == e1) && (ctm <= e2)))
3726 /* In between first and last hours (more than 2 hours) */
3727 || ((cth > s1) &&
3728 (cth < e1))
3729 /* Last hour with more than one hour */
3730 || ((cth > s1) &&
3731 ((cth == e1) && (ctm <= e2)))
3733 i->minmask[cth] |= (1 << (ctm / 2));
3736 #endif
3737 /* All done */
3738 return;
3741 static char *days[] =
3743 "sun",
3744 "mon",
3745 "tue",
3746 "wed",
3747 "thu",
3748 "fri",
3749 "sat",
3750 NULL,
3753 static char *months[] =
3755 "jan",
3756 "feb",
3757 "mar",
3758 "apr",
3759 "may",
3760 "jun",
3761 "jul",
3762 "aug",
3763 "sep",
3764 "oct",
3765 "nov",
3766 "dec",
3767 NULL,
3770 int ast_build_timing(struct ast_timing *i, const char *info_in)
3772 char info_save[256];
3773 char *info;
3775 /* Check for empty just in case */
3776 if (ast_strlen_zero(info_in))
3777 return 0;
3778 /* make a copy just in case we were passed a static string */
3779 ast_copy_string(info_save, info_in, sizeof(info_save));
3780 info = info_save;
3781 /* Assume everything except time */
3782 i->monthmask = 0xfff; /* 12 bits */
3783 i->daymask = 0x7fffffffU; /* 31 bits */
3784 i->dowmask = 0x7f; /* 7 bits */
3785 /* on each call, use strsep() to move info to the next argument */
3786 get_timerange(i, strsep(&info, "|"));
3787 if (info)
3788 i->dowmask = get_range(strsep(&info, "|"), 7, days, "day of week");
3789 if (info)
3790 i->daymask = get_range(strsep(&info, "|"), 31, NULL, "day");
3791 if (info)
3792 i->monthmask = get_range(strsep(&info, "|"), 12, months, "month");
3793 return 1;
3796 int ast_check_timing(const struct ast_timing *i)
3798 struct tm tm;
3799 time_t t = time(NULL);
3801 localtime_r(&t,&tm);
3803 /* If it's not the right month, return */
3804 if (!(i->monthmask & (1 << tm.tm_mon)))
3805 return 0;
3807 /* If it's not that time of the month.... */
3808 /* Warning, tm_mday has range 1..31! */
3809 if (!(i->daymask & (1 << (tm.tm_mday-1))))
3810 return 0;
3812 /* If it's not the right day of the week */
3813 if (!(i->dowmask & (1 << tm.tm_wday)))
3814 return 0;
3816 /* Sanity check the hour just to be safe */
3817 if ((tm.tm_hour < 0) || (tm.tm_hour > 23)) {
3818 ast_log(LOG_WARNING, "Insane time...\n");
3819 return 0;
3822 /* Now the tough part, we calculate if it fits
3823 in the right time based on min/hour */
3824 if (!(i->minmask[tm.tm_hour] & (1 << (tm.tm_min / 2))))
3825 return 0;
3827 /* If we got this far, then we're good */
3828 return 1;
3832 * errno values
3833 * ENOMEM - out of memory
3834 * EBUSY - can't lock
3835 * EEXIST - already included
3836 * EINVAL - there is no existence of context for inclusion
3838 int ast_context_add_include2(struct ast_context *con, const char *value,
3839 const char *registrar)
3841 struct ast_include *new_include;
3842 char *c;
3843 struct ast_include *i, *il = NULL; /* include, include_last */
3844 int length;
3845 char *p;
3847 length = sizeof(struct ast_include);
3848 length += 2 * (strlen(value) + 1);
3850 /* allocate new include structure ... */
3851 if (!(new_include = ast_calloc(1, length)))
3852 return -1;
3853 /* Fill in this structure. Use 'p' for assignments, as the fields
3854 * in the structure are 'const char *'
3856 p = new_include->stuff;
3857 new_include->name = p;
3858 strcpy(p, value);
3859 p += strlen(value) + 1;
3860 new_include->rname = p;
3861 strcpy(p, value);
3862 /* Strip off timing info, and process if it is there */
3863 if ( (c = strchr(p, '|')) ) {
3864 *c++ = '\0';
3865 new_include->hastime = ast_build_timing(&(new_include->timing), c);
3867 new_include->next = NULL;
3868 new_include->registrar = registrar;
3870 ast_mutex_lock(&con->lock);
3872 /* ... go to last include and check if context is already included too... */
3873 for (i = con->includes; i; i = i->next) {
3874 if (!strcasecmp(i->name, new_include->name)) {
3875 free(new_include);
3876 ast_mutex_unlock(&con->lock);
3877 errno = EEXIST;
3878 return -1;
3880 il = i;
3883 /* ... include new context into context list, unlock, return */
3884 if (il)
3885 il->next = new_include;
3886 else
3887 con->includes = new_include;
3888 if (option_verbose > 2)
3889 ast_verbose(VERBOSE_PREFIX_3 "Including context '%s' in context '%s'\n", new_include->name, ast_get_context_name(con));
3890 ast_mutex_unlock(&con->lock);
3892 return 0;
3896 * errno values
3897 * EBUSY - can't lock
3898 * ENOENT - no existence of context
3900 int ast_context_add_switch(const char *context, const char *sw, const char *data, int eval, const char *registrar)
3902 int ret = -1;
3903 struct ast_context *c = find_context_locked(context);
3905 if (c) { /* found, add switch to this context */
3906 ret = ast_context_add_switch2(c, sw, data, eval, registrar);
3907 ast_unlock_contexts();
3909 return ret;
3913 * errno values
3914 * ENOMEM - out of memory
3915 * EBUSY - can't lock
3916 * EEXIST - already included
3917 * EINVAL - there is no existence of context for inclusion
3919 int ast_context_add_switch2(struct ast_context *con, const char *value,
3920 const char *data, int eval, const char *registrar)
3922 struct ast_sw *new_sw;
3923 struct ast_sw *i;
3924 int length;
3925 char *p;
3927 length = sizeof(struct ast_sw);
3928 length += strlen(value) + 1;
3929 if (data)
3930 length += strlen(data);
3931 length++;
3932 if (eval) {
3933 /* Create buffer for evaluation of variables */
3934 length += SWITCH_DATA_LENGTH;
3935 length++;
3938 /* allocate new sw structure ... */
3939 if (!(new_sw = ast_calloc(1, length)))
3940 return -1;
3941 /* ... fill in this structure ... */
3942 p = new_sw->stuff;
3943 new_sw->name = p;
3944 strcpy(new_sw->name, value);
3945 p += strlen(value) + 1;
3946 new_sw->data = p;
3947 if (data) {
3948 strcpy(new_sw->data, data);
3949 p += strlen(data) + 1;
3950 } else {
3951 strcpy(new_sw->data, "");
3952 p++;
3954 if (eval)
3955 new_sw->tmpdata = p;
3956 new_sw->eval = eval;
3957 new_sw->registrar = registrar;
3959 /* ... try to lock this context ... */
3960 ast_mutex_lock(&con->lock);
3962 /* ... go to last sw and check if context is already swd too... */
3963 AST_LIST_TRAVERSE(&con->alts, i, list) {
3964 if (!strcasecmp(i->name, new_sw->name) && !strcasecmp(i->data, new_sw->data)) {
3965 free(new_sw);
3966 ast_mutex_unlock(&con->lock);
3967 errno = EEXIST;
3968 return -1;
3972 /* ... sw new context into context list, unlock, return */
3973 AST_LIST_INSERT_TAIL(&con->alts, new_sw, list);
3975 if (option_verbose > 2)
3976 ast_verbose(VERBOSE_PREFIX_3 "Including switch '%s/%s' in context '%s'\n", new_sw->name, new_sw->data, ast_get_context_name(con));
3978 ast_mutex_unlock(&con->lock);
3980 return 0;
3984 * EBUSY - can't lock
3985 * ENOENT - there is not context existence
3987 int ast_context_remove_ignorepat(const char *context, const char *ignorepat, const char *registrar)
3989 int ret = -1;
3990 struct ast_context *c = find_context_locked(context);
3992 if (c) {
3993 ret = ast_context_remove_ignorepat2(c, ignorepat, registrar);
3994 ast_unlock_contexts();
3996 return ret;
3999 int ast_context_remove_ignorepat2(struct ast_context *con, const char *ignorepat, const char *registrar)
4001 struct ast_ignorepat *ip, *ipl = NULL;
4003 ast_mutex_lock(&con->lock);
4005 for (ip = con->ignorepats; ip; ip = ip->next) {
4006 if (!strcmp(ip->pattern, ignorepat) &&
4007 (!registrar || (registrar == ip->registrar))) {
4008 if (ipl) {
4009 ipl->next = ip->next;
4010 free(ip);
4011 } else {
4012 con->ignorepats = ip->next;
4013 free(ip);
4015 ast_mutex_unlock(&con->lock);
4016 return 0;
4018 ipl = ip;
4021 ast_mutex_unlock(&con->lock);
4022 errno = EINVAL;
4023 return -1;
4027 * EBUSY - can't lock
4028 * ENOENT - there is no existence of context
4030 int ast_context_add_ignorepat(const char *context, const char *value, const char *registrar)
4032 int ret = -1;
4033 struct ast_context *c = find_context_locked(context);
4035 if (c) {
4036 ret = ast_context_add_ignorepat2(c, value, registrar);
4037 ast_unlock_contexts();
4039 return ret;
4042 int ast_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar)
4044 struct ast_ignorepat *ignorepat, *ignorepatc, *ignorepatl = NULL;
4045 int length;
4046 length = sizeof(struct ast_ignorepat);
4047 length += strlen(value) + 1;
4048 if (!(ignorepat = ast_calloc(1, length)))
4049 return -1;
4050 /* The cast to char * is because we need to write the initial value.
4051 * The field is not supposed to be modified otherwise
4053 strcpy((char *)ignorepat->pattern, value);
4054 ignorepat->next = NULL;
4055 ignorepat->registrar = registrar;
4056 ast_mutex_lock(&con->lock);
4057 for (ignorepatc = con->ignorepats; ignorepatc; ignorepatc = ignorepatc->next) {
4058 ignorepatl = ignorepatc;
4059 if (!strcasecmp(ignorepatc->pattern, value)) {
4060 /* Already there */
4061 ast_mutex_unlock(&con->lock);
4062 errno = EEXIST;
4063 return -1;
4066 if (ignorepatl)
4067 ignorepatl->next = ignorepat;
4068 else
4069 con->ignorepats = ignorepat;
4070 ast_mutex_unlock(&con->lock);
4071 return 0;
4075 int ast_ignore_pattern(const char *context, const char *pattern)
4077 struct ast_context *con = ast_context_find(context);
4078 if (con) {
4079 struct ast_ignorepat *pat;
4080 for (pat = con->ignorepats; pat; pat = pat->next) {
4081 if (ast_extension_match(pat->pattern, pattern))
4082 return 1;
4086 return 0;
4090 * EBUSY - can't lock
4091 * ENOENT - no existence of context
4094 int ast_add_extension(const char *context, int replace, const char *extension,
4095 int priority, const char *label, const char *callerid,
4096 const char *application, void *data, void (*datad)(void *), const char *registrar)
4098 int ret = -1;
4099 struct ast_context *c = find_context_locked(context);
4101 if (c) {
4102 ret = ast_add_extension2(c, replace, extension, priority, label, callerid,
4103 application, data, datad, registrar);
4104 ast_unlock_contexts();
4106 return ret;
4109 int ast_explicit_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
4111 if (!chan)
4112 return -1;
4114 if (!ast_strlen_zero(context))
4115 ast_copy_string(chan->context, context, sizeof(chan->context));
4116 if (!ast_strlen_zero(exten))
4117 ast_copy_string(chan->exten, exten, sizeof(chan->exten));
4118 if (priority > -1) {
4119 chan->priority = priority;
4120 /* see flag description in channel.h for explanation */
4121 if (ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP))
4122 chan->priority--;
4125 return 0;
4128 int ast_async_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
4130 int res = 0;
4132 ast_channel_lock(chan);
4134 if (chan->pbx) { /* This channel is currently in the PBX */
4135 ast_explicit_goto(chan, context, exten, priority);
4136 ast_softhangup_nolock(chan, AST_SOFTHANGUP_ASYNCGOTO);
4137 } else {
4138 /* In order to do it when the channel doesn't really exist within
4139 the PBX, we have to make a new channel, masquerade, and start the PBX
4140 at the new location */
4141 struct ast_channel *tmpchan = ast_channel_alloc(0);
4142 if (!tmpchan)
4143 res = -1;
4144 else {
4145 ast_string_field_build(tmpchan, name, "AsyncGoto/%s", chan->name);
4146 ast_setstate(tmpchan, chan->_state);
4147 /* Make formats okay */
4148 tmpchan->readformat = chan->readformat;
4149 tmpchan->writeformat = chan->writeformat;
4150 /* Setup proper location */
4151 ast_explicit_goto(tmpchan,
4152 S_OR(context, chan->context), S_OR(exten, chan->exten), priority);
4154 /* Masquerade into temp channel */
4155 ast_channel_masquerade(tmpchan, chan);
4157 /* Grab the locks and get going */
4158 ast_channel_lock(tmpchan);
4159 ast_do_masquerade(tmpchan);
4160 ast_channel_unlock(tmpchan);
4161 /* Start the PBX going on our stolen channel */
4162 if (ast_pbx_start(tmpchan)) {
4163 ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmpchan->name);
4164 ast_hangup(tmpchan);
4165 res = -1;
4169 ast_channel_unlock(chan);
4170 return res;
4173 int ast_async_goto_by_name(const char *channame, const char *context, const char *exten, int priority)
4175 struct ast_channel *chan;
4176 int res = -1;
4178 chan = ast_get_channel_by_name_locked(channame);
4179 if (chan) {
4180 res = ast_async_goto(chan, context, exten, priority);
4181 ast_channel_unlock(chan);
4183 return res;
4186 /*! \brief copy a string skipping whitespace */
4187 static int ext_strncpy(char *dst, const char *src, int len)
4189 int count=0;
4191 while (*src && (count < len - 1)) {
4192 switch(*src) {
4193 case ' ':
4194 /* otherwise exten => [a-b],1,... doesn't work */
4195 /* case '-': */
4196 /* Ignore */
4197 break;
4198 default:
4199 *dst = *src;
4200 dst++;
4202 src++;
4203 count++;
4205 *dst = '\0';
4207 return count;
4210 static void null_datad(void *foo)
4214 /*! \brief add the extension in the priority chain.
4215 * returns 0 on success, -1 on failure
4217 static int add_pri(struct ast_context *con, struct ast_exten *tmp,
4218 struct ast_exten *el, struct ast_exten *e, int replace)
4220 struct ast_exten *ep;
4222 for (ep = NULL; e ; ep = e, e = e->peer) {
4223 if (e->priority >= tmp->priority)
4224 break;
4226 if (!e) { /* go at the end, and ep is surely set because the list is not empty */
4227 ep->peer = tmp;
4228 return 0; /* success */
4230 if (e->priority == tmp->priority) {
4231 /* Can't have something exactly the same. Is this a
4232 replacement? If so, replace, otherwise, bonk. */
4233 if (!replace) {
4234 ast_log(LOG_WARNING, "Unable to register extension '%s', priority %d in '%s', already in use\n", tmp->exten, tmp->priority, con->name);
4235 tmp->datad(tmp->data);
4236 free(tmp);
4237 return -1;
4239 /* we are replacing e, so copy the link fields and then update
4240 * whoever pointed to e to point to us
4242 tmp->next = e->next; /* not meaningful if we are not first in the peer list */
4243 tmp->peer = e->peer; /* always meaningful */
4244 if (ep) /* We're in the peer list, just insert ourselves */
4245 ep->peer = tmp;
4246 else if (el) /* We're the first extension. Take over e's functions */
4247 el->next = tmp;
4248 else /* We're the very first extension. */
4249 con->root = tmp;
4250 if (tmp->priority == PRIORITY_HINT)
4251 ast_change_hint(e,tmp);
4252 /* Destroy the old one */
4253 e->datad(e->data);
4254 free(e);
4255 } else { /* Slip ourselves in just before e */
4256 tmp->peer = e;
4257 tmp->next = e->next; /* extension chain, or NULL if e is not the first extension */
4258 if (ep) /* Easy enough, we're just in the peer list */
4259 ep->peer = tmp;
4260 else { /* we are the first in some peer list, so link in the ext list */
4261 if (el)
4262 el->next = tmp; /* in the middle... */
4263 else
4264 con->root = tmp; /* ... or at the head */
4265 e->next = NULL; /* e is no more at the head, so e->next must be reset */
4267 /* And immediately return success. */
4268 if (tmp->priority == PRIORITY_HINT)
4269 ast_add_hint(tmp);
4271 return 0;
4274 /*! \brief
4275 * Main interface to add extensions to the list for out context.
4277 * We sort extensions in order of matching preference, so that we can
4278 * stop the search as soon as we find a suitable match.
4279 * This ordering also takes care of wildcards such as '.' (meaning
4280 * "one or more of any character") and '!' (which is 'earlymatch',
4281 * meaning "zero or more of any character" but also impacts the
4282 * return value from CANMATCH and EARLYMATCH.
4284 * The extension match rules defined in the devmeeting 2006.05.05 are
4285 * quite simple: WE SELECT THE LONGEST MATCH.
4286 * In detail, "longest" means the number of matched characters in
4287 * the extension. In case of ties (e.g. _XXX and 333) in the length
4288 * of a pattern, we give priority to entries with the smallest cardinality
4289 * (e.g, [5-9] comes before [2-8] before the former has only 5 elements,
4290 * while the latter has 7, etc.
4291 * In case of same cardinality, the first element in the range counts.
4292 * If we still have a tie, any final '!' will make this as a possibly
4293 * less specific pattern.
4295 * EBUSY - can't lock
4296 * EEXIST - extension with the same priority exist and no replace is set
4299 int ast_add_extension2(struct ast_context *con,
4300 int replace, const char *extension, int priority, const char *label, const char *callerid,
4301 const char *application, void *data, void (*datad)(void *),
4302 const char *registrar)
4305 * Sort extensions (or patterns) according to the rules indicated above.
4306 * These are implemented by the function ext_cmp()).
4307 * All priorities for the same ext/pattern/cid are kept in a list,
4308 * using the 'peer' field as a link field..
4310 struct ast_exten *tmp, *e, *el = NULL;
4311 int res;
4312 int length;
4313 char *p;
4314 char expand_buf[VAR_BUF_SIZE] = { 0, };
4316 /* if we are adding a hint, and there are global variables, and the hint
4317 contains variable references, then expand them
4319 ast_mutex_lock(&globalslock);
4320 if (priority == PRIORITY_HINT && AST_LIST_FIRST(&globals) && strstr(application, "${")) {
4321 pbx_substitute_variables_varshead(&globals, application, expand_buf, sizeof(expand_buf));
4322 application = expand_buf;
4324 ast_mutex_unlock(&globalslock);
4326 length = sizeof(struct ast_exten);
4327 length += strlen(extension) + 1;
4328 length += strlen(application) + 1;
4329 if (label)
4330 length += strlen(label) + 1;
4331 if (callerid)
4332 length += strlen(callerid) + 1;
4333 else
4334 length ++; /* just the '\0' */
4336 /* Be optimistic: Build the extension structure first */
4337 if (datad == NULL)
4338 datad = null_datad;
4339 if (!(tmp = ast_calloc(1, length)))
4340 return -1;
4342 /* use p as dst in assignments, as the fields are const char * */
4343 p = tmp->stuff;
4344 if (label) {
4345 tmp->label = p;
4346 strcpy(p, label);
4347 p += strlen(label) + 1;
4349 tmp->exten = p;
4350 p += ext_strncpy(p, extension, strlen(extension) + 1) + 1;
4351 tmp->priority = priority;
4352 tmp->cidmatch = p; /* but use p for assignments below */
4353 if (callerid) {
4354 p += ext_strncpy(p, callerid, strlen(callerid) + 1) + 1;
4355 tmp->matchcid = 1;
4356 } else {
4357 *p++ = '\0';
4358 tmp->matchcid = 0;
4360 tmp->app = p;
4361 strcpy(p, application);
4362 tmp->parent = con;
4363 tmp->data = data;
4364 tmp->datad = datad;
4365 tmp->registrar = registrar;
4367 ast_mutex_lock(&con->lock);
4368 res = 0; /* some compilers will think it is uninitialized otherwise */
4369 for (e = con->root; e; el = e, e = e->next) { /* scan the extension list */
4370 res = ext_cmp(e->exten, extension);
4371 if (res == 0) { /* extension match, now look at cidmatch */
4372 if (!e->matchcid && !tmp->matchcid)
4373 res = 0;
4374 else if (tmp->matchcid && !e->matchcid)
4375 res = 1;
4376 else if (e->matchcid && !tmp->matchcid)
4377 res = -1;
4378 else
4379 res = strcasecmp(e->cidmatch, tmp->cidmatch);
4381 if (res >= 0)
4382 break;
4384 if (e && res == 0) { /* exact match, insert in the pri chain */
4385 res = add_pri(con, tmp, el, e, replace);
4386 ast_mutex_unlock(&con->lock);
4387 if (res < 0) {
4388 errno = EEXIST; /* XXX do we care ? */
4389 return 0; /* XXX should we return -1 maybe ? */
4391 } else {
4393 * not an exact match, this is the first entry with this pattern,
4394 * so insert in the main list right before 'e' (if any)
4396 tmp->next = e;
4397 if (el)
4398 el->next = tmp;
4399 else
4400 con->root = tmp;
4401 ast_mutex_unlock(&con->lock);
4402 if (tmp->priority == PRIORITY_HINT)
4403 ast_add_hint(tmp);
4405 if (option_debug) {
4406 if (tmp->matchcid) {
4407 ast_log(LOG_DEBUG, "Added extension '%s' priority %d (CID match '%s') to %s\n",
4408 tmp->exten, tmp->priority, tmp->cidmatch, con->name);
4409 } else {
4410 ast_log(LOG_DEBUG, "Added extension '%s' priority %d to %s\n",
4411 tmp->exten, tmp->priority, con->name);
4413 } else if (option_verbose > 2) {
4414 if (tmp->matchcid) {
4415 ast_verbose( VERBOSE_PREFIX_3 "Added extension '%s' priority %d (CID match '%s')to %s\n",
4416 tmp->exten, tmp->priority, tmp->cidmatch, con->name);
4417 } else {
4418 ast_verbose( VERBOSE_PREFIX_3 "Added extension '%s' priority %d to %s\n",
4419 tmp->exten, tmp->priority, con->name);
4422 return 0;
4425 struct async_stat {
4426 pthread_t p;
4427 struct ast_channel *chan;
4428 char context[AST_MAX_CONTEXT];
4429 char exten[AST_MAX_EXTENSION];
4430 int priority;
4431 int timeout;
4432 char app[AST_MAX_EXTENSION];
4433 char appdata[1024];
4436 static void *async_wait(void *data)
4438 struct async_stat *as = data;
4439 struct ast_channel *chan = as->chan;
4440 int timeout = as->timeout;
4441 int res;
4442 struct ast_frame *f;
4443 struct ast_app *app;
4445 while (timeout && (chan->_state != AST_STATE_UP)) {
4446 res = ast_waitfor(chan, timeout);
4447 if (res < 1)
4448 break;
4449 if (timeout > -1)
4450 timeout = res;
4451 f = ast_read(chan);
4452 if (!f)
4453 break;
4454 if (f->frametype == AST_FRAME_CONTROL) {
4455 if ((f->subclass == AST_CONTROL_BUSY) ||
4456 (f->subclass == AST_CONTROL_CONGESTION) )
4457 break;
4459 ast_frfree(f);
4461 if (chan->_state == AST_STATE_UP) {
4462 if (!ast_strlen_zero(as->app)) {
4463 app = pbx_findapp(as->app);
4464 if (app) {
4465 if (option_verbose > 2)
4466 ast_verbose(VERBOSE_PREFIX_3 "Launching %s(%s) on %s\n", as->app, as->appdata, chan->name);
4467 pbx_exec(chan, app, as->appdata);
4468 } else
4469 ast_log(LOG_WARNING, "No such application '%s'\n", as->app);
4470 } else {
4471 if (!ast_strlen_zero(as->context))
4472 ast_copy_string(chan->context, as->context, sizeof(chan->context));
4473 if (!ast_strlen_zero(as->exten))
4474 ast_copy_string(chan->exten, as->exten, sizeof(chan->exten));
4475 if (as->priority > 0)
4476 chan->priority = as->priority;
4477 /* Run the PBX */
4478 if (ast_pbx_run(chan)) {
4479 ast_log(LOG_ERROR, "Failed to start PBX on %s\n", chan->name);
4480 } else {
4481 /* PBX will have taken care of this */
4482 chan = NULL;
4486 free(as);
4487 if (chan)
4488 ast_hangup(chan);
4489 return NULL;
4492 /*! Function to post an empty cdr after a spool call fails.
4494 * This function posts an empty cdr for a failed spool call
4497 int ast_pbx_outgoing_cdr_failed(void)
4499 /* allocate a channel */
4500 struct ast_channel *chan = ast_channel_alloc(0);
4502 if (!chan)
4503 return -1; /* failure */
4505 chan->cdr = ast_cdr_alloc(); /* allocate a cdr for the channel */
4507 if (!chan->cdr) {
4508 /* allocation of the cdr failed */
4509 ast_channel_free(chan); /* free the channel */
4510 return -1; /* return failure */
4513 /* allocation of the cdr was successful */
4514 ast_cdr_init(chan->cdr, chan); /* initilize our channel's cdr */
4515 ast_cdr_start(chan->cdr); /* record the start and stop time */
4516 ast_cdr_end(chan->cdr);
4517 ast_cdr_failed(chan->cdr); /* set the status to failed */
4518 ast_cdr_detach(chan->cdr); /* post and free the record */
4519 ast_channel_free(chan); /* free the channel */
4521 return 0; /* success */
4524 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)
4526 struct ast_channel *chan;
4527 struct async_stat *as;
4528 int res = -1, cdr_res = -1;
4529 struct outgoing_helper oh;
4530 pthread_attr_t attr;
4532 if (sync) {
4533 LOAD_OH(oh);
4534 chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
4535 if (channel) {
4536 *channel = chan;
4537 if (chan)
4538 ast_channel_lock(chan);
4540 if (chan) {
4541 if (chan->cdr) { /* check if the channel already has a cdr record, if not give it one */
4542 ast_log(LOG_WARNING, "%s already has a call record??\n", chan->name);
4543 } else {
4544 chan->cdr = ast_cdr_alloc(); /* allocate a cdr for the channel */
4545 if (!chan->cdr) {
4546 /* allocation of the cdr failed */
4547 free(chan->pbx);
4548 res = -1;
4549 goto outgoing_exten_cleanup;
4551 /* allocation of the cdr was successful */
4552 ast_cdr_init(chan->cdr, chan); /* initilize our channel's cdr */
4553 ast_cdr_start(chan->cdr);
4555 if (chan->_state == AST_STATE_UP) {
4556 res = 0;
4557 if (option_verbose > 3)
4558 ast_verbose(VERBOSE_PREFIX_4 "Channel %s was answered.\n", chan->name);
4560 if (sync > 1) {
4561 if (channel)
4562 ast_channel_unlock(chan);
4563 if (ast_pbx_run(chan)) {
4564 ast_log(LOG_ERROR, "Unable to run PBX on %s\n", chan->name);
4565 if (channel)
4566 *channel = NULL;
4567 ast_hangup(chan);
4568 res = -1;
4570 } else {
4571 if (ast_pbx_start(chan)) {
4572 ast_log(LOG_ERROR, "Unable to start PBX on %s\n", chan->name);
4573 if (channel) {
4574 *channel = NULL;
4575 ast_channel_unlock(chan);
4577 ast_hangup(chan);
4578 res = -1;
4581 } else {
4582 if (option_verbose > 3)
4583 ast_verbose(VERBOSE_PREFIX_4 "Channel %s was never answered.\n", chan->name);
4585 if(chan->cdr) { /* update the cdr */
4586 /* here we update the status of the call, which sould be busy.
4587 * if that fails then we set the status to failed */
4588 if (ast_cdr_disposition(chan->cdr, chan->hangupcause))
4589 ast_cdr_failed(chan->cdr);
4592 if (channel) {
4593 *channel = NULL;
4594 ast_channel_unlock(chan);
4596 ast_hangup(chan);
4600 if (res < 0) { /* the call failed for some reason */
4601 if (*reason == 0) { /* if the call failed (not busy or no answer)
4602 * update the cdr with the failed message */
4603 cdr_res = ast_pbx_outgoing_cdr_failed();
4604 if (cdr_res != 0) {
4605 res = cdr_res;
4606 goto outgoing_exten_cleanup;
4610 /* create a fake channel and execute the "failed" extension (if it exists) within the requested context */
4611 /* check if "failed" exists */
4612 if (ast_exists_extension(chan, context, "failed", 1, NULL)) {
4613 chan = ast_channel_alloc(0);
4614 if (chan) {
4615 ast_string_field_set(chan, name, "OutgoingSpoolFailed");
4616 if (!ast_strlen_zero(context))
4617 ast_copy_string(chan->context, context, sizeof(chan->context));
4618 set_ext_pri(chan, "failed", 1);
4619 ast_set_variables(chan, vars);
4620 if (account)
4621 ast_cdr_setaccount(chan, account);
4622 ast_pbx_run(chan);
4626 } else {
4627 if (!(as = ast_calloc(1, sizeof(*as)))) {
4628 res = -1;
4629 goto outgoing_exten_cleanup;
4631 chan = ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name);
4632 if (channel) {
4633 *channel = chan;
4634 if (chan)
4635 ast_channel_lock(chan);
4637 if (!chan) {
4638 free(as);
4639 res = -1;
4640 goto outgoing_exten_cleanup;
4642 as->chan = chan;
4643 ast_copy_string(as->context, context, sizeof(as->context));
4644 set_ext_pri(as->chan, exten, priority);
4645 as->timeout = timeout;
4646 ast_set_variables(chan, vars);
4647 if (account)
4648 ast_cdr_setaccount(chan, account);
4649 pthread_attr_init(&attr);
4650 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
4651 if (ast_pthread_create(&as->p, &attr, async_wait, as)) {
4652 ast_log(LOG_WARNING, "Failed to start async wait\n");
4653 free(as);
4654 if (channel) {
4655 *channel = NULL;
4656 ast_channel_unlock(chan);
4658 ast_hangup(chan);
4659 res = -1;
4660 goto outgoing_exten_cleanup;
4662 res = 0;
4664 outgoing_exten_cleanup:
4665 ast_variables_destroy(vars);
4666 return res;
4669 struct app_tmp {
4670 char app[256];
4671 char data[256];
4672 struct ast_channel *chan;
4673 pthread_t t;
4676 /*! \brief run the application and free the descriptor once done */
4677 static void *ast_pbx_run_app(void *data)
4679 struct app_tmp *tmp = data;
4680 struct ast_app *app;
4681 app = pbx_findapp(tmp->app);
4682 if (app) {
4683 if (option_verbose > 3)
4684 ast_verbose(VERBOSE_PREFIX_4 "Launching %s(%s) on %s\n", tmp->app, tmp->data, tmp->chan->name);
4685 pbx_exec(tmp->chan, app, tmp->data);
4686 } else
4687 ast_log(LOG_WARNING, "No such application '%s'\n", tmp->app);
4688 ast_hangup(tmp->chan);
4689 free(tmp);
4690 return NULL;
4693 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)
4695 struct ast_channel *chan;
4696 struct app_tmp *tmp;
4697 int res = -1, cdr_res = -1;
4698 struct outgoing_helper oh;
4699 pthread_attr_t attr;
4701 memset(&oh, 0, sizeof(oh));
4702 oh.vars = vars;
4703 oh.account = account;
4705 if (locked_channel)
4706 *locked_channel = NULL;
4707 if (ast_strlen_zero(app)) {
4708 res = -1;
4709 goto outgoing_app_cleanup;
4711 if (sync) {
4712 chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
4713 if (chan) {
4714 if (chan->cdr) { /* check if the channel already has a cdr record, if not give it one */
4715 ast_log(LOG_WARNING, "%s already has a call record??\n", chan->name);
4716 } else {
4717 chan->cdr = ast_cdr_alloc(); /* allocate a cdr for the channel */
4718 if(!chan->cdr) {
4719 /* allocation of the cdr failed */
4720 free(chan->pbx);
4721 res = -1;
4722 goto outgoing_app_cleanup;
4724 /* allocation of the cdr was successful */
4725 ast_cdr_init(chan->cdr, chan); /* initilize our channel's cdr */
4726 ast_cdr_start(chan->cdr);
4728 ast_set_variables(chan, vars);
4729 if (account)
4730 ast_cdr_setaccount(chan, account);
4731 if (chan->_state == AST_STATE_UP) {
4732 res = 0;
4733 if (option_verbose > 3)
4734 ast_verbose(VERBOSE_PREFIX_4 "Channel %s was answered.\n", chan->name);
4735 tmp = ast_calloc(1, sizeof(*tmp));
4736 if (!tmp)
4737 res = -1;
4738 else {
4739 ast_copy_string(tmp->app, app, sizeof(tmp->app));
4740 if (appdata)
4741 ast_copy_string(tmp->data, appdata, sizeof(tmp->data));
4742 tmp->chan = chan;
4743 if (sync > 1) {
4744 if (locked_channel)
4745 ast_channel_unlock(chan);
4746 ast_pbx_run_app(tmp);
4747 } else {
4748 pthread_attr_init(&attr);
4749 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
4750 if (locked_channel)
4751 ast_channel_lock(chan);
4752 if (ast_pthread_create(&tmp->t, &attr, ast_pbx_run_app, tmp)) {
4753 ast_log(LOG_WARNING, "Unable to spawn execute thread on %s: %s\n", chan->name, strerror(errno));
4754 free(tmp);
4755 if (locked_channel)
4756 ast_channel_unlock(chan);
4757 ast_hangup(chan);
4758 res = -1;
4759 } else {
4760 if (locked_channel)
4761 *locked_channel = chan;
4765 } else {
4766 if (option_verbose > 3)
4767 ast_verbose(VERBOSE_PREFIX_4 "Channel %s was never answered.\n", chan->name);
4768 if (chan->cdr) { /* update the cdr */
4769 /* here we update the status of the call, which sould be busy.
4770 * if that fails then we set the status to failed */
4771 if (ast_cdr_disposition(chan->cdr, chan->hangupcause))
4772 ast_cdr_failed(chan->cdr);
4774 ast_hangup(chan);
4778 if (res < 0) { /* the call failed for some reason */
4779 if (*reason == 0) { /* if the call failed (not busy or no answer)
4780 * update the cdr with the failed message */
4781 cdr_res = ast_pbx_outgoing_cdr_failed();
4782 if (cdr_res != 0) {
4783 res = cdr_res;
4784 goto outgoing_app_cleanup;
4789 } else {
4790 struct async_stat *as;
4791 if (!(as = ast_calloc(1, sizeof(*as)))) {
4792 res = -1;
4793 goto outgoing_app_cleanup;
4795 chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
4796 if (!chan) {
4797 free(as);
4798 res = -1;
4799 goto outgoing_app_cleanup;
4801 as->chan = chan;
4802 ast_copy_string(as->app, app, sizeof(as->app));
4803 if (appdata)
4804 ast_copy_string(as->appdata, appdata, sizeof(as->appdata));
4805 as->timeout = timeout;
4806 ast_set_variables(chan, vars);
4807 if (account)
4808 ast_cdr_setaccount(chan, account);
4809 /* Start a new thread, and get something handling this channel. */
4810 pthread_attr_init(&attr);
4811 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
4812 if (locked_channel)
4813 ast_channel_lock(chan);
4814 if (ast_pthread_create(&as->p, &attr, async_wait, as)) {
4815 ast_log(LOG_WARNING, "Failed to start async wait\n");
4816 free(as);
4817 if (locked_channel)
4818 ast_channel_unlock(chan);
4819 ast_hangup(chan);
4820 res = -1;
4821 goto outgoing_app_cleanup;
4822 } else {
4823 if (locked_channel)
4824 *locked_channel = chan;
4826 res = 0;
4828 outgoing_app_cleanup:
4829 ast_variables_destroy(vars);
4830 return res;
4833 void __ast_context_destroy(struct ast_context *con, const char *registrar)
4835 struct ast_context *tmp, *tmpl=NULL;
4836 struct ast_include *tmpi;
4837 struct ast_sw *sw;
4838 struct ast_exten *e, *el, *en;
4839 struct ast_ignorepat *ipi;
4841 ast_mutex_lock(&conlock);
4842 for (tmp = contexts; tmp; ) {
4843 struct ast_context *next; /* next starting point */
4844 for (; tmp; tmpl = tmp, tmp = tmp->next) {
4845 ast_log(LOG_DEBUG, "check ctx %s %s\n", tmp->name, tmp->registrar);
4846 if ( (!registrar || !strcasecmp(registrar, tmp->registrar)) &&
4847 (!con || !strcasecmp(tmp->name, con->name)) )
4848 break; /* found it */
4850 if (!tmp) /* not found, we are done */
4851 break;
4852 ast_mutex_lock(&tmp->lock);
4853 ast_log(LOG_DEBUG, "delete ctx %s %s\n", tmp->name, tmp->registrar);
4854 next = tmp->next;
4855 if (tmpl)
4856 tmpl->next = next;
4857 else
4858 contexts = next;
4859 /* Okay, now we're safe to let it go -- in a sense, we were
4860 ready to let it go as soon as we locked it. */
4861 ast_mutex_unlock(&tmp->lock);
4862 for (tmpi = tmp->includes; tmpi; ) { /* Free includes */
4863 struct ast_include *tmpil = tmpi;
4864 tmpi = tmpi->next;
4865 free(tmpil);
4867 for (ipi = tmp->ignorepats; ipi; ) { /* Free ignorepats */
4868 struct ast_ignorepat *ipl = ipi;
4869 ipi = ipi->next;
4870 free(ipl);
4872 while ((sw = AST_LIST_REMOVE_HEAD(&tmp->alts, list)))
4873 free(sw);
4874 for (e = tmp->root; e;) {
4875 for (en = e->peer; en;) {
4876 el = en;
4877 en = en->peer;
4878 destroy_exten(el);
4880 el = e;
4881 e = e->next;
4882 destroy_exten(el);
4884 ast_mutex_destroy(&tmp->lock);
4885 free(tmp);
4886 /* if we have a specific match, we are done, otherwise continue */
4887 tmp = con ? NULL : next;
4889 ast_mutex_unlock(&conlock);
4892 void ast_context_destroy(struct ast_context *con, const char *registrar)
4894 __ast_context_destroy(con,registrar);
4897 static void wait_for_hangup(struct ast_channel *chan, void *data)
4899 int res;
4900 struct ast_frame *f;
4901 int waittime;
4903 if (ast_strlen_zero(data) || (sscanf(data, "%d", &waittime) != 1) || (waittime < 0))
4904 waittime = -1;
4905 if (waittime > -1) {
4906 ast_safe_sleep(chan, waittime * 1000);
4907 } else do {
4908 res = ast_waitfor(chan, -1);
4909 if (res < 0)
4910 return;
4911 f = ast_read(chan);
4912 if (f)
4913 ast_frfree(f);
4914 } while(f);
4918 * \ingroup applications
4920 static int pbx_builtin_progress(struct ast_channel *chan, void *data)
4922 ast_indicate(chan, AST_CONTROL_PROGRESS);
4923 return 0;
4927 * \ingroup applications
4929 static int pbx_builtin_ringing(struct ast_channel *chan, void *data)
4931 ast_indicate(chan, AST_CONTROL_RINGING);
4932 return 0;
4936 * \ingroup applications
4938 static int pbx_builtin_busy(struct ast_channel *chan, void *data)
4940 ast_indicate(chan, AST_CONTROL_BUSY);
4941 ast_setstate(chan, AST_STATE_BUSY);
4942 wait_for_hangup(chan, data);
4943 return -1;
4947 * \ingroup applications
4949 static int pbx_builtin_congestion(struct ast_channel *chan, void *data)
4951 ast_indicate(chan, AST_CONTROL_CONGESTION);
4952 ast_setstate(chan, AST_STATE_BUSY);
4953 wait_for_hangup(chan, data);
4954 return -1;
4958 * \ingroup applications
4960 static int pbx_builtin_answer(struct ast_channel *chan, void *data)
4962 int delay = 0;
4963 int res;
4965 if (chan->_state == AST_STATE_UP)
4966 delay = 0;
4967 else if (!ast_strlen_zero(data))
4968 delay = atoi(data);
4970 res = ast_answer(chan);
4971 if (res)
4972 return res;
4974 if (delay)
4975 res = ast_safe_sleep(chan, delay);
4977 return res;
4980 AST_APP_OPTIONS(resetcdr_opts, {
4981 AST_APP_OPTION('w', AST_CDR_FLAG_POSTED),
4982 AST_APP_OPTION('a', AST_CDR_FLAG_LOCKED),
4983 AST_APP_OPTION('v', AST_CDR_FLAG_KEEP_VARS),
4987 * \ingroup applications
4989 static int pbx_builtin_resetcdr(struct ast_channel *chan, void *data)
4991 char *args;
4992 struct ast_flags flags = { 0 };
4994 if (!ast_strlen_zero(data)) {
4995 args = ast_strdupa(data);
4996 ast_app_parse_options(resetcdr_opts, &flags, NULL, args);
4999 ast_cdr_reset(chan->cdr, &flags);
5001 return 0;
5005 * \ingroup applications
5007 static int pbx_builtin_setamaflags(struct ast_channel *chan, void *data)
5009 /* Copy the AMA Flags as specified */
5010 ast_cdr_setamaflags(chan, data ? data : "");
5011 return 0;
5015 * \ingroup applications
5017 static int pbx_builtin_hangup(struct ast_channel *chan, void *data)
5019 if (!ast_strlen_zero(data)) {
5020 int cause;
5021 char *endptr;
5023 if ((cause = ast_str2cause(data)) > -1) {
5024 chan->hangupcause = cause;
5025 return -1;
5028 cause = strtol((const char *) data, &endptr, 10);
5029 if (cause != 0 || (data != endptr)) {
5030 chan->hangupcause = cause;
5031 return -1;
5034 ast_log(LOG_NOTICE, "Invalid cause given to Hangup(): \"%s\"\n", (char *) data);
5037 if (!chan->hangupcause) {
5038 chan->hangupcause = AST_CAUSE_NORMAL_CLEARING;
5041 return -1;
5045 * \ingroup applications
5047 static int pbx_builtin_gotoiftime(struct ast_channel *chan, void *data)
5049 int res=0;
5050 char *s, *ts;
5051 struct ast_timing timing;
5053 if (ast_strlen_zero(data)) {
5054 ast_log(LOG_WARNING, "GotoIfTime requires an argument:\n <time range>|<days of week>|<days of month>|<months>?[[context|]extension|]priority\n");
5055 return -1;
5058 ts = s = ast_strdupa(data);
5060 /* Separate the Goto path */
5061 strsep(&ts,"?");
5063 /* struct ast_include include contained garbage here, fixed by zeroing it on get_timerange */
5064 if (ast_build_timing(&timing, s) && ast_check_timing(&timing))
5065 res = pbx_builtin_goto(chan, ts);
5067 return res;
5071 * \ingroup applications
5073 static int pbx_builtin_execiftime(struct ast_channel *chan, void *data)
5075 char *s, *appname;
5076 struct ast_timing timing;
5077 struct ast_app *app;
5078 static const char *usage = "ExecIfTime requires an argument:\n <time range>|<days of week>|<days of month>|<months>?<appname>[|<appargs>]";
5080 if (ast_strlen_zero(data)) {
5081 ast_log(LOG_WARNING, "%s\n", usage);
5082 return -1;
5085 appname = ast_strdupa(data);
5087 s = strsep(&appname,"?"); /* Separate the timerange and application name/data */
5088 if (!appname) { /* missing application */
5089 ast_log(LOG_WARNING, "%s\n", usage);
5090 return -1;
5093 if (!ast_build_timing(&timing, s)) {
5094 ast_log(LOG_WARNING, "Invalid Time Spec: %s\nCorrect usage: %s\n", s, usage);
5095 return -1;
5098 if (!ast_check_timing(&timing)) /* outside the valid time window, just return */
5099 return 0;
5101 /* now split appname|appargs */
5102 if ((s = strchr(appname, '|')))
5103 *s++ = '\0';
5105 if ((app = pbx_findapp(appname))) {
5106 return pbx_exec(chan, app, S_OR(s, ""));
5107 } else {
5108 ast_log(LOG_WARNING, "Cannot locate application %s\n", appname);
5109 return -1;
5114 * \ingroup applications
5116 static int pbx_builtin_wait(struct ast_channel *chan, void *data)
5118 int ms;
5120 /* Wait for "n" seconds */
5121 if (data && (ms = atof(data)) > 0) {
5122 ms *= 1000;
5123 return ast_safe_sleep(chan, ms);
5125 return 0;
5129 * \ingroup applications
5131 static int pbx_builtin_waitexten(struct ast_channel *chan, void *data)
5133 int ms, res;
5134 struct ast_flags flags = {0};
5135 char *opts[1] = { NULL };
5136 char *parse;
5137 AST_DECLARE_APP_ARGS(args,
5138 AST_APP_ARG(timeout);
5139 AST_APP_ARG(options);
5142 if (!ast_strlen_zero(data)) {
5143 parse = ast_strdupa(data);
5144 AST_STANDARD_APP_ARGS(args, parse);
5145 } else
5146 memset(&args, 0, sizeof(args));
5148 if (args.options)
5149 ast_app_parse_options(waitexten_opts, &flags, opts, args.options);
5151 if (ast_test_flag(&flags, WAITEXTEN_MOH))
5152 ast_moh_start(chan, opts[0]);
5154 /* Wait for "n" seconds */
5155 if (args.timeout && (ms = atof(args.timeout)) > 0)
5156 ms *= 1000;
5157 else if (chan->pbx)
5158 ms = chan->pbx->rtimeout * 1000;
5159 else
5160 ms = 10000;
5161 res = ast_waitfordigit(chan, ms);
5162 if (!res) {
5163 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 1, chan->cid.cid_num)) {
5164 if (option_verbose > 2)
5165 ast_verbose(VERBOSE_PREFIX_3 "Timeout on %s, continuing...\n", chan->name);
5166 } else if (ast_exists_extension(chan, chan->context, "t", 1, chan->cid.cid_num)) {
5167 if (option_verbose > 2)
5168 ast_verbose(VERBOSE_PREFIX_3 "Timeout on %s, going to 't'\n", chan->name);
5169 set_ext_pri(chan, "t", 0); /* XXX is the 0 correct ? */
5170 } else {
5171 ast_log(LOG_WARNING, "Timeout but no rule 't' in context '%s'\n", chan->context);
5172 res = -1;
5176 if (ast_test_flag(&flags, WAITEXTEN_MOH))
5177 ast_moh_stop(chan);
5179 return res;
5183 * \ingroup applications
5185 static int pbx_builtin_background(struct ast_channel *chan, void *data)
5187 int res = 0;
5188 struct ast_flags flags = {0};
5189 char *parse;
5190 AST_DECLARE_APP_ARGS(args,
5191 AST_APP_ARG(filename);
5192 AST_APP_ARG(options);
5193 AST_APP_ARG(lang);
5194 AST_APP_ARG(context);
5197 if (ast_strlen_zero(data))
5198 ast_log(LOG_WARNING, "Background requires an argument (filename)\n");
5200 parse = ast_strdupa(data);
5202 AST_STANDARD_APP_ARGS(args, parse);
5204 if (!args.lang)
5205 args.lang = (char *)chan->language; /* XXX this is const */
5207 if (!args.context)
5208 args.context = chan->context;
5210 if (args.options) {
5211 if (!strcasecmp(args.options, "skip"))
5212 flags.flags = BACKGROUND_SKIP;
5213 else if (!strcasecmp(args.options, "noanswer"))
5214 flags.flags = BACKGROUND_NOANSWER;
5215 else
5216 ast_app_parse_options(background_opts, &flags, NULL, args.options);
5219 /* Answer if need be */
5220 if (chan->_state != AST_STATE_UP) {
5221 if (ast_test_flag(&flags, BACKGROUND_SKIP)) {
5222 return 0;
5223 } else if (!ast_test_flag(&flags, BACKGROUND_NOANSWER)) {
5224 res = ast_answer(chan);
5228 if (!res) {
5229 char *back = args.filename;
5230 char *front;
5231 ast_stopstream(chan); /* Stop anything playing */
5232 /* Stream the list of files */
5233 while (!res && (front = strsep(&back, "&")) ) {
5234 if ( (res = ast_streamfile(chan, front, args.lang)) ) {
5235 ast_log(LOG_WARNING, "ast_streamfile failed on %s for %s\n", chan->name, (char*)data);
5236 res = 0;
5237 break;
5239 if (ast_test_flag(&flags, BACKGROUND_PLAYBACK)) {
5240 res = ast_waitstream(chan, "");
5241 } else if (ast_test_flag(&flags, BACKGROUND_MATCHEXTEN)) {
5242 res = ast_waitstream_exten(chan, args.context);
5243 } else {
5244 res = ast_waitstream(chan, AST_DIGIT_ANY);
5246 ast_stopstream(chan);
5249 if (args.context != chan->context && res) {
5250 snprintf(chan->exten, sizeof(chan->exten), "%c", res);
5251 ast_copy_string(chan->context, args.context, sizeof(chan->context));
5252 chan->priority = 0;
5253 res = 0;
5255 return res;
5258 /*! Goto
5259 * \ingroup applications
5261 static int pbx_builtin_goto(struct ast_channel *chan, void *data)
5263 int res = ast_parseable_goto(chan, data);
5264 if (!res && (option_verbose > 2))
5265 ast_verbose( VERBOSE_PREFIX_3 "Goto (%s,%s,%d)\n", chan->context,chan->exten, chan->priority+1);
5266 return res;
5270 int pbx_builtin_serialize_variables(struct ast_channel *chan, char *buf, size_t size)
5272 struct ast_var_t *variables;
5273 const char *var, *val;
5274 int total = 0;
5276 if (!chan)
5277 return 0;
5279 memset(buf, 0, size);
5281 AST_LIST_TRAVERSE(&chan->varshead, variables, entries) {
5282 if(variables &&
5283 (var=ast_var_name(variables)) && (val=ast_var_value(variables)) &&
5284 !ast_strlen_zero(var) && !ast_strlen_zero(val)) {
5285 if (ast_build_string(&buf, &size, "%s=%s\n", var, val)) {
5286 ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
5287 break;
5288 } else
5289 total++;
5290 } else
5291 break;
5294 return total;
5297 const char *pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
5299 struct ast_var_t *variables;
5300 const char *ret = NULL;
5301 int i;
5302 struct varshead *places[2] = { NULL, &globals };
5304 if (!name)
5305 return NULL;
5306 if (chan)
5307 places[0] = &chan->varshead;
5309 for (i = 0; i < 2; i++) {
5310 if (!places[i])
5311 continue;
5312 if (places[i] == &globals)
5313 ast_mutex_lock(&globalslock);
5314 AST_LIST_TRAVERSE(places[i], variables, entries) {
5315 if (!strcmp(name, ast_var_name(variables))) {
5316 ret = ast_var_value(variables);
5317 break;
5320 if (places[i] == &globals)
5321 ast_mutex_unlock(&globalslock);
5322 if (ret)
5323 break;
5326 return ret;
5329 void pbx_builtin_pushvar_helper(struct ast_channel *chan, const char *name, const char *value)
5331 struct ast_var_t *newvariable;
5332 struct varshead *headp;
5334 if (name[strlen(name)-1] == ')') {
5335 char *function = ast_strdupa(name);
5337 ast_log(LOG_WARNING, "Cannot push a value onto a function\n");
5338 ast_func_write(chan, function, value);
5339 return;
5342 headp = (chan) ? &chan->varshead : &globals;
5344 if (value) {
5345 if ((option_verbose > 1) && (headp == &globals))
5346 ast_verbose(VERBOSE_PREFIX_2 "Setting global variable '%s' to '%s'\n", name, value);
5347 newvariable = ast_var_assign(name, value);
5348 if (headp == &globals)
5349 ast_mutex_lock(&globalslock);
5350 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
5351 if (headp == &globals)
5352 ast_mutex_unlock(&globalslock);
5356 void pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
5358 struct ast_var_t *newvariable;
5359 struct varshead *headp;
5360 const char *nametail = name;
5362 /* XXX may need locking on the channel ? */
5363 if (name[strlen(name)-1] == ')') {
5364 char *function = ast_strdupa(name);
5366 ast_func_write(chan, function, value);
5367 return;
5370 headp = (chan) ? &chan->varshead : &globals;
5372 /* For comparison purposes, we have to strip leading underscores */
5373 if (*nametail == '_') {
5374 nametail++;
5375 if (*nametail == '_')
5376 nametail++;
5379 if (headp == &globals)
5380 ast_mutex_lock(&globalslock);
5381 AST_LIST_TRAVERSE (headp, newvariable, entries) {
5382 if (strcasecmp(ast_var_name(newvariable), nametail) == 0) {
5383 /* there is already such a variable, delete it */
5384 AST_LIST_REMOVE(headp, newvariable, entries);
5385 ast_var_delete(newvariable);
5386 break;
5390 if (value) {
5391 if ((option_verbose > 1) && (headp == &globals))
5392 ast_verbose(VERBOSE_PREFIX_2 "Setting global variable '%s' to '%s'\n", name, value);
5393 newvariable = ast_var_assign(name, value);
5394 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
5397 if (headp == &globals)
5398 ast_mutex_unlock(&globalslock);
5401 int pbx_builtin_setvar(struct ast_channel *chan, void *data)
5403 char *name, *value, *mydata;
5404 int argc;
5405 char *argv[24]; /* this will only support a maximum of 24 variables being set in a single operation */
5406 int global = 0;
5407 int x;
5409 if (ast_strlen_zero(data)) {
5410 ast_log(LOG_WARNING, "Set requires at least one variable name/value pair.\n");
5411 return 0;
5414 mydata = ast_strdupa(data);
5415 argc = ast_app_separate_args(mydata, '|', argv, sizeof(argv) / sizeof(argv[0]));
5417 /* check for a trailing flags argument */
5418 if ((argc > 1) && !strchr(argv[argc-1], '=')) {
5419 argc--;
5420 if (strchr(argv[argc], 'g'))
5421 global = 1;
5424 for (x = 0; x < argc; x++) {
5425 name = argv[x];
5426 if ((value = strchr(name, '='))) {
5427 *value++ = '\0';
5428 pbx_builtin_setvar_helper((global) ? NULL : chan, name, value);
5429 } else
5430 ast_log(LOG_WARNING, "Ignoring entry '%s' with no = (and not last 'options' entry)\n", name);
5433 return(0);
5436 int pbx_builtin_importvar(struct ast_channel *chan, void *data)
5438 char *name;
5439 char *value;
5440 char *channel;
5441 char tmp[VAR_BUF_SIZE]="";
5443 if (ast_strlen_zero(data)) {
5444 ast_log(LOG_WARNING, "Ignoring, since there is no variable to set\n");
5445 return 0;
5448 value = ast_strdupa(data);
5449 name = strsep(&value,"=");
5450 channel = strsep(&value,"|");
5451 if (channel && value && name) { /*! \todo XXX should do !ast_strlen_zero(..) of the args ? */
5452 struct ast_channel *chan2 = ast_get_channel_by_name_locked(channel);
5453 if (chan2) {
5454 char *s = alloca(strlen(value) + 4);
5455 if (s) {
5456 sprintf(s, "${%s}", value);
5457 pbx_substitute_variables_helper(chan2, s, tmp, sizeof(tmp) - 1);
5459 ast_channel_unlock(chan2);
5461 pbx_builtin_setvar_helper(chan, name, tmp);
5464 return(0);
5467 /*! \todo XXX overwrites data ? */
5468 static int pbx_builtin_setglobalvar(struct ast_channel *chan, void *data)
5470 char *name;
5471 char *stringp = data;
5472 static int dep_warning = 0;
5474 if (ast_strlen_zero(data)) {
5475 ast_log(LOG_WARNING, "Ignoring, since there is no variable to set\n");
5476 return 0;
5479 name = strsep(&stringp, "=");
5481 if (!dep_warning) {
5482 dep_warning = 1;
5483 ast_log(LOG_WARNING, "SetGlobalVar is deprecated. Please use Set(GLOBAL(%s)=%s) instead.\n", name, stringp);
5486 /*! \todo XXX watch out, leading whitespace ? */
5487 pbx_builtin_setvar_helper(NULL, name, stringp);
5489 return(0);
5492 static int pbx_builtin_noop(struct ast_channel *chan, void *data)
5494 return 0;
5497 void pbx_builtin_clear_globals(void)
5499 struct ast_var_t *vardata;
5501 ast_mutex_lock(&globalslock);
5502 while ((vardata = AST_LIST_REMOVE_HEAD(&globals, entries)))
5503 ast_var_delete(vardata);
5504 ast_mutex_unlock(&globalslock);
5507 int pbx_checkcondition(const char *condition)
5509 if (ast_strlen_zero(condition)) /* NULL or empty strings are false */
5510 return 0;
5511 else if (*condition >= '0' && *condition <= '9') /* Numbers are evaluated for truth */
5512 return atoi(condition);
5513 else /* Strings are true */
5514 return 1;
5517 static int pbx_builtin_gotoif(struct ast_channel *chan, void *data)
5519 char *condition, *branch1, *branch2, *branch;
5520 int rc;
5521 char *stringp;
5523 if (ast_strlen_zero(data)) {
5524 ast_log(LOG_WARNING, "Ignoring, since there is no variable to check\n");
5525 return 0;
5528 stringp = ast_strdupa(data);
5529 condition = strsep(&stringp,"?");
5530 branch1 = strsep(&stringp,":");
5531 branch2 = strsep(&stringp,"");
5532 branch = pbx_checkcondition(condition) ? branch1 : branch2;
5534 if (ast_strlen_zero(branch)) {
5535 ast_log(LOG_DEBUG, "Not taking any branch\n");
5536 return 0;
5539 rc = pbx_builtin_goto(chan, branch);
5541 return rc;
5544 static int pbx_builtin_saynumber(struct ast_channel *chan, void *data)
5546 char tmp[256];
5547 char *number = tmp;
5548 char *options;
5550 if (ast_strlen_zero(data)) {
5551 ast_log(LOG_WARNING, "SayNumber requires an argument (number)\n");
5552 return -1;
5554 ast_copy_string(tmp, data, sizeof(tmp));
5555 strsep(&number, "|");
5556 options = strsep(&number, "|");
5557 if (options) {
5558 if ( strcasecmp(options, "f") && strcasecmp(options,"m") &&
5559 strcasecmp(options, "c") && strcasecmp(options, "n") ) {
5560 ast_log(LOG_WARNING, "SayNumber gender option is either 'f', 'm', 'c' or 'n'\n");
5561 return -1;
5564 return ast_say_number(chan, atoi(tmp), "", chan->language, options);
5567 static int pbx_builtin_saydigits(struct ast_channel *chan, void *data)
5569 int res = 0;
5571 if (data)
5572 res = ast_say_digit_str(chan, data, "", chan->language);
5573 return res;
5576 static int pbx_builtin_saycharacters(struct ast_channel *chan, void *data)
5578 int res = 0;
5580 if (data)
5581 res = ast_say_character_str(chan, data, "", chan->language);
5582 return res;
5585 static int pbx_builtin_sayphonetic(struct ast_channel *chan, void *data)
5587 int res = 0;
5589 if (data)
5590 res = ast_say_phonetic_str(chan, data, "", chan->language);
5591 return res;
5594 int load_pbx(void)
5596 int x;
5598 /* Initialize the PBX */
5599 if (option_verbose) {
5600 ast_verbose( "Asterisk PBX Core Initializing\n");
5601 ast_verbose( "Registering builtin applications:\n");
5603 AST_LIST_HEAD_INIT_NOLOCK(&globals);
5604 ast_cli_register_multiple(pbx_cli, sizeof(pbx_cli) / sizeof(pbx_cli[0]));
5606 /* Register builtin applications */
5607 for (x=0; x<sizeof(builtins) / sizeof(struct pbx_builtin); x++) {
5608 if (option_verbose)
5609 ast_verbose( VERBOSE_PREFIX_1 "[%s]\n", builtins[x].name);
5610 if (ast_register_application(builtins[x].name, builtins[x].execute, builtins[x].synopsis, builtins[x].description)) {
5611 ast_log(LOG_ERROR, "Unable to register builtin application '%s'\n", builtins[x].name);
5612 return -1;
5615 return 0;
5619 * Lock context list functions ...
5621 int ast_lock_contexts()
5623 return ast_mutex_lock(&conlock);
5626 int ast_unlock_contexts()
5628 return ast_mutex_unlock(&conlock);
5632 * Lock context ...
5634 int ast_lock_context(struct ast_context *con)
5636 return ast_mutex_lock(&con->lock);
5639 int ast_unlock_context(struct ast_context *con)
5641 return ast_mutex_unlock(&con->lock);
5645 * Name functions ...
5647 const char *ast_get_context_name(struct ast_context *con)
5649 return con ? con->name : NULL;
5652 struct ast_context *ast_get_extension_context(struct ast_exten *exten)
5654 return exten ? exten->parent : NULL;
5657 const char *ast_get_extension_name(struct ast_exten *exten)
5659 return exten ? exten->exten : NULL;
5662 const char *ast_get_extension_label(struct ast_exten *exten)
5664 return exten ? exten->label : NULL;
5667 const char *ast_get_include_name(struct ast_include *inc)
5669 return inc ? inc->name : NULL;
5672 const char *ast_get_ignorepat_name(struct ast_ignorepat *ip)
5674 return ip ? ip->pattern : NULL;
5677 int ast_get_extension_priority(struct ast_exten *exten)
5679 return exten ? exten->priority : -1;
5683 * Registrar info functions ...
5685 const char *ast_get_context_registrar(struct ast_context *c)
5687 return c ? c->registrar : NULL;
5690 const char *ast_get_extension_registrar(struct ast_exten *e)
5692 return e ? e->registrar : NULL;
5695 const char *ast_get_include_registrar(struct ast_include *i)
5697 return i ? i->registrar : NULL;
5700 const char *ast_get_ignorepat_registrar(struct ast_ignorepat *ip)
5702 return ip ? ip->registrar : NULL;
5705 int ast_get_extension_matchcid(struct ast_exten *e)
5707 return e ? e->matchcid : 0;
5710 const char *ast_get_extension_cidmatch(struct ast_exten *e)
5712 return e ? e->cidmatch : NULL;
5715 const char *ast_get_extension_app(struct ast_exten *e)
5717 return e ? e->app : NULL;
5720 void *ast_get_extension_app_data(struct ast_exten *e)
5722 return e ? e->data : NULL;
5725 const char *ast_get_switch_name(struct ast_sw *sw)
5727 return sw ? sw->name : NULL;
5730 const char *ast_get_switch_data(struct ast_sw *sw)
5732 return sw ? sw->data : NULL;
5735 const char *ast_get_switch_registrar(struct ast_sw *sw)
5737 return sw ? sw->registrar : NULL;
5741 * Walking functions ...
5743 struct ast_context *ast_walk_contexts(struct ast_context *con)
5745 return con ? con->next : contexts;
5748 struct ast_exten *ast_walk_context_extensions(struct ast_context *con,
5749 struct ast_exten *exten)
5751 if (!exten)
5752 return con ? con->root : NULL;
5753 else
5754 return exten->next;
5757 struct ast_sw *ast_walk_context_switches(struct ast_context *con,
5758 struct ast_sw *sw)
5760 if (!sw)
5761 return con ? AST_LIST_FIRST(&con->alts) : NULL;
5762 else
5763 return AST_LIST_NEXT(sw, list);
5766 struct ast_exten *ast_walk_extension_priorities(struct ast_exten *exten,
5767 struct ast_exten *priority)
5769 return priority ? priority->peer : exten;
5772 struct ast_include *ast_walk_context_includes(struct ast_context *con,
5773 struct ast_include *inc)
5775 if (!inc)
5776 return con ? con->includes : NULL;
5777 else
5778 return inc->next;
5781 struct ast_ignorepat *ast_walk_context_ignorepats(struct ast_context *con,
5782 struct ast_ignorepat *ip)
5784 if (!ip)
5785 return con ? con->ignorepats : NULL;
5786 else
5787 return ip->next;
5790 int ast_context_verify_includes(struct ast_context *con)
5792 struct ast_include *inc = NULL;
5793 int res = 0;
5795 while ( (inc = ast_walk_context_includes(con, inc)) )
5796 if (!ast_context_find(inc->rname)) {
5797 res = -1;
5798 ast_log(LOG_WARNING, "Context '%s' tries includes nonexistent context '%s'\n",
5799 ast_get_context_name(con), inc->rname);
5801 return res;
5805 static int __ast_goto_if_exists(struct ast_channel *chan, const char *context, const char *exten, int priority, int async)
5807 int (*goto_func)(struct ast_channel *chan, const char *context, const char *exten, int priority);
5809 if (!chan)
5810 return -2;
5812 if (context == NULL)
5813 context = chan->context;
5814 if (exten == NULL)
5815 exten = chan->exten;
5817 goto_func = (async) ? ast_async_goto : ast_explicit_goto;
5818 if (ast_exists_extension(chan, context, exten, priority, chan->cid.cid_num))
5819 return goto_func(chan, context, exten, priority);
5820 else
5821 return -3;
5824 int ast_goto_if_exists(struct ast_channel *chan, const char* context, const char *exten, int priority)
5826 return __ast_goto_if_exists(chan, context, exten, priority, 0);
5829 int ast_async_goto_if_exists(struct ast_channel *chan, const char * context, const char *exten, int priority)
5831 return __ast_goto_if_exists(chan, context, exten, priority, 1);
5834 int ast_parseable_goto(struct ast_channel *chan, const char *goto_string)
5836 char *exten, *pri, *context;
5837 char *stringp;
5838 int ipri;
5839 int mode = 0;
5841 if (ast_strlen_zero(goto_string)) {
5842 ast_log(LOG_WARNING, "Goto requires an argument (optional context|optional extension|priority)\n");
5843 return -1;
5845 stringp = ast_strdupa(goto_string);
5846 context = strsep(&stringp, "|"); /* guaranteed non-null */
5847 exten = strsep(&stringp, "|");
5848 pri = strsep(&stringp, "|");
5849 if (!exten) { /* Only a priority in this one */
5850 pri = context;
5851 exten = NULL;
5852 context = NULL;
5853 } else if (!pri) { /* Only an extension and priority in this one */
5854 pri = exten;
5855 exten = context;
5856 context = NULL;
5858 if (*pri == '+') {
5859 mode = 1;
5860 pri++;
5861 } else if (*pri == '-') {
5862 mode = -1;
5863 pri++;
5865 if (sscanf(pri, "%d", &ipri) != 1) {
5866 if ((ipri = ast_findlabel_extension(chan, context ? context : chan->context, exten ? exten : chan->exten,
5867 pri, chan->cid.cid_num)) < 1) {
5868 ast_log(LOG_WARNING, "Priority '%s' must be a number > 0, or valid label\n", pri);
5869 return -1;
5870 } else
5871 mode = 0;
5873 /* At this point we have a priority and maybe an extension and a context */
5875 if (mode)
5876 ipri = chan->priority + (ipri * mode);
5878 ast_explicit_goto(chan, context, exten, ipri);
5879 ast_cdr_update(chan);
5880 return 0;