add ExtenSpy variant of ChanSpy
[asterisk-bristuff.git] / pbx.c
blob4b009b629dbf630261fa6aa9ead7278a25dd9382
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 "asterisk.h"
28 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
30 #include <sys/types.h>
31 #include <string.h>
32 #include <unistd.h>
33 #include <stdlib.h>
34 #include <stdio.h>
35 #include <ctype.h>
36 #include <errno.h>
37 #include <time.h>
38 #include <sys/time.h>
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/stringfields.h"
63 /*!
64 * \note I M P O R T A N T :
66 * The speed of extension handling will likely be among the most important
67 * aspects of this PBX. The switching scheme as it exists right now isn't
68 * terribly bad (it's O(N+M), where N is the # of extensions and M is the avg #
69 * of priorities, but a constant search time here would be great ;-)
73 #ifdef LOW_MEMORY
74 #define EXT_DATA_SIZE 256
75 #else
76 #define EXT_DATA_SIZE 8192
77 #endif
79 #define SWITCH_DATA_LENGTH 256
81 #define VAR_BUF_SIZE 4096
83 #define VAR_NORMAL 1
84 #define VAR_SOFTTRAN 2
85 #define VAR_HARDTRAN 3
87 #define BACKGROUND_SKIP (1 << 0)
88 #define BACKGROUND_NOANSWER (1 << 1)
89 #define BACKGROUND_MATCHEXTEN (1 << 2)
90 #define BACKGROUND_PLAYBACK (1 << 3)
92 AST_APP_OPTIONS(background_opts, {
93 AST_APP_OPTION('s', BACKGROUND_SKIP),
94 AST_APP_OPTION('n', BACKGROUND_NOANSWER),
95 AST_APP_OPTION('m', BACKGROUND_MATCHEXTEN),
96 AST_APP_OPTION('p', BACKGROUND_PLAYBACK),
97 });
99 #define WAITEXTEN_MOH (1 << 0)
101 AST_APP_OPTIONS(waitexten_opts, {
102 AST_APP_OPTION_ARG('m', WAITEXTEN_MOH, 1),
105 struct ast_context;
108 \brief ast_exten: An extension
109 The dialplan is saved as a linked list with each context
110 having it's own linked list of extensions - one item per
111 priority.
113 struct ast_exten {
114 char *exten; /*!< Extension name */
115 int matchcid; /*!< Match caller id ? */
116 const char *cidmatch; /*!< Caller id to match for this extension */
117 int priority; /*!< Priority */
118 const char *label; /*!< Label */
119 struct ast_context *parent; /*!< The context this extension belongs to */
120 const char *app; /*!< Application to execute */
121 void *data; /*!< Data to use (arguments) */
122 void (*datad)(void *); /*!< Data destructor */
123 struct ast_exten *peer; /*!< Next higher priority with our extension */
124 const char *registrar; /*!< Registrar */
125 struct ast_exten *next; /*!< Extension with a greater ID */
126 char stuff[0];
129 /*! \brief ast_include: include= support in extensions.conf */
130 struct ast_include {
131 const char *name;
132 const char *rname; /*!< Context to include */
133 const char *registrar; /*!< Registrar */
134 int hastime; /*!< If time construct exists */
135 struct ast_timing timing; /*!< time construct */
136 struct ast_include *next; /*!< Link them together */
137 char stuff[0];
140 /*! \brief ast_sw: Switch statement in extensions.conf */
141 struct ast_sw {
142 char *name;
143 const char *registrar; /*!< Registrar */
144 char *data; /*!< Data load */
145 int eval;
146 AST_LIST_ENTRY(ast_sw) list;
147 char *tmpdata;
148 char stuff[0];
151 /*! \brief ast_ignorepat: Ignore patterns in dial plan */
152 struct ast_ignorepat {
153 const char *registrar;
154 struct ast_ignorepat *next;
155 const char pattern[0];
158 /*! \brief ast_context: An extension context */
159 struct ast_context {
160 ast_mutex_t lock; /*!< A lock to prevent multiple threads from clobbering the context */
161 struct ast_exten *root; /*!< The root of the list of extensions */
162 struct ast_context *next; /*!< Link them together */
163 struct ast_include *includes; /*!< Include other contexts */
164 struct ast_ignorepat *ignorepats; /*!< Patterns for which to continue playing dialtone */
165 const char *registrar; /*!< Registrar */
166 AST_LIST_HEAD_NOLOCK(, ast_sw) alts; /*!< Alternative switches */
167 char name[0]; /*!< Name of the context */
171 /*! \brief ast_app: A registered application */
172 struct ast_app {
173 int (*execute)(struct ast_channel *chan, void *data);
174 const char *synopsis; /*!< Synopsis text for 'show applications' */
175 const char *description; /*!< Description (help text) for 'show application &lt;name&gt;' */
176 AST_LIST_ENTRY(ast_app) list; /*!< Next app in list */
177 struct module *module; /*!< Module this app belongs to */
178 char name[0]; /*!< Name of the application */
181 /*! \brief ast_state_cb: An extension state notify register item */
182 struct ast_state_cb {
183 int id;
184 void *data;
185 ast_state_cb_type callback;
186 struct ast_state_cb *next;
189 /*! \brief Structure for dial plan hints
191 \note Hints are pointers from an extension in the dialplan to one or
192 more devices (tech/name) */
193 struct ast_hint {
194 struct ast_exten *exten; /*!< Extension */
195 int laststate; /*!< Last known state */
196 struct ast_state_cb *callbacks; /*!< Callback list for this extension */
197 AST_LIST_ENTRY(ast_hint) list; /*!< Pointer to next hint in list */
200 static const struct cfextension_states {
201 int extension_state;
202 const char * const text;
203 } extension_states[] = {
204 { AST_EXTENSION_NOT_INUSE, "Idle" },
205 { AST_EXTENSION_INUSE, "InUse" },
206 { AST_EXTENSION_BUSY, "Busy" },
207 { AST_EXTENSION_UNAVAILABLE, "Unavailable" },
208 { AST_EXTENSION_RINGING, "Ringing" },
209 { AST_EXTENSION_INUSE | AST_EXTENSION_RINGING, "InUse&Ringing" },
210 { AST_EXTENSION_ONHOLD, "Hold" },
211 { AST_EXTENSION_INUSE | AST_EXTENSION_ONHOLD, "InUse&Hold" }
214 static int pbx_builtin_answer(struct ast_channel *, void *);
215 static int pbx_builtin_goto(struct ast_channel *, void *);
216 static int pbx_builtin_hangup(struct ast_channel *, void *);
217 static int pbx_builtin_background(struct ast_channel *, void *);
218 static int pbx_builtin_wait(struct ast_channel *, void *);
219 static int pbx_builtin_waitexten(struct ast_channel *, void *);
220 static int pbx_builtin_resetcdr(struct ast_channel *, void *);
221 static int pbx_builtin_setamaflags(struct ast_channel *, void *);
222 static int pbx_builtin_ringing(struct ast_channel *, void *);
223 static int pbx_builtin_progress(struct ast_channel *, void *);
224 static int pbx_builtin_congestion(struct ast_channel *, void *);
225 static int pbx_builtin_busy(struct ast_channel *, void *);
226 static int pbx_builtin_setglobalvar(struct ast_channel *, void *);
227 static int pbx_builtin_noop(struct ast_channel *, void *);
228 static int pbx_builtin_gotoif(struct ast_channel *, void *);
229 static int pbx_builtin_gotoiftime(struct ast_channel *, void *);
230 static int pbx_builtin_execiftime(struct ast_channel *, void *);
231 static int pbx_builtin_saynumber(struct ast_channel *, void *);
232 static int pbx_builtin_saydigits(struct ast_channel *, void *);
233 static int pbx_builtin_saycharacters(struct ast_channel *, void *);
234 static int pbx_builtin_sayphonetic(struct ast_channel *, void *);
235 int pbx_builtin_setvar(struct ast_channel *, void *);
236 static int pbx_builtin_importvar(struct ast_channel *, void *);
238 AST_MUTEX_DEFINE_STATIC(globalslock);
239 static struct varshead globals;
241 static int autofallthrough = 0;
243 AST_MUTEX_DEFINE_STATIC(maxcalllock);
244 static int countcalls = 0;
246 static AST_LIST_HEAD_STATIC(acf_root, ast_custom_function);
248 /*! \brief Declaration of builtin applications */
249 static struct pbx_builtin {
250 char name[AST_MAX_APP];
251 int (*execute)(struct ast_channel *chan, void *data);
252 char *synopsis;
253 char *description;
254 } builtins[] =
256 /* These applications are built into the PBX core and do not
257 need separate modules */
259 { "Answer", pbx_builtin_answer,
260 "Answer a channel if ringing",
261 " Answer([delay]): If the call has not been answered, this application will\n"
262 "answer it. Otherwise, it has no effect on the call. If a delay is specified,\n"
263 "Asterisk will wait this number of milliseconds before answering the call.\n"
266 { "BackGround", pbx_builtin_background,
267 "Play an audio file while waiting for digits of an extension to go to.",
268 " Background(filename1[&filename2...][|options[|langoverride][|context]]):\n"
269 "This application will play the given list of files while waiting for an\n"
270 "extension to be dialed by the calling channel. To continue waiting for digits\n"
271 "after this application has finished playing files, the WaitExten application\n"
272 "should be used. The 'langoverride' option explicitly specifies which language\n"
273 "to attempt to use for the requested sound files. If a 'context' is specified,\n"
274 "this is the dialplan context that this application will use when exiting to a\n"
275 "dialed extension."
276 " If one of the requested sound files does not exist, call processing will be\n"
277 "terminated.\n"
278 " Options:\n"
279 " s - Causes the playback of the message to be skipped\n"
280 " if the channel is not in the 'up' state (i.e. it\n"
281 " hasn't been answered yet). If this happens, the\n"
282 " application will return immediately.\n"
283 " n - Don't answer the channel before playing the files.\n"
284 " m - Only break if a digit hit matches a one digit\n"
285 " extension in the destination context.\n"
288 { "Busy", pbx_builtin_busy,
289 "Indicate the Busy condition",
290 " Busy([timeout]): This application will indicate the busy condition to\n"
291 "the calling channel. If the optional timeout is specified, the calling channel\n"
292 "will be hung up after the specified number of seconds. Otherwise, this\n"
293 "application will wait until the calling channel hangs up.\n"
296 { "Congestion", pbx_builtin_congestion,
297 "Indicate the Congestion condition",
298 " Congestion([timeout]): This application will indicate the congestion\n"
299 "condition to the calling channel. If the optional timeout is specified, the\n"
300 "calling channel will be hung up after the specified number of seconds.\n"
301 "Otherwise, this application will wait until the calling channel hangs up.\n"
304 { "Goto", pbx_builtin_goto,
305 "Jump to a particular priority, extension, or context",
306 " Goto([[context|]extension|]priority): This application will cause the\n"
307 "calling channel to continue dialplan execution at the specified priority.\n"
308 "If no specific extension, or extension and context, are specified, then this\n"
309 "application will jump to the specified priority of the current extension.\n"
310 " If the attempt to jump to another location in the dialplan is not successful,\n"
311 "then the channel will continue at the next priority of the current extension.\n"
314 { "GotoIf", pbx_builtin_gotoif,
315 "Conditional goto",
316 " GotoIf(condition?[labeliftrue]:[labeliffalse]): This application will cause\n"
317 "the calling channel to jump to the specified location in the dialplan based on\n"
318 "the evaluation of the given condition. The channel will continue at\n"
319 "'labeliftrue' if the condition is true, or 'labeliffalse' if the condition is\n"
320 "false. The labels are specified with the same syntax as used within the Goto\n"
321 "application. If the label chosen by the condition is omitted, no jump is\n"
322 "performed, but execution continues with the next priority in the dialplan.\n"
325 { "GotoIfTime", pbx_builtin_gotoiftime,
326 "Conditional Goto based on the current time",
327 " GotoIfTime(<times>|<weekdays>|<mdays>|<months>?[[context|]exten|]priority):\n"
328 "This application will have the calling channel jump to the specified location\n"
329 "in the dialplan if the current time matches the given time specification.\n"
332 { "ExecIfTime", pbx_builtin_execiftime,
333 "Conditional application execution based on the current time",
334 " ExecIfTime(<times>|<weekdays>|<mdays>|<months>?appname[|appargs]):\n"
335 "This application will execute the specified dialplan application, with optional\n"
336 "arguments, if the current time matches the given time specification.\n"
339 { "Hangup", pbx_builtin_hangup,
340 "Hang up the calling channel",
341 " Hangup([causecode]): This application will hang up the calling channel.\n"
342 "If a causecode is given the channel's hangup cause will be set to the given\n"
343 "value.\n"
346 { "NoOp", pbx_builtin_noop,
347 "Do Nothing",
348 " NoOp(): This applicatiion does nothing. However, it is useful for debugging\n"
349 "purposes. Any text that is provided as arguments to this application can be\n"
350 "viewed at the Asterisk CLI. This method can be used to see the evaluations of\n"
351 "variables or functions without having any effect."
354 { "Progress", pbx_builtin_progress,
355 "Indicate progress",
356 " Progress(): This application will request that in-band progress information\n"
357 "be provided to the calling channel.\n"
360 { "ResetCDR", pbx_builtin_resetcdr,
361 "Resets the Call Data Record",
362 " ResetCDR([options]): This application causes the Call Data Record to be\n"
363 "reset.\n"
364 " Options:\n"
365 " w -- Store the current CDR record before resetting it.\n"
366 " a -- Store any stacked records.\n"
367 " v -- Save CDR variables.\n"
370 { "Ringing", pbx_builtin_ringing,
371 "Indicate ringing tone",
372 " Ringing(): This application will request that the channel indicate a ringing\n"
373 "tone to the user.\n"
376 { "SayNumber", pbx_builtin_saynumber,
377 "Say Number",
378 " SayNumber(digits[,gender]): This application will play the sounds that\n"
379 "correspond to the given number. Optionally, a gender may be specified.\n"
380 "This will use the language that is currently set for the channel. See the\n"
381 "LANGUAGE function for more information on setting the language for the channel.\n"
384 { "SayDigits", pbx_builtin_saydigits,
385 "Say Digits",
386 " SayDigits(digits): This application will play the sounds that correspond\n"
387 "to the digits of the given number. This will use the language that is currently\n"
388 "set for the channel. See the LANGUAGE function for more information on setting\n"
389 "the language for the channel.\n"
392 { "SayAlpha", pbx_builtin_saycharacters,
393 "Say Alpha",
394 " SayAlpha(string): This application will play the sounds that correspond to\n"
395 "the letters of the given string.\n"
398 { "SayPhonetic", pbx_builtin_sayphonetic,
399 "Say Phonetic",
400 " SayPhonetic(string): This application will play the sounds from the phonetic\n"
401 "alphabet that correspond to the letters in the given string.\n"
404 { "SetAMAFlags", pbx_builtin_setamaflags,
405 "Set the AMA Flags",
406 " SetAMAFlags([flag]): This application will set the channel's AMA Flags for\n"
407 " billing purposes.\n"
410 { "SetGlobalVar", pbx_builtin_setglobalvar,
411 "Set a global variable to a given value",
412 " SetGlobalVar(variable=value): This application sets a given global variable to\n"
413 "the specified value.\n"
416 { "Set", pbx_builtin_setvar,
417 "Set channel variable(s) or function value(s)",
418 " Set(name1=value1|name2=value2|..[|options])\n"
419 "This function can be used to set the value of channel variables or dialplan\n"
420 "functions. It will accept up to 24 name/value pairs. When setting variables,\n"
421 "if the variable name is prefixed with _, the variable will be inherited into\n"
422 "channels created from the current channel. If the variable name is prefixed\n"
423 "with __, the variable will be inherited into channels created from the current\n"
424 "channel and all children channels.\n"
425 " Options:\n"
426 " g - Set variable globally instead of on the channel\n"
427 " (applies only to variables, not functions)\n"
430 { "ImportVar", pbx_builtin_importvar,
431 "Import a variable from a channel into a new variable",
432 " ImportVar(newvar=channelname|variable): This application imports a variable\n"
433 "from the specified channel (as opposed to the current one) and stores it as\n"
434 "a variable in the current channel (the channel that is calling this\n"
435 "application). Variables created by this application have the same inheritance\n"
436 "properties as those created with the Set application. See the documentation for\n"
437 "Set for more information.\n"
440 { "Wait", pbx_builtin_wait,
441 "Waits for some time",
442 " Wait(seconds): This application waits for a specified number of seconds.\n"
443 "Then, dialplan execution will continue at the next priority.\n"
444 " Note that the seconds can be passed with fractions of a second. For example,\n"
445 "'1.5' will ask the application to wait for 1.5 seconds.\n"
448 { "WaitExten", pbx_builtin_waitexten,
449 "Waits for an extension to be entered",
450 " WaitExten([seconds][|options]): This application waits for the user to enter\n"
451 "a new extension for a specified number of seconds.\n"
452 " Note that the seconds can be passed with fractions of a second. For example,\n"
453 "'1.5' will ask the application to wait for 1.5 seconds.\n"
454 " Options:\n"
455 " m[(x)] - Provide music on hold to the caller while waiting for an extension.\n"
456 " Optionally, specify the class for music on hold within parenthesis.\n"
461 static struct ast_context *contexts = NULL;
462 AST_MUTEX_DEFINE_STATIC(conlock); /*!< Lock for the ast_context list */
464 static AST_LIST_HEAD_STATIC(apps, ast_app);
466 static AST_LIST_HEAD_STATIC(switches, ast_switch);
468 static int stateid = 1;
469 /* WARNING:
470 When holding this list's lock, do _not_ do anything that will cause conlock
471 to be taken, unless you _already_ hold it. The ast_merge_contexts_and_delete
472 function will take the locks in conlock/hints order, so any other
473 paths that require both locks must also take them in that order.
475 static AST_LIST_HEAD_STATIC(hints, ast_hint);
476 struct ast_state_cb *statecbs = NULL;
479 \note This function is special. It saves the stack so that no matter
480 how many times it is called, it returns to the same place */
481 int pbx_exec(struct ast_channel *c, /*!< Channel */
482 struct ast_app *app, /*!< Application */
483 void *data) /*!< Data for execution */
485 int res;
487 const char *saved_c_appl;
488 const char *saved_c_data;
490 if (c->cdr)
491 ast_cdr_setapp(c->cdr, app->name, data);
493 /* save channel values */
494 saved_c_appl= c->appl;
495 saved_c_data= c->data;
497 c->appl = app->name;
498 c->data = data;
499 /* XXX remember what to to when we have linked apps to modules */
500 if (app->module) {
501 /* XXX LOCAL_USER_ADD(app->module) */
503 res = app->execute(c, data);
504 if (app->module) {
505 /* XXX LOCAL_USER_REMOVE(app->module) */
507 /* restore channel values */
508 c->appl = saved_c_appl;
509 c->data = saved_c_data;
510 return res;
514 /*! Go no deeper than this through includes (not counting loops) */
515 #define AST_PBX_MAX_STACK 128
517 /*! \brief Find application handle in linked list
519 struct ast_app *pbx_findapp(const char *app)
521 struct ast_app *tmp;
523 AST_LIST_LOCK(&apps);
524 AST_LIST_TRAVERSE(&apps, tmp, list) {
525 if (!strcasecmp(tmp->name, app))
526 break;
528 AST_LIST_UNLOCK(&apps);
530 return tmp;
533 static struct ast_switch *pbx_findswitch(const char *sw)
535 struct ast_switch *asw;
537 AST_LIST_LOCK(&switches);
538 AST_LIST_TRAVERSE(&switches, asw, list) {
539 if (!strcasecmp(asw->name, sw))
540 break;
542 AST_LIST_UNLOCK(&switches);
544 return asw;
547 static inline int include_valid(struct ast_include *i)
549 if (!i->hastime)
550 return 1;
552 return ast_check_timing(&(i->timing));
555 static void pbx_destroy(struct ast_pbx *p)
557 free(p);
561 * Special characters used in patterns:
562 * '_' underscore is the leading character of a pattern.
563 * In other position it is treated as a regular char.
564 * ' ' '-' space and '-' are separator and ignored.
565 * . one or more of any character. Only allowed at the end of
566 * a pattern.
567 * ! zero or more of anything. Also impacts the result of CANMATCH
568 * and MATCHMORE. Only allowed at the end of a pattern.
569 * In the core routine, ! causes a match with a return code of 2.
570 * In turn, depending on the search mode: (XXX check if it is implemented)
571 * - E_MATCH retuns 1 (does match)
572 * - E_MATCHMORE returns 0 (no match)
573 * - E_CANMATCH returns 1 (does match)
575 * / should not appear as it is considered the separator of the CID info.
576 * XXX at the moment we may stop on this char.
578 * X Z N match ranges 0-9, 1-9, 2-9 respectively.
579 * [ denotes the start of a set of character. Everything inside
580 * is considered literally. We can have ranges a-d and individual
581 * characters. A '[' and '-' can be considered literally if they
582 * are just before ']'.
583 * XXX currently there is no way to specify ']' in a range, nor \ is
584 * considered specially.
586 * When we compare a pattern with a specific extension, all characters in the extension
587 * itself are considered literally with the only exception of '-' which is considered
588 * as a separator and thus ignored.
589 * XXX do we want to consider space as a separator as well ?
590 * XXX do we want to consider the separators in non-patterns as well ?
594 * \brief helper functions to sort extensions and patterns in the desired way,
595 * so that more specific patterns appear first.
597 * ext_cmp1 compares individual characters (or sets of), returning
598 * an int where bits 0-7 are the ASCII code of the first char in the set,
599 * while bit 8-15 are the cardinality of the set minus 1.
600 * This way more specific patterns (smaller cardinality) appear first.
601 * Wildcards have a special value, so that we can directly compare them to
602 * sets by subtracting the two values. In particular:
603 * 0x000xx one character, xx
604 * 0x0yyxx yy character set starting with xx
605 * 0x10000 '.' (one or more of anything)
606 * 0x20000 '!' (zero or more of anything)
607 * 0x30000 NUL (end of string)
608 * 0x40000 error in set.
609 * The pointer to the string is advanced according to needs.
610 * NOTES:
611 * 1. the empty set is equivalent to NUL.
612 * 2. given that a full set has always 0 as the first element,
613 * we could encode the special cases as 0xffXX where XX
614 * is 1, 2, 3, 4 as used above.
616 static int ext_cmp1(const char **p)
618 uint32_t chars[8];
619 int c, cmin = 0xff, count = 0;
620 const char *end;
622 /* load, sign extend and advance pointer until we find
623 * a valid character.
625 while ( (c = *(*p)++) && (c == ' ' || c == '-') )
626 ; /* ignore some characters */
628 /* always return unless we have a set of chars */
629 switch (c) {
630 default: /* ordinary character */
631 return 0x0000 | (c & 0xff);
633 case 'N': /* 2..9 */
634 return 0x0700 | '2' ;
636 case 'X': /* 0..9 */
637 return 0x0900 | '0';
639 case 'Z': /* 1..9 */
640 return 0x0800 | '1';
642 case '.': /* wildcard */
643 return 0x10000;
645 case '!': /* earlymatch */
646 return 0x20000; /* less specific than NULL */
648 case '\0': /* empty string */
649 *p = NULL;
650 return 0x30000;
652 case '[': /* pattern */
653 break;
655 /* locate end of set */
656 end = strchr(*p, ']');
658 if (end == NULL) {
659 ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");
660 return 0x40000; /* XXX make this entry go last... */
663 bzero(chars, sizeof(chars)); /* clear all chars in the set */
664 for (; *p < end ; (*p)++) {
665 unsigned char c1, c2; /* first-last char in range */
666 c1 = (unsigned char)((*p)[0]);
667 if (*p + 2 < end && (*p)[1] == '-') { /* this is a range */
668 c2 = (unsigned char)((*p)[2]);
669 *p += 2; /* skip a total of 3 chars */
670 } else /* individual character */
671 c2 = c1;
672 if (c1 < cmin)
673 cmin = c1;
674 for (; c1 <= c2; c1++) {
675 uint32_t mask = 1 << (c1 % 32);
676 if ( (chars[ c1 / 32 ] & mask) == 0)
677 count += 0x100;
678 chars[ c1 / 32 ] |= mask;
681 (*p)++;
682 return count == 0 ? 0x30000 : (count | cmin);
686 * \brief the full routine to compare extensions in rules.
688 static int ext_cmp(const char *a, const char *b)
690 /* make sure non-patterns come first.
691 * If a is not a pattern, it either comes first or
692 * we use strcmp to compare the strings.
694 int ret = 0;
696 if (a[0] != '_')
697 return (b[0] == '_') ? -1 : strcmp(a, b);
699 /* Now we know a is a pattern; if b is not, a comes first */
700 if (b[0] != '_')
701 return 1;
702 #if 0 /* old mode for ext matching */
703 return strcmp(a, b);
704 #endif
705 /* ok we need full pattern sorting routine */
706 while (!ret && a && b)
707 ret = ext_cmp1(&a) - ext_cmp1(&b);
708 if (ret == 0)
709 return 0;
710 else
711 return (ret > 0) ? 1 : -1;
715 * When looking up extensions, we can have different requests
716 * identified by the 'action' argument, as follows.
717 * Note that the coding is such that the low 4 bits are the
718 * third argument to extension_match_core.
720 enum ext_match_t {
721 E_MATCHMORE = 0x00, /* extension can match but only with more 'digits' */
722 E_CANMATCH = 0x01, /* extension can match with or without more 'digits' */
723 E_MATCH = 0x02, /* extension is an exact match */
724 E_MATCH_MASK = 0x03, /* mask for the argument to extension_match_core() */
725 E_SPAWN = 0x12, /* want to spawn an extension. Requires exact match */
726 E_FINDLABEL = 0x22 /* returns the priority for a given label. Requires exact match */
730 * Internal function for ast_extension_{match|close}
731 * return 0 on no-match, 1 on match, 2 on early match.
732 * mode is as follows:
733 * E_MATCH success only on exact match
734 * E_MATCHMORE success only on partial match (i.e. leftover digits in pattern)
735 * E_CANMATCH either of the above.
737 static int _extension_match_core(const char *pattern, const char *data, enum ext_match_t mode)
739 mode &= E_MATCH_MASK; /* only consider the relevant bits */
741 if (pattern[0] != '_') { /* not a pattern, try exact or partial match */
742 int ld = strlen(data), lp = strlen(pattern);
744 if (lp < ld) /* pattern too short, cannot match */
745 return 0;
746 /* depending on the mode, accept full or partial match or both */
747 if (mode == E_MATCH)
748 return !strcmp(pattern, data); /* 1 on match, 0 on fail */
749 if (ld == 0 || !strncasecmp(pattern, data, ld)) /* partial or full match */
750 return (mode == E_MATCHMORE) ? lp > ld : 1; /* XXX should consider '!' and '/' ? */
751 else
752 return 0;
754 pattern++; /* skip leading _ */
756 * XXX below we stop at '/' which is a separator for the CID info. However we should
757 * not store '/' in the pattern at all. When we insure it, we can remove the checks.
759 while (*data && *pattern && *pattern != '/') {
760 const char *end;
762 if (*data == '-') { /* skip '-' in data (just a separator) */
763 data++;
764 continue;
766 switch (toupper(*pattern)) {
767 case '[': /* a range */
768 end = strchr(pattern+1, ']'); /* XXX should deal with escapes ? */
769 if (end == NULL) {
770 ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");
771 return 0; /* unconditional failure */
773 for (pattern++; pattern != end; pattern++) {
774 if (pattern+2 < end && pattern[1] == '-') { /* this is a range */
775 if (*data >= pattern[0] && *data <= pattern[2])
776 break; /* match found */
777 else {
778 pattern += 2; /* skip a total of 3 chars */
779 continue;
781 } else if (*data == pattern[0])
782 break; /* match found */
784 if (pattern == end)
785 return 0;
786 pattern = end; /* skip and continue */
787 break;
788 case 'N':
789 if (*data < '2' || *data > '9')
790 return 0;
791 break;
792 case 'X':
793 if (*data < '0' || *data > '9')
794 return 0;
795 break;
796 case 'Z':
797 if (*data < '1' || *data > '9')
798 return 0;
799 break;
800 case '.': /* Must match, even with more digits */
801 return 1;
802 case '!': /* Early match */
803 return 2;
804 case ' ':
805 case '-': /* Ignore these in patterns */
806 data--; /* compensate the final data++ */
807 break;
808 default:
809 if (*data != *pattern)
810 return 0;
812 data++;
813 pattern++;
815 if (*data) /* data longer than pattern, no match */
816 return 0;
818 * match so far, but ran off the end of the data.
819 * Depending on what is next, determine match or not.
821 if (*pattern == '\0' || *pattern == '/') /* exact match */
822 return (mode == E_MATCHMORE) ? 0 : 1; /* this is a failure for E_MATCHMORE */
823 else if (*pattern == '!') /* early match */
824 return 2;
825 else /* partial match */
826 return (mode == E_MATCH) ? 0 : 1; /* this is a failure for E_MATCH */
830 * Wrapper around _extension_match_core() to do performance measurement
831 * using the profiling code.
833 static int extension_match_core(const char *pattern, const char *data, enum ext_match_t mode)
835 int i;
836 static int prof_id = -2; /* marker for 'unallocated' id */
837 if (prof_id == -2)
838 prof_id = ast_add_profile("ext_match", 0);
839 ast_mark(prof_id, 1);
840 i = _extension_match_core(pattern, data, mode);
841 ast_mark(prof_id, 0);
842 return i;
845 int ast_extension_match(const char *pattern, const char *data)
847 return extension_match_core(pattern, data, E_MATCH);
850 int ast_extension_close(const char *pattern, const char *data, int needmore)
852 if (needmore != E_MATCHMORE && needmore != E_CANMATCH)
853 ast_log(LOG_WARNING, "invalid argument %d\n", needmore);
854 return extension_match_core(pattern, data, needmore);
857 struct ast_context *ast_context_find(const char *name)
859 struct ast_context *tmp = NULL;
860 ast_mutex_lock(&conlock);
861 while ( (tmp = ast_walk_contexts(tmp)) ) {
862 if (!name || !strcasecmp(name, tmp->name))
863 break;
865 ast_mutex_unlock(&conlock);
866 return tmp;
869 #define STATUS_NO_CONTEXT 1
870 #define STATUS_NO_EXTENSION 2
871 #define STATUS_NO_PRIORITY 3
872 #define STATUS_NO_LABEL 4
873 #define STATUS_SUCCESS 5
875 static int matchcid(const char *cidpattern, const char *callerid)
877 /* If the Caller*ID pattern is empty, then we're matching NO Caller*ID, so
878 failing to get a number should count as a match, otherwise not */
880 if (ast_strlen_zero(callerid))
881 return ast_strlen_zero(cidpattern) ? 1 : 0;
883 return ast_extension_match(cidpattern, callerid);
886 /* request and result for pbx_find_extension */
887 struct pbx_find_info {
888 #if 0
889 const char *context;
890 const char *exten;
891 int priority;
892 #endif
894 char *incstack[AST_PBX_MAX_STACK]; /* filled during the search */
895 int stacklen; /* modified during the search */
896 int status; /* set on return */
897 struct ast_switch *swo; /* set on return */
898 const char *data; /* set on return */
899 const char *foundcontext; /* set on return */
902 static struct ast_exten *pbx_find_extension(struct ast_channel *chan,
903 struct ast_context *bypass, struct pbx_find_info *q,
904 const char *context, const char *exten, int priority,
905 const char *label, const char *callerid, enum ext_match_t action)
907 int x, res;
908 struct ast_context *tmp;
909 struct ast_exten *e, *eroot;
910 struct ast_include *i;
911 struct ast_sw *sw;
913 /* Initialize status if appropriate */
914 if (q->stacklen == 0) {
915 q->status = STATUS_NO_CONTEXT;
916 q->swo = NULL;
917 q->data = NULL;
918 q->foundcontext = NULL;
920 /* Check for stack overflow */
921 if (q->stacklen >= AST_PBX_MAX_STACK) {
922 ast_log(LOG_WARNING, "Maximum PBX stack exceeded\n");
923 return NULL;
925 /* Check first to see if we've already been checked */
926 for (x = 0; x < q->stacklen; x++) {
927 if (!strcasecmp(q->incstack[x], context))
928 return NULL;
930 if (bypass) /* bypass means we only look there */
931 tmp = bypass;
932 else { /* look in contexts */
933 tmp = NULL;
934 while ((tmp = ast_walk_contexts(tmp)) ) {
935 if (!strcmp(tmp->name, context))
936 break;
938 if (!tmp)
939 return NULL;
941 if (q->status < STATUS_NO_EXTENSION)
942 q->status = STATUS_NO_EXTENSION;
944 /* scan the list trying to match extension and CID */
945 eroot = NULL;
946 while ( (eroot = ast_walk_context_extensions(tmp, eroot)) ) {
947 int match = extension_match_core(eroot->exten, exten, action);
948 /* 0 on fail, 1 on match, 2 on earlymatch */
950 if (!match || (eroot->matchcid && !matchcid(eroot->cidmatch, callerid)))
951 continue; /* keep trying */
952 if (match == 2 && action == E_MATCHMORE) {
953 /* We match an extension ending in '!'.
954 * The decision in this case is final and is NULL (no match).
956 return NULL;
958 /* found entry, now look for the right priority */
959 if (q->status < STATUS_NO_PRIORITY)
960 q->status = STATUS_NO_PRIORITY;
961 e = NULL;
962 while ( (e = ast_walk_extension_priorities(eroot, e)) ) {
963 /* Match label or priority */
964 if (action == E_FINDLABEL) {
965 if (q->status < STATUS_NO_LABEL)
966 q->status = STATUS_NO_LABEL;
967 if (label && e->label && !strcmp(label, e->label))
968 break; /* found it */
969 } else if (e->priority == priority) {
970 break; /* found it */
971 } /* else keep searching */
973 if (e) { /* found a valid match */
974 q->status = STATUS_SUCCESS;
975 q->foundcontext = context;
976 return e;
979 /* Check alternative switches */
980 AST_LIST_TRAVERSE(&tmp->alts, sw, list) {
981 struct ast_switch *asw = pbx_findswitch(sw->name);
982 ast_switch_f *aswf = NULL;
983 char *datap;
985 if (!asw) {
986 ast_log(LOG_WARNING, "No such switch '%s'\n", sw->name);
987 continue;
989 /* Substitute variables now */
990 if (sw->eval)
991 pbx_substitute_variables_helper(chan, sw->data, sw->tmpdata, SWITCH_DATA_LENGTH - 1);
993 /* equivalent of extension_match_core() at the switch level */
994 if (action == E_CANMATCH)
995 aswf = asw->canmatch;
996 else if (action == E_MATCHMORE)
997 aswf = asw->matchmore;
998 else /* action == E_MATCH */
999 aswf = asw->exists;
1000 datap = sw->eval ? sw->tmpdata : sw->data;
1001 res = !aswf ? 0 : aswf(chan, context, exten, priority, callerid, datap);
1002 if (res) { /* Got a match */
1003 q->swo = asw;
1004 q->data = datap;
1005 q->foundcontext = context;
1006 /* XXX keep status = STATUS_NO_CONTEXT ? */
1007 return NULL;
1010 q->incstack[q->stacklen++] = tmp->name; /* Setup the stack */
1011 /* Now try any includes we have in this context */
1012 for (i = tmp->includes; i; i = i->next) {
1013 if (include_valid(i)) {
1014 if ((e = pbx_find_extension(chan, bypass, q, i->rname, exten, priority, label, callerid, action)))
1015 return e;
1016 if (q->swo)
1017 return NULL;
1020 return NULL;
1023 /* Note that it's negative -- that's important later. */
1024 #define DONT_HAVE_LENGTH 0x80000000
1026 /*! \brief extract offset:length from variable name.
1027 * Returns 1 if there is a offset:length part, which is
1028 * trimmed off (values go into variables)
1030 static int parse_variable_name(char *var, int *offset, int *length, int *isfunc)
1032 int parens=0;
1034 *offset = 0;
1035 *length = DONT_HAVE_LENGTH;
1036 *isfunc = 0;
1037 for (; *var; var++) {
1038 if (*var == '(') {
1039 (*isfunc)++;
1040 parens++;
1041 } else if (*var == ')') {
1042 parens--;
1043 } else if (*var == ':' && parens == 0) {
1044 *var++ = '\0';
1045 sscanf(var, "%d:%d", offset, length);
1046 return 1; /* offset:length valid */
1049 return 0;
1052 /*! \brief takes a substring. It is ok to call with value == workspace.
1054 * offset < 0 means start from the end of the string and set the beginning
1055 * to be that many characters back.
1056 * length is the length of the substring, -1 means unlimited
1057 * (we take any negative value).
1058 * Always return a copy in workspace.
1060 static char *substring(const char *value, int offset, int length, char *workspace, size_t workspace_len)
1062 char *ret = workspace;
1063 int lr; /* length of the input string after the copy */
1065 ast_copy_string(workspace, value, workspace_len); /* always make a copy */
1067 /* Quick check if no need to do anything */
1068 if (offset == 0 && length < 0) /* take the whole string */
1069 return ret;
1071 lr = strlen(ret); /* compute length after copy, so we never go out of the workspace */
1073 if (offset < 0) { /* translate negative offset into positive ones */
1074 offset = lr + offset;
1075 if (offset < 0) /* If the negative offset was greater than the length of the string, just start at the beginning */
1076 offset = 0;
1079 /* too large offset result in empty string so we know what to return */
1080 if (offset >= lr)
1081 return ret + lr; /* the final '\0' */
1083 ret += offset; /* move to the start position */
1084 if (length >= 0 && length < lr - offset) /* truncate if necessary */
1085 ret[length] = '\0';
1087 return ret;
1090 /*! \brief pbx_retrieve_variable: Support for Asterisk built-in variables and
1091 functions in the dialplan
1092 ---*/
1093 void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp)
1095 const char not_found = '\0';
1096 char *tmpvar;
1097 const char *s; /* the result */
1098 int offset, length;
1099 int i, need_substring;
1100 struct varshead *places[2] = { headp, &globals }; /* list of places where we may look */
1102 if (c) {
1103 places[0] = &c->varshead;
1106 * Make a copy of var because parse_variable_name() modifies the string.
1107 * Then if called directly, we might need to run substring() on the result;
1108 * remember this for later in 'need_substring', 'offset' and 'length'
1110 tmpvar = ast_strdupa(var); /* parse_variable_name modifies the string */
1111 need_substring = parse_variable_name(tmpvar, &offset, &length, &i /* ignored */);
1114 * Look first into predefined variables, then into variable lists.
1115 * Variable 's' points to the result, according to the following rules:
1116 * s == &not_found (set at the beginning) means that we did not find a
1117 * matching variable and need to look into more places.
1118 * If s != &not_found, s is a valid result string as follows:
1119 * s = NULL if the variable does not have a value;
1120 * you typically do this when looking for an unset predefined variable.
1121 * s = workspace if the result has been assembled there;
1122 * typically done when the result is built e.g. with an snprintf(),
1123 * so we don't need to do an additional copy.
1124 * s != workspace in case we have a string, that needs to be copied
1125 * (the ast_copy_string is done once for all at the end).
1126 * Typically done when the result is already available in some string.
1128 s = &not_found; /* default value */
1129 if (c) { /* This group requires a valid channel */
1130 /* Names with common parts are looked up a piece at a time using strncmp. */
1131 if (!strncmp(var, "CALL", 4)) {
1132 if (!strncmp(var + 4, "ING", 3)) {
1133 if (!strcmp(var + 7, "PRES")) { /* CALLINGPRES */
1134 snprintf(workspace, workspacelen, "%d", c->cid.cid_pres);
1135 s = workspace;
1136 } else if (!strcmp(var + 7, "ANI2")) { /* CALLINGANI2 */
1137 snprintf(workspace, workspacelen, "%d", c->cid.cid_ani2);
1138 s = workspace;
1139 } else if (!strcmp(var + 7, "TON")) { /* CALLINGTON */
1140 snprintf(workspace, workspacelen, "%d", c->cid.cid_ton);
1141 s = workspace;
1142 } else if (!strcmp(var + 7, "TNS")) { /* CALLINGTNS */
1143 snprintf(workspace, workspacelen, "%d", c->cid.cid_tns);
1144 s = workspace;
1147 } else if (!strcmp(var, "HINT")) {
1148 s = ast_get_hint(workspace, workspacelen, NULL, 0, c, c->context, c->exten) ? workspace : NULL;
1149 } else if (!strcmp(var, "HINTNAME")) {
1150 s = ast_get_hint(NULL, 0, workspace, workspacelen, c, c->context, c->exten) ? workspace : NULL;
1151 } else if (!strcmp(var, "EXTEN")) {
1152 s = c->exten;
1153 } else if (!strcmp(var, "CONTEXT")) {
1154 s = c->context;
1155 } else if (!strcmp(var, "PRIORITY")) {
1156 snprintf(workspace, workspacelen, "%d", c->priority);
1157 s = workspace;
1158 } else if (!strcmp(var, "CHANNEL")) {
1159 s = c->name;
1160 } else if (!strcmp(var, "UNIQUEID")) {
1161 s = c->uniqueid;
1162 } else if (!strcmp(var, "HANGUPCAUSE")) {
1163 snprintf(workspace, workspacelen, "%d", c->hangupcause);
1164 s = workspace;
1167 if (s == &not_found) { /* look for more */
1168 if (!strcmp(var, "EPOCH")) {
1169 snprintf(workspace, workspacelen, "%u",(int)time(NULL));
1170 s = workspace;
1171 } else if (!strcmp(var, "SYSTEMNAME")) {
1172 s = ast_config_AST_SYSTEM_NAME;
1175 /* if not found, look into chanvars or global vars */
1176 for (i = 0; s == &not_found && i < (sizeof(places) / sizeof(places[0])); i++) {
1177 struct ast_var_t *variables;
1178 if (!places[i])
1179 continue;
1180 if (places[i] == &globals)
1181 ast_mutex_lock(&globalslock);
1182 AST_LIST_TRAVERSE(places[i], variables, entries) {
1183 if (strcasecmp(ast_var_name(variables), var)==0) {
1184 s = ast_var_value(variables);
1185 break;
1188 if (places[i] == &globals)
1189 ast_mutex_unlock(&globalslock);
1191 if (s == &not_found || s == NULL)
1192 *ret = NULL;
1193 else {
1194 if (s != workspace)
1195 ast_copy_string(workspace, s, workspacelen);
1196 *ret = workspace;
1197 if (need_substring)
1198 *ret = substring(*ret, offset, length, workspace, workspacelen);
1202 /*! \brief CLI function to show installed custom functions
1203 \addtogroup CLI_functions
1205 static int handle_show_functions(int fd, int argc, char *argv[])
1207 struct ast_custom_function *acf;
1208 int count_acf = 0;
1209 int like = 0;
1211 if (argc == 4 && (!strcmp(argv[2], "like")) ) {
1212 like = 1;
1213 } else if (argc != 2) {
1214 return RESULT_SHOWUSAGE;
1217 ast_cli(fd, "%s Custom Functions:\n--------------------------------------------------------------------------------\n", like ? "Matching" : "Installed");
1219 AST_LIST_LOCK(&acf_root);
1220 AST_LIST_TRAVERSE(&acf_root, acf, acflist) {
1221 if (!like || strstr(acf->name, argv[3])) {
1222 count_acf++;
1223 ast_cli(fd, "%-20.20s %-35.35s %s\n", acf->name, acf->syntax, acf->synopsis);
1226 AST_LIST_UNLOCK(&acf_root);
1228 ast_cli(fd, "%d %scustom functions installed.\n", count_acf, like ? "matching " : "");
1230 return RESULT_SUCCESS;
1233 static int handle_show_function(int fd, int argc, char *argv[])
1235 struct ast_custom_function *acf;
1236 /* Maximum number of characters added by terminal coloring is 22 */
1237 char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
1238 char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
1239 char stxtitle[40], *syntax = NULL;
1240 int synopsis_size, description_size, syntax_size;
1242 if (argc < 3)
1243 return RESULT_SHOWUSAGE;
1245 if (!(acf = ast_custom_function_find(argv[2]))) {
1246 ast_cli(fd, "No function by that name registered.\n");
1247 return RESULT_FAILURE;
1251 if (acf->synopsis)
1252 synopsis_size = strlen(acf->synopsis) + 23;
1253 else
1254 synopsis_size = strlen("Not available") + 23;
1255 synopsis = alloca(synopsis_size);
1257 if (acf->desc)
1258 description_size = strlen(acf->desc) + 23;
1259 else
1260 description_size = strlen("Not available") + 23;
1261 description = alloca(description_size);
1263 if (acf->syntax)
1264 syntax_size = strlen(acf->syntax) + 23;
1265 else
1266 syntax_size = strlen("Not available") + 23;
1267 syntax = alloca(syntax_size);
1269 snprintf(info, 64 + AST_MAX_APP, "\n -= Info about function '%s' =- \n\n", acf->name);
1270 term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
1271 term_color(stxtitle, "[Syntax]\n", COLOR_MAGENTA, 0, 40);
1272 term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
1273 term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
1274 term_color(syntax,
1275 acf->syntax ? acf->syntax : "Not available",
1276 COLOR_CYAN, 0, syntax_size);
1277 term_color(synopsis,
1278 acf->synopsis ? acf->synopsis : "Not available",
1279 COLOR_CYAN, 0, synopsis_size);
1280 term_color(description,
1281 acf->desc ? acf->desc : "Not available",
1282 COLOR_CYAN, 0, description_size);
1284 ast_cli(fd,"%s%s%s\n\n%s%s\n\n%s%s\n", infotitle, stxtitle, syntax, syntitle, synopsis, destitle, description);
1286 return RESULT_SUCCESS;
1289 static char *complete_show_function(const char *line, const char *word, int pos, int state)
1291 struct ast_custom_function *acf;
1292 char *ret = NULL;
1293 int which = 0;
1294 int wordlen = strlen(word);
1296 /* case-insensitive for convenience in this 'complete' function */
1297 AST_LIST_LOCK(&acf_root);
1298 AST_LIST_TRAVERSE(&acf_root, acf, acflist) {
1299 if (!strncasecmp(word, acf->name, wordlen) && ++which > state) {
1300 ret = strdup(acf->name);
1301 break;
1304 AST_LIST_UNLOCK(&acf_root);
1306 return ret;
1309 struct ast_custom_function *ast_custom_function_find(const char *name)
1311 struct ast_custom_function *acf = NULL;
1313 AST_LIST_LOCK(&acf_root);
1314 AST_LIST_TRAVERSE(&acf_root, acf, acflist) {
1315 if (!strcmp(name, acf->name))
1316 break;
1318 AST_LIST_UNLOCK(&acf_root);
1320 return acf;
1323 int ast_custom_function_unregister(struct ast_custom_function *acf)
1325 struct ast_custom_function *cur;
1327 if (!acf)
1328 return -1;
1330 AST_LIST_LOCK(&acf_root);
1331 AST_LIST_TRAVERSE_SAFE_BEGIN(&acf_root, cur, acflist) {
1332 if (cur == acf) {
1333 AST_LIST_REMOVE_CURRENT(&acf_root, acflist);
1334 if (option_verbose > 1)
1335 ast_verbose(VERBOSE_PREFIX_2 "Unregistered custom function %s\n", acf->name);
1336 break;
1339 AST_LIST_TRAVERSE_SAFE_END
1340 AST_LIST_UNLOCK(&acf_root);
1342 return acf ? 0 : -1;
1345 int ast_custom_function_register(struct ast_custom_function *acf)
1347 struct ast_custom_function *cur;
1349 if (!acf)
1350 return -1;
1352 AST_LIST_LOCK(&acf_root);
1354 if (ast_custom_function_find(acf->name)) {
1355 ast_log(LOG_ERROR, "Function %s already registered.\n", acf->name);
1356 AST_LIST_UNLOCK(&acf_root);
1357 return -1;
1360 /* Store in alphabetical order */
1361 AST_LIST_TRAVERSE_SAFE_BEGIN(&acf_root, cur, acflist) {
1362 if (strcasecmp(acf->name, cur->name) < 0) {
1363 AST_LIST_INSERT_BEFORE_CURRENT(&acf_root, acf, acflist);
1364 break;
1367 AST_LIST_TRAVERSE_SAFE_END
1368 if (!cur)
1369 AST_LIST_INSERT_TAIL(&acf_root, acf, acflist);
1371 AST_LIST_UNLOCK(&acf_root);
1373 if (option_verbose > 1)
1374 ast_verbose(VERBOSE_PREFIX_2 "Registered custom function %s\n", acf->name);
1376 return 0;
1379 /*! \brief return a pointer to the arguments of the function,
1380 * and terminates the function name with '\\0'
1382 static char *func_args(char *function)
1384 char *args = strchr(function, '(');
1386 if (!args)
1387 ast_log(LOG_WARNING, "Function doesn't contain parentheses. Assuming null argument.\n");
1388 else {
1389 char *p;
1390 *args++ = '\0';
1391 if ((p = strrchr(args, ')')) )
1392 *p = '\0';
1393 else
1394 ast_log(LOG_WARNING, "Can't find trailing parenthesis?\n");
1396 return args;
1399 int ast_func_read(struct ast_channel *chan, char *function, char *workspace, size_t len)
1401 char *args = func_args(function);
1402 struct ast_custom_function *acfptr = ast_custom_function_find(function);
1404 if (acfptr == NULL)
1405 ast_log(LOG_ERROR, "Function %s not registered\n", function);
1406 else if (!acfptr->read)
1407 ast_log(LOG_ERROR, "Function %s cannot be read\n", function);
1408 else
1409 return acfptr->read(chan, function, args, workspace, len);
1410 return -1;
1413 int ast_func_write(struct ast_channel *chan, char *function, const char *value)
1415 char *args = func_args(function);
1416 struct ast_custom_function *acfptr = ast_custom_function_find(function);
1418 if (acfptr == NULL)
1419 ast_log(LOG_ERROR, "Function %s not registered\n", function);
1420 else if (!acfptr->write)
1421 ast_log(LOG_ERROR, "Function %s cannot be written to\n", function);
1422 else
1423 return acfptr->write(chan, function, args, value);
1425 return -1;
1428 static void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int count)
1430 /* Substitutes variables into cp2, based on string cp1, and assuming cp2 to be
1431 zero-filled */
1432 char *cp4;
1433 const char *tmp, *whereweare;
1434 int length, offset, offset2, isfunction;
1435 char *workspace = NULL;
1436 char *ltmp = NULL, *var = NULL;
1437 char *nextvar, *nextexp, *nextthing;
1438 char *vars, *vare;
1439 int pos, brackets, needsub, len;
1441 whereweare=tmp=cp1;
1442 while (!ast_strlen_zero(whereweare) && count) {
1443 /* Assume we're copying the whole remaining string */
1444 pos = strlen(whereweare);
1445 nextvar = NULL;
1446 nextexp = NULL;
1447 nextthing = strchr(whereweare, '$');
1448 if (nextthing) {
1449 switch(nextthing[1]) {
1450 case '{':
1451 nextvar = nextthing;
1452 pos = nextvar - whereweare;
1453 break;
1454 case '[':
1455 nextexp = nextthing;
1456 pos = nextexp - whereweare;
1457 break;
1461 if (pos) {
1462 /* Can't copy more than 'count' bytes */
1463 if (pos > count)
1464 pos = count;
1466 /* Copy that many bytes */
1467 memcpy(cp2, whereweare, pos);
1469 count -= pos;
1470 cp2 += pos;
1471 whereweare += pos;
1474 if (nextvar) {
1475 /* We have a variable. Find the start and end, and determine
1476 if we are going to have to recursively call ourselves on the
1477 contents */
1478 vars = vare = nextvar + 2;
1479 brackets = 1;
1480 needsub = 0;
1482 /* Find the end of it */
1483 while (brackets && *vare) {
1484 if ((vare[0] == '$') && (vare[1] == '{')) {
1485 needsub++;
1486 } else if (vare[0] == '{') {
1487 brackets++;
1488 } else if (vare[0] == '}') {
1489 brackets--;
1490 } else if ((vare[0] == '$') && (vare[1] == '['))
1491 needsub++;
1492 vare++;
1494 if (brackets)
1495 ast_log(LOG_NOTICE, "Error in extension logic (missing '}')\n");
1496 len = vare - vars - 1;
1498 /* Skip totally over variable string */
1499 whereweare += (len + 3);
1501 if (!var)
1502 var = alloca(VAR_BUF_SIZE);
1504 /* Store variable name (and truncate) */
1505 ast_copy_string(var, vars, len + 1);
1507 /* Substitute if necessary */
1508 if (needsub) {
1509 if (!ltmp)
1510 ltmp = alloca(VAR_BUF_SIZE);
1512 memset(ltmp, 0, VAR_BUF_SIZE);
1513 pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1);
1514 vars = ltmp;
1515 } else {
1516 vars = var;
1519 if (!workspace)
1520 workspace = alloca(VAR_BUF_SIZE);
1522 workspace[0] = '\0';
1524 parse_variable_name(vars, &offset, &offset2, &isfunction);
1525 if (isfunction) {
1526 /* Evaluate function */
1527 cp4 = ast_func_read(c, vars, workspace, VAR_BUF_SIZE) ? NULL : workspace;
1529 ast_log(LOG_DEBUG, "Function result is '%s'\n", cp4 ? cp4 : "(null)");
1530 } else {
1531 /* Retrieve variable value */
1532 pbx_retrieve_variable(c, vars, &cp4, workspace, VAR_BUF_SIZE, headp);
1534 if (cp4) {
1535 cp4 = substring(cp4, offset, offset2, workspace, VAR_BUF_SIZE);
1537 length = strlen(cp4);
1538 if (length > count)
1539 length = count;
1540 memcpy(cp2, cp4, length);
1541 count -= length;
1542 cp2 += length;
1544 } else if (nextexp) {
1545 /* We have an expression. Find the start and end, and determine
1546 if we are going to have to recursively call ourselves on the
1547 contents */
1548 vars = vare = nextexp + 2;
1549 brackets = 1;
1550 needsub = 0;
1552 /* Find the end of it */
1553 while(brackets && *vare) {
1554 if ((vare[0] == '$') && (vare[1] == '[')) {
1555 needsub++;
1556 brackets++;
1557 vare++;
1558 } else if (vare[0] == '[') {
1559 brackets++;
1560 } else if (vare[0] == ']') {
1561 brackets--;
1562 } else if ((vare[0] == '$') && (vare[1] == '{')) {
1563 needsub++;
1564 vare++;
1566 vare++;
1568 if (brackets)
1569 ast_log(LOG_NOTICE, "Error in extension logic (missing ']')\n");
1570 len = vare - vars - 1;
1572 /* Skip totally over expression */
1573 whereweare += (len + 3);
1575 if (!var)
1576 var = alloca(VAR_BUF_SIZE);
1578 /* Store variable name (and truncate) */
1579 ast_copy_string(var, vars, len + 1);
1581 /* Substitute if necessary */
1582 if (needsub) {
1583 if (!ltmp)
1584 ltmp = alloca(VAR_BUF_SIZE);
1586 memset(ltmp, 0, VAR_BUF_SIZE);
1587 pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1);
1588 vars = ltmp;
1589 } else {
1590 vars = var;
1593 length = ast_expr(vars, cp2, count);
1595 if (length) {
1596 ast_log(LOG_DEBUG, "Expression result is '%s'\n", cp2);
1597 count -= length;
1598 cp2 += length;
1600 } else
1601 break;
1605 void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
1607 pbx_substitute_variables_helper_full(c, (c) ? &c->varshead : NULL, cp1, cp2, count);
1610 void pbx_substitute_variables_varshead(struct varshead *headp, const char *cp1, char *cp2, int count)
1612 pbx_substitute_variables_helper_full(NULL, headp, cp1, cp2, count);
1615 static void pbx_substitute_variables(char *passdata, int datalen, struct ast_channel *c, struct ast_exten *e)
1617 memset(passdata, 0, datalen);
1619 /* No variables or expressions in e->data, so why scan it? */
1620 if (!strchr(e->data, '$') && !strstr(e->data,"${") && !strstr(e->data,"$[") && !strstr(e->data,"$(")) {
1621 ast_copy_string(passdata, e->data, datalen);
1622 return;
1625 pbx_substitute_variables_helper(c, e->data, passdata, datalen - 1);
1628 /*! \brief The return value depends on the action:
1630 * E_MATCH, E_CANMATCH, E_MATCHMORE require a real match,
1631 * and return 0 on failure, -1 on match;
1632 * E_FINDLABEL maps the label to a priority, and returns
1633 * the priority on success, ... XXX
1634 * E_SPAWN, spawn an application,
1635 * and return 0 on success, -1 on failure.
1637 static int pbx_extension_helper(struct ast_channel *c, struct ast_context *con,
1638 const char *context, const char *exten, int priority,
1639 const char *label, const char *callerid, enum ext_match_t action)
1641 struct ast_exten *e;
1642 struct ast_app *app;
1643 int res;
1644 struct pbx_find_info q = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */
1645 char passdata[EXT_DATA_SIZE];
1647 int matching_action = (action == E_MATCH || action == E_CANMATCH || action == E_MATCHMORE);
1649 ast_mutex_lock(&conlock);
1650 e = pbx_find_extension(c, con, &q, context, exten, priority, label, callerid, action);
1651 if (e) {
1652 if (matching_action) {
1653 ast_mutex_unlock(&conlock);
1654 return -1; /* success, we found it */
1655 } else if (action == E_FINDLABEL) { /* map the label to a priority */
1656 res = e->priority;
1657 ast_mutex_unlock(&conlock);
1658 return res; /* the priority we were looking for */
1659 } else { /* spawn */
1660 app = pbx_findapp(e->app);
1661 ast_mutex_unlock(&conlock);
1662 if (!app) {
1663 ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
1664 return -1;
1666 if (c->context != context)
1667 ast_copy_string(c->context, context, sizeof(c->context));
1668 if (c->exten != exten)
1669 ast_copy_string(c->exten, exten, sizeof(c->exten));
1670 c->priority = priority;
1671 pbx_substitute_variables(passdata, sizeof(passdata), c, e);
1672 if (option_debug) {
1673 char atmp[80];
1674 char atmp2[EXT_DATA_SIZE+100];
1675 ast_log(LOG_DEBUG, "Launching '%s'\n", app->name);
1676 snprintf(atmp, sizeof(atmp), "STACK-%s-%s-%d", context, exten, priority);
1677 snprintf(atmp2, sizeof(atmp2), "%s(\"%s\", \"%s\") %s",
1678 app->name, c->name, passdata, "in new stack");
1679 pbx_builtin_setvar_helper(c, atmp, atmp2);
1681 if (option_verbose > 2) {
1682 char tmp[80], tmp2[80], tmp3[EXT_DATA_SIZE];
1683 ast_verbose( VERBOSE_PREFIX_3 "Executing [%s@%s:%d] %s(\"%s\", \"%s\") %s\n",
1684 exten, context, priority,
1685 term_color(tmp, app->name, COLOR_BRCYAN, 0, sizeof(tmp)),
1686 term_color(tmp2, c->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
1687 term_color(tmp3, passdata, COLOR_BRMAGENTA, 0, sizeof(tmp3)),
1688 "in new stack");
1690 manager_event(EVENT_FLAG_CALL, "Newexten",
1691 "Channel: %s\r\n"
1692 "Context: %s\r\n"
1693 "Extension: %s\r\n"
1694 "Priority: %d\r\n"
1695 "Application: %s\r\n"
1696 "AppData: %s\r\n"
1697 "Uniqueid: %s\r\n",
1698 c->name, c->context, c->exten, c->priority, app->name, passdata, c->uniqueid);
1699 return pbx_exec(c, app, passdata); /* 0 on success, -1 on failure */
1701 } else if (q.swo) { /* not found here, but in another switch */
1702 ast_mutex_unlock(&conlock);
1703 if (matching_action)
1704 return -1;
1705 else {
1706 if (!q.swo->exec) {
1707 ast_log(LOG_WARNING, "No execution engine for switch %s\n", q.swo->name);
1708 res = -1;
1710 return q.swo->exec(c, q.foundcontext ? q.foundcontext : context, exten, priority, callerid, q.data);
1712 } else { /* not found anywhere, see what happened */
1713 ast_mutex_unlock(&conlock);
1714 switch (q.status) {
1715 case STATUS_NO_CONTEXT:
1716 if (!matching_action)
1717 ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", context);
1718 break;
1719 case STATUS_NO_EXTENSION:
1720 if (!matching_action)
1721 ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, context);
1722 break;
1723 case STATUS_NO_PRIORITY:
1724 if (!matching_action)
1725 ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, context);
1726 break;
1727 case STATUS_NO_LABEL:
1728 if (context)
1729 ast_log(LOG_NOTICE, "No such label '%s' in extension '%s' in context '%s'\n", label, exten, context);
1730 break;
1731 default:
1732 ast_log(LOG_DEBUG, "Shouldn't happen!\n");
1735 return (matching_action) ? 0 : -1;
1739 /*! \brief ast_hint_extension: Find hint for given extension in context */
1740 static struct ast_exten *ast_hint_extension(struct ast_channel *c, const char *context, const char *exten)
1742 struct ast_exten *e;
1743 struct pbx_find_info q = { .stacklen = 0 }; /* the rest is set in pbx_find_context */
1745 ast_mutex_lock(&conlock);
1746 e = pbx_find_extension(c, NULL, &q, context, exten, PRIORITY_HINT, NULL, "", E_MATCH);
1747 ast_mutex_unlock(&conlock);
1749 return e;
1752 /*! \brief ast_extensions_state2: Check state of extension by using hints */
1753 static int ast_extension_state2(struct ast_exten *e)
1755 char hint[AST_MAX_EXTENSION];
1756 char *cur, *rest;
1757 int allunavailable = 1, allbusy = 1, allfree = 1, allonhold = 1;
1758 int busy = 0, inuse = 0, ring = 0;
1760 if (!e)
1761 return -1;
1763 ast_copy_string(hint, ast_get_extension_app(e), sizeof(hint));
1765 rest = hint; /* One or more devices separated with a & character */
1766 while ( (cur = strsep(&rest, "&")) ) {
1767 int res = ast_device_state(cur);
1768 switch (res) {
1769 case AST_DEVICE_NOT_INUSE:
1770 allunavailable = 0;
1771 allbusy = 0;
1772 allonhold = 0;
1773 break;
1774 case AST_DEVICE_INUSE:
1775 inuse = 1;
1776 allunavailable = 0;
1777 allfree = 0;
1778 allonhold = 0;
1779 break;
1780 case AST_DEVICE_RINGING:
1781 ring = 1;
1782 allunavailable = 0;
1783 allfree = 0;
1784 allonhold = 0;
1785 break;
1786 case AST_DEVICE_RINGINUSE:
1787 inuse = 1;
1788 ring = 1;
1789 allunavailable = 0;
1790 allfree = 0;
1791 allonhold = 0;
1792 break;
1793 case AST_DEVICE_ONHOLD:
1794 allunavailable = 0;
1795 allfree = 0;
1796 break;
1797 case AST_DEVICE_BUSY:
1798 allunavailable = 0;
1799 allfree = 0;
1800 allonhold = 0;
1801 busy = 1;
1802 break;
1803 case AST_DEVICE_UNAVAILABLE:
1804 case AST_DEVICE_INVALID:
1805 allbusy = 0;
1806 allfree = 0;
1807 allonhold = 0;
1808 break;
1809 default:
1810 allunavailable = 0;
1811 allbusy = 0;
1812 allfree = 0;
1813 allonhold = 0;
1817 if (!inuse && ring)
1818 return AST_EXTENSION_RINGING;
1819 if (inuse && ring)
1820 return (AST_EXTENSION_INUSE | AST_EXTENSION_RINGING);
1821 if (inuse)
1822 return AST_EXTENSION_INUSE;
1823 if (allfree)
1824 return AST_EXTENSION_NOT_INUSE;
1825 if (allonhold)
1826 return AST_EXTENSION_ONHOLD;
1827 if (allbusy)
1828 return AST_EXTENSION_BUSY;
1829 if (allunavailable)
1830 return AST_EXTENSION_UNAVAILABLE;
1831 if (busy)
1832 return AST_EXTENSION_INUSE;
1834 return AST_EXTENSION_NOT_INUSE;
1837 /*! \brief ast_extension_state2str: Return extension_state as string */
1838 const char *ast_extension_state2str(int extension_state)
1840 int i;
1842 for (i = 0; (i < (sizeof(extension_states) / sizeof(extension_states[0]))); i++) {
1843 if (extension_states[i].extension_state == extension_state)
1844 return extension_states[i].text;
1846 return "Unknown";
1849 /*! \brief ast_extension_state: Check extension state for an extension by using hint */
1850 int ast_extension_state(struct ast_channel *c, const char *context, const char *exten)
1852 struct ast_exten *e;
1854 e = ast_hint_extension(c, context, exten); /* Do we have a hint for this extension ? */
1855 if (!e)
1856 return -1; /* No hint, return -1 */
1858 return ast_extension_state2(e); /* Check all devices in the hint */
1861 void ast_hint_state_changed(const char *device)
1863 struct ast_hint *hint;
1865 AST_LIST_LOCK(&hints);
1867 AST_LIST_TRAVERSE(&hints, hint, list) {
1868 struct ast_state_cb *cblist;
1869 char buf[AST_MAX_EXTENSION];
1870 char *parse = buf;
1871 char *cur;
1872 int state;
1874 ast_copy_string(buf, ast_get_extension_app(hint->exten), sizeof(buf));
1875 while ( (cur = strsep(&parse, "&")) ) {
1876 if (!strcasecmp(cur, device))
1877 break;
1879 if (!cur)
1880 continue;
1882 /* Get device state for this hint */
1883 state = ast_extension_state2(hint->exten);
1885 if ((state == -1) || (state == hint->laststate))
1886 continue;
1888 /* Device state changed since last check - notify the watchers */
1890 /* For general callbacks */
1891 for (cblist = statecbs; cblist; cblist = cblist->next)
1892 cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data);
1894 /* For extension callbacks */
1895 for (cblist = hint->callbacks; cblist; cblist = cblist->next)
1896 cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data);
1898 hint->laststate = state; /* record we saw the change */
1901 AST_LIST_UNLOCK(&hints);
1904 /*! \brief ast_extension_state_add: Add watcher for extension states */
1905 int ast_extension_state_add(const char *context, const char *exten,
1906 ast_state_cb_type callback, void *data)
1908 struct ast_hint *hint;
1909 struct ast_state_cb *cblist;
1910 struct ast_exten *e;
1912 /* If there's no context and extension: add callback to statecbs list */
1913 if (!context && !exten) {
1914 AST_LIST_LOCK(&hints);
1916 for (cblist = statecbs; cblist; cblist = cblist->next) {
1917 if (cblist->callback == callback) {
1918 cblist->data = data;
1919 AST_LIST_UNLOCK(&hints);
1920 return 0;
1924 /* Now insert the callback */
1925 if (!(cblist = ast_calloc(1, sizeof(*cblist)))) {
1926 AST_LIST_UNLOCK(&hints);
1927 return -1;
1929 cblist->id = 0;
1930 cblist->callback = callback;
1931 cblist->data = data;
1933 cblist->next = statecbs;
1934 statecbs = cblist;
1936 AST_LIST_UNLOCK(&hints);
1937 return 0;
1940 if (!context || !exten)
1941 return -1;
1943 /* This callback type is for only one hint, so get the hint */
1944 e = ast_hint_extension(NULL, context, exten);
1945 if (!e) {
1946 return -1;
1949 /* Find the hint in the list of hints */
1950 AST_LIST_LOCK(&hints);
1952 AST_LIST_TRAVERSE(&hints, hint, list) {
1953 if (hint->exten == e)
1954 break;
1957 if (!hint) {
1958 /* We have no hint, sorry */
1959 AST_LIST_UNLOCK(&hints);
1960 return -1;
1963 /* Now insert the callback in the callback list */
1964 if (!(cblist = ast_calloc(1, sizeof(*cblist)))) {
1965 AST_LIST_UNLOCK(&hints);
1966 return -1;
1968 cblist->id = stateid++; /* Unique ID for this callback */
1969 cblist->callback = callback; /* Pointer to callback routine */
1970 cblist->data = data; /* Data for the callback */
1972 cblist->next = hint->callbacks;
1973 hint->callbacks = cblist;
1975 AST_LIST_UNLOCK(&hints);
1976 return cblist->id;
1979 /*! \brief ast_extension_state_del: Remove a watcher from the callback list */
1980 int ast_extension_state_del(int id, ast_state_cb_type callback)
1982 struct ast_state_cb **p_cur = NULL; /* address of pointer to us */
1983 int ret = -1;
1985 if (!id && !callback)
1986 return -1;
1988 AST_LIST_LOCK(&hints);
1990 if (!id) { /* id == 0 is a callback without extension */
1991 for (p_cur = &statecbs; *p_cur; p_cur = &(*p_cur)->next) {
1992 if ((*p_cur)->callback == callback)
1993 break;
1995 } else { /* callback with extension, find the callback based on ID */
1996 struct ast_hint *hint;
1997 AST_LIST_TRAVERSE(&hints, hint, list) {
1998 for (p_cur = &hint->callbacks; *p_cur; p_cur = &(*p_cur)->next) {
1999 if ((*p_cur)->id == id)
2000 break;
2002 if (*p_cur) /* found in the inner loop */
2003 break;
2006 if (p_cur && *p_cur) {
2007 struct ast_state_cb *cur = *p_cur;
2008 *p_cur = cur->next;
2009 free(cur);
2010 ret = 0;
2012 AST_LIST_UNLOCK(&hints);
2013 return ret;
2016 /*! \brief ast_add_hint: Add hint to hint list, check initial extension state */
2017 static int ast_add_hint(struct ast_exten *e)
2019 struct ast_hint *hint;
2021 if (!e)
2022 return -1;
2024 AST_LIST_LOCK(&hints);
2026 /* Search if hint exists, do nothing */
2027 AST_LIST_TRAVERSE(&hints, hint, list) {
2028 if (hint->exten == e) {
2029 AST_LIST_UNLOCK(&hints);
2030 if (option_debug > 1)
2031 ast_log(LOG_DEBUG, "HINTS: Not re-adding existing hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
2032 return -1;
2036 if (option_debug > 1)
2037 ast_log(LOG_DEBUG, "HINTS: Adding hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
2039 if (!(hint = ast_calloc(1, sizeof(*hint)))) {
2040 AST_LIST_UNLOCK(&hints);
2041 return -1;
2043 /* Initialize and insert new item at the top */
2044 hint->exten = e;
2045 hint->laststate = ast_extension_state2(e);
2046 AST_LIST_INSERT_HEAD(&hints, hint, list);
2048 AST_LIST_UNLOCK(&hints);
2049 return 0;
2052 /*! \brief ast_change_hint: Change hint for an extension */
2053 static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
2055 struct ast_hint *hint;
2056 int res = -1;
2058 AST_LIST_LOCK(&hints);
2059 AST_LIST_TRAVERSE(&hints, hint, list) {
2060 if (hint->exten == oe) {
2061 hint->exten = ne;
2062 res = 0;
2063 break;
2066 AST_LIST_UNLOCK(&hints);
2068 return res;
2071 /*! \brief ast_remove_hint: Remove hint from extension */
2072 static int ast_remove_hint(struct ast_exten *e)
2074 /* Cleanup the Notifys if hint is removed */
2075 struct ast_hint *hint;
2076 struct ast_state_cb *cblist, *cbprev;
2077 int res = -1;
2079 if (!e)
2080 return -1;
2082 AST_LIST_LOCK(&hints);
2083 AST_LIST_TRAVERSE_SAFE_BEGIN(&hints, hint, list) {
2084 if (hint->exten == e) {
2085 cbprev = NULL;
2086 cblist = hint->callbacks;
2087 while (cblist) {
2088 /* Notify with -1 and remove all callbacks */
2089 cbprev = cblist;
2090 cblist = cblist->next;
2091 cbprev->callback(hint->exten->parent->name, hint->exten->exten, AST_EXTENSION_DEACTIVATED, cbprev->data);
2092 free(cbprev);
2094 hint->callbacks = NULL;
2095 AST_LIST_REMOVE_CURRENT(&hints, list);
2096 free(hint);
2097 res = 0;
2098 break;
2101 AST_LIST_TRAVERSE_SAFE_END
2102 AST_LIST_UNLOCK(&hints);
2104 return res;
2108 /*! \brief ast_get_hint: Get hint for channel */
2109 int ast_get_hint(char *hint, int hintsize, char *name, int namesize, struct ast_channel *c, const char *context, const char *exten)
2111 struct ast_exten *e = ast_hint_extension(c, context, exten);
2113 if (e) {
2114 if (hint)
2115 ast_copy_string(hint, ast_get_extension_app(e), hintsize);
2116 if (name) {
2117 const char *tmp = ast_get_extension_app_data(e);
2118 if (tmp)
2119 ast_copy_string(name, tmp, namesize);
2121 return -1;
2123 return 0;
2126 int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
2128 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_MATCH);
2131 int ast_findlabel_extension(struct ast_channel *c, const char *context, const char *exten, const char *label, const char *callerid)
2133 return pbx_extension_helper(c, NULL, context, exten, 0, label, callerid, E_FINDLABEL);
2136 int ast_findlabel_extension2(struct ast_channel *c, struct ast_context *con, const char *exten, const char *label, const char *callerid)
2138 return pbx_extension_helper(c, con, NULL, exten, 0, label, callerid, E_FINDLABEL);
2141 int ast_canmatch_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
2143 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_CANMATCH);
2146 int ast_matchmore_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
2148 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_MATCHMORE);
2151 int ast_spawn_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
2153 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_SPAWN);
2156 /* helper function to set extension and priority */
2157 static void set_ext_pri(struct ast_channel *c, const char *exten, int pri)
2159 ast_copy_string(c->exten, exten, sizeof(c->exten));
2160 c->priority = pri;
2164 * \brief collect digits from the channel into the buffer,
2165 * return -1 on error, 0 on timeout or done.
2167 static int collect_digits(struct ast_channel *c, int waittime, char *buf, int buflen, int pos)
2169 int digit;
2171 buf[pos] = '\0'; /* make sure it is properly terminated */
2172 while (ast_matchmore_extension(c, c->context, buf, 1, c->cid.cid_num)) {
2173 /* As long as we're willing to wait, and as long as it's not defined,
2174 keep reading digits until we can't possibly get a right answer anymore. */
2175 digit = ast_waitfordigit(c, waittime * 1000);
2176 if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
2177 c->_softhangup = 0;
2178 } else {
2179 if (!digit) /* No entry */
2180 break;
2181 if (digit < 0) /* Error, maybe a hangup */
2182 return -1;
2183 if (pos < buflen - 1) { /* XXX maybe error otherwise ? */
2184 buf[pos++] = digit;
2185 buf[pos] = '\0';
2187 waittime = c->pbx->dtimeout;
2190 return 0;
2193 static int __ast_pbx_run(struct ast_channel *c)
2195 int found = 0; /* set if we find at least one match */
2196 int res = 0;
2197 int autoloopflag;
2198 int error = 0; /* set an error conditions */
2200 /* A little initial setup here */
2201 if (c->pbx) {
2202 ast_log(LOG_WARNING, "%s already has PBX structure??\n", c->name);
2203 /* XXX and now what ? */
2204 free(c->pbx);
2206 if (!(c->pbx = ast_calloc(1, sizeof(*c->pbx))))
2207 return -1;
2208 if (c->amaflags) {
2209 if (!c->cdr) {
2210 c->cdr = ast_cdr_alloc();
2211 if (!c->cdr) {
2212 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
2213 free(c->pbx);
2214 return -1;
2216 ast_cdr_init(c->cdr, c);
2219 /* Set reasonable defaults */
2220 c->pbx->rtimeout = 10;
2221 c->pbx->dtimeout = 5;
2223 autoloopflag = ast_test_flag(c, AST_FLAG_IN_AUTOLOOP); /* save value to restore at the end */
2224 ast_set_flag(c, AST_FLAG_IN_AUTOLOOP);
2226 /* Start by trying whatever the channel is set to */
2227 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2228 /* If not successful fall back to 's' */
2229 if (option_verbose > 1)
2230 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);
2231 /* XXX the original code used the existing priority in the call to
2232 * ast_exists_extension(), and reset it to 1 afterwards.
2233 * I believe the correct thing is to set it to 1 immediately.
2235 set_ext_pri(c, "s", 1);
2236 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2237 /* JK02: And finally back to default if everything else failed */
2238 if (option_verbose > 1)
2239 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);
2240 ast_copy_string(c->context, "default", sizeof(c->context));
2243 if (c->cdr && ast_tvzero(c->cdr->start))
2244 ast_cdr_start(c->cdr);
2245 for (;;) {
2246 char dst_exten[256]; /* buffer to accumulate digits */
2247 int pos = 0; /* XXX should check bounds */
2248 int digit = 0;
2250 /* loop on priorities in this context/exten */
2251 while (ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2252 found = 1;
2253 if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
2254 /* Something bad happened, or a hangup has been requested. */
2255 if (strchr("0123456789ABCDEF*#", res)) {
2256 ast_log(LOG_DEBUG, "Oooh, got something to jump out with ('%c')!\n", res);
2257 pos = 0;
2258 dst_exten[pos++] = digit = res;
2259 dst_exten[pos] = '\0';
2260 break;
2262 if (res == AST_PBX_KEEPALIVE) {
2263 if (option_debug)
2264 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
2265 else if (option_verbose > 1)
2266 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
2267 error = 1;
2268 break;
2270 if (option_debug)
2271 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2272 else if (option_verbose > 1)
2273 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2274 if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
2275 c->_softhangup =0;
2276 } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
2277 /* atimeout, nothing bad */
2278 } else {
2279 if (c->cdr)
2280 ast_cdr_update(c);
2281 error = 1;
2282 break;
2285 if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT && ast_exists_extension(c,c->context,"T",1,c->cid.cid_num)) {
2286 set_ext_pri(c, "T", 0); /* 0 will become 1 with the c->priority++; at the end */
2287 /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
2288 c->whentohangup = 0;
2289 c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
2290 } else if (c->_softhangup) {
2291 ast_log(LOG_DEBUG, "Extension %s, priority %d returned normally even though call was hung up\n",
2292 c->exten, c->priority);
2293 error = 1;
2294 break;
2296 c->priority++;
2297 } /* end while - from here on we can use 'break' to go out */
2298 if (error)
2299 break;
2301 /* XXX we get here on non-existing extension or a keypress or hangup ? */
2303 if (!ast_exists_extension(c, c->context, c->exten, 1, c->cid.cid_num)) {
2304 /* If there is no match at priority 1, it is not a valid extension anymore.
2305 * Try to continue at "i", 1 or exit if the latter does not exist.
2307 if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
2308 if (option_verbose > 2)
2309 ast_verbose(VERBOSE_PREFIX_3 "Sent into invalid extension '%s' in context '%s' on %s\n", c->exten, c->context, c->name);
2310 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", c->exten);
2311 set_ext_pri(c, "i", 1);
2312 } else {
2313 ast_log(LOG_WARNING, "Channel '%s' sent into invalid extension '%s' in context '%s', but no invalid handler\n",
2314 c->name, c->exten, c->context);
2315 error = 1; /* we know what to do with it */
2316 break;
2318 } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
2319 /* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */
2320 c->_softhangup = 0;
2321 } else { /* keypress received, get more digits for a full extension */
2322 int waittime = 0;
2323 if (digit)
2324 waittime = c->pbx->dtimeout;
2325 else if (!autofallthrough)
2326 waittime = c->pbx->rtimeout;
2327 if (!waittime) {
2328 const char *status = pbx_builtin_getvar_helper(c, "DIALSTATUS");
2329 if (!status)
2330 status = "UNKNOWN";
2331 if (option_verbose > 2)
2332 ast_verbose(VERBOSE_PREFIX_2 "Auto fallthrough, channel '%s' status is '%s'\n", c->name, status);
2333 if (!strcasecmp(status, "CONGESTION"))
2334 res = pbx_builtin_congestion(c, "10");
2335 else if (!strcasecmp(status, "CHANUNAVAIL"))
2336 res = pbx_builtin_congestion(c, "10");
2337 else if (!strcasecmp(status, "BUSY"))
2338 res = pbx_builtin_busy(c, "10");
2339 error = 1; /* XXX disable message */
2340 break; /* exit from the 'for' loop */
2343 if (collect_digits(c, waittime, dst_exten, sizeof(dst_exten), pos))
2344 break;
2345 if (ast_exists_extension(c, c->context, dst_exten, 1, c->cid.cid_num)) /* Prepare the next cycle */
2346 set_ext_pri(c, dst_exten, 1);
2347 else {
2348 /* No such extension */
2349 if (!ast_strlen_zero(dst_exten)) {
2350 /* An invalid extension */
2351 if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
2352 if (option_verbose > 2)
2353 ast_verbose( VERBOSE_PREFIX_3 "Invalid extension '%s' in context '%s' on %s\n", dst_exten, c->context, c->name);
2354 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", dst_exten);
2355 set_ext_pri(c, "i", 1);
2356 } else {
2357 ast_log(LOG_WARNING, "Invalid extension '%s', but no rule 'i' in context '%s'\n", dst_exten, c->context);
2358 found = 1; /* XXX disable message */
2359 break;
2361 } else {
2362 /* A simple timeout */
2363 if (ast_exists_extension(c, c->context, "t", 1, c->cid.cid_num)) {
2364 if (option_verbose > 2)
2365 ast_verbose( VERBOSE_PREFIX_3 "Timeout on %s\n", c->name);
2366 set_ext_pri(c, "t", 1);
2367 } else {
2368 ast_log(LOG_WARNING, "Timeout, but no rule 't' in context '%s'\n", c->context);
2369 found = 1; /* XXX disable message */
2370 break;
2374 if (c->cdr) {
2375 if (option_verbose > 2)
2376 ast_verbose(VERBOSE_PREFIX_2 "CDR updated on %s\n",c->name);
2377 ast_cdr_update(c);
2381 if (!found && !error)
2382 ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", c->name);
2383 if ((res != AST_PBX_KEEPALIVE) && ast_exists_extension(c, c->context, "h", 1, c->cid.cid_num)) {
2384 if (c->cdr && ast_opt_end_cdr_before_h_exten)
2385 ast_cdr_end(c->cdr);
2386 set_ext_pri(c, "h", 1);
2387 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2388 if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
2389 /* Something bad happened, or a hangup has been requested. */
2390 if (option_debug)
2391 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2392 else if (option_verbose > 1)
2393 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2394 break;
2396 c->priority++;
2399 ast_set2_flag(c, autoloopflag, AST_FLAG_IN_AUTOLOOP);
2401 pbx_destroy(c->pbx);
2402 c->pbx = NULL;
2403 if (res != AST_PBX_KEEPALIVE)
2404 ast_hangup(c);
2405 return 0;
2408 /* Returns 0 on success, non-zero if call limit was reached */
2409 static int increase_call_count(const struct ast_channel *c)
2411 int failed = 0;
2412 double curloadavg;
2413 ast_mutex_lock(&maxcalllock);
2414 if (option_maxcalls) {
2415 if (countcalls >= option_maxcalls) {
2416 ast_log(LOG_NOTICE, "Maximum call limit of %d calls exceeded by '%s'!\n", option_maxcalls, c->name);
2417 failed = -1;
2420 if (option_maxload) {
2421 getloadavg(&curloadavg, 1);
2422 if (curloadavg >= option_maxload) {
2423 ast_log(LOG_NOTICE, "Maximum loadavg limit of %f load exceeded by '%s' (currently %f)!\n", option_maxload, c->name, curloadavg);
2424 failed = -1;
2427 if (!failed)
2428 countcalls++;
2429 ast_mutex_unlock(&maxcalllock);
2431 return failed;
2434 static void decrease_call_count(void)
2436 ast_mutex_lock(&maxcalllock);
2437 if (countcalls > 0)
2438 countcalls--;
2439 ast_mutex_unlock(&maxcalllock);
2442 static void destroy_exten(struct ast_exten *e)
2444 if (e->priority == PRIORITY_HINT)
2445 ast_remove_hint(e);
2447 if (e->datad)
2448 e->datad(e->data);
2449 free(e);
2452 static void *pbx_thread(void *data)
2454 /* Oh joyeous kernel, we're a new thread, with nothing to do but
2455 answer this channel and get it going.
2457 /* NOTE:
2458 The launcher of this function _MUST_ increment 'countcalls'
2459 before invoking the function; it will be decremented when the
2460 PBX has finished running on the channel
2462 struct ast_channel *c = data;
2464 __ast_pbx_run(c);
2465 decrease_call_count();
2467 pthread_exit(NULL);
2469 return NULL;
2472 enum ast_pbx_result ast_pbx_start(struct ast_channel *c)
2474 pthread_t t;
2475 pthread_attr_t attr;
2477 if (!c) {
2478 ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
2479 return AST_PBX_FAILED;
2482 if (increase_call_count(c))
2483 return AST_PBX_CALL_LIMIT;
2485 /* Start a new thread, and get something handling this channel. */
2486 pthread_attr_init(&attr);
2487 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
2488 if (ast_pthread_create(&t, &attr, pbx_thread, c)) {
2489 ast_log(LOG_WARNING, "Failed to create new channel thread\n");
2490 return AST_PBX_FAILED;
2493 return AST_PBX_SUCCESS;
2496 enum ast_pbx_result ast_pbx_run(struct ast_channel *c)
2498 enum ast_pbx_result res = AST_PBX_SUCCESS;
2500 if (increase_call_count(c))
2501 return AST_PBX_CALL_LIMIT;
2503 res = __ast_pbx_run(c);
2504 decrease_call_count();
2506 return res;
2509 int ast_active_calls(void)
2511 return countcalls;
2514 int pbx_set_autofallthrough(int newval)
2516 int oldval = autofallthrough;
2517 autofallthrough = newval;
2518 return oldval;
2521 /* lookup for a context with a given name,
2522 * return with conlock held if found, NULL if not found
2524 static struct ast_context *find_context_locked(const char *context)
2526 struct ast_context *c = NULL;
2528 ast_lock_contexts();
2529 while ( (c = ast_walk_contexts(c)) ) {
2530 if (!strcmp(ast_get_context_name(c), context))
2531 return c;
2533 ast_unlock_contexts();
2535 return NULL;
2539 * This function locks contexts list by &conlist, search for the right context
2540 * structure, leave context list locked and call ast_context_remove_include2
2541 * which removes include, unlock contexts list and return ...
2543 int ast_context_remove_include(const char *context, const char *include, const char *registrar)
2545 int ret = -1;
2546 struct ast_context *c = find_context_locked(context);
2548 if (c) {
2549 /* found, remove include from this context ... */
2550 ret = ast_context_remove_include2(c, include, registrar);
2551 ast_unlock_contexts();
2553 return ret;
2557 * When we call this function, &conlock lock must be locked, because when
2558 * we giving *con argument, some process can remove/change this context
2559 * and after that there can be segfault.
2561 * This function locks given context, removes include, unlock context and
2562 * return.
2564 int ast_context_remove_include2(struct ast_context *con, const char *include, const char *registrar)
2566 struct ast_include *i, *pi = NULL;
2567 int ret = -1;
2569 ast_mutex_lock(&con->lock);
2571 /* find our include */
2572 for (i = con->includes; i; pi = i, i = i->next) {
2573 if (!strcmp(i->name, include) &&
2574 (!registrar || !strcmp(i->registrar, registrar))) {
2575 /* remove from list */
2576 if (pi)
2577 pi->next = i->next;
2578 else
2579 con->includes = i->next;
2580 /* free include and return */
2581 free(i);
2582 ret = 0;
2583 break;
2587 ast_mutex_unlock(&con->lock);
2588 return ret;
2592 * \note This function locks contexts list by &conlist, search for the rigt context
2593 * structure, leave context list locked and call ast_context_remove_switch2
2594 * which removes switch, unlock contexts list and return ...
2596 int ast_context_remove_switch(const char *context, const char *sw, const char *data, const char *registrar)
2598 int ret = -1; /* default error return */
2599 struct ast_context *c = find_context_locked(context);
2601 if (c) {
2602 /* remove switch from this context ... */
2603 ret = ast_context_remove_switch2(c, sw, data, registrar);
2604 ast_unlock_contexts();
2606 return ret;
2610 * \brief This function locks given context, removes switch, unlock context and
2611 * return.
2612 * \note When we call this function, &conlock lock must be locked, because when
2613 * we giving *con argument, some process can remove/change this context
2614 * and after that there can be segfault.
2617 int ast_context_remove_switch2(struct ast_context *con, const char *sw, const char *data, const char *registrar)
2619 struct ast_sw *i;
2620 int ret = -1;
2622 ast_mutex_lock(&con->lock);
2624 /* walk switches */
2625 AST_LIST_TRAVERSE_SAFE_BEGIN(&con->alts, i, list) {
2626 if (!strcmp(i->name, sw) && !strcmp(i->data, data) &&
2627 (!registrar || !strcmp(i->registrar, registrar))) {
2628 /* found, remove from list */
2629 AST_LIST_REMOVE_CURRENT(&con->alts, list);
2630 free(i); /* free switch and return */
2631 ret = 0;
2632 break;
2635 AST_LIST_TRAVERSE_SAFE_END
2637 ast_mutex_unlock(&con->lock);
2639 return ret;
2643 * \note This functions lock contexts list, search for the right context,
2644 * call ast_context_remove_extension2, unlock contexts list and return.
2645 * In this function we are using
2647 int ast_context_remove_extension(const char *context, const char *extension, int priority, const char *registrar)
2649 int ret = -1; /* default error return */
2650 struct ast_context *c = find_context_locked(context);
2652 if (c) { /* ... remove extension ... */
2653 ret = ast_context_remove_extension2(c, extension, priority, registrar);
2654 ast_unlock_contexts();
2656 return ret;
2660 * \brief This functionc locks given context, search for the right extension and
2661 * fires out all peer in this extensions with given priority. If priority
2662 * is set to 0, all peers are removed. After that, unlock context and
2663 * return.
2664 * \note When do you want to call this function, make sure that &conlock is locked,
2665 * because some process can handle with your *con context before you lock
2666 * it.
2669 int ast_context_remove_extension2(struct ast_context *con, const char *extension, int priority, const char *registrar)
2671 struct ast_exten *exten, *prev_exten = NULL;
2672 struct ast_exten *peer;
2674 ast_mutex_lock(&con->lock);
2676 /* scan the extension list to find matching extension-registrar */
2677 for (exten = con->root; exten; prev_exten = exten, exten = exten->next) {
2678 if (!strcmp(exten->exten, extension) &&
2679 (!registrar || !strcmp(exten->registrar, registrar)))
2680 break;
2682 if (!exten) {
2683 /* we can't find right extension */
2684 ast_mutex_unlock(&con->lock);
2685 return -1;
2688 /* should we free all peers in this extension? (priority == 0)? */
2689 if (priority == 0) {
2690 /* remove this extension from context list */
2691 if (prev_exten)
2692 prev_exten->next = exten->next;
2693 else
2694 con->root = exten->next;
2696 /* fire out all peers */
2697 while ( (peer = exten) ) {
2698 exten = peer->peer; /* prepare for next entry */
2699 destroy_exten(peer);
2701 } else {
2702 /* scan the priority list to remove extension with exten->priority == priority */
2703 struct ast_exten *previous_peer = NULL;
2705 for (peer = exten; peer; previous_peer = peer, peer = peer->peer) {
2706 if (peer->priority == priority &&
2707 (!registrar || !strcmp(peer->registrar, registrar) ))
2708 break; /* found our priority */
2710 if (!peer) { /* not found */
2711 ast_mutex_unlock(&con->lock);
2712 return -1;
2714 /* we are first priority extension? */
2715 if (!previous_peer) {
2717 * We are first in the priority chain, so must update the extension chain.
2718 * The next node is either the next priority or the next extension
2720 struct ast_exten *next_node = peer->peer ? peer->peer : peer->next;
2722 if (!prev_exten) /* change the root... */
2723 con->root = next_node;
2724 else
2725 prev_exten->next = next_node; /* unlink */
2726 if (peer->peer) /* XXX update the new head of the pri list */
2727 peer->peer->next = peer->next;
2728 } else { /* easy, we are not first priority in extension */
2729 previous_peer->peer = peer->peer;
2732 /* now, free whole priority extension */
2733 destroy_exten(peer);
2734 /* XXX should we return -1 ? */
2736 ast_mutex_unlock(&con->lock);
2737 return 0;
2741 /*! \brief Dynamically register a new dial plan application */
2742 int ast_register_application(const char *app, int (*execute)(struct ast_channel *, void *), const char *synopsis, const char *description)
2744 struct ast_app *tmp, *cur = NULL;
2745 char tmps[80];
2746 int length;
2748 AST_LIST_LOCK(&apps);
2749 AST_LIST_TRAVERSE(&apps, tmp, list) {
2750 if (!strcasecmp(app, tmp->name)) {
2751 ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
2752 AST_LIST_UNLOCK(&apps);
2753 return -1;
2757 length = sizeof(*tmp) + strlen(app) + 1;
2759 if (!(tmp = ast_calloc(1, length))) {
2760 AST_LIST_UNLOCK(&apps);
2761 return -1;
2764 strcpy(tmp->name, app);
2765 tmp->execute = execute;
2766 tmp->synopsis = synopsis;
2767 tmp->description = description;
2769 /* Store in alphabetical order */
2770 AST_LIST_TRAVERSE_SAFE_BEGIN(&apps, cur, list) {
2771 if (strcasecmp(tmp->name, cur->name) < 0) {
2772 AST_LIST_INSERT_BEFORE_CURRENT(&apps, tmp, list);
2773 break;
2776 AST_LIST_TRAVERSE_SAFE_END
2777 if (!cur)
2778 AST_LIST_INSERT_TAIL(&apps, tmp, list);
2780 if (option_verbose > 1)
2781 ast_verbose( VERBOSE_PREFIX_2 "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
2783 AST_LIST_UNLOCK(&apps);
2785 return 0;
2789 * Append to the list. We don't have a tail pointer because we need
2790 * to scan the list anyways to check for duplicates during insertion.
2792 int ast_register_switch(struct ast_switch *sw)
2794 struct ast_switch *tmp;
2796 AST_LIST_LOCK(&switches);
2797 AST_LIST_TRAVERSE(&switches, tmp, list) {
2798 if (!strcasecmp(tmp->name, sw->name)) {
2799 AST_LIST_UNLOCK(&switches);
2800 ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name);
2801 return -1;
2804 AST_LIST_INSERT_TAIL(&switches, sw, list);
2805 AST_LIST_UNLOCK(&switches);
2807 return 0;
2810 void ast_unregister_switch(struct ast_switch *sw)
2812 AST_LIST_LOCK(&switches);
2813 AST_LIST_REMOVE(&switches, sw, list);
2814 AST_LIST_UNLOCK(&switches);
2818 * Help for CLI commands ...
2820 static char show_application_help[] =
2821 "Usage: show application <application> [<application> [<application> [...]]]\n"
2822 " Describes a particular application.\n";
2824 static char show_functions_help[] =
2825 "Usage: show functions [like <text>]\n"
2826 " List builtin functions, optionally only those matching a given string\n";
2828 static char show_function_help[] =
2829 "Usage: show function <function>\n"
2830 " Describe a particular dialplan function.\n";
2832 static char show_applications_help[] =
2833 "Usage: show applications [{like|describing} <text>]\n"
2834 " List applications which are currently available.\n"
2835 " If 'like', <text> will be a substring of the app name\n"
2836 " If 'describing', <text> will be a substring of the description\n";
2838 static char show_dialplan_help[] =
2839 "Usage: show dialplan [exten@][context]\n"
2840 " Show dialplan\n";
2842 static char show_switches_help[] =
2843 "Usage: show switches\n"
2844 " Show registered switches\n";
2846 static char show_hints_help[] =
2847 "Usage: show hints\n"
2848 " Show registered hints\n";
2850 static char show_globals_help[] =
2851 "Usage: show globals\n"
2852 " Show current global dialplan variables and their values\n";
2854 static char set_global_help[] =
2855 "Usage: set global <name> <value>\n"
2856 " Set global dialplan variable <name> to <value>\n";
2860 * IMPLEMENTATION OF CLI FUNCTIONS IS IN THE SAME ORDER AS COMMANDS HELPS
2865 * \brief 'show application' CLI command implementation functions ...
2869 * There is a possibility to show informations about more than one
2870 * application at one time. You can type 'show application Dial Echo' and
2871 * you will see informations about these two applications ...
2873 static char *complete_show_application(const char *line, const char *word, int pos, int state)
2875 struct ast_app *a;
2876 char *ret = NULL;
2877 int which = 0;
2878 int wordlen = strlen(word);
2880 /* return the n-th [partial] matching entry */
2881 AST_LIST_LOCK(&apps);
2882 AST_LIST_TRAVERSE(&apps, a, list) {
2883 if (!strncasecmp(word, a->name, wordlen) && ++which > state) {
2884 ret = strdup(a->name);
2885 break;
2888 AST_LIST_UNLOCK(&apps);
2890 return ret;
2893 static int handle_show_application(int fd, int argc, char *argv[])
2895 struct ast_app *a;
2896 int app, no_registered_app = 1;
2898 if (argc < 3)
2899 return RESULT_SHOWUSAGE;
2901 /* ... go through all applications ... */
2902 AST_LIST_LOCK(&apps);
2903 AST_LIST_TRAVERSE(&apps, a, list) {
2904 /* ... compare this application name with all arguments given
2905 * to 'show application' command ... */
2906 for (app = 2; app < argc; app++) {
2907 if (!strcasecmp(a->name, argv[app])) {
2908 /* Maximum number of characters added by terminal coloring is 22 */
2909 char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
2910 char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
2911 int synopsis_size, description_size;
2913 no_registered_app = 0;
2915 if (a->synopsis)
2916 synopsis_size = strlen(a->synopsis) + 23;
2917 else
2918 synopsis_size = strlen("Not available") + 23;
2919 synopsis = alloca(synopsis_size);
2921 if (a->description)
2922 description_size = strlen(a->description) + 23;
2923 else
2924 description_size = strlen("Not available") + 23;
2925 description = alloca(description_size);
2927 if (synopsis && description) {
2928 snprintf(info, 64 + AST_MAX_APP, "\n -= Info about application '%s' =- \n\n", a->name);
2929 term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
2930 term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
2931 term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
2932 term_color(synopsis,
2933 a->synopsis ? a->synopsis : "Not available",
2934 COLOR_CYAN, 0, synopsis_size);
2935 term_color(description,
2936 a->description ? a->description : "Not available",
2937 COLOR_CYAN, 0, description_size);
2939 ast_cli(fd,"%s%s%s\n\n%s%s\n", infotitle, syntitle, synopsis, destitle, description);
2940 } else {
2941 /* ... one of our applications, show info ...*/
2942 ast_cli(fd,"\n -= Info about application '%s' =- \n\n"
2943 "[Synopsis]\n %s\n\n"
2944 "[Description]\n%s\n",
2945 a->name,
2946 a->synopsis ? a->synopsis : "Not available",
2947 a->description ? a->description : "Not available");
2952 AST_LIST_UNLOCK(&apps);
2954 /* we found at least one app? no? */
2955 if (no_registered_app) {
2956 ast_cli(fd, "Your application(s) is (are) not registered\n");
2957 return RESULT_FAILURE;
2960 return RESULT_SUCCESS;
2963 /*! \brief handle_show_hints: CLI support for listing registred dial plan hints */
2964 static int handle_show_hints(int fd, int argc, char *argv[])
2966 struct ast_hint *hint;
2967 int num = 0;
2968 int watchers;
2969 struct ast_state_cb *watcher;
2971 if (AST_LIST_EMPTY(&hints)) {
2972 ast_cli(fd, "There are no registered dialplan hints\n");
2973 return RESULT_SUCCESS;
2975 /* ... we have hints ... */
2976 ast_cli(fd, "\n -= Registered Asterisk Dial Plan Hints =-\n");
2977 AST_LIST_LOCK(&hints);
2978 AST_LIST_TRAVERSE(&hints, hint, list) {
2979 watchers = 0;
2980 for (watcher = hint->callbacks; watcher; watcher = watcher->next)
2981 watchers++;
2982 ast_cli(fd, " %20s@%-20.20s: %-20.20s State:%-15.15s Watchers %2d\n",
2983 ast_get_extension_name(hint->exten),
2984 ast_get_context_name(ast_get_extension_context(hint->exten)),
2985 ast_get_extension_app(hint->exten),
2986 ast_extension_state2str(hint->laststate), watchers);
2987 num++;
2989 ast_cli(fd, "----------------\n");
2990 ast_cli(fd, "- %d hints registered\n", num);
2991 AST_LIST_UNLOCK(&hints);
2992 return RESULT_SUCCESS;
2995 /*! \brief handle_show_switches: CLI support for listing registred dial plan switches */
2996 static int handle_show_switches(int fd, int argc, char *argv[])
2998 struct ast_switch *sw;
3000 AST_LIST_LOCK(&switches);
3002 if (AST_LIST_EMPTY(&switches)) {
3003 AST_LIST_UNLOCK(&switches);
3004 ast_cli(fd, "There are no registered alternative switches\n");
3005 return RESULT_SUCCESS;
3008 ast_cli(fd, "\n -= Registered Asterisk Alternative Switches =-\n");
3009 AST_LIST_TRAVERSE(&switches, sw, list)
3010 ast_cli(fd, "%s: %s\n", sw->name, sw->description);
3012 AST_LIST_UNLOCK(&switches);
3014 return RESULT_SUCCESS;
3018 * 'show applications' CLI command implementation functions ...
3020 static int handle_show_applications(int fd, int argc, char *argv[])
3022 struct ast_app *a;
3023 int like = 0, describing = 0;
3024 int total_match = 0; /* Number of matches in like clause */
3025 int total_apps = 0; /* Number of apps registered */
3027 AST_LIST_LOCK(&apps);
3029 if (AST_LIST_EMPTY(&apps)) {
3030 ast_cli(fd, "There are no registered applications\n");
3031 AST_LIST_UNLOCK(&apps);
3032 return -1;
3035 /* show applications like <keyword> */
3036 if ((argc == 4) && (!strcmp(argv[2], "like"))) {
3037 like = 1;
3038 } else if ((argc > 3) && (!strcmp(argv[2], "describing"))) {
3039 describing = 1;
3042 /* show applications describing <keyword1> [<keyword2>] [...] */
3043 if ((!like) && (!describing)) {
3044 ast_cli(fd, " -= Registered Asterisk Applications =-\n");
3045 } else {
3046 ast_cli(fd, " -= Matching Asterisk Applications =-\n");
3049 AST_LIST_TRAVERSE(&apps, a, list) {
3050 int printapp = 0;
3051 total_apps++;
3052 if (like) {
3053 if (strcasestr(a->name, argv[3])) {
3054 printapp = 1;
3055 total_match++;
3057 } else if (describing) {
3058 if (a->description) {
3059 /* Match all words on command line */
3060 int i;
3061 printapp = 1;
3062 for (i = 3; i < argc; i++) {
3063 if (!strcasestr(a->description, argv[i])) {
3064 printapp = 0;
3065 } else {
3066 total_match++;
3070 } else {
3071 printapp = 1;
3074 if (printapp) {
3075 ast_cli(fd," %20s: %s\n", a->name, a->synopsis ? a->synopsis : "<Synopsis not available>");
3078 if ((!like) && (!describing)) {
3079 ast_cli(fd, " -= %d Applications Registered =-\n",total_apps);
3080 } else {
3081 ast_cli(fd, " -= %d Applications Matching =-\n",total_match);
3084 AST_LIST_UNLOCK(&apps);
3086 return RESULT_SUCCESS;
3089 static char *complete_show_applications(const char *line, const char *word, int pos, int state)
3091 static char* choices[] = { "like", "describing", NULL };
3093 return (pos != 2) ? NULL : ast_cli_complete(word, choices, state);
3097 * 'show dialplan' CLI command implementation functions ...
3099 static char *complete_show_dialplan_context(const char *line, const char *word, int pos,
3100 int state)
3102 struct ast_context *c = NULL;
3103 char *ret = NULL;
3104 int which = 0;
3105 int wordlen;
3107 /* we are do completion of [exten@]context on second position only */
3108 if (pos != 2)
3109 return NULL;
3111 ast_lock_contexts();
3113 wordlen = strlen(word);
3115 /* walk through all contexts and return the n-th match */
3116 while ( (c = ast_walk_contexts(c)) ) {
3117 if (!strncasecmp(word, ast_get_context_name(c), wordlen) && ++which > state) {
3118 ret = ast_strdup(ast_get_context_name(c));
3119 break;
3123 ast_unlock_contexts();
3125 return ret;
3128 struct dialplan_counters {
3129 int total_context;
3130 int total_exten;
3131 int total_prio;
3132 int context_existence;
3133 int extension_existence;
3136 /*! \brief helper function to print an extension */
3137 static void print_ext(struct ast_exten *e, char * buf, int buflen)
3139 int prio = ast_get_extension_priority(e);
3140 if (prio == PRIORITY_HINT) {
3141 snprintf(buf, buflen, "hint: %s",
3142 ast_get_extension_app(e));
3143 } else {
3144 snprintf(buf, buflen, "%d. %s(%s)",
3145 prio, ast_get_extension_app(e),
3146 (char *)ast_get_extension_app_data(e));
3150 /* XXX not verified */
3151 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[])
3153 struct ast_context *c = NULL;
3154 int res = 0, old_total_exten = dpc->total_exten;
3156 ast_lock_contexts();
3158 /* walk all contexts ... */
3159 while ( (c = ast_walk_contexts(c)) ) {
3160 struct ast_exten *e;
3161 struct ast_include *i;
3162 struct ast_ignorepat *ip;
3163 char buf[256], buf2[256];
3164 int context_info_printed = 0;
3166 if (context && strcmp(ast_get_context_name(c), context))
3167 continue; /* skip this one, name doesn't match */
3169 dpc->context_existence = 1;
3171 ast_lock_context(c);
3173 /* are we looking for exten too? if yes, we print context
3174 * only if we find our extension.
3175 * Otherwise print context even if empty ?
3176 * XXX i am not sure how the rinclude is handled.
3177 * I think it ought to go inside.
3179 if (!exten) {
3180 dpc->total_context++;
3181 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
3182 ast_get_context_name(c), ast_get_context_registrar(c));
3183 context_info_printed = 1;
3186 /* walk extensions ... */
3187 e = NULL;
3188 while ( (e = ast_walk_context_extensions(c, e)) ) {
3189 struct ast_exten *p;
3191 if (exten && !ast_extension_match(ast_get_extension_name(e), exten))
3192 continue; /* skip, extension match failed */
3194 dpc->extension_existence = 1;
3196 /* may we print context info? */
3197 if (!context_info_printed) {
3198 dpc->total_context++;
3199 if (rinclude) { /* TODO Print more info about rinclude */
3200 ast_cli(fd, "[ Included context '%s' created by '%s' ]\n",
3201 ast_get_context_name(c), ast_get_context_registrar(c));
3202 } else {
3203 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
3204 ast_get_context_name(c), ast_get_context_registrar(c));
3206 context_info_printed = 1;
3208 dpc->total_prio++;
3210 /* write extension name and first peer */
3211 snprintf(buf, sizeof(buf), "'%s' =>", ast_get_extension_name(e));
3213 print_ext(e, buf2, sizeof(buf2));
3215 ast_cli(fd, " %-17s %-45s [%s]\n", buf, buf2,
3216 ast_get_extension_registrar(e));
3218 dpc->total_exten++;
3219 /* walk next extension peers */
3220 p = e; /* skip the first one, we already got it */
3221 while ( (p = ast_walk_extension_priorities(e, p)) ) {
3222 const char *el = ast_get_extension_label(p);
3223 dpc->total_prio++;
3224 if (el)
3225 snprintf(buf, sizeof(buf), " [%s]", el);
3226 else
3227 buf[0] = '\0';
3228 print_ext(p, buf2, sizeof(buf2));
3230 ast_cli(fd," %-17s %-45s [%s]\n", buf, buf2,
3231 ast_get_extension_registrar(p));
3235 /* walk included and write info ... */
3236 i = NULL;
3237 while ( (i = ast_walk_context_includes(c, i)) ) {
3238 snprintf(buf, sizeof(buf), "'%s'", ast_get_include_name(i));
3239 if (exten) {
3240 /* Check all includes for the requested extension */
3241 if (includecount >= AST_PBX_MAX_STACK) {
3242 ast_log(LOG_NOTICE, "Maximum include depth exceeded!\n");
3243 } else {
3244 int dupe=0;
3245 int x;
3246 for (x=0;x<includecount;x++) {
3247 if (!strcasecmp(includes[x], ast_get_include_name(i))) {
3248 dupe++;
3249 break;
3252 if (!dupe) {
3253 includes[includecount] = ast_get_include_name(i);
3254 show_dialplan_helper(fd, ast_get_include_name(i), exten, dpc, i, includecount + 1, includes);
3255 } else {
3256 ast_log(LOG_WARNING, "Avoiding circular include of %s within %s\n", ast_get_include_name(i), context);
3259 } else {
3260 ast_cli(fd, " Include => %-45s [%s]\n",
3261 buf, ast_get_include_registrar(i));
3265 /* walk ignore patterns and write info ... */
3266 ip = NULL;
3267 while ( (ip = ast_walk_context_ignorepats(c, ip)) ) {
3268 const char *ipname = ast_get_ignorepat_name(ip);
3269 char ignorepat[AST_MAX_EXTENSION];
3270 snprintf(buf, sizeof(buf), "'%s'", ipname);
3271 snprintf(ignorepat, sizeof(ignorepat), "_%s.", ipname);
3272 if (!exten || ast_extension_match(ignorepat, exten)) {
3273 ast_cli(fd, " Ignore pattern => %-45s [%s]\n",
3274 buf, ast_get_ignorepat_registrar(ip));
3277 if (!rinclude) {
3278 struct ast_sw *sw = NULL;
3279 while ( (sw = ast_walk_context_switches(c, sw)) ) {
3280 snprintf(buf, sizeof(buf), "'%s/%s'",
3281 ast_get_switch_name(sw),
3282 ast_get_switch_data(sw));
3283 ast_cli(fd, " Alt. Switch => %-45s [%s]\n",
3284 buf, ast_get_switch_registrar(sw));
3288 ast_unlock_context(c);
3290 /* if we print something in context, make an empty line */
3291 if (context_info_printed)
3292 ast_cli(fd, "\r\n");
3294 ast_unlock_contexts();
3296 return (dpc->total_exten == old_total_exten) ? -1 : res;
3299 static int handle_show_dialplan(int fd, int argc, char *argv[])
3301 char *exten = NULL, *context = NULL;
3302 /* Variables used for different counters */
3303 struct dialplan_counters counters;
3305 const char *incstack[AST_PBX_MAX_STACK];
3306 memset(&counters, 0, sizeof(counters));
3308 if (argc != 2 && argc != 3)
3309 return RESULT_SHOWUSAGE;
3311 /* we obtain [exten@]context? if yes, split them ... */
3312 if (argc == 3) {
3313 if (strchr(argv[2], '@')) { /* split into exten & context */
3314 context = ast_strdupa(argv[2]);
3315 exten = strsep(&context, "@");
3316 /* change empty strings to NULL */
3317 if (ast_strlen_zero(exten))
3318 exten = NULL;
3319 } else { /* no '@' char, only context given */
3320 context = argv[2];
3322 if (ast_strlen_zero(context))
3323 context = NULL;
3325 /* else Show complete dial plan, context and exten are NULL */
3326 show_dialplan_helper(fd, context, exten, &counters, NULL, 0, incstack);
3328 /* check for input failure and throw some error messages */
3329 if (context && !counters.context_existence) {
3330 ast_cli(fd, "There is no existence of '%s' context\n", context);
3331 return RESULT_FAILURE;
3334 if (exten && !counters.extension_existence) {
3335 if (context)
3336 ast_cli(fd, "There is no existence of %s@%s extension\n",
3337 exten, context);
3338 else
3339 ast_cli(fd,
3340 "There is no existence of '%s' extension in all contexts\n",
3341 exten);
3342 return RESULT_FAILURE;
3345 ast_cli(fd,"-= %d %s (%d %s) in %d %s. =-\n",
3346 counters.total_exten, counters.total_exten == 1 ? "extension" : "extensions",
3347 counters.total_prio, counters.total_prio == 1 ? "priority" : "priorities",
3348 counters.total_context, counters.total_context == 1 ? "context" : "contexts");
3350 /* everything ok */
3351 return RESULT_SUCCESS;
3354 /*! \brief CLI support for listing global variables in a parseable way */
3355 static int handle_show_globals(int fd, int argc, char *argv[])
3357 int i = 0;
3358 struct ast_var_t *newvariable;
3360 ast_mutex_lock(&globalslock);
3361 AST_LIST_TRAVERSE (&globals, newvariable, entries) {
3362 i++;
3363 ast_cli(fd, " %s=%s\n", ast_var_name(newvariable), ast_var_value(newvariable));
3365 ast_mutex_unlock(&globalslock);
3366 ast_cli(fd, "\n -- %d variables\n", i);
3368 return RESULT_SUCCESS;
3371 /*! \brief CLI support for setting global variables */
3372 static int handle_set_global(int fd, int argc, char *argv[])
3374 if (argc != 4)
3375 return RESULT_SHOWUSAGE;
3377 pbx_builtin_setvar_helper(NULL, argv[2], argv[3]);
3378 ast_cli(fd, "\n -- Global variable %s set to %s\n", argv[2], argv[3]);
3380 return RESULT_SUCCESS;
3386 * CLI entries for upper commands ...
3388 static struct ast_cli_entry pbx_cli[] = {
3389 { { "show", "applications", NULL }, handle_show_applications,
3390 "Shows registered dialplan applications", show_applications_help, complete_show_applications },
3391 { { "show", "functions", NULL }, handle_show_functions,
3392 "Shows registered dialplan functions", show_functions_help },
3393 { { "show" , "function", NULL }, handle_show_function,
3394 "Describe a specific dialplan function", show_function_help, complete_show_function },
3395 { { "show", "application", NULL }, handle_show_application,
3396 "Describe a specific dialplan application", show_application_help, complete_show_application },
3397 { { "show", "dialplan", NULL }, handle_show_dialplan,
3398 "Show dialplan", show_dialplan_help, complete_show_dialplan_context },
3399 { { "show", "switches", NULL }, handle_show_switches,
3400 "Show alternative switches", show_switches_help },
3401 { { "show", "hints", NULL }, handle_show_hints,
3402 "Show dialplan hints", show_hints_help },
3403 { { "show", "globals", NULL }, handle_show_globals,
3404 "Show global dialplan variables", show_globals_help },
3405 { { "set", "global", NULL }, handle_set_global,
3406 "Set global dialplan variable", set_global_help },
3409 int ast_unregister_application(const char *app)
3411 struct ast_app *tmp;
3413 AST_LIST_LOCK(&apps);
3414 AST_LIST_TRAVERSE_SAFE_BEGIN(&apps, tmp, list) {
3415 if (!strcasecmp(app, tmp->name)) {
3416 AST_LIST_REMOVE_CURRENT(&apps, list);
3417 if (option_verbose > 1)
3418 ast_verbose( VERBOSE_PREFIX_2 "Unregistered application '%s'\n", tmp->name);
3419 free(tmp);
3420 break;
3423 AST_LIST_TRAVERSE_SAFE_END
3424 AST_LIST_UNLOCK(&apps);
3426 return tmp ? 0 : -1;
3429 struct ast_context *ast_context_create(struct ast_context **extcontexts, const char *name, const char *registrar)
3431 struct ast_context *tmp, **local_contexts;
3432 int length = sizeof(struct ast_context) + strlen(name) + 1;
3434 if (!extcontexts) {
3435 ast_mutex_lock(&conlock);
3436 local_contexts = &contexts;
3437 } else
3438 local_contexts = extcontexts;
3440 for (tmp = *local_contexts; tmp; tmp = tmp->next) {
3441 if (!strcasecmp(tmp->name, name)) {
3442 ast_log(LOG_WARNING, "Tried to register context '%s', already in use\n", name);
3443 if (!extcontexts)
3444 ast_mutex_unlock(&conlock);
3445 return NULL;
3448 if ((tmp = ast_calloc(1, length))) {
3449 ast_mutex_init(&tmp->lock);
3450 strcpy(tmp->name, name);
3451 tmp->root = NULL;
3452 tmp->registrar = registrar;
3453 tmp->next = *local_contexts;
3454 tmp->includes = NULL;
3455 tmp->ignorepats = NULL;
3456 *local_contexts = tmp;
3457 if (option_debug)
3458 ast_log(LOG_DEBUG, "Registered context '%s'\n", tmp->name);
3459 else if (option_verbose > 2)
3460 ast_verbose( VERBOSE_PREFIX_3 "Registered extension context '%s'\n", tmp->name);
3463 if (!extcontexts)
3464 ast_mutex_unlock(&conlock);
3465 return tmp;
3468 void __ast_context_destroy(struct ast_context *con, const char *registrar);
3470 struct store_hint {
3471 char *context;
3472 char *exten;
3473 struct ast_state_cb *callbacks;
3474 int laststate;
3475 AST_LIST_ENTRY(store_hint) list;
3476 char data[1];
3479 AST_LIST_HEAD(store_hints, store_hint);
3481 /* XXX this does not check that multiple contexts are merged */
3482 void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char *registrar)
3484 struct ast_context *tmp, *lasttmp = NULL;
3485 struct store_hints store = AST_LIST_HEAD_INIT_VALUE;
3486 struct store_hint *this;
3487 struct ast_hint *hint;
3488 struct ast_exten *exten;
3489 int length;
3490 struct ast_state_cb *thiscb, *prevcb;
3492 /* it is very important that this function hold the hint list lock _and_ the conlock
3493 during its operation; not only do we need to ensure that the list of contexts
3494 and extensions does not change, but also that no hint callbacks (watchers) are
3495 added or removed during the merge/delete process
3497 in addition, the locks _must_ be taken in this order, because there are already
3498 other code paths that use this order
3500 ast_mutex_lock(&conlock);
3501 AST_LIST_LOCK(&hints);
3503 /* preserve all watchers for hints associated with this registrar */
3504 AST_LIST_TRAVERSE(&hints, hint, list) {
3505 if (hint->callbacks && !strcmp(registrar, hint->exten->parent->registrar)) {
3506 length = strlen(hint->exten->exten) + strlen(hint->exten->parent->name) + 2 + sizeof(*this);
3507 if (!(this = ast_calloc(1, length)))
3508 continue;
3509 this->callbacks = hint->callbacks;
3510 hint->callbacks = NULL;
3511 this->laststate = hint->laststate;
3512 this->context = this->data;
3513 strcpy(this->data, hint->exten->parent->name);
3514 this->exten = this->data + strlen(this->context) + 1;
3515 strcpy(this->exten, hint->exten->exten);
3516 AST_LIST_INSERT_HEAD(&store, this, list);
3520 tmp = *extcontexts;
3521 if (registrar) {
3522 /* XXX remove previous contexts from same registrar */
3523 ast_log(LOG_DEBUG, "must remove any reg %s\n", registrar);
3524 __ast_context_destroy(NULL,registrar);
3525 while (tmp) {
3526 lasttmp = tmp;
3527 tmp = tmp->next;
3529 } else {
3530 /* XXX remove contexts with the same name */
3531 while (tmp) {
3532 ast_log(LOG_WARNING, "must remove %s reg %s\n", tmp->name, tmp->registrar);
3533 __ast_context_destroy(tmp,tmp->registrar);
3534 lasttmp = tmp;
3535 tmp = tmp->next;
3538 if (lasttmp) {
3539 lasttmp->next = contexts;
3540 contexts = *extcontexts;
3541 *extcontexts = NULL;
3542 } else
3543 ast_log(LOG_WARNING, "Requested contexts didn't get merged\n");
3545 /* restore the watchers for hints that can be found; notify those that
3546 cannot be restored
3548 while ((this = AST_LIST_REMOVE_HEAD(&store, list))) {
3549 exten = ast_hint_extension(NULL, this->context, this->exten);
3550 /* Find the hint in the list of hints */
3551 AST_LIST_TRAVERSE(&hints, hint, list) {
3552 if (hint->exten == exten)
3553 break;
3555 if (!exten || !hint) {
3556 /* this hint has been removed, notify the watchers */
3557 prevcb = NULL;
3558 thiscb = this->callbacks;
3559 while (thiscb) {
3560 prevcb = thiscb;
3561 thiscb = thiscb->next;
3562 prevcb->callback(this->context, this->exten, AST_EXTENSION_REMOVED, prevcb->data);
3563 free(prevcb);
3565 } else {
3566 thiscb = this->callbacks;
3567 while (thiscb->next)
3568 thiscb = thiscb->next;
3569 thiscb->next = hint->callbacks;
3570 hint->callbacks = this->callbacks;
3571 hint->laststate = this->laststate;
3573 free(this);
3576 AST_LIST_UNLOCK(&hints);
3577 ast_mutex_unlock(&conlock);
3579 return;
3583 * errno values
3584 * EBUSY - can't lock
3585 * ENOENT - no existence of context
3587 int ast_context_add_include(const char *context, const char *include, const char *registrar)
3589 int ret = -1;
3590 struct ast_context *c = find_context_locked(context);
3592 if (c) {
3593 ret = ast_context_add_include2(c, include, registrar);
3594 ast_unlock_contexts();
3596 return ret;
3599 /*! \brief Helper for get_range.
3600 * return the index of the matching entry, starting from 1.
3601 * If names is not supplied, try numeric values.
3603 static int lookup_name(const char *s, char *const names[], int max)
3605 int i;
3607 if (names) {
3608 for (i = 0; names[i]; i++) {
3609 if (!strcasecmp(s, names[i]))
3610 return i+1;
3612 } else if (sscanf(s, "%d", &i) == 1 && i >= 1 && i <= max) {
3613 return i;
3615 return 0; /* error return */
3618 /*! \brief helper function to return a range up to max (7, 12, 31 respectively).
3619 * names, if supplied, is an array of names that should be mapped to numbers.
3621 static unsigned get_range(char *src, int max, char *const names[], const char *msg)
3623 int s, e; /* start and ending position */
3624 unsigned int mask = 0;
3626 /* Check for whole range */
3627 if (ast_strlen_zero(src) || !strcmp(src, "*")) {
3628 s = 0;
3629 e = max - 1;
3630 } else {
3631 /* Get start and ending position */
3632 char *c = strchr(src, '-');
3633 if (c)
3634 *c++ = '\0';
3635 /* Find the start */
3636 s = lookup_name(src, names, max);
3637 if (!s) {
3638 ast_log(LOG_WARNING, "Invalid %s '%s', assuming none\n", msg, src);
3639 return 0;
3641 s--;
3642 if (c) { /* find end of range */
3643 e = lookup_name(c, names, max);
3644 if (!e) {
3645 ast_log(LOG_WARNING, "Invalid end %s '%s', assuming none\n", msg, c);
3646 return 0;
3648 e--;
3649 } else
3650 e = s;
3652 /* Fill the mask. Remember that ranges are cyclic */
3653 mask = 1 << e; /* initialize with last element */
3654 while (s != e) {
3655 if (s >= max) {
3656 s = 0;
3657 mask |= (1 << s);
3658 } else {
3659 mask |= (1 << s);
3660 s++;
3663 return mask;
3666 /*! \brief store a bitmask of valid times, one bit each 2 minute */
3667 static void get_timerange(struct ast_timing *i, char *times)
3669 char *e;
3670 int x;
3671 int s1, s2;
3672 int e1, e2;
3673 /* int cth, ctm; */
3675 /* start disabling all times, fill the fields with 0's, as they may contain garbage */
3676 memset(i->minmask, 0, sizeof(i->minmask));
3678 /* 2-minutes per bit, since the mask has only 32 bits :( */
3679 /* Star is all times */
3680 if (ast_strlen_zero(times) || !strcmp(times, "*")) {
3681 for (x=0; x<24; x++)
3682 i->minmask[x] = 0x3fffffff; /* 30 bits */
3683 return;
3685 /* Otherwise expect a range */
3686 e = strchr(times, '-');
3687 if (!e) {
3688 ast_log(LOG_WARNING, "Time range is not valid. Assuming no restrictions based on time.\n");
3689 return;
3691 *e++ = '\0';
3692 /* XXX why skip non digits ? */
3693 while (*e && !isdigit(*e))
3694 e++;
3695 if (!*e) {
3696 ast_log(LOG_WARNING, "Invalid time range. Assuming no restrictions based on time.\n");
3697 return;
3699 if (sscanf(times, "%d:%d", &s1, &s2) != 2) {
3700 ast_log(LOG_WARNING, "%s isn't a time. Assuming no restrictions based on time.\n", times);
3701 return;
3703 if (sscanf(e, "%d:%d", &e1, &e2) != 2) {
3704 ast_log(LOG_WARNING, "%s isn't a time. Assuming no restrictions based on time.\n", e);
3705 return;
3707 /* XXX this needs to be optimized */
3708 #if 1
3709 s1 = s1 * 30 + s2/2;
3710 if ((s1 < 0) || (s1 >= 24*30)) {
3711 ast_log(LOG_WARNING, "%s isn't a valid start time. Assuming no time.\n", times);
3712 return;
3714 e1 = e1 * 30 + e2/2;
3715 if ((e1 < 0) || (e1 >= 24*30)) {
3716 ast_log(LOG_WARNING, "%s isn't a valid end time. Assuming no time.\n", e);
3717 return;
3719 /* Go through the time and enable each appropriate bit */
3720 for (x=s1;x != e1;x = (x + 1) % (24 * 30)) {
3721 i->minmask[x/30] |= (1 << (x % 30));
3723 /* Do the last one */
3724 i->minmask[x/30] |= (1 << (x % 30));
3725 #else
3726 for (cth=0; cth<24; cth++) {
3727 /* Initialize masks to blank */
3728 i->minmask[cth] = 0;
3729 for (ctm=0; ctm<30; ctm++) {
3730 if (
3731 /* First hour with more than one hour */
3732 (((cth == s1) && (ctm >= s2)) &&
3733 ((cth < e1)))
3734 /* Only one hour */
3735 || (((cth == s1) && (ctm >= s2)) &&
3736 ((cth == e1) && (ctm <= e2)))
3737 /* In between first and last hours (more than 2 hours) */
3738 || ((cth > s1) &&
3739 (cth < e1))
3740 /* Last hour with more than one hour */
3741 || ((cth > s1) &&
3742 ((cth == e1) && (ctm <= e2)))
3744 i->minmask[cth] |= (1 << (ctm / 2));
3747 #endif
3748 /* All done */
3749 return;
3752 static char *days[] =
3754 "sun",
3755 "mon",
3756 "tue",
3757 "wed",
3758 "thu",
3759 "fri",
3760 "sat",
3761 NULL,
3764 static char *months[] =
3766 "jan",
3767 "feb",
3768 "mar",
3769 "apr",
3770 "may",
3771 "jun",
3772 "jul",
3773 "aug",
3774 "sep",
3775 "oct",
3776 "nov",
3777 "dec",
3778 NULL,
3781 int ast_build_timing(struct ast_timing *i, const char *info_in)
3783 char info_save[256];
3784 char *info;
3786 /* Check for empty just in case */
3787 if (ast_strlen_zero(info_in))
3788 return 0;
3789 /* make a copy just in case we were passed a static string */
3790 ast_copy_string(info_save, info_in, sizeof(info_save));
3791 info = info_save;
3792 /* Assume everything except time */
3793 i->monthmask = 0xfff; /* 12 bits */
3794 i->daymask = 0x7fffffffU; /* 31 bits */
3795 i->dowmask = 0x7f; /* 7 bits */
3796 /* on each call, use strsep() to move info to the next argument */
3797 get_timerange(i, strsep(&info, "|"));
3798 if (info)
3799 i->dowmask = get_range(strsep(&info, "|"), 7, days, "day of week");
3800 if (info)
3801 i->daymask = get_range(strsep(&info, "|"), 31, NULL, "day");
3802 if (info)
3803 i->monthmask = get_range(strsep(&info, "|"), 12, months, "month");
3804 return 1;
3807 int ast_check_timing(const struct ast_timing *i)
3809 struct tm tm;
3810 time_t t = time(NULL);
3812 localtime_r(&t,&tm);
3814 /* If it's not the right month, return */
3815 if (!(i->monthmask & (1 << tm.tm_mon)))
3816 return 0;
3818 /* If it's not that time of the month.... */
3819 /* Warning, tm_mday has range 1..31! */
3820 if (!(i->daymask & (1 << (tm.tm_mday-1))))
3821 return 0;
3823 /* If it's not the right day of the week */
3824 if (!(i->dowmask & (1 << tm.tm_wday)))
3825 return 0;
3827 /* Sanity check the hour just to be safe */
3828 if ((tm.tm_hour < 0) || (tm.tm_hour > 23)) {
3829 ast_log(LOG_WARNING, "Insane time...\n");
3830 return 0;
3833 /* Now the tough part, we calculate if it fits
3834 in the right time based on min/hour */
3835 if (!(i->minmask[tm.tm_hour] & (1 << (tm.tm_min / 2))))
3836 return 0;
3838 /* If we got this far, then we're good */
3839 return 1;
3843 * errno values
3844 * ENOMEM - out of memory
3845 * EBUSY - can't lock
3846 * EEXIST - already included
3847 * EINVAL - there is no existence of context for inclusion
3849 int ast_context_add_include2(struct ast_context *con, const char *value,
3850 const char *registrar)
3852 struct ast_include *new_include;
3853 char *c;
3854 struct ast_include *i, *il = NULL; /* include, include_last */
3855 int length;
3856 char *p;
3858 length = sizeof(struct ast_include);
3859 length += 2 * (strlen(value) + 1);
3861 /* allocate new include structure ... */
3862 if (!(new_include = ast_calloc(1, length)))
3863 return -1;
3864 /* Fill in this structure. Use 'p' for assignments, as the fields
3865 * in the structure are 'const char *'
3867 p = new_include->stuff;
3868 new_include->name = p;
3869 strcpy(p, value);
3870 p += strlen(value) + 1;
3871 new_include->rname = p;
3872 strcpy(p, value);
3873 /* Strip off timing info, and process if it is there */
3874 if ( (c = strchr(p, '|')) ) {
3875 *c++ = '\0';
3876 new_include->hastime = ast_build_timing(&(new_include->timing), c);
3878 new_include->next = NULL;
3879 new_include->registrar = registrar;
3881 ast_mutex_lock(&con->lock);
3883 /* ... go to last include and check if context is already included too... */
3884 for (i = con->includes; i; i = i->next) {
3885 if (!strcasecmp(i->name, new_include->name)) {
3886 free(new_include);
3887 ast_mutex_unlock(&con->lock);
3888 errno = EEXIST;
3889 return -1;
3891 il = i;
3894 /* ... include new context into context list, unlock, return */
3895 if (il)
3896 il->next = new_include;
3897 else
3898 con->includes = new_include;
3899 if (option_verbose > 2)
3900 ast_verbose(VERBOSE_PREFIX_3 "Including context '%s' in context '%s'\n", new_include->name, ast_get_context_name(con));
3901 ast_mutex_unlock(&con->lock);
3903 return 0;
3907 * errno values
3908 * EBUSY - can't lock
3909 * ENOENT - no existence of context
3911 int ast_context_add_switch(const char *context, const char *sw, const char *data, int eval, const char *registrar)
3913 int ret = -1;
3914 struct ast_context *c = find_context_locked(context);
3916 if (c) { /* found, add switch to this context */
3917 ret = ast_context_add_switch2(c, sw, data, eval, registrar);
3918 ast_unlock_contexts();
3920 return ret;
3924 * errno values
3925 * ENOMEM - out of memory
3926 * EBUSY - can't lock
3927 * EEXIST - already included
3928 * EINVAL - there is no existence of context for inclusion
3930 int ast_context_add_switch2(struct ast_context *con, const char *value,
3931 const char *data, int eval, const char *registrar)
3933 struct ast_sw *new_sw;
3934 struct ast_sw *i;
3935 int length;
3936 char *p;
3938 length = sizeof(struct ast_sw);
3939 length += strlen(value) + 1;
3940 if (data)
3941 length += strlen(data);
3942 length++;
3943 if (eval) {
3944 /* Create buffer for evaluation of variables */
3945 length += SWITCH_DATA_LENGTH;
3946 length++;
3949 /* allocate new sw structure ... */
3950 if (!(new_sw = ast_calloc(1, length)))
3951 return -1;
3952 /* ... fill in this structure ... */
3953 p = new_sw->stuff;
3954 new_sw->name = p;
3955 strcpy(new_sw->name, value);
3956 p += strlen(value) + 1;
3957 new_sw->data = p;
3958 if (data) {
3959 strcpy(new_sw->data, data);
3960 p += strlen(data) + 1;
3961 } else {
3962 strcpy(new_sw->data, "");
3963 p++;
3965 if (eval)
3966 new_sw->tmpdata = p;
3967 new_sw->eval = eval;
3968 new_sw->registrar = registrar;
3970 /* ... try to lock this context ... */
3971 ast_mutex_lock(&con->lock);
3973 /* ... go to last sw and check if context is already swd too... */
3974 AST_LIST_TRAVERSE(&con->alts, i, list) {
3975 if (!strcasecmp(i->name, new_sw->name) && !strcasecmp(i->data, new_sw->data)) {
3976 free(new_sw);
3977 ast_mutex_unlock(&con->lock);
3978 errno = EEXIST;
3979 return -1;
3983 /* ... sw new context into context list, unlock, return */
3984 AST_LIST_INSERT_TAIL(&con->alts, new_sw, list);
3986 if (option_verbose > 2)
3987 ast_verbose(VERBOSE_PREFIX_3 "Including switch '%s/%s' in context '%s'\n", new_sw->name, new_sw->data, ast_get_context_name(con));
3989 ast_mutex_unlock(&con->lock);
3991 return 0;
3995 * EBUSY - can't lock
3996 * ENOENT - there is not context existence
3998 int ast_context_remove_ignorepat(const char *context, const char *ignorepat, const char *registrar)
4000 int ret = -1;
4001 struct ast_context *c = find_context_locked(context);
4003 if (c) {
4004 ret = ast_context_remove_ignorepat2(c, ignorepat, registrar);
4005 ast_unlock_contexts();
4007 return ret;
4010 int ast_context_remove_ignorepat2(struct ast_context *con, const char *ignorepat, const char *registrar)
4012 struct ast_ignorepat *ip, *ipl = NULL;
4014 ast_mutex_lock(&con->lock);
4016 for (ip = con->ignorepats; ip; ip = ip->next) {
4017 if (!strcmp(ip->pattern, ignorepat) &&
4018 (!registrar || (registrar == ip->registrar))) {
4019 if (ipl) {
4020 ipl->next = ip->next;
4021 free(ip);
4022 } else {
4023 con->ignorepats = ip->next;
4024 free(ip);
4026 ast_mutex_unlock(&con->lock);
4027 return 0;
4029 ipl = ip;
4032 ast_mutex_unlock(&con->lock);
4033 errno = EINVAL;
4034 return -1;
4038 * EBUSY - can't lock
4039 * ENOENT - there is no existence of context
4041 int ast_context_add_ignorepat(const char *context, const char *value, const char *registrar)
4043 int ret = -1;
4044 struct ast_context *c = find_context_locked(context);
4046 if (c) {
4047 ret = ast_context_add_ignorepat2(c, value, registrar);
4048 ast_unlock_contexts();
4050 return ret;
4053 int ast_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar)
4055 struct ast_ignorepat *ignorepat, *ignorepatc, *ignorepatl = NULL;
4056 int length;
4057 length = sizeof(struct ast_ignorepat);
4058 length += strlen(value) + 1;
4059 if (!(ignorepat = ast_calloc(1, length)))
4060 return -1;
4061 /* The cast to char * is because we need to write the initial value.
4062 * The field is not supposed to be modified otherwise
4064 strcpy((char *)ignorepat->pattern, value);
4065 ignorepat->next = NULL;
4066 ignorepat->registrar = registrar;
4067 ast_mutex_lock(&con->lock);
4068 for (ignorepatc = con->ignorepats; ignorepatc; ignorepatc = ignorepatc->next) {
4069 ignorepatl = ignorepatc;
4070 if (!strcasecmp(ignorepatc->pattern, value)) {
4071 /* Already there */
4072 ast_mutex_unlock(&con->lock);
4073 errno = EEXIST;
4074 return -1;
4077 if (ignorepatl)
4078 ignorepatl->next = ignorepat;
4079 else
4080 con->ignorepats = ignorepat;
4081 ast_mutex_unlock(&con->lock);
4082 return 0;
4086 int ast_ignore_pattern(const char *context, const char *pattern)
4088 struct ast_context *con = ast_context_find(context);
4089 if (con) {
4090 struct ast_ignorepat *pat;
4091 for (pat = con->ignorepats; pat; pat = pat->next) {
4092 if (ast_extension_match(pat->pattern, pattern))
4093 return 1;
4097 return 0;
4101 * EBUSY - can't lock
4102 * ENOENT - no existence of context
4105 int ast_add_extension(const char *context, int replace, const char *extension,
4106 int priority, const char *label, const char *callerid,
4107 const char *application, void *data, void (*datad)(void *), const char *registrar)
4109 int ret = -1;
4110 struct ast_context *c = find_context_locked(context);
4112 if (c) {
4113 ret = ast_add_extension2(c, replace, extension, priority, label, callerid,
4114 application, data, datad, registrar);
4115 ast_unlock_contexts();
4117 return ret;
4120 int ast_explicit_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
4122 if (!chan)
4123 return -1;
4125 if (!ast_strlen_zero(context))
4126 ast_copy_string(chan->context, context, sizeof(chan->context));
4127 if (!ast_strlen_zero(exten))
4128 ast_copy_string(chan->exten, exten, sizeof(chan->exten));
4129 if (priority > -1) {
4130 chan->priority = priority;
4131 /* see flag description in channel.h for explanation */
4132 if (ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP))
4133 chan->priority--;
4136 return 0;
4139 int ast_async_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
4141 int res = 0;
4143 ast_channel_lock(chan);
4145 if (chan->pbx) { /* This channel is currently in the PBX */
4146 ast_explicit_goto(chan, context, exten, priority);
4147 ast_softhangup_nolock(chan, AST_SOFTHANGUP_ASYNCGOTO);
4148 } else {
4149 /* In order to do it when the channel doesn't really exist within
4150 the PBX, we have to make a new channel, masquerade, and start the PBX
4151 at the new location */
4152 struct ast_channel *tmpchan = ast_channel_alloc(0);
4153 if (!tmpchan)
4154 res = -1;
4155 else {
4156 ast_string_field_build(tmpchan, name, "AsyncGoto/%s", chan->name);
4157 ast_setstate(tmpchan, chan->_state);
4158 /* Make formats okay */
4159 tmpchan->readformat = chan->readformat;
4160 tmpchan->writeformat = chan->writeformat;
4161 /* Setup proper location */
4162 ast_explicit_goto(tmpchan,
4163 S_OR(context, chan->context), S_OR(exten, chan->exten), priority);
4165 /* Masquerade into temp channel */
4166 ast_channel_masquerade(tmpchan, chan);
4168 /* Grab the locks and get going */
4169 ast_channel_lock(tmpchan);
4170 ast_do_masquerade(tmpchan);
4171 ast_channel_unlock(tmpchan);
4172 /* Start the PBX going on our stolen channel */
4173 if (ast_pbx_start(tmpchan)) {
4174 ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmpchan->name);
4175 ast_hangup(tmpchan);
4176 res = -1;
4180 ast_channel_unlock(chan);
4181 return res;
4184 int ast_async_goto_by_name(const char *channame, const char *context, const char *exten, int priority)
4186 struct ast_channel *chan;
4187 int res = -1;
4189 chan = ast_get_channel_by_name_locked(channame);
4190 if (chan) {
4191 res = ast_async_goto(chan, context, exten, priority);
4192 ast_channel_unlock(chan);
4194 return res;
4197 /*! \brief copy a string skipping whitespace */
4198 static int ext_strncpy(char *dst, const char *src, int len)
4200 int count=0;
4202 while (*src && (count < len - 1)) {
4203 switch(*src) {
4204 case ' ':
4205 /* otherwise exten => [a-b],1,... doesn't work */
4206 /* case '-': */
4207 /* Ignore */
4208 break;
4209 default:
4210 *dst = *src;
4211 dst++;
4213 src++;
4214 count++;
4216 *dst = '\0';
4218 return count;
4221 static void null_datad(void *foo)
4225 /*! \brief add the extension in the priority chain.
4226 * returns 0 on success, -1 on failure
4228 static int add_pri(struct ast_context *con, struct ast_exten *tmp,
4229 struct ast_exten *el, struct ast_exten *e, int replace)
4231 struct ast_exten *ep;
4233 for (ep = NULL; e ; ep = e, e = e->peer) {
4234 if (e->priority >= tmp->priority)
4235 break;
4237 if (!e) { /* go at the end, and ep is surely set because the list is not empty */
4238 ep->peer = tmp;
4239 return 0; /* success */
4241 if (e->priority == tmp->priority) {
4242 /* Can't have something exactly the same. Is this a
4243 replacement? If so, replace, otherwise, bonk. */
4244 if (!replace) {
4245 ast_log(LOG_WARNING, "Unable to register extension '%s', priority %d in '%s', already in use\n", tmp->exten, tmp->priority, con->name);
4246 tmp->datad(tmp->data);
4247 free(tmp);
4248 return -1;
4250 /* we are replacing e, so copy the link fields and then update
4251 * whoever pointed to e to point to us
4253 tmp->next = e->next; /* not meaningful if we are not first in the peer list */
4254 tmp->peer = e->peer; /* always meaningful */
4255 if (ep) /* We're in the peer list, just insert ourselves */
4256 ep->peer = tmp;
4257 else if (el) /* We're the first extension. Take over e's functions */
4258 el->next = tmp;
4259 else /* We're the very first extension. */
4260 con->root = tmp;
4261 if (tmp->priority == PRIORITY_HINT)
4262 ast_change_hint(e,tmp);
4263 /* Destroy the old one */
4264 e->datad(e->data);
4265 free(e);
4266 } else { /* Slip ourselves in just before e */
4267 tmp->peer = e;
4268 tmp->next = e->next; /* extension chain, or NULL if e is not the first extension */
4269 if (ep) /* Easy enough, we're just in the peer list */
4270 ep->peer = tmp;
4271 else { /* we are the first in some peer list, so link in the ext list */
4272 if (el)
4273 el->next = tmp; /* in the middle... */
4274 else
4275 con->root = tmp; /* ... or at the head */
4276 e->next = NULL; /* e is no more at the head, so e->next must be reset */
4278 /* And immediately return success. */
4279 if (tmp->priority == PRIORITY_HINT)
4280 ast_add_hint(tmp);
4282 return 0;
4285 /*! \brief
4286 * Main interface to add extensions to the list for out context.
4288 * We sort extensions in order of matching preference, so that we can
4289 * stop the search as soon as we find a suitable match.
4290 * This ordering also takes care of wildcards such as '.' (meaning
4291 * "one or more of any character") and '!' (which is 'earlymatch',
4292 * meaning "zero or more of any character" but also impacts the
4293 * return value from CANMATCH and EARLYMATCH.
4295 * The extension match rules defined in the devmeeting 2006.05.05 are
4296 * quite simple: WE SELECT THE LONGEST MATCH.
4297 * In detail, "longest" means the number of matched characters in
4298 * the extension. In case of ties (e.g. _XXX and 333) in the length
4299 * of a pattern, we give priority to entries with the smallest cardinality
4300 * (e.g, [5-9] comes before [2-8] before the former has only 5 elements,
4301 * while the latter has 7, etc.
4302 * In case of same cardinality, the first element in the range counts.
4303 * If we still have a tie, any final '!' will make this as a possibly
4304 * less specific pattern.
4306 * EBUSY - can't lock
4307 * EEXIST - extension with the same priority exist and no replace is set
4310 int ast_add_extension2(struct ast_context *con,
4311 int replace, const char *extension, int priority, const char *label, const char *callerid,
4312 const char *application, void *data, void (*datad)(void *),
4313 const char *registrar)
4316 * Sort extensions (or patterns) according to the rules indicated above.
4317 * These are implemented by the function ext_cmp()).
4318 * All priorities for the same ext/pattern/cid are kept in a list,
4319 * using the 'peer' field as a link field..
4321 struct ast_exten *tmp, *e, *el = NULL;
4322 int res;
4323 int length;
4324 char *p;
4325 char expand_buf[VAR_BUF_SIZE] = { 0, };
4327 /* if we are adding a hint, and there are global variables, and the hint
4328 contains variable references, then expand them
4330 ast_mutex_lock(&globalslock);
4331 if (priority == PRIORITY_HINT && AST_LIST_FIRST(&globals) && strstr(application, "${")) {
4332 pbx_substitute_variables_varshead(&globals, application, expand_buf, sizeof(expand_buf));
4333 application = expand_buf;
4335 ast_mutex_unlock(&globalslock);
4337 length = sizeof(struct ast_exten);
4338 length += strlen(extension) + 1;
4339 length += strlen(application) + 1;
4340 if (label)
4341 length += strlen(label) + 1;
4342 if (callerid)
4343 length += strlen(callerid) + 1;
4344 else
4345 length ++; /* just the '\0' */
4347 /* Be optimistic: Build the extension structure first */
4348 if (datad == NULL)
4349 datad = null_datad;
4350 if (!(tmp = ast_calloc(1, length)))
4351 return -1;
4353 /* use p as dst in assignments, as the fields are const char * */
4354 p = tmp->stuff;
4355 if (label) {
4356 tmp->label = p;
4357 strcpy(p, label);
4358 p += strlen(label) + 1;
4360 tmp->exten = p;
4361 p += ext_strncpy(p, extension, strlen(extension) + 1) + 1;
4362 tmp->priority = priority;
4363 tmp->cidmatch = p; /* but use p for assignments below */
4364 if (callerid) {
4365 p += ext_strncpy(p, callerid, strlen(callerid) + 1) + 1;
4366 tmp->matchcid = 1;
4367 } else {
4368 *p++ = '\0';
4369 tmp->matchcid = 0;
4371 tmp->app = p;
4372 strcpy(p, application);
4373 tmp->parent = con;
4374 tmp->data = data;
4375 tmp->datad = datad;
4376 tmp->registrar = registrar;
4378 ast_mutex_lock(&con->lock);
4379 res = 0; /* some compilers will think it is uninitialized otherwise */
4380 for (e = con->root; e; el = e, e = e->next) { /* scan the extension list */
4381 res = ext_cmp(e->exten, extension);
4382 if (res == 0) { /* extension match, now look at cidmatch */
4383 if (!e->matchcid && !tmp->matchcid)
4384 res = 0;
4385 else if (tmp->matchcid && !e->matchcid)
4386 res = 1;
4387 else if (e->matchcid && !tmp->matchcid)
4388 res = -1;
4389 else
4390 res = strcasecmp(e->cidmatch, tmp->cidmatch);
4392 if (res >= 0)
4393 break;
4395 if (e && res == 0) { /* exact match, insert in the pri chain */
4396 res = add_pri(con, tmp, el, e, replace);
4397 ast_mutex_unlock(&con->lock);
4398 if (res < 0) {
4399 errno = EEXIST; /* XXX do we care ? */
4400 return 0; /* XXX should we return -1 maybe ? */
4402 } else {
4404 * not an exact match, this is the first entry with this pattern,
4405 * so insert in the main list right before 'e' (if any)
4407 tmp->next = e;
4408 if (el)
4409 el->next = tmp;
4410 else
4411 con->root = tmp;
4412 ast_mutex_unlock(&con->lock);
4413 if (tmp->priority == PRIORITY_HINT)
4414 ast_add_hint(tmp);
4416 if (option_debug) {
4417 if (tmp->matchcid) {
4418 ast_log(LOG_DEBUG, "Added extension '%s' priority %d (CID match '%s') to %s\n",
4419 tmp->exten, tmp->priority, tmp->cidmatch, con->name);
4420 } else {
4421 ast_log(LOG_DEBUG, "Added extension '%s' priority %d to %s\n",
4422 tmp->exten, tmp->priority, con->name);
4424 } else if (option_verbose > 2) {
4425 if (tmp->matchcid) {
4426 ast_verbose( VERBOSE_PREFIX_3 "Added extension '%s' priority %d (CID match '%s')to %s\n",
4427 tmp->exten, tmp->priority, tmp->cidmatch, con->name);
4428 } else {
4429 ast_verbose( VERBOSE_PREFIX_3 "Added extension '%s' priority %d to %s\n",
4430 tmp->exten, tmp->priority, con->name);
4433 return 0;
4436 struct async_stat {
4437 pthread_t p;
4438 struct ast_channel *chan;
4439 char context[AST_MAX_CONTEXT];
4440 char exten[AST_MAX_EXTENSION];
4441 int priority;
4442 int timeout;
4443 char app[AST_MAX_EXTENSION];
4444 char appdata[1024];
4447 static void *async_wait(void *data)
4449 struct async_stat *as = data;
4450 struct ast_channel *chan = as->chan;
4451 int timeout = as->timeout;
4452 int res;
4453 struct ast_frame *f;
4454 struct ast_app *app;
4456 while (timeout && (chan->_state != AST_STATE_UP)) {
4457 res = ast_waitfor(chan, timeout);
4458 if (res < 1)
4459 break;
4460 if (timeout > -1)
4461 timeout = res;
4462 f = ast_read(chan);
4463 if (!f)
4464 break;
4465 if (f->frametype == AST_FRAME_CONTROL) {
4466 if ((f->subclass == AST_CONTROL_BUSY) ||
4467 (f->subclass == AST_CONTROL_CONGESTION) ) {
4468 ast_frfree(f);
4469 break;
4472 ast_frfree(f);
4474 if (chan->_state == AST_STATE_UP) {
4475 if (!ast_strlen_zero(as->app)) {
4476 app = pbx_findapp(as->app);
4477 if (app) {
4478 if (option_verbose > 2)
4479 ast_verbose(VERBOSE_PREFIX_3 "Launching %s(%s) on %s\n", as->app, as->appdata, chan->name);
4480 pbx_exec(chan, app, as->appdata);
4481 } else
4482 ast_log(LOG_WARNING, "No such application '%s'\n", as->app);
4483 } else {
4484 if (!ast_strlen_zero(as->context))
4485 ast_copy_string(chan->context, as->context, sizeof(chan->context));
4486 if (!ast_strlen_zero(as->exten))
4487 ast_copy_string(chan->exten, as->exten, sizeof(chan->exten));
4488 if (as->priority > 0)
4489 chan->priority = as->priority;
4490 /* Run the PBX */
4491 if (ast_pbx_run(chan)) {
4492 ast_log(LOG_ERROR, "Failed to start PBX on %s\n", chan->name);
4493 } else {
4494 /* PBX will have taken care of this */
4495 chan = NULL;
4499 free(as);
4500 if (chan)
4501 ast_hangup(chan);
4502 return NULL;
4505 /*! Function to post an empty cdr after a spool call fails.
4507 * This function posts an empty cdr for a failed spool call
4510 static int ast_pbx_outgoing_cdr_failed(void)
4512 /* allocate a channel */
4513 struct ast_channel *chan = ast_channel_alloc(0);
4515 if (!chan)
4516 return -1; /* failure */
4518 chan->cdr = ast_cdr_alloc(); /* allocate a cdr for the channel */
4520 if (!chan->cdr) {
4521 /* allocation of the cdr failed */
4522 ast_channel_free(chan); /* free the channel */
4523 return -1; /* return failure */
4526 /* allocation of the cdr was successful */
4527 ast_cdr_init(chan->cdr, chan); /* initilize our channel's cdr */
4528 ast_cdr_start(chan->cdr); /* record the start and stop time */
4529 ast_cdr_end(chan->cdr);
4530 ast_cdr_failed(chan->cdr); /* set the status to failed */
4531 ast_cdr_detach(chan->cdr); /* post and free the record */
4532 ast_channel_free(chan); /* free the channel */
4534 return 0; /* success */
4537 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)
4539 struct ast_channel *chan;
4540 struct async_stat *as;
4541 int res = -1, cdr_res = -1;
4542 struct outgoing_helper oh;
4543 pthread_attr_t attr;
4545 if (sync) {
4546 LOAD_OH(oh);
4547 chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
4548 if (channel) {
4549 *channel = chan;
4550 if (chan)
4551 ast_channel_lock(chan);
4553 if (chan) {
4554 if (chan->cdr) { /* check if the channel already has a cdr record, if not give it one */
4555 ast_log(LOG_WARNING, "%s already has a call record??\n", chan->name);
4556 } else {
4557 chan->cdr = ast_cdr_alloc(); /* allocate a cdr for the channel */
4558 if (!chan->cdr) {
4559 /* allocation of the cdr failed */
4560 free(chan->pbx);
4561 res = -1;
4562 goto outgoing_exten_cleanup;
4564 /* allocation of the cdr was successful */
4565 ast_cdr_init(chan->cdr, chan); /* initilize our channel's cdr */
4566 ast_cdr_start(chan->cdr);
4568 if (chan->_state == AST_STATE_UP) {
4569 res = 0;
4570 if (option_verbose > 3)
4571 ast_verbose(VERBOSE_PREFIX_4 "Channel %s was answered.\n", chan->name);
4573 if (sync > 1) {
4574 if (channel)
4575 ast_channel_unlock(chan);
4576 if (ast_pbx_run(chan)) {
4577 ast_log(LOG_ERROR, "Unable to run PBX on %s\n", chan->name);
4578 if (channel)
4579 *channel = NULL;
4580 ast_hangup(chan);
4581 res = -1;
4583 } else {
4584 if (ast_pbx_start(chan)) {
4585 ast_log(LOG_ERROR, "Unable to start PBX on %s\n", chan->name);
4586 if (channel) {
4587 *channel = NULL;
4588 ast_channel_unlock(chan);
4590 ast_hangup(chan);
4591 res = -1;
4594 } else {
4595 if (option_verbose > 3)
4596 ast_verbose(VERBOSE_PREFIX_4 "Channel %s was never answered.\n", chan->name);
4598 if(chan->cdr) { /* update the cdr */
4599 /* here we update the status of the call, which sould be busy.
4600 * if that fails then we set the status to failed */
4601 if (ast_cdr_disposition(chan->cdr, chan->hangupcause))
4602 ast_cdr_failed(chan->cdr);
4605 if (channel) {
4606 *channel = NULL;
4607 ast_channel_unlock(chan);
4609 ast_hangup(chan);
4613 if (res < 0) { /* the call failed for some reason */
4614 if (*reason == 0) { /* if the call failed (not busy or no answer)
4615 * update the cdr with the failed message */
4616 cdr_res = ast_pbx_outgoing_cdr_failed();
4617 if (cdr_res != 0) {
4618 res = cdr_res;
4619 goto outgoing_exten_cleanup;
4623 /* create a fake channel and execute the "failed" extension (if it exists) within the requested context */
4624 /* check if "failed" exists */
4625 if (ast_exists_extension(chan, context, "failed", 1, NULL)) {
4626 chan = ast_channel_alloc(0);
4627 if (chan) {
4628 ast_string_field_set(chan, name, "OutgoingSpoolFailed");
4629 if (!ast_strlen_zero(context))
4630 ast_copy_string(chan->context, context, sizeof(chan->context));
4631 set_ext_pri(chan, "failed", 1);
4632 ast_set_variables(chan, vars);
4633 if (account)
4634 ast_cdr_setaccount(chan, account);
4635 ast_pbx_run(chan);
4639 } else {
4640 if (!(as = ast_calloc(1, sizeof(*as)))) {
4641 res = -1;
4642 goto outgoing_exten_cleanup;
4644 chan = ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name);
4645 if (channel) {
4646 *channel = chan;
4647 if (chan)
4648 ast_channel_lock(chan);
4650 if (!chan) {
4651 free(as);
4652 res = -1;
4653 goto outgoing_exten_cleanup;
4655 as->chan = chan;
4656 ast_copy_string(as->context, context, sizeof(as->context));
4657 set_ext_pri(as->chan, exten, priority);
4658 as->timeout = timeout;
4659 ast_set_variables(chan, vars);
4660 if (account)
4661 ast_cdr_setaccount(chan, account);
4662 pthread_attr_init(&attr);
4663 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
4664 if (ast_pthread_create(&as->p, &attr, async_wait, as)) {
4665 ast_log(LOG_WARNING, "Failed to start async wait\n");
4666 free(as);
4667 if (channel) {
4668 *channel = NULL;
4669 ast_channel_unlock(chan);
4671 ast_hangup(chan);
4672 res = -1;
4673 goto outgoing_exten_cleanup;
4675 res = 0;
4677 outgoing_exten_cleanup:
4678 ast_variables_destroy(vars);
4679 return res;
4682 struct app_tmp {
4683 char app[256];
4684 char data[256];
4685 struct ast_channel *chan;
4686 pthread_t t;
4689 /*! \brief run the application and free the descriptor once done */
4690 static void *ast_pbx_run_app(void *data)
4692 struct app_tmp *tmp = data;
4693 struct ast_app *app;
4694 app = pbx_findapp(tmp->app);
4695 if (app) {
4696 if (option_verbose > 3)
4697 ast_verbose(VERBOSE_PREFIX_4 "Launching %s(%s) on %s\n", tmp->app, tmp->data, tmp->chan->name);
4698 pbx_exec(tmp->chan, app, tmp->data);
4699 } else
4700 ast_log(LOG_WARNING, "No such application '%s'\n", tmp->app);
4701 ast_hangup(tmp->chan);
4702 free(tmp);
4703 return NULL;
4706 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)
4708 struct ast_channel *chan;
4709 struct app_tmp *tmp;
4710 int res = -1, cdr_res = -1;
4711 struct outgoing_helper oh;
4712 pthread_attr_t attr;
4714 memset(&oh, 0, sizeof(oh));
4715 oh.vars = vars;
4716 oh.account = account;
4718 if (locked_channel)
4719 *locked_channel = NULL;
4720 if (ast_strlen_zero(app)) {
4721 res = -1;
4722 goto outgoing_app_cleanup;
4724 if (sync) {
4725 chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
4726 if (chan) {
4727 if (chan->cdr) { /* check if the channel already has a cdr record, if not give it one */
4728 ast_log(LOG_WARNING, "%s already has a call record??\n", chan->name);
4729 } else {
4730 chan->cdr = ast_cdr_alloc(); /* allocate a cdr for the channel */
4731 if(!chan->cdr) {
4732 /* allocation of the cdr failed */
4733 free(chan->pbx);
4734 res = -1;
4735 goto outgoing_app_cleanup;
4737 /* allocation of the cdr was successful */
4738 ast_cdr_init(chan->cdr, chan); /* initilize our channel's cdr */
4739 ast_cdr_start(chan->cdr);
4741 ast_set_variables(chan, vars);
4742 if (account)
4743 ast_cdr_setaccount(chan, account);
4744 if (chan->_state == AST_STATE_UP) {
4745 res = 0;
4746 if (option_verbose > 3)
4747 ast_verbose(VERBOSE_PREFIX_4 "Channel %s was answered.\n", chan->name);
4748 tmp = ast_calloc(1, sizeof(*tmp));
4749 if (!tmp)
4750 res = -1;
4751 else {
4752 ast_copy_string(tmp->app, app, sizeof(tmp->app));
4753 if (appdata)
4754 ast_copy_string(tmp->data, appdata, sizeof(tmp->data));
4755 tmp->chan = chan;
4756 if (sync > 1) {
4757 if (locked_channel)
4758 ast_channel_unlock(chan);
4759 ast_pbx_run_app(tmp);
4760 } else {
4761 pthread_attr_init(&attr);
4762 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
4763 if (locked_channel)
4764 ast_channel_lock(chan);
4765 if (ast_pthread_create(&tmp->t, &attr, ast_pbx_run_app, tmp)) {
4766 ast_log(LOG_WARNING, "Unable to spawn execute thread on %s: %s\n", chan->name, strerror(errno));
4767 free(tmp);
4768 if (locked_channel)
4769 ast_channel_unlock(chan);
4770 ast_hangup(chan);
4771 res = -1;
4772 } else {
4773 if (locked_channel)
4774 *locked_channel = chan;
4778 } else {
4779 if (option_verbose > 3)
4780 ast_verbose(VERBOSE_PREFIX_4 "Channel %s was never answered.\n", chan->name);
4781 if (chan->cdr) { /* update the cdr */
4782 /* here we update the status of the call, which sould be busy.
4783 * if that fails then we set the status to failed */
4784 if (ast_cdr_disposition(chan->cdr, chan->hangupcause))
4785 ast_cdr_failed(chan->cdr);
4787 ast_hangup(chan);
4791 if (res < 0) { /* the call failed for some reason */
4792 if (*reason == 0) { /* if the call failed (not busy or no answer)
4793 * update the cdr with the failed message */
4794 cdr_res = ast_pbx_outgoing_cdr_failed();
4795 if (cdr_res != 0) {
4796 res = cdr_res;
4797 goto outgoing_app_cleanup;
4802 } else {
4803 struct async_stat *as;
4804 if (!(as = ast_calloc(1, sizeof(*as)))) {
4805 res = -1;
4806 goto outgoing_app_cleanup;
4808 chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
4809 if (!chan) {
4810 free(as);
4811 res = -1;
4812 goto outgoing_app_cleanup;
4814 as->chan = chan;
4815 ast_copy_string(as->app, app, sizeof(as->app));
4816 if (appdata)
4817 ast_copy_string(as->appdata, appdata, sizeof(as->appdata));
4818 as->timeout = timeout;
4819 ast_set_variables(chan, vars);
4820 if (account)
4821 ast_cdr_setaccount(chan, account);
4822 /* Start a new thread, and get something handling this channel. */
4823 pthread_attr_init(&attr);
4824 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
4825 if (locked_channel)
4826 ast_channel_lock(chan);
4827 if (ast_pthread_create(&as->p, &attr, async_wait, as)) {
4828 ast_log(LOG_WARNING, "Failed to start async wait\n");
4829 free(as);
4830 if (locked_channel)
4831 ast_channel_unlock(chan);
4832 ast_hangup(chan);
4833 res = -1;
4834 goto outgoing_app_cleanup;
4835 } else {
4836 if (locked_channel)
4837 *locked_channel = chan;
4839 res = 0;
4841 outgoing_app_cleanup:
4842 ast_variables_destroy(vars);
4843 return res;
4846 void __ast_context_destroy(struct ast_context *con, const char *registrar)
4848 struct ast_context *tmp, *tmpl=NULL;
4849 struct ast_include *tmpi;
4850 struct ast_sw *sw;
4851 struct ast_exten *e, *el, *en;
4852 struct ast_ignorepat *ipi;
4854 ast_mutex_lock(&conlock);
4855 for (tmp = contexts; tmp; ) {
4856 struct ast_context *next; /* next starting point */
4857 for (; tmp; tmpl = tmp, tmp = tmp->next) {
4858 ast_log(LOG_DEBUG, "check ctx %s %s\n", tmp->name, tmp->registrar);
4859 if ( (!registrar || !strcasecmp(registrar, tmp->registrar)) &&
4860 (!con || !strcasecmp(tmp->name, con->name)) )
4861 break; /* found it */
4863 if (!tmp) /* not found, we are done */
4864 break;
4865 ast_mutex_lock(&tmp->lock);
4866 ast_log(LOG_DEBUG, "delete ctx %s %s\n", tmp->name, tmp->registrar);
4867 next = tmp->next;
4868 if (tmpl)
4869 tmpl->next = next;
4870 else
4871 contexts = next;
4872 /* Okay, now we're safe to let it go -- in a sense, we were
4873 ready to let it go as soon as we locked it. */
4874 ast_mutex_unlock(&tmp->lock);
4875 for (tmpi = tmp->includes; tmpi; ) { /* Free includes */
4876 struct ast_include *tmpil = tmpi;
4877 tmpi = tmpi->next;
4878 free(tmpil);
4880 for (ipi = tmp->ignorepats; ipi; ) { /* Free ignorepats */
4881 struct ast_ignorepat *ipl = ipi;
4882 ipi = ipi->next;
4883 free(ipl);
4885 while ((sw = AST_LIST_REMOVE_HEAD(&tmp->alts, list)))
4886 free(sw);
4887 for (e = tmp->root; e;) {
4888 for (en = e->peer; en;) {
4889 el = en;
4890 en = en->peer;
4891 destroy_exten(el);
4893 el = e;
4894 e = e->next;
4895 destroy_exten(el);
4897 ast_mutex_destroy(&tmp->lock);
4898 free(tmp);
4899 /* if we have a specific match, we are done, otherwise continue */
4900 tmp = con ? NULL : next;
4902 ast_mutex_unlock(&conlock);
4905 void ast_context_destroy(struct ast_context *con, const char *registrar)
4907 __ast_context_destroy(con,registrar);
4910 static void wait_for_hangup(struct ast_channel *chan, void *data)
4912 int res;
4913 struct ast_frame *f;
4914 int waittime;
4916 if (ast_strlen_zero(data) || (sscanf(data, "%d", &waittime) != 1) || (waittime < 0))
4917 waittime = -1;
4918 if (waittime > -1) {
4919 ast_safe_sleep(chan, waittime * 1000);
4920 } else do {
4921 res = ast_waitfor(chan, -1);
4922 if (res < 0)
4923 return;
4924 f = ast_read(chan);
4925 if (f)
4926 ast_frfree(f);
4927 } while(f);
4931 * \ingroup applications
4933 static int pbx_builtin_progress(struct ast_channel *chan, void *data)
4935 ast_indicate(chan, AST_CONTROL_PROGRESS);
4936 return 0;
4940 * \ingroup applications
4942 static int pbx_builtin_ringing(struct ast_channel *chan, void *data)
4944 ast_indicate(chan, AST_CONTROL_RINGING);
4945 return 0;
4949 * \ingroup applications
4951 static int pbx_builtin_busy(struct ast_channel *chan, void *data)
4953 ast_indicate(chan, AST_CONTROL_BUSY);
4954 /* Don't change state of an UP channel, just indicate
4955 busy in audio */
4956 if (chan->_state != AST_STATE_UP)
4957 ast_setstate(chan, AST_STATE_BUSY);
4958 wait_for_hangup(chan, data);
4959 return -1;
4963 * \ingroup applications
4965 static int pbx_builtin_congestion(struct ast_channel *chan, void *data)
4967 ast_indicate(chan, AST_CONTROL_CONGESTION);
4968 /* Don't change state of an UP channel, just indicate
4969 congestion in audio */
4970 if (chan->_state != AST_STATE_UP)
4971 ast_setstate(chan, AST_STATE_BUSY);
4972 wait_for_hangup(chan, data);
4973 return -1;
4977 * \ingroup applications
4979 static int pbx_builtin_answer(struct ast_channel *chan, void *data)
4981 int delay = 0;
4982 int res;
4984 if (chan->_state == AST_STATE_UP)
4985 delay = 0;
4986 else if (!ast_strlen_zero(data))
4987 delay = atoi(data);
4989 res = ast_answer(chan);
4990 if (res)
4991 return res;
4993 if (delay)
4994 res = ast_safe_sleep(chan, delay);
4996 return res;
4999 AST_APP_OPTIONS(resetcdr_opts, {
5000 AST_APP_OPTION('w', AST_CDR_FLAG_POSTED),
5001 AST_APP_OPTION('a', AST_CDR_FLAG_LOCKED),
5002 AST_APP_OPTION('v', AST_CDR_FLAG_KEEP_VARS),
5006 * \ingroup applications
5008 static int pbx_builtin_resetcdr(struct ast_channel *chan, void *data)
5010 char *args;
5011 struct ast_flags flags = { 0 };
5013 if (!ast_strlen_zero(data)) {
5014 args = ast_strdupa(data);
5015 ast_app_parse_options(resetcdr_opts, &flags, NULL, args);
5018 ast_cdr_reset(chan->cdr, &flags);
5020 return 0;
5024 * \ingroup applications
5026 static int pbx_builtin_setamaflags(struct ast_channel *chan, void *data)
5028 /* Copy the AMA Flags as specified */
5029 ast_cdr_setamaflags(chan, data ? data : "");
5030 return 0;
5034 * \ingroup applications
5036 static int pbx_builtin_hangup(struct ast_channel *chan, void *data)
5038 if (!ast_strlen_zero(data)) {
5039 int cause;
5040 char *endptr;
5042 if ((cause = ast_str2cause(data)) > -1) {
5043 chan->hangupcause = cause;
5044 return -1;
5047 cause = strtol((const char *) data, &endptr, 10);
5048 if (cause != 0 || (data != endptr)) {
5049 chan->hangupcause = cause;
5050 return -1;
5053 ast_log(LOG_NOTICE, "Invalid cause given to Hangup(): \"%s\"\n", (char *) data);
5056 if (!chan->hangupcause) {
5057 chan->hangupcause = AST_CAUSE_NORMAL_CLEARING;
5060 return -1;
5064 * \ingroup applications
5066 static int pbx_builtin_gotoiftime(struct ast_channel *chan, void *data)
5068 int res=0;
5069 char *s, *ts;
5070 struct ast_timing timing;
5072 if (ast_strlen_zero(data)) {
5073 ast_log(LOG_WARNING, "GotoIfTime requires an argument:\n <time range>|<days of week>|<days of month>|<months>?[[context|]extension|]priority\n");
5074 return -1;
5077 ts = s = ast_strdupa(data);
5079 /* Separate the Goto path */
5080 strsep(&ts,"?");
5082 /* struct ast_include include contained garbage here, fixed by zeroing it on get_timerange */
5083 if (ast_build_timing(&timing, s) && ast_check_timing(&timing))
5084 res = pbx_builtin_goto(chan, ts);
5086 return res;
5090 * \ingroup applications
5092 static int pbx_builtin_execiftime(struct ast_channel *chan, void *data)
5094 char *s, *appname;
5095 struct ast_timing timing;
5096 struct ast_app *app;
5097 static const char *usage = "ExecIfTime requires an argument:\n <time range>|<days of week>|<days of month>|<months>?<appname>[|<appargs>]";
5099 if (ast_strlen_zero(data)) {
5100 ast_log(LOG_WARNING, "%s\n", usage);
5101 return -1;
5104 appname = ast_strdupa(data);
5106 s = strsep(&appname,"?"); /* Separate the timerange and application name/data */
5107 if (!appname) { /* missing application */
5108 ast_log(LOG_WARNING, "%s\n", usage);
5109 return -1;
5112 if (!ast_build_timing(&timing, s)) {
5113 ast_log(LOG_WARNING, "Invalid Time Spec: %s\nCorrect usage: %s\n", s, usage);
5114 return -1;
5117 if (!ast_check_timing(&timing)) /* outside the valid time window, just return */
5118 return 0;
5120 /* now split appname|appargs */
5121 if ((s = strchr(appname, '|')))
5122 *s++ = '\0';
5124 if ((app = pbx_findapp(appname))) {
5125 return pbx_exec(chan, app, S_OR(s, ""));
5126 } else {
5127 ast_log(LOG_WARNING, "Cannot locate application %s\n", appname);
5128 return -1;
5133 * \ingroup applications
5135 static int pbx_builtin_wait(struct ast_channel *chan, void *data)
5137 int ms;
5139 /* Wait for "n" seconds */
5140 if (data && (ms = atof(data)) > 0) {
5141 ms *= 1000;
5142 return ast_safe_sleep(chan, ms);
5144 return 0;
5148 * \ingroup applications
5150 static int pbx_builtin_waitexten(struct ast_channel *chan, void *data)
5152 int ms, res;
5153 struct ast_flags flags = {0};
5154 char *opts[1] = { NULL };
5155 char *parse;
5156 AST_DECLARE_APP_ARGS(args,
5157 AST_APP_ARG(timeout);
5158 AST_APP_ARG(options);
5161 if (!ast_strlen_zero(data)) {
5162 parse = ast_strdupa(data);
5163 AST_STANDARD_APP_ARGS(args, parse);
5164 } else
5165 memset(&args, 0, sizeof(args));
5167 if (args.options)
5168 ast_app_parse_options(waitexten_opts, &flags, opts, args.options);
5170 if (ast_test_flag(&flags, WAITEXTEN_MOH))
5171 ast_indicate_data(chan, AST_CONTROL_HOLD, opts[0], strlen(opts[0]));
5173 /* Wait for "n" seconds */
5174 if (args.timeout && (ms = atof(args.timeout)) > 0)
5175 ms *= 1000;
5176 else if (chan->pbx)
5177 ms = chan->pbx->rtimeout * 1000;
5178 else
5179 ms = 10000;
5180 res = ast_waitfordigit(chan, ms);
5181 if (!res) {
5182 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 1, chan->cid.cid_num)) {
5183 if (option_verbose > 2)
5184 ast_verbose(VERBOSE_PREFIX_3 "Timeout on %s, continuing...\n", chan->name);
5185 } else if (ast_exists_extension(chan, chan->context, "t", 1, chan->cid.cid_num)) {
5186 if (option_verbose > 2)
5187 ast_verbose(VERBOSE_PREFIX_3 "Timeout on %s, going to 't'\n", chan->name);
5188 set_ext_pri(chan, "t", 0); /* XXX is the 0 correct ? */
5189 } else {
5190 ast_log(LOG_WARNING, "Timeout but no rule 't' in context '%s'\n", chan->context);
5191 res = -1;
5195 if (ast_test_flag(&flags, WAITEXTEN_MOH))
5196 ast_indicate(chan, AST_CONTROL_UNHOLD);
5198 return res;
5202 * \ingroup applications
5204 static int pbx_builtin_background(struct ast_channel *chan, void *data)
5206 int res = 0;
5207 struct ast_flags flags = {0};
5208 char *parse;
5209 AST_DECLARE_APP_ARGS(args,
5210 AST_APP_ARG(filename);
5211 AST_APP_ARG(options);
5212 AST_APP_ARG(lang);
5213 AST_APP_ARG(context);
5216 if (ast_strlen_zero(data))
5217 ast_log(LOG_WARNING, "Background requires an argument (filename)\n");
5219 parse = ast_strdupa(data);
5221 AST_STANDARD_APP_ARGS(args, parse);
5223 if (!args.lang)
5224 args.lang = (char *)chan->language; /* XXX this is const */
5226 if (!args.context)
5227 args.context = chan->context;
5229 if (args.options) {
5230 if (!strcasecmp(args.options, "skip"))
5231 flags.flags = BACKGROUND_SKIP;
5232 else if (!strcasecmp(args.options, "noanswer"))
5233 flags.flags = BACKGROUND_NOANSWER;
5234 else
5235 ast_app_parse_options(background_opts, &flags, NULL, args.options);
5238 /* Answer if need be */
5239 if (chan->_state != AST_STATE_UP) {
5240 if (ast_test_flag(&flags, BACKGROUND_SKIP)) {
5241 return 0;
5242 } else if (!ast_test_flag(&flags, BACKGROUND_NOANSWER)) {
5243 res = ast_answer(chan);
5247 if (!res) {
5248 char *back = args.filename;
5249 char *front;
5250 ast_stopstream(chan); /* Stop anything playing */
5251 /* Stream the list of files */
5252 while (!res && (front = strsep(&back, "&")) ) {
5253 if ( (res = ast_streamfile(chan, front, args.lang)) ) {
5254 ast_log(LOG_WARNING, "ast_streamfile failed on %s for %s\n", chan->name, (char*)data);
5255 res = 0;
5256 break;
5258 if (ast_test_flag(&flags, BACKGROUND_PLAYBACK)) {
5259 res = ast_waitstream(chan, "");
5260 } else if (ast_test_flag(&flags, BACKGROUND_MATCHEXTEN)) {
5261 res = ast_waitstream_exten(chan, args.context);
5262 } else {
5263 res = ast_waitstream(chan, AST_DIGIT_ANY);
5265 ast_stopstream(chan);
5268 if (args.context != chan->context && res) {
5269 snprintf(chan->exten, sizeof(chan->exten), "%c", res);
5270 ast_copy_string(chan->context, args.context, sizeof(chan->context));
5271 chan->priority = 0;
5272 res = 0;
5274 return res;
5277 /*! Goto
5278 * \ingroup applications
5280 static int pbx_builtin_goto(struct ast_channel *chan, void *data)
5282 int res = ast_parseable_goto(chan, data);
5283 if (!res && (option_verbose > 2))
5284 ast_verbose( VERBOSE_PREFIX_3 "Goto (%s,%s,%d)\n", chan->context,chan->exten, chan->priority+1);
5285 return res;
5289 int pbx_builtin_serialize_variables(struct ast_channel *chan, char *buf, size_t size)
5291 struct ast_var_t *variables;
5292 const char *var, *val;
5293 int total = 0;
5295 if (!chan)
5296 return 0;
5298 memset(buf, 0, size);
5300 AST_LIST_TRAVERSE(&chan->varshead, variables, entries) {
5301 if(variables &&
5302 (var=ast_var_name(variables)) && (val=ast_var_value(variables)) &&
5303 !ast_strlen_zero(var) && !ast_strlen_zero(val)) {
5304 if (ast_build_string(&buf, &size, "%s=%s\n", var, val)) {
5305 ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
5306 break;
5307 } else
5308 total++;
5309 } else
5310 break;
5313 return total;
5316 const char *pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
5318 struct ast_var_t *variables;
5319 const char *ret = NULL;
5320 int i;
5321 struct varshead *places[2] = { NULL, &globals };
5323 if (!name)
5324 return NULL;
5325 if (chan)
5326 places[0] = &chan->varshead;
5328 for (i = 0; i < 2; i++) {
5329 if (!places[i])
5330 continue;
5331 if (places[i] == &globals)
5332 ast_mutex_lock(&globalslock);
5333 AST_LIST_TRAVERSE(places[i], variables, entries) {
5334 if (!strcmp(name, ast_var_name(variables))) {
5335 ret = ast_var_value(variables);
5336 break;
5339 if (places[i] == &globals)
5340 ast_mutex_unlock(&globalslock);
5341 if (ret)
5342 break;
5345 return ret;
5348 void pbx_builtin_pushvar_helper(struct ast_channel *chan, const char *name, const char *value)
5350 struct ast_var_t *newvariable;
5351 struct varshead *headp;
5353 if (name[strlen(name)-1] == ')') {
5354 char *function = ast_strdupa(name);
5356 ast_log(LOG_WARNING, "Cannot push a value onto a function\n");
5357 ast_func_write(chan, function, value);
5358 return;
5361 headp = (chan) ? &chan->varshead : &globals;
5363 if (value) {
5364 if ((option_verbose > 1) && (headp == &globals))
5365 ast_verbose(VERBOSE_PREFIX_2 "Setting global variable '%s' to '%s'\n", name, value);
5366 newvariable = ast_var_assign(name, value);
5367 if (headp == &globals)
5368 ast_mutex_lock(&globalslock);
5369 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
5370 if (headp == &globals)
5371 ast_mutex_unlock(&globalslock);
5375 void pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
5377 struct ast_var_t *newvariable;
5378 struct varshead *headp;
5379 const char *nametail = name;
5381 /* XXX may need locking on the channel ? */
5382 if (name[strlen(name)-1] == ')') {
5383 char *function = ast_strdupa(name);
5385 ast_func_write(chan, function, value);
5386 return;
5389 headp = (chan) ? &chan->varshead : &globals;
5391 /* For comparison purposes, we have to strip leading underscores */
5392 if (*nametail == '_') {
5393 nametail++;
5394 if (*nametail == '_')
5395 nametail++;
5398 if (headp == &globals)
5399 ast_mutex_lock(&globalslock);
5400 AST_LIST_TRAVERSE (headp, newvariable, entries) {
5401 if (strcasecmp(ast_var_name(newvariable), nametail) == 0) {
5402 /* there is already such a variable, delete it */
5403 AST_LIST_REMOVE(headp, newvariable, entries);
5404 ast_var_delete(newvariable);
5405 break;
5409 if (value) {
5410 if ((option_verbose > 1) && (headp == &globals))
5411 ast_verbose(VERBOSE_PREFIX_2 "Setting global variable '%s' to '%s'\n", name, value);
5412 newvariable = ast_var_assign(name, value);
5413 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
5416 if (headp == &globals)
5417 ast_mutex_unlock(&globalslock);
5420 int pbx_builtin_setvar(struct ast_channel *chan, void *data)
5422 char *name, *value, *mydata;
5423 int argc;
5424 char *argv[24]; /* this will only support a maximum of 24 variables being set in a single operation */
5425 int global = 0;
5426 int x;
5428 if (ast_strlen_zero(data)) {
5429 ast_log(LOG_WARNING, "Set requires at least one variable name/value pair.\n");
5430 return 0;
5433 mydata = ast_strdupa(data);
5434 argc = ast_app_separate_args(mydata, '|', argv, sizeof(argv) / sizeof(argv[0]));
5436 /* check for a trailing flags argument */
5437 if ((argc > 1) && !strchr(argv[argc-1], '=')) {
5438 argc--;
5439 if (strchr(argv[argc], 'g'))
5440 global = 1;
5443 for (x = 0; x < argc; x++) {
5444 name = argv[x];
5445 if ((value = strchr(name, '='))) {
5446 *value++ = '\0';
5447 pbx_builtin_setvar_helper((global) ? NULL : chan, name, value);
5448 } else
5449 ast_log(LOG_WARNING, "Ignoring entry '%s' with no = (and not last 'options' entry)\n", name);
5452 return(0);
5455 int pbx_builtin_importvar(struct ast_channel *chan, void *data)
5457 char *name;
5458 char *value;
5459 char *channel;
5460 char tmp[VAR_BUF_SIZE]="";
5462 if (ast_strlen_zero(data)) {
5463 ast_log(LOG_WARNING, "Ignoring, since there is no variable to set\n");
5464 return 0;
5467 value = ast_strdupa(data);
5468 name = strsep(&value,"=");
5469 channel = strsep(&value,"|");
5470 if (channel && value && name) { /*! \todo XXX should do !ast_strlen_zero(..) of the args ? */
5471 struct ast_channel *chan2 = ast_get_channel_by_name_locked(channel);
5472 if (chan2) {
5473 char *s = alloca(strlen(value) + 4);
5474 if (s) {
5475 sprintf(s, "${%s}", value);
5476 pbx_substitute_variables_helper(chan2, s, tmp, sizeof(tmp) - 1);
5478 ast_channel_unlock(chan2);
5480 pbx_builtin_setvar_helper(chan, name, tmp);
5483 return(0);
5486 /*! \todo XXX overwrites data ? */
5487 static int pbx_builtin_setglobalvar(struct ast_channel *chan, void *data)
5489 char *name;
5490 char *stringp = data;
5491 static int dep_warning = 0;
5493 if (ast_strlen_zero(data)) {
5494 ast_log(LOG_WARNING, "Ignoring, since there is no variable to set\n");
5495 return 0;
5498 name = strsep(&stringp, "=");
5500 if (!dep_warning) {
5501 dep_warning = 1;
5502 ast_log(LOG_WARNING, "SetGlobalVar is deprecated. Please use Set(GLOBAL(%s)=%s) instead.\n", name, stringp);
5505 /*! \todo XXX watch out, leading whitespace ? */
5506 pbx_builtin_setvar_helper(NULL, name, stringp);
5508 return(0);
5511 static int pbx_builtin_noop(struct ast_channel *chan, void *data)
5513 return 0;
5516 void pbx_builtin_clear_globals(void)
5518 struct ast_var_t *vardata;
5520 ast_mutex_lock(&globalslock);
5521 while ((vardata = AST_LIST_REMOVE_HEAD(&globals, entries)))
5522 ast_var_delete(vardata);
5523 ast_mutex_unlock(&globalslock);
5526 int pbx_checkcondition(const char *condition)
5528 if (ast_strlen_zero(condition)) /* NULL or empty strings are false */
5529 return 0;
5530 else if (*condition >= '0' && *condition <= '9') /* Numbers are evaluated for truth */
5531 return atoi(condition);
5532 else /* Strings are true */
5533 return 1;
5536 static int pbx_builtin_gotoif(struct ast_channel *chan, void *data)
5538 char *condition, *branch1, *branch2, *branch;
5539 int rc;
5540 char *stringp;
5542 if (ast_strlen_zero(data)) {
5543 ast_log(LOG_WARNING, "Ignoring, since there is no variable to check\n");
5544 return 0;
5547 stringp = ast_strdupa(data);
5548 condition = strsep(&stringp,"?");
5549 branch1 = strsep(&stringp,":");
5550 branch2 = strsep(&stringp,"");
5551 branch = pbx_checkcondition(condition) ? branch1 : branch2;
5553 if (ast_strlen_zero(branch)) {
5554 ast_log(LOG_DEBUG, "Not taking any branch\n");
5555 return 0;
5558 rc = pbx_builtin_goto(chan, branch);
5560 return rc;
5563 static int pbx_builtin_saynumber(struct ast_channel *chan, void *data)
5565 char tmp[256];
5566 char *number = tmp;
5567 char *options;
5569 if (ast_strlen_zero(data)) {
5570 ast_log(LOG_WARNING, "SayNumber requires an argument (number)\n");
5571 return -1;
5573 ast_copy_string(tmp, data, sizeof(tmp));
5574 strsep(&number, "|");
5575 options = strsep(&number, "|");
5576 if (options) {
5577 if ( strcasecmp(options, "f") && strcasecmp(options,"m") &&
5578 strcasecmp(options, "c") && strcasecmp(options, "n") ) {
5579 ast_log(LOG_WARNING, "SayNumber gender option is either 'f', 'm', 'c' or 'n'\n");
5580 return -1;
5583 return ast_say_number(chan, atoi(tmp), "", chan->language, options);
5586 static int pbx_builtin_saydigits(struct ast_channel *chan, void *data)
5588 int res = 0;
5590 if (data)
5591 res = ast_say_digit_str(chan, data, "", chan->language);
5592 return res;
5595 static int pbx_builtin_saycharacters(struct ast_channel *chan, void *data)
5597 int res = 0;
5599 if (data)
5600 res = ast_say_character_str(chan, data, "", chan->language);
5601 return res;
5604 static int pbx_builtin_sayphonetic(struct ast_channel *chan, void *data)
5606 int res = 0;
5608 if (data)
5609 res = ast_say_phonetic_str(chan, data, "", chan->language);
5610 return res;
5613 int load_pbx(void)
5615 int x;
5617 /* Initialize the PBX */
5618 if (option_verbose) {
5619 ast_verbose( "Asterisk PBX Core Initializing\n");
5620 ast_verbose( "Registering builtin applications:\n");
5622 AST_LIST_HEAD_INIT_NOLOCK(&globals);
5623 ast_cli_register_multiple(pbx_cli, sizeof(pbx_cli) / sizeof(pbx_cli[0]));
5625 /* Register builtin applications */
5626 for (x=0; x<sizeof(builtins) / sizeof(struct pbx_builtin); x++) {
5627 if (option_verbose)
5628 ast_verbose( VERBOSE_PREFIX_1 "[%s]\n", builtins[x].name);
5629 if (ast_register_application(builtins[x].name, builtins[x].execute, builtins[x].synopsis, builtins[x].description)) {
5630 ast_log(LOG_ERROR, "Unable to register builtin application '%s'\n", builtins[x].name);
5631 return -1;
5634 return 0;
5638 * Lock context list functions ...
5640 int ast_lock_contexts()
5642 return ast_mutex_lock(&conlock);
5645 int ast_unlock_contexts()
5647 return ast_mutex_unlock(&conlock);
5651 * Lock context ...
5653 int ast_lock_context(struct ast_context *con)
5655 return ast_mutex_lock(&con->lock);
5658 int ast_unlock_context(struct ast_context *con)
5660 return ast_mutex_unlock(&con->lock);
5664 * Name functions ...
5666 const char *ast_get_context_name(struct ast_context *con)
5668 return con ? con->name : NULL;
5671 struct ast_context *ast_get_extension_context(struct ast_exten *exten)
5673 return exten ? exten->parent : NULL;
5676 const char *ast_get_extension_name(struct ast_exten *exten)
5678 return exten ? exten->exten : NULL;
5681 const char *ast_get_extension_label(struct ast_exten *exten)
5683 return exten ? exten->label : NULL;
5686 const char *ast_get_include_name(struct ast_include *inc)
5688 return inc ? inc->name : NULL;
5691 const char *ast_get_ignorepat_name(struct ast_ignorepat *ip)
5693 return ip ? ip->pattern : NULL;
5696 int ast_get_extension_priority(struct ast_exten *exten)
5698 return exten ? exten->priority : -1;
5702 * Registrar info functions ...
5704 const char *ast_get_context_registrar(struct ast_context *c)
5706 return c ? c->registrar : NULL;
5709 const char *ast_get_extension_registrar(struct ast_exten *e)
5711 return e ? e->registrar : NULL;
5714 const char *ast_get_include_registrar(struct ast_include *i)
5716 return i ? i->registrar : NULL;
5719 const char *ast_get_ignorepat_registrar(struct ast_ignorepat *ip)
5721 return ip ? ip->registrar : NULL;
5724 int ast_get_extension_matchcid(struct ast_exten *e)
5726 return e ? e->matchcid : 0;
5729 const char *ast_get_extension_cidmatch(struct ast_exten *e)
5731 return e ? e->cidmatch : NULL;
5734 const char *ast_get_extension_app(struct ast_exten *e)
5736 return e ? e->app : NULL;
5739 void *ast_get_extension_app_data(struct ast_exten *e)
5741 return e ? e->data : NULL;
5744 const char *ast_get_switch_name(struct ast_sw *sw)
5746 return sw ? sw->name : NULL;
5749 const char *ast_get_switch_data(struct ast_sw *sw)
5751 return sw ? sw->data : NULL;
5754 const char *ast_get_switch_registrar(struct ast_sw *sw)
5756 return sw ? sw->registrar : NULL;
5760 * Walking functions ...
5762 struct ast_context *ast_walk_contexts(struct ast_context *con)
5764 return con ? con->next : contexts;
5767 struct ast_exten *ast_walk_context_extensions(struct ast_context *con,
5768 struct ast_exten *exten)
5770 if (!exten)
5771 return con ? con->root : NULL;
5772 else
5773 return exten->next;
5776 struct ast_sw *ast_walk_context_switches(struct ast_context *con,
5777 struct ast_sw *sw)
5779 if (!sw)
5780 return con ? AST_LIST_FIRST(&con->alts) : NULL;
5781 else
5782 return AST_LIST_NEXT(sw, list);
5785 struct ast_exten *ast_walk_extension_priorities(struct ast_exten *exten,
5786 struct ast_exten *priority)
5788 return priority ? priority->peer : exten;
5791 struct ast_include *ast_walk_context_includes(struct ast_context *con,
5792 struct ast_include *inc)
5794 if (!inc)
5795 return con ? con->includes : NULL;
5796 else
5797 return inc->next;
5800 struct ast_ignorepat *ast_walk_context_ignorepats(struct ast_context *con,
5801 struct ast_ignorepat *ip)
5803 if (!ip)
5804 return con ? con->ignorepats : NULL;
5805 else
5806 return ip->next;
5809 int ast_context_verify_includes(struct ast_context *con)
5811 struct ast_include *inc = NULL;
5812 int res = 0;
5814 while ( (inc = ast_walk_context_includes(con, inc)) )
5815 if (!ast_context_find(inc->rname)) {
5816 res = -1;
5817 ast_log(LOG_WARNING, "Context '%s' tries includes nonexistent context '%s'\n",
5818 ast_get_context_name(con), inc->rname);
5820 return res;
5824 static int __ast_goto_if_exists(struct ast_channel *chan, const char *context, const char *exten, int priority, int async)
5826 int (*goto_func)(struct ast_channel *chan, const char *context, const char *exten, int priority);
5828 if (!chan)
5829 return -2;
5831 if (context == NULL)
5832 context = chan->context;
5833 if (exten == NULL)
5834 exten = chan->exten;
5836 goto_func = (async) ? ast_async_goto : ast_explicit_goto;
5837 if (ast_exists_extension(chan, context, exten, priority, chan->cid.cid_num))
5838 return goto_func(chan, context, exten, priority);
5839 else
5840 return -3;
5843 int ast_goto_if_exists(struct ast_channel *chan, const char* context, const char *exten, int priority)
5845 return __ast_goto_if_exists(chan, context, exten, priority, 0);
5848 int ast_async_goto_if_exists(struct ast_channel *chan, const char * context, const char *exten, int priority)
5850 return __ast_goto_if_exists(chan, context, exten, priority, 1);
5853 int ast_parseable_goto(struct ast_channel *chan, const char *goto_string)
5855 char *exten, *pri, *context;
5856 char *stringp;
5857 int ipri;
5858 int mode = 0;
5860 if (ast_strlen_zero(goto_string)) {
5861 ast_log(LOG_WARNING, "Goto requires an argument (optional context|optional extension|priority)\n");
5862 return -1;
5864 stringp = ast_strdupa(goto_string);
5865 context = strsep(&stringp, "|"); /* guaranteed non-null */
5866 exten = strsep(&stringp, "|");
5867 pri = strsep(&stringp, "|");
5868 if (!exten) { /* Only a priority in this one */
5869 pri = context;
5870 exten = NULL;
5871 context = NULL;
5872 } else if (!pri) { /* Only an extension and priority in this one */
5873 pri = exten;
5874 exten = context;
5875 context = NULL;
5877 if (*pri == '+') {
5878 mode = 1;
5879 pri++;
5880 } else if (*pri == '-') {
5881 mode = -1;
5882 pri++;
5884 if (sscanf(pri, "%d", &ipri) != 1) {
5885 if ((ipri = ast_findlabel_extension(chan, context ? context : chan->context, exten ? exten : chan->exten,
5886 pri, chan->cid.cid_num)) < 1) {
5887 ast_log(LOG_WARNING, "Priority '%s' must be a number > 0, or valid label\n", pri);
5888 return -1;
5889 } else
5890 mode = 0;
5892 /* At this point we have a priority and maybe an extension and a context */
5894 if (mode)
5895 ipri = chan->priority + (ipri * mode);
5897 ast_explicit_goto(chan, context, exten, ipri);
5898 ast_cdr_update(chan);
5899 return 0;