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.
21 * \brief Core PBX routines.
23 * \author Mark Spencer <markster@digium.com>
26 #include <sys/types.h>
38 ASTERISK_FILE_VERSION(__FILE__
, "$Revision$")
40 #include "asterisk/lock.h"
41 #include "asterisk/cli.h"
42 #include "asterisk/pbx.h"
43 #include "asterisk/channel.h"
44 #include "asterisk/options.h"
45 #include "asterisk/logger.h"
46 #include "asterisk/file.h"
47 #include "asterisk/callerid.h"
48 #include "asterisk/cdr.h"
49 #include "asterisk/config.h"
50 #include "asterisk/term.h"
51 #include "asterisk/manager.h"
52 #include "asterisk/ast_expr.h"
53 #include "asterisk/linkedlists.h"
54 #define SAY_STUBS /* generate declarations and stubs for say methods */
55 #include "asterisk/say.h"
56 #include "asterisk/utils.h"
57 #include "asterisk/causes.h"
58 #include "asterisk/musiconhold.h"
59 #include "asterisk/app.h"
60 #include "asterisk/devicestate.h"
61 #include "asterisk/compat.h"
62 #include "asterisk/stringfields.h"
65 * \note I M P O R T A N T :
67 * The speed of extension handling will likely be among the most important
68 * aspects of this PBX. The switching scheme as it exists right now isn't
69 * terribly bad (it's O(N+M), where N is the # of extensions and M is the avg #
70 * of priorities, but a constant search time here would be great ;-)
75 #define EXT_DATA_SIZE 256
77 #define EXT_DATA_SIZE 8192
80 #define SWITCH_DATA_LENGTH 256
82 #define VAR_BUF_SIZE 4096
85 #define VAR_SOFTTRAN 2
86 #define VAR_HARDTRAN 3
88 #define BACKGROUND_SKIP (1 << 0)
89 #define BACKGROUND_NOANSWER (1 << 1)
90 #define BACKGROUND_MATCHEXTEN (1 << 2)
91 #define BACKGROUND_PLAYBACK (1 << 3)
93 AST_APP_OPTIONS(background_opts
, {
94 AST_APP_OPTION('s', BACKGROUND_SKIP
),
95 AST_APP_OPTION('n', BACKGROUND_NOANSWER
),
96 AST_APP_OPTION('m', BACKGROUND_MATCHEXTEN
),
97 AST_APP_OPTION('p', BACKGROUND_PLAYBACK
),
100 #define WAITEXTEN_MOH (1 << 0)
102 AST_APP_OPTIONS(waitexten_opts
, {
103 AST_APP_OPTION_ARG('m', WAITEXTEN_MOH
, 1),
109 \brief ast_exten: An extension
110 The dialplan is saved as a linked list with each context
111 having it's own linked list of extensions - one item per
115 char *exten
; /*!< Extension name */
116 int matchcid
; /*!< Match caller id ? */
117 const char *cidmatch
; /*!< Caller id to match for this extension */
118 int priority
; /*!< Priority */
119 const char *label
; /*!< Label */
120 struct ast_context
*parent
; /*!< The context this extension belongs to */
121 const char *app
; /*!< Application to execute */
122 void *data
; /*!< Data to use (arguments) */
123 void (*datad
)(void *); /*!< Data destructor */
124 struct ast_exten
*peer
; /*!< Next higher priority with our extension */
125 const char *registrar
; /*!< Registrar */
126 struct ast_exten
*next
; /*!< Extension with a greater ID */
130 /*! \brief ast_include: include= support in extensions.conf */
133 const char *rname
; /*!< Context to include */
134 const char *registrar
; /*!< Registrar */
135 int hastime
; /*!< If time construct exists */
136 struct ast_timing timing
; /*!< time construct */
137 struct ast_include
*next
; /*!< Link them together */
141 /*! \brief ast_sw: Switch statement in extensions.conf */
144 const char *registrar
; /*!< Registrar */
145 char *data
; /*!< Data load */
147 AST_LIST_ENTRY(ast_sw
) list
;
152 /*! \brief ast_ignorepat: Ignore patterns in dial plan */
153 struct ast_ignorepat
{
154 const char *registrar
;
155 struct ast_ignorepat
*next
;
156 const char pattern
[0];
159 /*! \brief ast_context: An extension context */
161 ast_mutex_t lock
; /*!< A lock to prevent multiple threads from clobbering the context */
162 struct ast_exten
*root
; /*!< The root of the list of extensions */
163 struct ast_context
*next
; /*!< Link them together */
164 struct ast_include
*includes
; /*!< Include other contexts */
165 struct ast_ignorepat
*ignorepats
; /*!< Patterns for which to continue playing dialtone */
166 const char *registrar
; /*!< Registrar */
167 AST_LIST_HEAD_NOLOCK(, ast_sw
) alts
; /*!< Alternative switches */
168 char name
[0]; /*!< Name of the context */
172 /*! \brief ast_app: A registered application */
174 int (*execute
)(struct ast_channel
*chan
, void *data
);
175 const char *synopsis
; /*!< Synopsis text for 'show applications' */
176 const char *description
; /*!< Description (help text) for 'show application <name>' */
177 AST_LIST_ENTRY(ast_app
) list
; /*!< Next app in list */
178 struct module
*module
; /*!< Module this app belongs to */
179 char name
[0]; /*!< Name of the application */
182 /*! \brief ast_state_cb: An extension state notify register item */
183 struct ast_state_cb
{
186 ast_state_cb_type callback
;
187 struct ast_state_cb
*next
;
190 /*! \brief Structure for dial plan hints
192 Hints are pointers from an extension in the dialplan to one or
193 more devices (tech/name) */
195 struct ast_exten
*exten
; /*!< Extension */
196 int laststate
; /*!< Last known state */
197 struct ast_state_cb
*callbacks
; /*!< Callback list for this extension */
198 AST_LIST_ENTRY(ast_hint
) list
; /*!< Pointer to next hint in list */
201 static const struct cfextension_states
{
203 const char * const text
;
204 } extension_states
[] = {
205 { AST_EXTENSION_NOT_INUSE
, "Idle" },
206 { AST_EXTENSION_INUSE
, "InUse" },
207 { AST_EXTENSION_BUSY
, "Busy" },
208 { AST_EXTENSION_UNAVAILABLE
, "Unavailable" },
209 { AST_EXTENSION_RINGING
, "Ringing" },
210 { AST_EXTENSION_INUSE
| AST_EXTENSION_RINGING
, "InUse&Ringing" }
213 int ast_pbx_outgoing_cdr_failed(void);
215 static int pbx_builtin_answer(struct ast_channel
*, void *);
216 static int pbx_builtin_goto(struct ast_channel
*, void *);
217 static int pbx_builtin_hangup(struct ast_channel
*, void *);
218 static int pbx_builtin_background(struct ast_channel
*, void *);
219 static int pbx_builtin_wait(struct ast_channel
*, void *);
220 static int pbx_builtin_waitexten(struct ast_channel
*, void *);
221 static int pbx_builtin_resetcdr(struct ast_channel
*, void *);
222 static int pbx_builtin_setamaflags(struct ast_channel
*, void *);
223 static int pbx_builtin_ringing(struct ast_channel
*, void *);
224 static int pbx_builtin_progress(struct ast_channel
*, void *);
225 static int pbx_builtin_congestion(struct ast_channel
*, void *);
226 static int pbx_builtin_busy(struct ast_channel
*, void *);
227 static int pbx_builtin_setglobalvar(struct ast_channel
*, void *);
228 static int pbx_builtin_noop(struct ast_channel
*, void *);
229 static int pbx_builtin_gotoif(struct ast_channel
*, void *);
230 static int pbx_builtin_gotoiftime(struct ast_channel
*, void *);
231 static int pbx_builtin_execiftime(struct ast_channel
*, void *);
232 static int pbx_builtin_saynumber(struct ast_channel
*, void *);
233 static int pbx_builtin_saydigits(struct ast_channel
*, void *);
234 static int pbx_builtin_saycharacters(struct ast_channel
*, void *);
235 static int pbx_builtin_sayphonetic(struct ast_channel
*, void *);
236 int pbx_builtin_setvar(struct ast_channel
*, void *);
237 static int pbx_builtin_importvar(struct ast_channel
*, void *);
239 AST_MUTEX_DEFINE_STATIC(globalslock
);
240 static struct varshead globals
;
242 static int autofallthrough
= 0;
244 AST_MUTEX_DEFINE_STATIC(maxcalllock
);
245 static int countcalls
= 0;
247 static AST_LIST_HEAD_STATIC(acf_root
, ast_custom_function
);
249 /*! \brief Declaration of builtin applications */
250 static struct pbx_builtin
{
251 char name
[AST_MAX_APP
];
252 int (*execute
)(struct ast_channel
*chan
, void *data
);
257 /* These applications are built into the PBX core and do not
258 need separate modules */
260 { "Answer", pbx_builtin_answer
,
261 "Answer a channel if ringing",
262 " Answer([delay]): If the call has not been answered, this application will\n"
263 "answer it. Otherwise, it has no effect on the call. If a delay is specified,\n"
264 "Asterisk will wait this number of milliseconds before answering the call.\n"
267 { "BackGround", pbx_builtin_background
,
268 "Play an audio file while waiting for digits of an extension to go to.\n",
269 " Background(filename1[&filename2...][|options[|langoverride][|context]]):\n"
270 "This application will play the given list of files while waiting for an\n"
271 "extension to be dialed by the calling channel. To continue waiting for digits\n"
272 "after this application has finished playing files, the WaitExten application\n"
273 "should be used. The 'langoverride' option explicitly specifies which language\n"
274 "to attempt to use for the requested sound files. If a 'context' is specified,\n"
275 "this is the dialplan context that this application will use when exiting to a\n"
277 " If one of the requested sound files does not exist, call processing will be\n"
280 " s - Causes the playback of the message to be skipped\n"
281 " if the channel is not in the 'up' state (i.e. it\n"
282 " hasn't been answered yet). If this happens, the\n"
283 " application will return immediately.\n"
284 " n - Don't answer the channel before playing the files.\n"
285 " m - Only break if a digit hit matches a one digit\n"
286 " extension in the destination context.\n"
289 { "Busy", pbx_builtin_busy
,
290 "Indicate the Busy condition",
291 " Busy([timeout]): This application will indicate the busy condition to\n"
292 "the calling channel. If the optional timeout is specified, the calling channel\n"
293 "will be hung up after the specified number of seconds. Otherwise, this\n"
294 "application will wait until the calling channel hangs up.\n"
297 { "Congestion", pbx_builtin_congestion
,
298 "Indicate the Congestion condition",
299 " Congestion([timeout]): This application will indicate the congestion\n"
300 "condition to the calling channel. If the optional timeout is specified, the\n"
301 "calling channel will be hung up after the specified number of seconds.\n"
302 "Otherwise, this application will wait until the calling channel hangs up.\n"
305 { "Goto", pbx_builtin_goto
,
306 "Jump to a particular priority, extension, or context",
307 " Goto([[context|]extension|]priority): This application will cause the\n"
308 "calling channel to continue dialplan execution at the specified priority.\n"
309 "If no specific extension, or extension and context, are specified, then this\n"
310 "application will jump to the specified priority of the current extension.\n"
311 " If the attempt to jump to another location in the dialplan is not successful,\n"
312 "then the channel will continue at the next priority of the current extension.\n"
315 { "GotoIf", pbx_builtin_gotoif
,
317 " GotoIf(condition?[labeliftrue]:[labeliffalse]): This application will cause\n"
318 "the calling channel to jump to the specified location in the dialplan based on\n"
319 "the evaluation of the given condition. The channel will continue at\n"
320 "'labeliftrue' if the condition is true, or 'labeliffalse' if the condition is\n"
321 "false. The labels are specified with the same syntax as used within the Goto\n"
322 "application. If the label chosen by the condition is omitted, no jump is\n"
323 "performed, but execution continues with the next priority in the dialplan.\n"
326 { "GotoIfTime", pbx_builtin_gotoiftime
,
327 "Conditional Goto based on the current time",
328 " GotoIfTime(<times>|<weekdays>|<mdays>|<months>?[[context|]exten|]priority):\n"
329 "This application will have the calling channel jump to the specified location\n"
330 "in the dialplan if the current time matches the given time specification.\n"
333 { "ExecIfTime", pbx_builtin_execiftime
,
334 "Conditional application execution based on the current time",
335 " ExecIfTime(<times>|<weekdays>|<mdays>|<months>?appname[|appargs]):\n"
336 "This application will execute the specified dialplan application, with optional\n"
337 "arguments, if the current time matches the given time specification.\n"
340 { "Hangup", pbx_builtin_hangup
,
341 "Hang up the calling channel",
342 " Hangup([causecode]): This application will hang up the calling channel.\n"
343 "If a causecode is given the channel's hangup cause will be set to the given\n"
347 { "NoOp", pbx_builtin_noop
,
349 " NoOp(): This applicatiion does nothing. However, it is useful for debugging\n"
350 "purposes. Any text that is provided as arguments to this application can be\n"
351 "viewed at the Asterisk CLI. This method can be used to see the evaluations of\n"
352 "variables or functions without having any effect."
355 { "Progress", pbx_builtin_progress
,
357 " Progress(): This application will request that in-band progress information\n"
358 "be provided to the calling channel.\n"
361 { "ResetCDR", pbx_builtin_resetcdr
,
362 "Resets the Call Data Record",
363 " ResetCDR([options]): This application causes the Call Data Record to be\n"
366 " w -- Store the current CDR record before resetting it.\n"
367 " a -- Store any stacked records.\n"
368 " v -- Save CDR variables.\n"
371 { "Ringing", pbx_builtin_ringing
,
372 "Indicate ringing tone",
373 " Ringing(): This application will request that the channel indicate a ringing\n"
374 "tone to the user.\n"
377 { "SayNumber", pbx_builtin_saynumber
,
379 " SayNumber(digits[,gender]): This application will play the sounds that\n"
380 "correspond to the given number. Optionally, a gender may be specified.\n"
381 "This will use the language that is currently set for the channel. See the\n"
382 "LANGUAGE function for more information on setting the language for the channel.\n"
385 { "SayDigits", pbx_builtin_saydigits
,
387 " SayDigits(digits): This application will play the sounds that correspond\n"
388 "to the digits of the given number. This will use the language that is currently\n"
389 "set for the channel. See the LANGUAGE function for more information on setting\n"
390 "the language for the channel.\n"
393 { "SayAlpha", pbx_builtin_saycharacters
,
395 " SayAlpha(string): This application will play the sounds that correspond to\n"
396 "the letters of the given string.\n"
399 { "SayPhonetic", pbx_builtin_sayphonetic
,
401 " SayPhonetic(string): This application will play the sounds from the phonetic\n"
402 "alphabet that correspond to the letters in the given string.\n"
405 { "SetAMAFlags", pbx_builtin_setamaflags
,
407 " SetAMAFlags([flag]): This application will set the channel's AMA Flags for\n"
408 " billing purposes.\n"
411 { "SetGlobalVar", pbx_builtin_setglobalvar
,
412 "Set a global variable to a given value",
413 " SetGlobalVar(variable=value): This application sets a given global variable to\n"
414 "the specified value.\n"
417 { "Set", pbx_builtin_setvar
,
418 "Set channel variable(s) or function value(s)",
419 " Set(name1=value1|name2=value2|..[|options])\n"
420 "This function can be used to set the value of channel variables or dialplan\n"
421 "functions. It will accept up to 24 name/value pairs. When setting variables,\n"
422 "if the variable name is prefixed with _, the variable will be inherited into\n"
423 "channels created from the current channel. If the variable name is prefixed\n"
424 "with __, the variable will be inherited into channels created from the current\n"
425 "channel and all children channels.\n"
427 " g - Set variable globally instead of on the channel\n"
428 " (applies only to variables, not functions)\n"
431 { "ImportVar", pbx_builtin_importvar
,
432 "Import a variable from a channel into a new variable",
433 " ImportVar(newvar=channelname|variable): This application imports a variable\n"
434 "from the specified channel (as opposed to the current one) and stores it as\n"
435 "a variable in the current channel (the channel that is calling this\n"
436 "application). Variables created by this application have the same inheritance\n"
437 "properties as those created with the Set application. See the documentation for\n"
438 "Set for more information.\n"
441 { "Wait", pbx_builtin_wait
,
442 "Waits for some time",
443 " Wait(seconds): This application waits for a specified number of seconds.\n"
444 "Then, dialplan execution will continue at the next priority.\n"
445 " Note that the seconds can be passed with fractions of a second. For example,\n"
446 "'1.5' will ask the application to wait for 1.5 seconds.\n"
449 { "WaitExten", pbx_builtin_waitexten
,
450 "Waits for an extension to be entered",
451 " WaitExten([seconds][|options]): This application waits for the user to enter\n"
452 "a new extension for a specified number of seconds.\n"
453 " Note that the seconds can be passed with fractions of a second. For example,\n"
454 "'1.5' will ask the application to wait for 1.5 seconds.\n"
456 " m[(x)] - Provide music on hold to the caller while waiting for an extension.\n"
457 " Optionally, specify the class for music on hold within parenthesis.\n"
462 static struct ast_context
*contexts
= NULL
;
463 AST_MUTEX_DEFINE_STATIC(conlock
); /*!< Lock for the ast_context list */
465 static AST_LIST_HEAD_STATIC(apps
, ast_app
);
467 static AST_LIST_HEAD_STATIC(switches
, ast_switch
);
469 static int stateid
= 1;
471 When holding this list's lock, do _not_ do anything that will cause conlock
472 to be taken, unless you _already_ hold it. The ast_merge_contexts_and_delete
473 function will take the locks in conlock/hints order, so any other
474 paths that require both locks must also take them in that order.
476 static AST_LIST_HEAD_STATIC(hints
, ast_hint
);
477 struct ast_state_cb
*statecbs
= NULL
;
480 \note This function is special. It saves the stack so that no matter
481 how many times it is called, it returns to the same place */
482 int pbx_exec(struct ast_channel
*c
, /*!< Channel */
483 struct ast_app
*app
, /*!< Application */
484 void *data
) /*!< Data for execution */
488 const char *saved_c_appl
;
489 const char *saved_c_data
;
492 ast_cdr_setapp(c
->cdr
, app
->name
, data
);
494 /* save channel values */
495 saved_c_appl
= c
->appl
;
496 saved_c_data
= c
->data
;
500 /* XXX remember what to to when we have linked apps to modules */
502 /* XXX LOCAL_USER_ADD(app->module) */
504 res
= app
->execute(c
, data
);
506 /* XXX LOCAL_USER_REMOVE(app->module) */
508 /* restore channel values */
509 c
->appl
= saved_c_appl
;
510 c
->data
= saved_c_data
;
515 /*! Go no deeper than this through includes (not counting loops) */
516 #define AST_PBX_MAX_STACK 128
518 /*! \brief Find application handle in linked list
520 struct ast_app
*pbx_findapp(const char *app
)
524 AST_LIST_LOCK(&apps
);
525 AST_LIST_TRAVERSE(&apps
, tmp
, list
) {
526 if (!strcasecmp(tmp
->name
, app
))
529 AST_LIST_UNLOCK(&apps
);
534 static struct ast_switch
*pbx_findswitch(const char *sw
)
536 struct ast_switch
*asw
;
538 AST_LIST_LOCK(&switches
);
539 AST_LIST_TRAVERSE(&switches
, asw
, list
) {
540 if (!strcasecmp(asw
->name
, sw
))
543 AST_LIST_UNLOCK(&switches
);
548 static inline int include_valid(struct ast_include
*i
)
553 return ast_check_timing(&(i
->timing
));
556 static void pbx_destroy(struct ast_pbx
*p
)
562 * Special characters used in patterns:
563 * '_' underscore is the leading character of a pattern.
564 * In other position it is treated as a regular char.
565 * ' ' '-' space and '-' are separator and ignored.
566 * . one or more of any character. Only allowed at the end of
568 * ! zero or more of anything. Also impacts the result of CANMATCH
569 * and MATCHMORE. Only allowed at the end of a pattern.
570 * In the core routine, ! causes a match with a return code of 2.
571 * In turn, depending on the search mode: (XXX check if it is implemented)
572 * - E_MATCH retuns 1 (does match)
573 * - E_MATCHMORE returns 0 (no match)
574 * - E_CANMATCH returns 1 (does match)
576 * / should not appear as it is considered the separator of the CID info.
577 * XXX at the moment we may stop on this char.
579 * X Z N match ranges 0-9, 1-9, 2-9 respectively.
580 * [ denotes the start of a set of character. Everything inside
581 * is considered literally. We can have ranges a-d and individual
582 * characters. A '[' and '-' can be considered literally if they
583 * are just before ']'.
584 * XXX currently there is no way to specify ']' in a range, nor \ is
585 * considered specially.
587 * When we compare a pattern with a specific extension, all characters in the extension
588 * itself are considered literally with the only exception of '-' which is considered
589 * as a separator and thus ignored.
590 * XXX do we want to consider space as a separator as well ?
591 * XXX do we want to consider the separators in non-patterns as well ?
595 * \brief helper functions to sort extensions and patterns in the desired way,
596 * so that more specific patterns appear first.
598 * ext_cmp1 compares individual characters (or sets of), returning
599 * an int where bits 0-7 are the ASCII code of the first char in the set,
600 * while bit 8-15 are the cardinality of the set minus 1.
601 * This way more specific patterns (smaller cardinality) appear first.
602 * Wildcards have a special value, so that we can directly compare them to
603 * sets by subtracting the two values. In particular:
604 * 0x000xx one character, xx
605 * 0x0yyxx yy character set starting with xx
606 * 0x10000 '.' (one or more of anything)
607 * 0x20000 '!' (zero or more of anything)
608 * 0x30000 NUL (end of string)
609 * 0x40000 error in set.
610 * The pointer to the string is advanced according to needs.
612 * 1. the empty set is equivalent to NUL.
613 * 2. given that a full set has always 0 as the first element,
614 * we could encode the special cases as 0xffXX where XX
615 * is 1, 2, 3, 4 as used above.
617 static int ext_cmp1(const char **p
)
620 int c
, cmin
= 0xff, count
= 0;
623 /* load, sign extend and advance pointer until we find
626 while ( (c
= *(*p
)++) && (c
== ' ' || c
== '-') )
627 ; /* ignore some characters */
629 /* always return unless we have a set of chars */
631 default: /* ordinary character */
632 return 0x0000 | (c
& 0xff);
635 return 0x0700 | '2' ;
643 case '.': /* wildcard */
646 case '!': /* earlymatch */
647 return 0x20000; /* less specific than NULL */
649 case '\0': /* empty string */
653 case '[': /* pattern */
656 /* locate end of set */
657 end
= strchr(*p
, ']');
660 ast_log(LOG_WARNING
, "Wrong usage of [] in the extension\n");
661 return 0x40000; /* XXX make this entry go last... */
664 bzero(chars
, sizeof(chars
)); /* clear all chars in the set */
665 for (; *p
< end
; (*p
)++) {
666 unsigned char c1
, c2
; /* first-last char in range */
667 c1
= (unsigned char)((*p
)[0]);
668 if (*p
+ 2 < end
&& (*p
)[1] == '-') { /* this is a range */
669 c2
= (unsigned char)((*p
)[2]);
670 *p
+= 2; /* skip a total of 3 chars */
671 } else /* individual character */
675 for (; c1
<= c2
; c1
++) {
676 uint32_t mask
= 1 << (c1
% 32);
677 if ( (chars
[ c1
/ 32 ] & mask
) == 0)
679 chars
[ c1
/ 32 ] |= mask
;
683 return count
== 0 ? 0x30000 : (count
| cmin
);
687 * \brief the full routine to compare extensions in rules.
689 static int ext_cmp(const char *a
, const char *b
)
691 /* make sure non-patterns come first.
692 * If a is not a pattern, it either comes first or
693 * we use strcmp to compare the strings.
698 return (b
[0] == '_') ? -1 : strcmp(a
, b
);
700 /* Now we know a is a pattern; if b is not, a comes first */
703 #if 0 /* old mode for ext matching */
706 /* ok we need full pattern sorting routine */
707 while (!ret
&& a
&& b
)
708 ret
= ext_cmp1(&a
) - ext_cmp1(&b
);
712 return (ret
> 0) ? 1 : -1;
716 * When looking up extensions, we can have different requests
717 * identified by the 'action' argument, as follows.
718 * Note that the coding is such that the low 4 bits are the
719 * third argument to extension_match_core.
722 E_MATCHMORE
= 0x00, /* extension can match but only with more 'digits' */
723 E_CANMATCH
= 0x01, /* extension can match with or without more 'digits' */
724 E_MATCH
= 0x02, /* extension is an exact match */
725 E_MATCH_MASK
= 0x03, /* mask for the argument to extension_match_core() */
726 E_SPAWN
= 0x12, /* want to spawn an extension. Requires exact match */
727 E_FINDLABEL
= 0x22 /* returns the priority for a given label. Requires exact match */
731 * Internal function for ast_extension_{match|close}
732 * return 0 on no-match, 1 on match, 2 on early match.
733 * mode is as follows:
734 * E_MATCH success only on exact match
735 * E_MATCHMORE success only on partial match (i.e. leftover digits in pattern)
736 * E_CANMATCH either of the above.
738 static int _extension_match_core(const char *pattern
, const char *data
, enum ext_match_t mode
)
740 mode
&= E_MATCH_MASK
; /* only consider the relevant bits */
742 if (pattern
[0] != '_') { /* not a pattern, try exact or partial match */
743 int ld
= strlen(data
), lp
= strlen(pattern
);
745 if (lp
< ld
) /* pattern too short, cannot match */
747 /* depending on the mode, accept full or partial match or both */
749 return !strcmp(pattern
, data
); /* 1 on match, 0 on fail */
750 if (ld
== 0 || !strncasecmp(pattern
, data
, ld
)) /* partial or full match */
751 return (mode
== E_MATCHMORE
) ? lp
> ld
: 1; /* XXX should consider '!' and '/' ? */
755 pattern
++; /* skip leading _ */
757 * XXX below we stop at '/' which is a separator for the CID info. However we should
758 * not store '/' in the pattern at all. When we insure it, we can remove the checks.
760 while (*data
&& *pattern
&& *pattern
!= '/') {
763 if (*data
== '-') { /* skip '-' in data (just a separator) */
767 switch (toupper(*pattern
)) {
768 case '[': /* a range */
769 end
= strchr(pattern
+1, ']'); /* XXX should deal with escapes ? */
771 ast_log(LOG_WARNING
, "Wrong usage of [] in the extension\n");
772 return 0; /* unconditional failure */
774 for (pattern
++; pattern
!= end
; pattern
++) {
775 if (pattern
+2 < end
&& pattern
[1] == '-') { /* this is a range */
776 if (*data
>= pattern
[0] && *data
<= pattern
[2])
777 break; /* match found */
779 pattern
+= 2; /* skip a total of 3 chars */
782 } else if (*data
== pattern
[0])
783 break; /* match found */
787 pattern
= end
; /* skip and continue */
790 if (*data
< '2' || *data
> '9')
794 if (*data
< '0' || *data
> '9')
798 if (*data
< '1' || *data
> '9')
801 case '.': /* Must match, even with more digits */
803 case '!': /* Early match */
806 case '-': /* Ignore these in patterns */
807 data
--; /* compensate the final data++ */
810 if (*data
!= *pattern
)
816 if (*data
) /* data longer than pattern, no match */
819 * match so far, but ran off the end of the data.
820 * Depending on what is next, determine match or not.
822 if (*pattern
== '\0' || *pattern
== '/') /* exact match */
823 return (mode
== E_MATCHMORE
) ? 0 : 1; /* this is a failure for E_MATCHMORE */
824 else if (*pattern
== '!') /* early match */
826 else /* partial match */
827 return (mode
== E_MATCH
) ? 0 : 1; /* this is a failure for E_MATCH */
831 * Wrapper around _extension_match_core() to do performance measurement
832 * using the profiling code.
834 static int extension_match_core(const char *pattern
, const char *data
, enum ext_match_t mode
)
837 static int prof_id
= -2; /* marker for 'unallocated' id */
839 prof_id
= ast_add_profile("ext_match", 0);
840 ast_mark(prof_id
, 1);
841 i
= _extension_match_core(pattern
, data
, mode
);
842 ast_mark(prof_id
, 0);
846 int ast_extension_match(const char *pattern
, const char *data
)
848 return extension_match_core(pattern
, data
, E_MATCH
);
851 int ast_extension_close(const char *pattern
, const char *data
, int needmore
)
853 if (needmore
!= E_MATCHMORE
&& needmore
!= E_CANMATCH
)
854 ast_log(LOG_WARNING
, "invalid argument %d\n", needmore
);
855 return extension_match_core(pattern
, data
, needmore
);
858 struct ast_context
*ast_context_find(const char *name
)
860 struct ast_context
*tmp
= NULL
;
861 ast_mutex_lock(&conlock
);
862 while ( (tmp
= ast_walk_contexts(tmp
)) ) {
863 if (!name
|| !strcasecmp(name
, tmp
->name
))
866 ast_mutex_unlock(&conlock
);
870 #define STATUS_NO_CONTEXT 1
871 #define STATUS_NO_EXTENSION 2
872 #define STATUS_NO_PRIORITY 3
873 #define STATUS_NO_LABEL 4
874 #define STATUS_SUCCESS 5
876 static int matchcid(const char *cidpattern
, const char *callerid
)
878 /* If the Caller*ID pattern is empty, then we're matching NO Caller*ID, so
879 failing to get a number should count as a match, otherwise not */
881 if (ast_strlen_zero(callerid
))
882 return ast_strlen_zero(cidpattern
) ? 1 : 0;
884 return ast_extension_match(cidpattern
, callerid
);
887 /* request and result for pbx_find_extension */
888 struct pbx_find_info
{
895 char *incstack
[AST_PBX_MAX_STACK
]; /* filled during the search */
896 int stacklen
; /* modified during the search */
897 int status
; /* set on return */
898 struct ast_switch
*swo
; /* set on return */
899 const char *data
; /* set on return */
900 const char *foundcontext
; /* set on return */
903 static struct ast_exten
*pbx_find_extension(struct ast_channel
*chan
,
904 struct ast_context
*bypass
, struct pbx_find_info
*q
,
905 const char *context
, const char *exten
, int priority
,
906 const char *label
, const char *callerid
, enum ext_match_t action
)
909 struct ast_context
*tmp
;
910 struct ast_exten
*e
, *eroot
;
911 struct ast_include
*i
;
914 /* Initialize status if appropriate */
915 if (q
->stacklen
== 0) {
916 q
->status
= STATUS_NO_CONTEXT
;
919 q
->foundcontext
= NULL
;
921 /* Check for stack overflow */
922 if (q
->stacklen
>= AST_PBX_MAX_STACK
) {
923 ast_log(LOG_WARNING
, "Maximum PBX stack exceeded\n");
926 /* Check first to see if we've already been checked */
927 for (x
= 0; x
< q
->stacklen
; x
++) {
928 if (!strcasecmp(q
->incstack
[x
], context
))
931 if (bypass
) /* bypass means we only look there */
933 else { /* look in contexts */
935 while ((tmp
= ast_walk_contexts(tmp
)) ) {
936 if (!strcmp(tmp
->name
, context
))
942 if (q
->status
< STATUS_NO_EXTENSION
)
943 q
->status
= STATUS_NO_EXTENSION
;
945 /* scan the list trying to match extension and CID */
947 while ( (eroot
= ast_walk_context_extensions(tmp
, eroot
)) ) {
948 int match
= extension_match_core(eroot
->exten
, exten
, action
);
949 /* 0 on fail, 1 on match, 2 on earlymatch */
951 if (!match
|| (eroot
->matchcid
&& !matchcid(eroot
->cidmatch
, callerid
)))
952 continue; /* keep trying */
953 if (match
== 2 && action
== E_MATCHMORE
) {
954 /* We match an extension ending in '!'.
955 * The decision in this case is final and is NULL (no match).
959 /* found entry, now look for the right priority */
960 if (q
->status
< STATUS_NO_PRIORITY
)
961 q
->status
= STATUS_NO_PRIORITY
;
963 while ( (e
= ast_walk_extension_priorities(eroot
, e
)) ) {
964 /* Match label or priority */
965 if (action
== E_FINDLABEL
) {
966 if (q
->status
< STATUS_NO_LABEL
)
967 q
->status
= STATUS_NO_LABEL
;
968 if (label
&& e
->label
&& !strcmp(label
, e
->label
))
969 break; /* found it */
970 } else if (e
->priority
== priority
) {
971 break; /* found it */
972 } /* else keep searching */
974 if (e
) { /* found a valid match */
975 q
->status
= STATUS_SUCCESS
;
976 q
->foundcontext
= context
;
980 /* Check alternative switches */
981 AST_LIST_TRAVERSE(&tmp
->alts
, sw
, list
) {
982 struct ast_switch
*asw
= pbx_findswitch(sw
->name
);
983 ast_switch_f
*aswf
= NULL
;
987 ast_log(LOG_WARNING
, "No such switch '%s'\n", sw
->name
);
990 /* Substitute variables now */
992 pbx_substitute_variables_helper(chan
, sw
->data
, sw
->tmpdata
, SWITCH_DATA_LENGTH
- 1);
994 /* equivalent of extension_match_core() at the switch level */
995 if (action
== E_CANMATCH
)
996 aswf
= asw
->canmatch
;
997 else if (action
== E_MATCHMORE
)
998 aswf
= asw
->matchmore
;
999 else /* action == E_MATCH */
1001 datap
= sw
->eval
? sw
->tmpdata
: sw
->data
;
1002 res
= !aswf
? 0 : aswf(chan
, context
, exten
, priority
, callerid
, datap
);
1003 if (res
) { /* Got a match */
1006 q
->foundcontext
= context
;
1007 /* XXX keep status = STATUS_NO_CONTEXT ? */
1011 q
->incstack
[q
->stacklen
++] = tmp
->name
; /* Setup the stack */
1012 /* Now try any includes we have in this context */
1013 for (i
= tmp
->includes
; i
; i
= i
->next
) {
1014 if (include_valid(i
)) {
1015 if ((e
= pbx_find_extension(chan
, bypass
, q
, i
->rname
, exten
, priority
, label
, callerid
, action
)))
1024 /* Note that it's negative -- that's important later. */
1025 #define DONT_HAVE_LENGTH 0x80000000
1027 /*! \brief extract offset:length from variable name.
1028 * Returns 1 if there is a offset:length part, which is
1029 * trimmed off (values go into variables)
1031 static int parse_variable_name(char *var
, int *offset
, int *length
, int *isfunc
)
1036 *length
= DONT_HAVE_LENGTH
;
1038 for (; *var
; var
++) {
1042 } else if (*var
== ')') {
1044 } else if (*var
== ':' && parens
== 0) {
1046 sscanf(var
, "%d:%d", offset
, length
);
1047 return 1; /* offset:length valid */
1053 /*! \brief takes a substring. It is ok to call with value == workspace.
1055 * offset < 0 means start from the end of the string and set the beginning
1056 * to be that many characters back.
1057 * length is the length of the substring, -1 means unlimited
1058 * (we take any negative value).
1059 * Always return a copy in workspace.
1061 static char *substring(const char *value
, int offset
, int length
, char *workspace
, size_t workspace_len
)
1063 char *ret
= workspace
;
1064 int lr
; /* length of the input string after the copy */
1066 ast_copy_string(workspace
, value
, workspace_len
); /* always make a copy */
1068 /* Quick check if no need to do anything */
1069 if (offset
== 0 && length
< 0) /* take the whole string */
1072 lr
= strlen(ret
); /* compute length after copy, so we never go out of the workspace */
1074 if (offset
< 0) { /* translate negative offset into positive ones */
1075 offset
= lr
+ offset
;
1076 if (offset
< 0) /* If the negative offset was greater than the length of the string, just start at the beginning */
1080 /* too large offset result in empty string so we know what to return */
1082 return ret
+ lr
; /* the final '\0' */
1084 ret
+= offset
; /* move to the start position */
1085 if (length
>= 0 && length
< lr
- offset
) /* truncate if necessary */
1091 /*! \brief pbx_retrieve_variable: Support for Asterisk built-in variables and
1092 functions in the dialplan
1094 void pbx_retrieve_variable(struct ast_channel
*c
, const char *var
, char **ret
, char *workspace
, int workspacelen
, struct varshead
*headp
)
1096 const char not_found
= '\0';
1098 const char *s
; /* the result */
1100 int i
, need_substring
;
1101 struct varshead
*places
[2] = { headp
, &globals
}; /* list of places where we may look */
1104 places
[0] = &c
->varshead
;
1107 * Make a copy of var because parse_variable_name() modifies the string.
1108 * Then if called directly, we might need to run substring() on the result;
1109 * remember this for later in 'need_substring', 'offset' and 'length'
1111 tmpvar
= ast_strdupa(var
); /* parse_variable_name modifies the string */
1112 need_substring
= parse_variable_name(tmpvar
, &offset
, &length
, &i
/* ignored */);
1115 * Look first into predefined variables, then into variable lists.
1116 * Variable 's' points to the result, according to the following rules:
1117 * s == ¬_found (set at the beginning) means that we did not find a
1118 * matching variable and need to look into more places.
1119 * If s != ¬_found, s is a valid result string as follows:
1120 * s = NULL if the variable does not have a value;
1121 * you typically do this when looking for an unset predefined variable.
1122 * s = workspace if the result has been assembled there;
1123 * typically done when the result is built e.g. with an snprintf(),
1124 * so we don't need to do an additional copy.
1125 * s != workspace in case we have a string, that needs to be copied
1126 * (the ast_copy_string is done once for all at the end).
1127 * Typically done when the result is already available in some string.
1129 s
= ¬_found
; /* default value */
1130 if (c
) { /* This group requires a valid channel */
1131 /* Names with common parts are looked up a piece at a time using strncmp. */
1132 if (!strncmp(var
, "CALL", 4)) {
1133 if (!strncmp(var
+ 4, "ING", 3)) {
1134 if (!strcmp(var
+ 7, "PRES")) { /* CALLINGPRES */
1135 snprintf(workspace
, workspacelen
, "%d", c
->cid
.cid_pres
);
1137 } else if (!strcmp(var
+ 7, "ANI2")) { /* CALLINGANI2 */
1138 snprintf(workspace
, workspacelen
, "%d", c
->cid
.cid_ani2
);
1140 } else if (!strcmp(var
+ 7, "TON")) { /* CALLINGTON */
1141 snprintf(workspace
, workspacelen
, "%d", c
->cid
.cid_ton
);
1143 } else if (!strcmp(var
+ 7, "TNS")) { /* CALLINGTNS */
1144 snprintf(workspace
, workspacelen
, "%d", c
->cid
.cid_tns
);
1148 } else if (!strcmp(var
, "HINT")) {
1149 s
= ast_get_hint(workspace
, workspacelen
, NULL
, 0, c
, c
->context
, c
->exten
) ? workspace
: NULL
;
1150 } else if (!strcmp(var
, "HINTNAME")) {
1151 s
= ast_get_hint(NULL
, 0, workspace
, workspacelen
, c
, c
->context
, c
->exten
) ? workspace
: NULL
;
1152 } else if (!strcmp(var
, "EXTEN")) {
1154 } else if (!strcmp(var
, "CONTEXT")) {
1156 } else if (!strcmp(var
, "PRIORITY")) {
1157 snprintf(workspace
, workspacelen
, "%d", c
->priority
);
1159 } else if (!strcmp(var
, "CHANNEL")) {
1161 } else if (!strcmp(var
, "UNIQUEID")) {
1163 } else if (!strcmp(var
, "HANGUPCAUSE")) {
1164 snprintf(workspace
, workspacelen
, "%d", c
->hangupcause
);
1168 if (s
== ¬_found
) { /* look for more */
1169 if (!strcmp(var
, "EPOCH")) {
1170 snprintf(workspace
, workspacelen
, "%u",(int)time(NULL
));
1172 } else if (!strcmp(var
, "SYSTEMNAME")) {
1173 s
= ast_config_AST_SYSTEM_NAME
;
1176 /* if not found, look into chanvars or global vars */
1177 for (i
= 0; s
== ¬_found
&& i
< (sizeof(places
) / sizeof(places
[0])); i
++) {
1178 struct ast_var_t
*variables
;
1181 if (places
[i
] == &globals
)
1182 ast_mutex_lock(&globalslock
);
1183 AST_LIST_TRAVERSE(places
[i
], variables
, entries
) {
1184 if (strcasecmp(ast_var_name(variables
), var
)==0) {
1185 s
= ast_var_value(variables
);
1189 if (places
[i
] == &globals
)
1190 ast_mutex_unlock(&globalslock
);
1192 if (s
== ¬_found
|| s
== NULL
)
1196 ast_copy_string(workspace
, s
, workspacelen
);
1199 *ret
= substring(*ret
, offset
, length
, workspace
, workspacelen
);
1203 /*! \brief CLI function to show installed custom functions
1204 \addtogroup CLI_functions
1206 static int handle_show_functions(int fd
, int argc
, char *argv
[])
1208 struct ast_custom_function
*acf
;
1212 if (argc
== 4 && (!strcmp(argv
[2], "like")) ) {
1214 } else if (argc
!= 2) {
1215 return RESULT_SHOWUSAGE
;
1218 ast_cli(fd
, "%s Custom Functions:\n--------------------------------------------------------------------------------\n", like
? "Matching" : "Installed");
1220 AST_LIST_LOCK(&acf_root
);
1221 AST_LIST_TRAVERSE(&acf_root
, acf
, acflist
) {
1222 if (!like
|| strstr(acf
->name
, argv
[3])) {
1224 ast_cli(fd
, "%-20.20s %-35.35s %s\n", acf
->name
, acf
->syntax
, acf
->synopsis
);
1227 AST_LIST_UNLOCK(&acf_root
);
1229 ast_cli(fd
, "%d %scustom functions installed.\n", count_acf
, like
? "matching " : "");
1231 return RESULT_SUCCESS
;
1234 static int handle_show_function(int fd
, int argc
, char *argv
[])
1236 struct ast_custom_function
*acf
;
1237 /* Maximum number of characters added by terminal coloring is 22 */
1238 char infotitle
[64 + AST_MAX_APP
+ 22], syntitle
[40], destitle
[40];
1239 char info
[64 + AST_MAX_APP
], *synopsis
= NULL
, *description
= NULL
;
1240 char stxtitle
[40], *syntax
= NULL
;
1241 int synopsis_size
, description_size
, syntax_size
;
1244 return RESULT_SHOWUSAGE
;
1246 if (!(acf
= ast_custom_function_find(argv
[2]))) {
1247 ast_cli(fd
, "No function by that name registered.\n");
1248 return RESULT_FAILURE
;
1253 synopsis_size
= strlen(acf
->synopsis
) + 23;
1255 synopsis_size
= strlen("Not available") + 23;
1256 synopsis
= alloca(synopsis_size
);
1259 description_size
= strlen(acf
->desc
) + 23;
1261 description_size
= strlen("Not available") + 23;
1262 description
= alloca(description_size
);
1265 syntax_size
= strlen(acf
->syntax
) + 23;
1267 syntax_size
= strlen("Not available") + 23;
1268 syntax
= alloca(syntax_size
);
1270 snprintf(info
, 64 + AST_MAX_APP
, "\n -= Info about function '%s' =- \n\n", acf
->name
);
1271 term_color(infotitle
, info
, COLOR_MAGENTA
, 0, 64 + AST_MAX_APP
+ 22);
1272 term_color(stxtitle
, "[Syntax]\n", COLOR_MAGENTA
, 0, 40);
1273 term_color(syntitle
, "[Synopsis]\n", COLOR_MAGENTA
, 0, 40);
1274 term_color(destitle
, "[Description]\n", COLOR_MAGENTA
, 0, 40);
1276 acf
->syntax
? acf
->syntax
: "Not available",
1277 COLOR_CYAN
, 0, syntax_size
);
1278 term_color(synopsis
,
1279 acf
->synopsis
? acf
->synopsis
: "Not available",
1280 COLOR_CYAN
, 0, synopsis_size
);
1281 term_color(description
,
1282 acf
->desc
? acf
->desc
: "Not available",
1283 COLOR_CYAN
, 0, description_size
);
1285 ast_cli(fd
,"%s%s%s\n\n%s%s\n\n%s%s\n", infotitle
, stxtitle
, syntax
, syntitle
, synopsis
, destitle
, description
);
1287 return RESULT_SUCCESS
;
1290 static char *complete_show_function(const char *line
, const char *word
, int pos
, int state
)
1292 struct ast_custom_function
*acf
;
1295 int wordlen
= strlen(word
);
1297 /* case-insensitive for convenience in this 'complete' function */
1298 AST_LIST_LOCK(&acf_root
);
1299 AST_LIST_TRAVERSE(&acf_root
, acf
, acflist
) {
1300 if (!strncasecmp(word
, acf
->name
, wordlen
) && ++which
> state
) {
1301 ret
= strdup(acf
->name
);
1305 AST_LIST_UNLOCK(&acf_root
);
1310 struct ast_custom_function
*ast_custom_function_find(const char *name
)
1312 struct ast_custom_function
*acf
= NULL
;
1314 AST_LIST_LOCK(&acf_root
);
1315 AST_LIST_TRAVERSE(&acf_root
, acf
, acflist
) {
1316 if (!strcmp(name
, acf
->name
))
1319 AST_LIST_UNLOCK(&acf_root
);
1324 int ast_custom_function_unregister(struct ast_custom_function
*acf
)
1326 struct ast_custom_function
*cur
;
1331 AST_LIST_LOCK(&acf_root
);
1332 AST_LIST_TRAVERSE_SAFE_BEGIN(&acf_root
, cur
, acflist
) {
1334 AST_LIST_REMOVE_CURRENT(&acf_root
, acflist
);
1335 if (option_verbose
> 1)
1336 ast_verbose(VERBOSE_PREFIX_2
"Unregistered custom function %s\n", acf
->name
);
1340 AST_LIST_TRAVERSE_SAFE_END
1341 AST_LIST_UNLOCK(&acf_root
);
1343 return acf
? 0 : -1;
1346 int ast_custom_function_register(struct ast_custom_function
*acf
)
1348 struct ast_custom_function
*cur
;
1353 AST_LIST_LOCK(&acf_root
);
1355 if (ast_custom_function_find(acf
->name
)) {
1356 ast_log(LOG_ERROR
, "Function %s already registered.\n", acf
->name
);
1357 AST_LIST_UNLOCK(&acf_root
);
1361 /* Store in alphabetical order */
1362 AST_LIST_TRAVERSE_SAFE_BEGIN(&acf_root
, cur
, acflist
) {
1363 if (strcasecmp(acf
->name
, cur
->name
) < 0) {
1364 AST_LIST_INSERT_BEFORE_CURRENT(&acf_root
, acf
, acflist
);
1368 AST_LIST_TRAVERSE_SAFE_END
1370 AST_LIST_INSERT_TAIL(&acf_root
, acf
, acflist
);
1372 AST_LIST_UNLOCK(&acf_root
);
1374 if (option_verbose
> 1)
1375 ast_verbose(VERBOSE_PREFIX_2
"Registered custom function %s\n", acf
->name
);
1380 /*! \brief return a pointer to the arguments of the function,
1381 * and terminates the function name with '\\0'
1383 static char *func_args(char *function
)
1385 char *args
= strchr(function
, '(');
1388 ast_log(LOG_WARNING
, "Function doesn't contain parentheses. Assuming null argument.\n");
1392 if ((p
= strrchr(args
, ')')) )
1395 ast_log(LOG_WARNING
, "Can't find trailing parenthesis?\n");
1400 int ast_func_read(struct ast_channel
*chan
, char *function
, char *workspace
, size_t len
)
1402 char *args
= func_args(function
);
1403 struct ast_custom_function
*acfptr
= ast_custom_function_find(function
);
1406 ast_log(LOG_ERROR
, "Function %s not registered\n", function
);
1407 else if (!acfptr
->read
)
1408 ast_log(LOG_ERROR
, "Function %s cannot be read\n", function
);
1410 return acfptr
->read(chan
, function
, args
, workspace
, len
);
1414 int ast_func_write(struct ast_channel
*chan
, char *function
, const char *value
)
1416 char *args
= func_args(function
);
1417 struct ast_custom_function
*acfptr
= ast_custom_function_find(function
);
1420 ast_log(LOG_ERROR
, "Function %s not registered\n", function
);
1421 else if (!acfptr
->write
)
1422 ast_log(LOG_ERROR
, "Function %s cannot be written to\n", function
);
1424 return acfptr
->write(chan
, function
, args
, value
);
1429 static void pbx_substitute_variables_helper_full(struct ast_channel
*c
, struct varshead
*headp
, const char *cp1
, char *cp2
, int count
)
1431 /* Substitutes variables into cp2, based on string cp1, and assuming cp2 to be
1434 const char *tmp
, *whereweare
;
1435 int length
, offset
, offset2
, isfunction
;
1436 char *workspace
= NULL
;
1437 char *ltmp
= NULL
, *var
= NULL
;
1438 char *nextvar
, *nextexp
, *nextthing
;
1440 int pos
, brackets
, needsub
, len
;
1443 while (!ast_strlen_zero(whereweare
) && count
) {
1444 /* Assume we're copying the whole remaining string */
1445 pos
= strlen(whereweare
);
1448 nextthing
= strchr(whereweare
, '$');
1450 switch(nextthing
[1]) {
1452 nextvar
= nextthing
;
1453 pos
= nextvar
- whereweare
;
1456 nextexp
= nextthing
;
1457 pos
= nextexp
- whereweare
;
1463 /* Can't copy more than 'count' bytes */
1467 /* Copy that many bytes */
1468 memcpy(cp2
, whereweare
, pos
);
1476 /* We have a variable. Find the start and end, and determine
1477 if we are going to have to recursively call ourselves on the
1479 vars
= vare
= nextvar
+ 2;
1483 /* Find the end of it */
1484 while (brackets
&& *vare
) {
1485 if ((vare
[0] == '$') && (vare
[1] == '{')) {
1487 } else if (vare
[0] == '{') {
1489 } else if (vare
[0] == '}') {
1491 } else if ((vare
[0] == '$') && (vare
[1] == '['))
1496 ast_log(LOG_NOTICE
, "Error in extension logic (missing '}')\n");
1497 len
= vare
- vars
- 1;
1499 /* Skip totally over variable string */
1500 whereweare
+= (len
+ 3);
1503 var
= alloca(VAR_BUF_SIZE
);
1505 /* Store variable name (and truncate) */
1506 ast_copy_string(var
, vars
, len
+ 1);
1508 /* Substitute if necessary */
1511 ltmp
= alloca(VAR_BUF_SIZE
);
1513 memset(ltmp
, 0, VAR_BUF_SIZE
);
1514 pbx_substitute_variables_helper_full(c
, headp
, var
, ltmp
, VAR_BUF_SIZE
- 1);
1521 workspace
= alloca(VAR_BUF_SIZE
);
1523 workspace
[0] = '\0';
1525 parse_variable_name(vars
, &offset
, &offset2
, &isfunction
);
1527 /* Evaluate function */
1528 cp4
= ast_func_read(c
, vars
, workspace
, VAR_BUF_SIZE
) ? NULL
: workspace
;
1530 ast_log(LOG_DEBUG
, "Function result is '%s'\n", cp4
? cp4
: "(null)");
1532 /* Retrieve variable value */
1533 pbx_retrieve_variable(c
, vars
, &cp4
, workspace
, VAR_BUF_SIZE
, headp
);
1536 cp4
= substring(cp4
, offset
, offset2
, workspace
, VAR_BUF_SIZE
);
1538 length
= strlen(cp4
);
1541 memcpy(cp2
, cp4
, length
);
1545 } else if (nextexp
) {
1546 /* We have an expression. Find the start and end, and determine
1547 if we are going to have to recursively call ourselves on the
1549 vars
= vare
= nextexp
+ 2;
1553 /* Find the end of it */
1554 while(brackets
&& *vare
) {
1555 if ((vare
[0] == '$') && (vare
[1] == '[')) {
1559 } else if (vare
[0] == '[') {
1561 } else if (vare
[0] == ']') {
1563 } else if ((vare
[0] == '$') && (vare
[1] == '{')) {
1570 ast_log(LOG_NOTICE
, "Error in extension logic (missing ']')\n");
1571 len
= vare
- vars
- 1;
1573 /* Skip totally over expression */
1574 whereweare
+= (len
+ 3);
1577 var
= alloca(VAR_BUF_SIZE
);
1579 /* Store variable name (and truncate) */
1580 ast_copy_string(var
, vars
, len
+ 1);
1582 /* Substitute if necessary */
1585 ltmp
= alloca(VAR_BUF_SIZE
);
1587 memset(ltmp
, 0, VAR_BUF_SIZE
);
1588 pbx_substitute_variables_helper_full(c
, headp
, var
, ltmp
, VAR_BUF_SIZE
- 1);
1594 length
= ast_expr(vars
, cp2
, count
);
1597 ast_log(LOG_DEBUG
, "Expression result is '%s'\n", cp2
);
1606 void pbx_substitute_variables_helper(struct ast_channel
*c
, const char *cp1
, char *cp2
, int count
)
1608 pbx_substitute_variables_helper_full(c
, (c
) ? &c
->varshead
: NULL
, cp1
, cp2
, count
);
1611 void pbx_substitute_variables_varshead(struct varshead
*headp
, const char *cp1
, char *cp2
, int count
)
1613 pbx_substitute_variables_helper_full(NULL
, headp
, cp1
, cp2
, count
);
1616 static void pbx_substitute_variables(char *passdata
, int datalen
, struct ast_channel
*c
, struct ast_exten
*e
)
1618 memset(passdata
, 0, datalen
);
1620 /* No variables or expressions in e->data, so why scan it? */
1621 if (!strchr(e
->data
, '$') && !strstr(e
->data
,"${") && !strstr(e
->data
,"$[") && !strstr(e
->data
,"$(")) {
1622 ast_copy_string(passdata
, e
->data
, datalen
);
1626 pbx_substitute_variables_helper(c
, e
->data
, passdata
, datalen
- 1);
1629 /*! \brief The return value depends on the action:
1631 * E_MATCH, E_CANMATCH, E_MATCHMORE require a real match,
1632 * and return 0 on failure, -1 on match;
1633 * E_FINDLABEL maps the label to a priority, and returns
1634 * the priority on success, ... XXX
1635 * E_SPAWN, spawn an application,
1636 * and return 0 on success, -1 on failure.
1638 static int pbx_extension_helper(struct ast_channel
*c
, struct ast_context
*con
,
1639 const char *context
, const char *exten
, int priority
,
1640 const char *label
, const char *callerid
, enum ext_match_t action
)
1642 struct ast_exten
*e
;
1643 struct ast_app
*app
;
1645 struct pbx_find_info q
= { .stacklen
= 0 }; /* the rest is reset in pbx_find_extension */
1646 char passdata
[EXT_DATA_SIZE
];
1648 int matching_action
= (action
== E_MATCH
|| action
== E_CANMATCH
|| action
== E_MATCHMORE
);
1650 ast_mutex_lock(&conlock
);
1651 e
= pbx_find_extension(c
, con
, &q
, context
, exten
, priority
, label
, callerid
, action
);
1653 if (matching_action
) {
1654 ast_mutex_unlock(&conlock
);
1655 return -1; /* success, we found it */
1656 } else if (action
== E_FINDLABEL
) { /* map the label to a priority */
1658 ast_mutex_unlock(&conlock
);
1659 return res
; /* the priority we were looking for */
1660 } else { /* spawn */
1661 app
= pbx_findapp(e
->app
);
1662 ast_mutex_unlock(&conlock
);
1664 ast_log(LOG_WARNING
, "No application '%s' for extension (%s, %s, %d)\n", e
->app
, context
, exten
, priority
);
1667 if (c
->context
!= context
)
1668 ast_copy_string(c
->context
, context
, sizeof(c
->context
));
1669 if (c
->exten
!= exten
)
1670 ast_copy_string(c
->exten
, exten
, sizeof(c
->exten
));
1671 c
->priority
= priority
;
1672 pbx_substitute_variables(passdata
, sizeof(passdata
), c
, e
);
1675 char atmp2
[EXT_DATA_SIZE
+100];
1676 ast_log(LOG_DEBUG
, "Launching '%s'\n", app
->name
);
1677 snprintf(atmp
, sizeof(atmp
), "STACK-%s-%s-%d", context
, exten
, priority
);
1678 snprintf(atmp2
, sizeof(atmp2
), "%s(\"%s\", \"%s\") %s",
1679 app
->name
, c
->name
, passdata
, "in new stack");
1680 pbx_builtin_setvar_helper(c
, atmp
, atmp2
);
1682 if (option_verbose
> 2) {
1683 char tmp
[80], tmp2
[80], tmp3
[EXT_DATA_SIZE
];
1684 ast_verbose( VERBOSE_PREFIX_3
"Executing [%s:%d] %s(\"%s\", \"%s\") %s\n",
1686 term_color(tmp
, app
->name
, COLOR_BRCYAN
, 0, sizeof(tmp
)),
1687 term_color(tmp2
, c
->name
, COLOR_BRMAGENTA
, 0, sizeof(tmp2
)),
1688 term_color(tmp3
, passdata
, COLOR_BRMAGENTA
, 0, sizeof(tmp3
)),
1691 manager_event(EVENT_FLAG_CALL
, "Newexten",
1696 "Application: %s\r\n"
1699 c
->name
, c
->context
, c
->exten
, c
->priority
, app
->name
, passdata
, c
->uniqueid
);
1700 return pbx_exec(c
, app
, passdata
); /* 0 on success, -1 on failure */
1702 } else if (q
.swo
) { /* not found here, but in another switch */
1703 ast_mutex_unlock(&conlock
);
1704 if (matching_action
)
1708 ast_log(LOG_WARNING
, "No execution engine for switch %s\n", q
.swo
->name
);
1711 return q
.swo
->exec(c
, q
.foundcontext
? q
.foundcontext
: context
, exten
, priority
, callerid
, q
.data
);
1713 } else { /* not found anywhere, see what happened */
1714 ast_mutex_unlock(&conlock
);
1716 case STATUS_NO_CONTEXT
:
1717 if (!matching_action
)
1718 ast_log(LOG_NOTICE
, "Cannot find extension context '%s'\n", context
);
1720 case STATUS_NO_EXTENSION
:
1721 if (!matching_action
)
1722 ast_log(LOG_NOTICE
, "Cannot find extension '%s' in context '%s'\n", exten
, context
);
1724 case STATUS_NO_PRIORITY
:
1725 if (!matching_action
)
1726 ast_log(LOG_NOTICE
, "No such priority %d in extension '%s' in context '%s'\n", priority
, exten
, context
);
1728 case STATUS_NO_LABEL
:
1730 ast_log(LOG_NOTICE
, "No such label '%s' in extension '%s' in context '%s'\n", label
, exten
, context
);
1733 ast_log(LOG_DEBUG
, "Shouldn't happen!\n");
1736 return (matching_action
) ? 0 : -1;
1740 /*! \brief ast_hint_extension: Find hint for given extension in context */
1741 static struct ast_exten
*ast_hint_extension(struct ast_channel
*c
, const char *context
, const char *exten
)
1743 struct ast_exten
*e
;
1744 struct pbx_find_info q
= { .stacklen
= 0 }; /* the rest is set in pbx_find_context */
1746 ast_mutex_lock(&conlock
);
1747 e
= pbx_find_extension(c
, NULL
, &q
, context
, exten
, PRIORITY_HINT
, NULL
, "", E_MATCH
);
1748 ast_mutex_unlock(&conlock
);
1753 /*! \brief ast_extensions_state2: Check state of extension by using hints */
1754 static int ast_extension_state2(struct ast_exten
*e
)
1756 char hint
[AST_MAX_EXTENSION
];
1758 int allunavailable
= 1, allbusy
= 1, allfree
= 1;
1759 int busy
= 0, inuse
= 0, ring
= 0;
1764 ast_copy_string(hint
, ast_get_extension_app(e
), sizeof(hint
));
1766 rest
= hint
; /* One or more devices separated with a & character */
1767 while ( (cur
= strsep(&rest
, "&")) ) {
1768 int res
= ast_device_state(cur
);
1770 case AST_DEVICE_NOT_INUSE
:
1774 case AST_DEVICE_INUSE
:
1779 case AST_DEVICE_RINGING
:
1784 case AST_DEVICE_RINGINUSE
:
1790 case AST_DEVICE_BUSY
:
1795 case AST_DEVICE_UNAVAILABLE
:
1796 case AST_DEVICE_INVALID
:
1808 return AST_EXTENSION_RINGING
;
1810 return (AST_EXTENSION_INUSE
| AST_EXTENSION_RINGING
);
1812 return AST_EXTENSION_INUSE
;
1814 return AST_EXTENSION_NOT_INUSE
;
1816 return AST_EXTENSION_BUSY
;
1818 return AST_EXTENSION_UNAVAILABLE
;
1820 return AST_EXTENSION_INUSE
;
1822 return AST_EXTENSION_NOT_INUSE
;
1825 /*! \brief ast_extension_state2str: Return extension_state as string */
1826 const char *ast_extension_state2str(int extension_state
)
1830 for (i
= 0; (i
< (sizeof(extension_states
) / sizeof(extension_states
[0]))); i
++) {
1831 if (extension_states
[i
].extension_state
== extension_state
)
1832 return extension_states
[i
].text
;
1837 /*! \brief ast_extension_state: Check extension state for an extension by using hint */
1838 int ast_extension_state(struct ast_channel
*c
, const char *context
, const char *exten
)
1840 struct ast_exten
*e
;
1842 e
= ast_hint_extension(c
, context
, exten
); /* Do we have a hint for this extension ? */
1844 return -1; /* No hint, return -1 */
1846 return ast_extension_state2(e
); /* Check all devices in the hint */
1849 void ast_hint_state_changed(const char *device
)
1851 struct ast_hint
*hint
;
1853 AST_LIST_LOCK(&hints
);
1855 AST_LIST_TRAVERSE(&hints
, hint
, list
) {
1856 struct ast_state_cb
*cblist
;
1857 char buf
[AST_MAX_EXTENSION
];
1862 ast_copy_string(buf
, ast_get_extension_app(hint
->exten
), sizeof(buf
));
1863 while ( (cur
= strsep(&parse
, "&")) ) {
1864 if (!strcasecmp(cur
, device
))
1870 /* Get device state for this hint */
1871 state
= ast_extension_state2(hint
->exten
);
1873 if ((state
== -1) || (state
== hint
->laststate
))
1876 /* Device state changed since last check - notify the watchers */
1878 /* For general callbacks */
1879 for (cblist
= statecbs
; cblist
; cblist
= cblist
->next
)
1880 cblist
->callback(hint
->exten
->parent
->name
, hint
->exten
->exten
, state
, cblist
->data
);
1882 /* For extension callbacks */
1883 for (cblist
= hint
->callbacks
; cblist
; cblist
= cblist
->next
)
1884 cblist
->callback(hint
->exten
->parent
->name
, hint
->exten
->exten
, state
, cblist
->data
);
1886 hint
->laststate
= state
; /* record we saw the change */
1889 AST_LIST_UNLOCK(&hints
);
1892 /*! \brief ast_extension_state_add: Add watcher for extension states */
1893 int ast_extension_state_add(const char *context
, const char *exten
,
1894 ast_state_cb_type callback
, void *data
)
1896 struct ast_hint
*hint
;
1897 struct ast_state_cb
*cblist
;
1898 struct ast_exten
*e
;
1900 /* If there's no context and extension: add callback to statecbs list */
1901 if (!context
&& !exten
) {
1902 AST_LIST_LOCK(&hints
);
1904 for (cblist
= statecbs
; cblist
; cblist
= cblist
->next
) {
1905 if (cblist
->callback
== callback
) {
1906 cblist
->data
= data
;
1907 AST_LIST_UNLOCK(&hints
);
1912 /* Now insert the callback */
1913 if (!(cblist
= ast_calloc(1, sizeof(*cblist
)))) {
1914 AST_LIST_UNLOCK(&hints
);
1918 cblist
->callback
= callback
;
1919 cblist
->data
= data
;
1921 cblist
->next
= statecbs
;
1924 AST_LIST_UNLOCK(&hints
);
1928 if (!context
|| !exten
)
1931 /* This callback type is for only one hint, so get the hint */
1932 e
= ast_hint_extension(NULL
, context
, exten
);
1937 /* Find the hint in the list of hints */
1938 AST_LIST_LOCK(&hints
);
1940 AST_LIST_TRAVERSE(&hints
, hint
, list
) {
1941 if (hint
->exten
== e
)
1946 /* We have no hint, sorry */
1947 AST_LIST_UNLOCK(&hints
);
1951 /* Now insert the callback in the callback list */
1952 if (!(cblist
= ast_calloc(1, sizeof(*cblist
)))) {
1953 AST_LIST_UNLOCK(&hints
);
1956 cblist
->id
= stateid
++; /* Unique ID for this callback */
1957 cblist
->callback
= callback
; /* Pointer to callback routine */
1958 cblist
->data
= data
; /* Data for the callback */
1960 cblist
->next
= hint
->callbacks
;
1961 hint
->callbacks
= cblist
;
1963 AST_LIST_UNLOCK(&hints
);
1967 /*! \brief ast_extension_state_del: Remove a watcher from the callback list */
1968 int ast_extension_state_del(int id
, ast_state_cb_type callback
)
1970 struct ast_state_cb
**p_cur
= NULL
; /* address of pointer to us */
1973 if (!id
&& !callback
)
1976 AST_LIST_LOCK(&hints
);
1978 if (!id
) { /* id == 0 is a callback without extension */
1979 for (p_cur
= &statecbs
; *p_cur
; p_cur
= &(*p_cur
)->next
) {
1980 if ((*p_cur
)->callback
== callback
)
1983 } else { /* callback with extension, find the callback based on ID */
1984 struct ast_hint
*hint
;
1985 AST_LIST_TRAVERSE(&hints
, hint
, list
) {
1986 for (p_cur
= &hint
->callbacks
; *p_cur
; p_cur
= &(*p_cur
)->next
) {
1987 if ((*p_cur
)->id
== id
)
1990 if (*p_cur
) /* found in the inner loop */
1994 if (p_cur
&& *p_cur
) {
1995 struct ast_state_cb
*cur
= *p_cur
;
2000 AST_LIST_UNLOCK(&hints
);
2004 /*! \brief ast_add_hint: Add hint to hint list, check initial extension state */
2005 static int ast_add_hint(struct ast_exten
*e
)
2007 struct ast_hint
*hint
;
2012 AST_LIST_LOCK(&hints
);
2014 /* Search if hint exists, do nothing */
2015 AST_LIST_TRAVERSE(&hints
, hint
, list
) {
2016 if (hint
->exten
== e
) {
2017 AST_LIST_UNLOCK(&hints
);
2018 if (option_debug
> 1)
2019 ast_log(LOG_DEBUG
, "HINTS: Not re-adding existing hint %s: %s\n", ast_get_extension_name(e
), ast_get_extension_app(e
));
2024 if (option_debug
> 1)
2025 ast_log(LOG_DEBUG
, "HINTS: Adding hint %s: %s\n", ast_get_extension_name(e
), ast_get_extension_app(e
));
2027 if (!(hint
= ast_calloc(1, sizeof(*hint
)))) {
2028 AST_LIST_UNLOCK(&hints
);
2031 /* Initialize and insert new item at the top */
2033 hint
->laststate
= ast_extension_state2(e
);
2034 AST_LIST_INSERT_HEAD(&hints
, hint
, list
);
2036 AST_LIST_UNLOCK(&hints
);
2040 /*! \brief ast_change_hint: Change hint for an extension */
2041 static int ast_change_hint(struct ast_exten
*oe
, struct ast_exten
*ne
)
2043 struct ast_hint
*hint
;
2046 AST_LIST_LOCK(&hints
);
2047 AST_LIST_TRAVERSE(&hints
, hint
, list
) {
2048 if (hint
->exten
== oe
) {
2054 AST_LIST_UNLOCK(&hints
);
2059 /*! \brief ast_remove_hint: Remove hint from extension */
2060 static int ast_remove_hint(struct ast_exten
*e
)
2062 /* Cleanup the Notifys if hint is removed */
2063 struct ast_hint
*hint
;
2064 struct ast_state_cb
*cblist
, *cbprev
;
2070 AST_LIST_LOCK(&hints
);
2071 AST_LIST_TRAVERSE_SAFE_BEGIN(&hints
, hint
, list
) {
2072 if (hint
->exten
== e
) {
2074 cblist
= hint
->callbacks
;
2076 /* Notify with -1 and remove all callbacks */
2078 cblist
= cblist
->next
;
2079 cbprev
->callback(hint
->exten
->parent
->name
, hint
->exten
->exten
, AST_EXTENSION_DEACTIVATED
, cbprev
->data
);
2082 hint
->callbacks
= NULL
;
2083 AST_LIST_REMOVE_CURRENT(&hints
, list
);
2089 AST_LIST_TRAVERSE_SAFE_END
2090 AST_LIST_UNLOCK(&hints
);
2096 /*! \brief ast_get_hint: Get hint for channel */
2097 int ast_get_hint(char *hint
, int hintsize
, char *name
, int namesize
, struct ast_channel
*c
, const char *context
, const char *exten
)
2099 struct ast_exten
*e
= ast_hint_extension(c
, context
, exten
);
2103 ast_copy_string(hint
, ast_get_extension_app(e
), hintsize
);
2105 const char *tmp
= ast_get_extension_app_data(e
);
2107 ast_copy_string(name
, tmp
, namesize
);
2114 int ast_exists_extension(struct ast_channel
*c
, const char *context
, const char *exten
, int priority
, const char *callerid
)
2116 return pbx_extension_helper(c
, NULL
, context
, exten
, priority
, NULL
, callerid
, E_MATCH
);
2119 int ast_findlabel_extension(struct ast_channel
*c
, const char *context
, const char *exten
, const char *label
, const char *callerid
)
2121 return pbx_extension_helper(c
, NULL
, context
, exten
, 0, label
, callerid
, E_FINDLABEL
);
2124 int ast_findlabel_extension2(struct ast_channel
*c
, struct ast_context
*con
, const char *exten
, const char *label
, const char *callerid
)
2126 return pbx_extension_helper(c
, con
, NULL
, exten
, 0, label
, callerid
, E_FINDLABEL
);
2129 int ast_canmatch_extension(struct ast_channel
*c
, const char *context
, const char *exten
, int priority
, const char *callerid
)
2131 return pbx_extension_helper(c
, NULL
, context
, exten
, priority
, NULL
, callerid
, E_CANMATCH
);
2134 int ast_matchmore_extension(struct ast_channel
*c
, const char *context
, const char *exten
, int priority
, const char *callerid
)
2136 return pbx_extension_helper(c
, NULL
, context
, exten
, priority
, NULL
, callerid
, E_MATCHMORE
);
2139 int ast_spawn_extension(struct ast_channel
*c
, const char *context
, const char *exten
, int priority
, const char *callerid
)
2141 return pbx_extension_helper(c
, NULL
, context
, exten
, priority
, NULL
, callerid
, E_SPAWN
);
2144 /* helper function to set extension and priority */
2145 static void set_ext_pri(struct ast_channel
*c
, const char *exten
, int pri
)
2147 ast_copy_string(c
->exten
, exten
, sizeof(c
->exten
));
2152 * \brief collect digits from the channel into the buffer,
2153 * return -1 on error, 0 on timeout or done.
2155 static int collect_digits(struct ast_channel
*c
, int waittime
, char *buf
, int buflen
, int pos
)
2159 buf
[pos
] = '\0'; /* make sure it is properly terminated */
2160 while (ast_matchmore_extension(c
, c
->context
, buf
, 1, c
->cid
.cid_num
)) {
2161 /* As long as we're willing to wait, and as long as it's not defined,
2162 keep reading digits until we can't possibly get a right answer anymore. */
2163 digit
= ast_waitfordigit(c
, waittime
* 1000);
2164 if (c
->_softhangup
== AST_SOFTHANGUP_ASYNCGOTO
) {
2167 if (!digit
) /* No entry */
2169 if (digit
< 0) /* Error, maybe a hangup */
2171 if (pos
< buflen
- 1) { /* XXX maybe error otherwise ? */
2175 waittime
= c
->pbx
->dtimeout
;
2181 static int __ast_pbx_run(struct ast_channel
*c
)
2183 int found
= 0; /* set if we find at least one match */
2186 int error
= 0; /* set an error conditions */
2188 /* A little initial setup here */
2190 ast_log(LOG_WARNING
, "%s already has PBX structure??\n", c
->name
);
2191 /* XXX and now what ? */
2194 if (!(c
->pbx
= ast_calloc(1, sizeof(*c
->pbx
))))
2198 c
->cdr
= ast_cdr_alloc();
2200 ast_log(LOG_WARNING
, "Unable to create Call Detail Record\n");
2204 ast_cdr_init(c
->cdr
, c
);
2207 /* Set reasonable defaults */
2208 c
->pbx
->rtimeout
= 10;
2209 c
->pbx
->dtimeout
= 5;
2211 autoloopflag
= ast_test_flag(c
, AST_FLAG_IN_AUTOLOOP
); /* save value to restore at the end */
2212 ast_set_flag(c
, AST_FLAG_IN_AUTOLOOP
);
2214 /* Start by trying whatever the channel is set to */
2215 if (!ast_exists_extension(c
, c
->context
, c
->exten
, c
->priority
, c
->cid
.cid_num
)) {
2216 /* If not successful fall back to 's' */
2217 if (option_verbose
> 1)
2218 ast_verbose( VERBOSE_PREFIX_2
"Starting %s at %s,%s,%d failed so falling back to exten 's'\n", c
->name
, c
->context
, c
->exten
, c
->priority
);
2219 /* XXX the original code used the existing priority in the call to
2220 * ast_exists_extension(), and reset it to 1 afterwards.
2221 * I believe the correct thing is to set it to 1 immediately.
2223 set_ext_pri(c
, "s", 1);
2224 if (!ast_exists_extension(c
, c
->context
, c
->exten
, c
->priority
, c
->cid
.cid_num
)) {
2225 /* JK02: And finally back to default if everything else failed */
2226 if (option_verbose
> 1)
2227 ast_verbose( VERBOSE_PREFIX_2
"Starting %s at %s,%s,%d still failed so falling back to context 'default'\n", c
->name
, c
->context
, c
->exten
, c
->priority
);
2228 ast_copy_string(c
->context
, "default", sizeof(c
->context
));
2231 if (c
->cdr
&& ast_tvzero(c
->cdr
->start
))
2232 ast_cdr_start(c
->cdr
);
2234 char dst_exten
[256]; /* buffer to accumulate digits */
2235 int pos
= 0; /* XXX should check bounds */
2238 /* loop on priorities in this context/exten */
2239 while (ast_exists_extension(c
, c
->context
, c
->exten
, c
->priority
, c
->cid
.cid_num
)) {
2241 if ((res
= ast_spawn_extension(c
, c
->context
, c
->exten
, c
->priority
, c
->cid
.cid_num
))) {
2242 /* Something bad happened, or a hangup has been requested. */
2243 if (strchr("0123456789ABCDEF*#", res
)) {
2244 ast_log(LOG_DEBUG
, "Oooh, got something to jump out with ('%c')!\n", res
);
2246 dst_exten
[pos
++] = digit
= res
;
2247 dst_exten
[pos
] = '\0';
2250 if (res
== AST_PBX_KEEPALIVE
) {
2252 ast_log(LOG_DEBUG
, "Spawn extension (%s,%s,%d) exited KEEPALIVE on '%s'\n", c
->context
, c
->exten
, c
->priority
, c
->name
);
2253 else if (option_verbose
> 1)
2254 ast_verbose( VERBOSE_PREFIX_2
"Spawn extension (%s, %s, %d) exited KEEPALIVE on '%s'\n", c
->context
, c
->exten
, c
->priority
, c
->name
);
2259 ast_log(LOG_DEBUG
, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c
->context
, c
->exten
, c
->priority
, c
->name
);
2260 else if (option_verbose
> 1)
2261 ast_verbose( VERBOSE_PREFIX_2
"Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c
->context
, c
->exten
, c
->priority
, c
->name
);
2262 if (c
->_softhangup
== AST_SOFTHANGUP_ASYNCGOTO
) {
2264 } else if (c
->_softhangup
== AST_SOFTHANGUP_TIMEOUT
) {
2265 /* atimeout, nothing bad */
2273 if (c
->_softhangup
== AST_SOFTHANGUP_TIMEOUT
&& ast_exists_extension(c
,c
->context
,"T",1,c
->cid
.cid_num
)) {
2274 set_ext_pri(c
, "T", 0); /* 0 will become 1 with the c->priority++; at the end */
2275 /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
2276 c
->whentohangup
= 0;
2277 c
->_softhangup
&= ~AST_SOFTHANGUP_TIMEOUT
;
2278 } else if (c
->_softhangup
) {
2279 ast_log(LOG_DEBUG
, "Extension %s, priority %d returned normally even though call was hung up\n",
2280 c
->exten
, c
->priority
);
2285 } /* end while - from here on we can use 'break' to go out */
2289 /* XXX we get here on non-existing extension or a keypress or hangup ? */
2291 if (!ast_exists_extension(c
, c
->context
, c
->exten
, 1, c
->cid
.cid_num
)) {
2292 /* If there is no match at priority 1, it is not a valid extension anymore.
2293 * Try to continue at "i", 1 or exit if the latter does not exist.
2295 if (ast_exists_extension(c
, c
->context
, "i", 1, c
->cid
.cid_num
)) {
2296 if (option_verbose
> 2)
2297 ast_verbose(VERBOSE_PREFIX_3
"Sent into invalid extension '%s' in context '%s' on %s\n", c
->exten
, c
->context
, c
->name
);
2298 pbx_builtin_setvar_helper(c
, "INVALID_EXTEN", c
->exten
);
2299 set_ext_pri(c
, "i", 1);
2301 ast_log(LOG_WARNING
, "Channel '%s' sent into invalid extension '%s' in context '%s', but no invalid handler\n",
2302 c
->name
, c
->exten
, c
->context
);
2303 error
= 1; /* we know what to do with it */
2306 } else if (c
->_softhangup
== AST_SOFTHANGUP_TIMEOUT
) {
2307 /* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */
2309 } else { /* keypress received, get more digits for a full extension */
2312 waittime
= c
->pbx
->dtimeout
;
2313 else if (!autofallthrough
)
2314 waittime
= c
->pbx
->rtimeout
;
2316 const char *status
= pbx_builtin_getvar_helper(c
, "DIALSTATUS");
2319 if (option_verbose
> 2)
2320 ast_verbose(VERBOSE_PREFIX_2
"Auto fallthrough, channel '%s' status is '%s'\n", c
->name
, status
);
2321 if (!strcasecmp(status
, "CONGESTION"))
2322 res
= pbx_builtin_congestion(c
, "10");
2323 else if (!strcasecmp(status
, "CHANUNAVAIL"))
2324 res
= pbx_builtin_congestion(c
, "10");
2325 else if (!strcasecmp(status
, "BUSY"))
2326 res
= pbx_builtin_busy(c
, "10");
2327 error
= 1; /* XXX disable message */
2328 break; /* exit from the 'for' loop */
2331 if (collect_digits(c
, waittime
, dst_exten
, sizeof(dst_exten
), pos
))
2333 if (ast_exists_extension(c
, c
->context
, dst_exten
, 1, c
->cid
.cid_num
)) /* Prepare the next cycle */
2334 set_ext_pri(c
, dst_exten
, 1);
2336 /* No such extension */
2337 if (!ast_strlen_zero(dst_exten
)) {
2338 /* An invalid extension */
2339 if (ast_exists_extension(c
, c
->context
, "i", 1, c
->cid
.cid_num
)) {
2340 if (option_verbose
> 2)
2341 ast_verbose( VERBOSE_PREFIX_3
"Invalid extension '%s' in context '%s' on %s\n", dst_exten
, c
->context
, c
->name
);
2342 pbx_builtin_setvar_helper(c
, "INVALID_EXTEN", dst_exten
);
2343 set_ext_pri(c
, "i", 1);
2345 ast_log(LOG_WARNING
, "Invalid extension '%s', but no rule 'i' in context '%s'\n", dst_exten
, c
->context
);
2346 found
= 1; /* XXX disable message */
2350 /* A simple timeout */
2351 if (ast_exists_extension(c
, c
->context
, "t", 1, c
->cid
.cid_num
)) {
2352 if (option_verbose
> 2)
2353 ast_verbose( VERBOSE_PREFIX_3
"Timeout on %s\n", c
->name
);
2354 set_ext_pri(c
, "t", 1);
2356 ast_log(LOG_WARNING
, "Timeout, but no rule 't' in context '%s'\n", c
->context
);
2357 found
= 1; /* XXX disable message */
2363 if (option_verbose
> 2)
2364 ast_verbose(VERBOSE_PREFIX_2
"CDR updated on %s\n",c
->name
);
2369 if (!found
&& !error
)
2370 ast_log(LOG_WARNING
, "Don't know what to do with '%s'\n", c
->name
);
2371 if ((res
!= AST_PBX_KEEPALIVE
) && ast_exists_extension(c
, c
->context
, "h", 1, c
->cid
.cid_num
)) {
2372 if (c
->cdr
&& ast_opt_end_cdr_before_h_exten
)
2373 ast_cdr_end(c
->cdr
);
2374 set_ext_pri(c
, "h", 1);
2375 while(ast_exists_extension(c
, c
->context
, c
->exten
, c
->priority
, c
->cid
.cid_num
)) {
2376 if ((res
= ast_spawn_extension(c
, c
->context
, c
->exten
, c
->priority
, c
->cid
.cid_num
))) {
2377 /* Something bad happened, or a hangup has been requested. */
2379 ast_log(LOG_DEBUG
, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c
->context
, c
->exten
, c
->priority
, c
->name
);
2380 else if (option_verbose
> 1)
2381 ast_verbose( VERBOSE_PREFIX_2
"Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c
->context
, c
->exten
, c
->priority
, c
->name
);
2387 ast_set2_flag(c
, autoloopflag
, AST_FLAG_IN_AUTOLOOP
);
2389 pbx_destroy(c
->pbx
);
2391 if (res
!= AST_PBX_KEEPALIVE
)
2396 /* Returns 0 on success, non-zero if call limit was reached */
2397 static int increase_call_count(const struct ast_channel
*c
)
2401 ast_mutex_lock(&maxcalllock
);
2402 if (option_maxcalls
) {
2403 if (countcalls
>= option_maxcalls
) {
2404 ast_log(LOG_NOTICE
, "Maximum call limit of %d calls exceeded by '%s'!\n", option_maxcalls
, c
->name
);
2408 if (option_maxload
) {
2409 getloadavg(&curloadavg
, 1);
2410 if (curloadavg
>= option_maxload
) {
2411 ast_log(LOG_NOTICE
, "Maximum loadavg limit of %f load exceeded by '%s' (currently %f)!\n", option_maxload
, c
->name
, curloadavg
);
2417 ast_mutex_unlock(&maxcalllock
);
2422 static void decrease_call_count(void)
2424 ast_mutex_lock(&maxcalllock
);
2427 ast_mutex_unlock(&maxcalllock
);
2430 static void destroy_exten(struct ast_exten
*e
)
2432 if (e
->priority
== PRIORITY_HINT
)
2440 static void *pbx_thread(void *data
)
2442 /* Oh joyeous kernel, we're a new thread, with nothing to do but
2443 answer this channel and get it going.
2446 The launcher of this function _MUST_ increment 'countcalls'
2447 before invoking the function; it will be decremented when the
2448 PBX has finished running on the channel
2450 struct ast_channel
*c
= data
;
2453 decrease_call_count();
2460 enum ast_pbx_result
ast_pbx_start(struct ast_channel
*c
)
2463 pthread_attr_t attr
;
2466 ast_log(LOG_WARNING
, "Asked to start thread on NULL channel?\n");
2467 return AST_PBX_FAILED
;
2470 if (increase_call_count(c
))
2471 return AST_PBX_CALL_LIMIT
;
2473 /* Start a new thread, and get something handling this channel. */
2474 pthread_attr_init(&attr
);
2475 pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
2476 if (ast_pthread_create(&t
, &attr
, pbx_thread
, c
)) {
2477 ast_log(LOG_WARNING
, "Failed to create new channel thread\n");
2478 return AST_PBX_FAILED
;
2481 return AST_PBX_SUCCESS
;
2484 enum ast_pbx_result
ast_pbx_run(struct ast_channel
*c
)
2486 enum ast_pbx_result res
= AST_PBX_SUCCESS
;
2488 if (increase_call_count(c
))
2489 return AST_PBX_CALL_LIMIT
;
2491 res
= __ast_pbx_run(c
);
2492 decrease_call_count();
2497 int ast_active_calls(void)
2502 int pbx_set_autofallthrough(int newval
)
2504 int oldval
= autofallthrough
;
2505 autofallthrough
= newval
;
2509 /* lookup for a context with a given name,
2510 * return with conlock held if found, NULL if not found
2512 static struct ast_context
*find_context_locked(const char *context
)
2514 struct ast_context
*c
= NULL
;
2516 ast_lock_contexts();
2517 while ( (c
= ast_walk_contexts(c
)) ) {
2518 if (!strcmp(ast_get_context_name(c
), context
))
2521 ast_unlock_contexts();
2527 * This function locks contexts list by &conlist, search for the right context
2528 * structure, leave context list locked and call ast_context_remove_include2
2529 * which removes include, unlock contexts list and return ...
2531 int ast_context_remove_include(const char *context
, const char *include
, const char *registrar
)
2534 struct ast_context
*c
= find_context_locked(context
);
2537 /* found, remove include from this context ... */
2538 ret
= ast_context_remove_include2(c
, include
, registrar
);
2539 ast_unlock_contexts();
2545 * When we call this function, &conlock lock must be locked, because when
2546 * we giving *con argument, some process can remove/change this context
2547 * and after that there can be segfault.
2549 * This function locks given context, removes include, unlock context and
2552 int ast_context_remove_include2(struct ast_context
*con
, const char *include
, const char *registrar
)
2554 struct ast_include
*i
, *pi
= NULL
;
2557 ast_mutex_lock(&con
->lock
);
2559 /* find our include */
2560 for (i
= con
->includes
; i
; pi
= i
, i
= i
->next
) {
2561 if (!strcmp(i
->name
, include
) &&
2562 (!registrar
|| !strcmp(i
->registrar
, registrar
))) {
2563 /* remove from list */
2567 con
->includes
= i
->next
;
2568 /* free include and return */
2575 ast_mutex_unlock(&con
->lock
);
2580 * \note This function locks contexts list by &conlist, search for the rigt context
2581 * structure, leave context list locked and call ast_context_remove_switch2
2582 * which removes switch, unlock contexts list and return ...
2584 int ast_context_remove_switch(const char *context
, const char *sw
, const char *data
, const char *registrar
)
2586 int ret
= -1; /* default error return */
2587 struct ast_context
*c
= find_context_locked(context
);
2590 /* remove switch from this context ... */
2591 ret
= ast_context_remove_switch2(c
, sw
, data
, registrar
);
2592 ast_unlock_contexts();
2598 * \brief This function locks given context, removes switch, unlock context and
2600 * \note When we call this function, &conlock lock must be locked, because when
2601 * we giving *con argument, some process can remove/change this context
2602 * and after that there can be segfault.
2605 int ast_context_remove_switch2(struct ast_context
*con
, const char *sw
, const char *data
, const char *registrar
)
2610 ast_mutex_lock(&con
->lock
);
2613 AST_LIST_TRAVERSE_SAFE_BEGIN(&con
->alts
, i
, list
) {
2614 if (!strcmp(i
->name
, sw
) && !strcmp(i
->data
, data
) &&
2615 (!registrar
|| !strcmp(i
->registrar
, registrar
))) {
2616 /* found, remove from list */
2617 AST_LIST_REMOVE_CURRENT(&con
->alts
, list
);
2618 free(i
); /* free switch and return */
2623 AST_LIST_TRAVERSE_SAFE_END
2625 ast_mutex_unlock(&con
->lock
);
2631 * \note This functions lock contexts list, search for the right context,
2632 * call ast_context_remove_extension2, unlock contexts list and return.
2633 * In this function we are using
2635 int ast_context_remove_extension(const char *context
, const char *extension
, int priority
, const char *registrar
)
2637 int ret
= -1; /* default error return */
2638 struct ast_context
*c
= find_context_locked(context
);
2640 if (c
) { /* ... remove extension ... */
2641 ret
= ast_context_remove_extension2(c
, extension
, priority
, registrar
);
2642 ast_unlock_contexts();
2648 * \brief This functionc locks given context, search for the right extension and
2649 * fires out all peer in this extensions with given priority. If priority
2650 * is set to 0, all peers are removed. After that, unlock context and
2652 * \note When do you want to call this function, make sure that &conlock is locked,
2653 * because some process can handle with your *con context before you lock
2657 int ast_context_remove_extension2(struct ast_context
*con
, const char *extension
, int priority
, const char *registrar
)
2659 struct ast_exten
*exten
, *prev_exten
= NULL
;
2660 struct ast_exten
*peer
;
2662 ast_mutex_lock(&con
->lock
);
2664 /* scan the extension list to find matching extension-registrar */
2665 for (exten
= con
->root
; exten
; prev_exten
= exten
, exten
= exten
->next
) {
2666 if (!strcmp(exten
->exten
, extension
) &&
2667 (!registrar
|| !strcmp(exten
->registrar
, registrar
)))
2671 /* we can't find right extension */
2672 ast_mutex_unlock(&con
->lock
);
2676 /* should we free all peers in this extension? (priority == 0)? */
2677 if (priority
== 0) {
2678 /* remove this extension from context list */
2680 prev_exten
->next
= exten
->next
;
2682 con
->root
= exten
->next
;
2684 /* fire out all peers */
2685 while ( (peer
= exten
) ) {
2686 exten
= peer
->peer
; /* prepare for next entry */
2687 destroy_exten(peer
);
2690 /* scan the priority list to remove extension with exten->priority == priority */
2691 struct ast_exten
*previous_peer
= NULL
;
2693 for (peer
= exten
; peer
; previous_peer
= peer
, peer
= peer
->peer
) {
2694 if (peer
->priority
== priority
&&
2695 (!registrar
|| !strcmp(peer
->registrar
, registrar
) ))
2696 break; /* found our priority */
2698 if (!peer
) { /* not found */
2699 ast_mutex_unlock(&con
->lock
);
2702 /* we are first priority extension? */
2703 if (!previous_peer
) {
2705 * We are first in the priority chain, so must update the extension chain.
2706 * The next node is either the next priority or the next extension
2708 struct ast_exten
*next_node
= peer
->peer
? peer
->peer
: peer
->next
;
2710 if (!prev_exten
) /* change the root... */
2711 con
->root
= next_node
;
2713 prev_exten
->next
= next_node
; /* unlink */
2714 if (peer
->peer
) /* XXX update the new head of the pri list */
2715 peer
->peer
->next
= peer
->next
;
2716 } else { /* easy, we are not first priority in extension */
2717 previous_peer
->peer
= peer
->peer
;
2720 /* now, free whole priority extension */
2721 destroy_exten(peer
);
2722 /* XXX should we return -1 ? */
2724 ast_mutex_unlock(&con
->lock
);
2729 /*! \brief Dynamically register a new dial plan application */
2730 int ast_register_application(const char *app
, int (*execute
)(struct ast_channel
*, void *), const char *synopsis
, const char *description
)
2732 struct ast_app
*tmp
, *cur
= NULL
;
2736 AST_LIST_LOCK(&apps
);
2737 AST_LIST_TRAVERSE(&apps
, tmp
, list
) {
2738 if (!strcasecmp(app
, tmp
->name
)) {
2739 ast_log(LOG_WARNING
, "Already have an application '%s'\n", app
);
2740 AST_LIST_UNLOCK(&apps
);
2745 length
= sizeof(*tmp
) + strlen(app
) + 1;
2747 if (!(tmp
= ast_calloc(1, length
))) {
2748 AST_LIST_UNLOCK(&apps
);
2752 strcpy(tmp
->name
, app
);
2753 tmp
->execute
= execute
;
2754 tmp
->synopsis
= synopsis
;
2755 tmp
->description
= description
;
2757 /* Store in alphabetical order */
2758 AST_LIST_TRAVERSE_SAFE_BEGIN(&apps
, cur
, list
) {
2759 if (strcasecmp(tmp
->name
, cur
->name
) < 0) {
2760 AST_LIST_INSERT_BEFORE_CURRENT(&apps
, tmp
, list
);
2764 AST_LIST_TRAVERSE_SAFE_END
2766 AST_LIST_INSERT_TAIL(&apps
, tmp
, list
);
2768 if (option_verbose
> 1)
2769 ast_verbose( VERBOSE_PREFIX_2
"Registered application '%s'\n", term_color(tmps
, tmp
->name
, COLOR_BRCYAN
, 0, sizeof(tmps
)));
2771 AST_LIST_UNLOCK(&apps
);
2777 * Append to the list. We don't have a tail pointer because we need
2778 * to scan the list anyways to check for duplicates during insertion.
2780 int ast_register_switch(struct ast_switch
*sw
)
2782 struct ast_switch
*tmp
;
2784 AST_LIST_LOCK(&switches
);
2785 AST_LIST_TRAVERSE(&switches
, tmp
, list
) {
2786 if (!strcasecmp(tmp
->name
, sw
->name
)) {
2787 AST_LIST_UNLOCK(&switches
);
2788 ast_log(LOG_WARNING
, "Switch '%s' already found\n", sw
->name
);
2792 AST_LIST_INSERT_TAIL(&switches
, sw
, list
);
2793 AST_LIST_UNLOCK(&switches
);
2798 void ast_unregister_switch(struct ast_switch
*sw
)
2800 AST_LIST_LOCK(&switches
);
2801 AST_LIST_REMOVE(&switches
, sw
, list
);
2802 AST_LIST_UNLOCK(&switches
);
2806 * Help for CLI commands ...
2808 static char show_application_help
[] =
2809 "Usage: show application <application> [<application> [<application> [...]]]\n"
2810 " Describes a particular application.\n";
2812 static char show_functions_help
[] =
2813 "Usage: show functions [like <text>]\n"
2814 " List builtin functions, optionally only those matching a given string\n";
2816 static char show_function_help
[] =
2817 "Usage: show function <function>\n"
2818 " Describe a particular dialplan function.\n";
2820 static char show_applications_help
[] =
2821 "Usage: show applications [{like|describing} <text>]\n"
2822 " List applications which are currently available.\n"
2823 " If 'like', <text> will be a substring of the app name\n"
2824 " If 'describing', <text> will be a substring of the description\n";
2826 static char show_dialplan_help
[] =
2827 "Usage: show dialplan [exten@][context]\n"
2830 static char show_switches_help
[] =
2831 "Usage: show switches\n"
2832 " Show registered switches\n";
2834 static char show_hints_help
[] =
2835 "Usage: show hints\n"
2836 " Show registered hints\n";
2838 static char show_globals_help
[] =
2839 "Usage: show globals\n"
2840 " Show current global dialplan variables and their values\n";
2842 static char set_global_help
[] =
2843 "Usage: set global <name> <value>\n"
2844 " Set global dialplan variable <name> to <value>\n";
2848 * IMPLEMENTATION OF CLI FUNCTIONS IS IN THE SAME ORDER AS COMMANDS HELPS
2853 * \brief 'show application' CLI command implementation functions ...
2857 * There is a possibility to show informations about more than one
2858 * application at one time. You can type 'show application Dial Echo' and
2859 * you will see informations about these two applications ...
2861 static char *complete_show_application(const char *line
, const char *word
, int pos
, int state
)
2866 int wordlen
= strlen(word
);
2868 /* return the n-th [partial] matching entry */
2869 AST_LIST_LOCK(&apps
);
2870 AST_LIST_TRAVERSE(&apps
, a
, list
) {
2871 if (!strncasecmp(word
, a
->name
, wordlen
) && ++which
> state
) {
2872 ret
= strdup(a
->name
);
2876 AST_LIST_UNLOCK(&apps
);
2881 static int handle_show_application(int fd
, int argc
, char *argv
[])
2884 int app
, no_registered_app
= 1;
2887 return RESULT_SHOWUSAGE
;
2889 /* ... go through all applications ... */
2890 AST_LIST_LOCK(&apps
);
2891 AST_LIST_TRAVERSE(&apps
, a
, list
) {
2892 /* ... compare this application name with all arguments given
2893 * to 'show application' command ... */
2894 for (app
= 2; app
< argc
; app
++) {
2895 if (!strcasecmp(a
->name
, argv
[app
])) {
2896 /* Maximum number of characters added by terminal coloring is 22 */
2897 char infotitle
[64 + AST_MAX_APP
+ 22], syntitle
[40], destitle
[40];
2898 char info
[64 + AST_MAX_APP
], *synopsis
= NULL
, *description
= NULL
;
2899 int synopsis_size
, description_size
;
2901 no_registered_app
= 0;
2904 synopsis_size
= strlen(a
->synopsis
) + 23;
2906 synopsis_size
= strlen("Not available") + 23;
2907 synopsis
= alloca(synopsis_size
);
2910 description_size
= strlen(a
->description
) + 23;
2912 description_size
= strlen("Not available") + 23;
2913 description
= alloca(description_size
);
2915 if (synopsis
&& description
) {
2916 snprintf(info
, 64 + AST_MAX_APP
, "\n -= Info about application '%s' =- \n\n", a
->name
);
2917 term_color(infotitle
, info
, COLOR_MAGENTA
, 0, 64 + AST_MAX_APP
+ 22);
2918 term_color(syntitle
, "[Synopsis]\n", COLOR_MAGENTA
, 0, 40);
2919 term_color(destitle
, "[Description]\n", COLOR_MAGENTA
, 0, 40);
2920 term_color(synopsis
,
2921 a
->synopsis
? a
->synopsis
: "Not available",
2922 COLOR_CYAN
, 0, synopsis_size
);
2923 term_color(description
,
2924 a
->description
? a
->description
: "Not available",
2925 COLOR_CYAN
, 0, description_size
);
2927 ast_cli(fd
,"%s%s%s\n\n%s%s\n", infotitle
, syntitle
, synopsis
, destitle
, description
);
2929 /* ... one of our applications, show info ...*/
2930 ast_cli(fd
,"\n -= Info about application '%s' =- \n\n"
2931 "[Synopsis]\n %s\n\n"
2932 "[Description]\n%s\n",
2934 a
->synopsis
? a
->synopsis
: "Not available",
2935 a
->description
? a
->description
: "Not available");
2940 AST_LIST_UNLOCK(&apps
);
2942 /* we found at least one app? no? */
2943 if (no_registered_app
) {
2944 ast_cli(fd
, "Your application(s) is (are) not registered\n");
2945 return RESULT_FAILURE
;
2948 return RESULT_SUCCESS
;
2951 /*! \brief handle_show_hints: CLI support for listing registred dial plan hints */
2952 static int handle_show_hints(int fd
, int argc
, char *argv
[])
2954 struct ast_hint
*hint
;
2957 struct ast_state_cb
*watcher
;
2959 if (AST_LIST_EMPTY(&hints
)) {
2960 ast_cli(fd
, "There are no registered dialplan hints\n");
2961 return RESULT_SUCCESS
;
2963 /* ... we have hints ... */
2964 ast_cli(fd
, "\n -= Registered Asterisk Dial Plan Hints =-\n");
2965 AST_LIST_LOCK(&hints
);
2966 AST_LIST_TRAVERSE(&hints
, hint
, list
) {
2968 for (watcher
= hint
->callbacks
; watcher
; watcher
= watcher
->next
)
2970 ast_cli(fd
, " %20s@%-20.20s: %-20.20s State:%-15.15s Watchers %2d\n",
2971 ast_get_extension_name(hint
->exten
),
2972 ast_get_context_name(ast_get_extension_context(hint
->exten
)),
2973 ast_get_extension_app(hint
->exten
),
2974 ast_extension_state2str(hint
->laststate
), watchers
);
2977 ast_cli(fd
, "----------------\n");
2978 ast_cli(fd
, "- %d hints registered\n", num
);
2979 AST_LIST_UNLOCK(&hints
);
2980 return RESULT_SUCCESS
;
2983 /*! \brief handle_show_switches: CLI support for listing registred dial plan switches */
2984 static int handle_show_switches(int fd
, int argc
, char *argv
[])
2986 struct ast_switch
*sw
;
2988 AST_LIST_LOCK(&switches
);
2990 if (AST_LIST_EMPTY(&switches
)) {
2991 AST_LIST_UNLOCK(&switches
);
2992 ast_cli(fd
, "There are no registered alternative switches\n");
2993 return RESULT_SUCCESS
;
2996 ast_cli(fd
, "\n -= Registered Asterisk Alternative Switches =-\n");
2997 AST_LIST_TRAVERSE(&switches
, sw
, list
)
2998 ast_cli(fd
, "%s: %s\n", sw
->name
, sw
->description
);
3000 AST_LIST_UNLOCK(&switches
);
3002 return RESULT_SUCCESS
;
3006 * 'show applications' CLI command implementation functions ...
3008 static int handle_show_applications(int fd
, int argc
, char *argv
[])
3011 int like
= 0, describing
= 0;
3012 int total_match
= 0; /* Number of matches in like clause */
3013 int total_apps
= 0; /* Number of apps registered */
3015 AST_LIST_LOCK(&apps
);
3017 if (AST_LIST_EMPTY(&apps
)) {
3018 ast_cli(fd
, "There are no registered applications\n");
3019 AST_LIST_UNLOCK(&apps
);
3023 /* show applications like <keyword> */
3024 if ((argc
== 4) && (!strcmp(argv
[2], "like"))) {
3026 } else if ((argc
> 3) && (!strcmp(argv
[2], "describing"))) {
3030 /* show applications describing <keyword1> [<keyword2>] [...] */
3031 if ((!like
) && (!describing
)) {
3032 ast_cli(fd
, " -= Registered Asterisk Applications =-\n");
3034 ast_cli(fd
, " -= Matching Asterisk Applications =-\n");
3037 AST_LIST_TRAVERSE(&apps
, a
, list
) {
3041 if (strcasestr(a
->name
, argv
[3])) {
3045 } else if (describing
) {
3046 if (a
->description
) {
3047 /* Match all words on command line */
3050 for (i
= 3; i
< argc
; i
++) {
3051 if (!strcasestr(a
->description
, argv
[i
])) {
3063 ast_cli(fd
," %20s: %s\n", a
->name
, a
->synopsis
? a
->synopsis
: "<Synopsis not available>");
3066 if ((!like
) && (!describing
)) {
3067 ast_cli(fd
, " -= %d Applications Registered =-\n",total_apps
);
3069 ast_cli(fd
, " -= %d Applications Matching =-\n",total_match
);
3072 AST_LIST_UNLOCK(&apps
);
3074 return RESULT_SUCCESS
;
3077 static char *complete_show_applications(const char *line
, const char *word
, int pos
, int state
)
3079 static char* choices
[] = { "like", "describing", NULL
};
3081 return (pos
!= 2) ? NULL
: ast_cli_complete(word
, choices
, state
);
3085 * 'show dialplan' CLI command implementation functions ...
3087 static char *complete_show_dialplan_context(const char *line
, const char *word
, int pos
,
3090 struct ast_context
*c
= NULL
;
3095 /* we are do completion of [exten@]context on second position only */
3099 ast_lock_contexts();
3101 wordlen
= strlen(word
);
3103 /* walk through all contexts and return the n-th match */
3104 while ( (c
= ast_walk_contexts(c
)) ) {
3105 if (!strncasecmp(word
, ast_get_context_name(c
), wordlen
) && ++which
> state
) {
3106 ret
= ast_strdup(ast_get_context_name(c
));
3111 ast_unlock_contexts();
3116 struct dialplan_counters
{
3120 int context_existence
;
3121 int extension_existence
;
3124 /*! \brief helper function to print an extension */
3125 static void print_ext(struct ast_exten
*e
, char * buf
, int buflen
)
3127 int prio
= ast_get_extension_priority(e
);
3128 if (prio
== PRIORITY_HINT
) {
3129 snprintf(buf
, buflen
, "hint: %s",
3130 ast_get_extension_app(e
));
3132 snprintf(buf
, buflen
, "%d. %s(%s)",
3133 prio
, ast_get_extension_app(e
),
3134 (char *)ast_get_extension_app_data(e
));
3138 /* XXX not verified */
3139 static int show_dialplan_helper(int fd
, const char *context
, const char *exten
, struct dialplan_counters
*dpc
, struct ast_include
*rinclude
, int includecount
, const char *includes
[])
3141 struct ast_context
*c
= NULL
;
3142 int res
= 0, old_total_exten
= dpc
->total_exten
;
3144 ast_lock_contexts();
3146 /* walk all contexts ... */
3147 while ( (c
= ast_walk_contexts(c
)) ) {
3148 struct ast_exten
*e
;
3149 struct ast_include
*i
;
3150 struct ast_ignorepat
*ip
;
3151 char buf
[256], buf2
[256];
3152 int context_info_printed
= 0;
3154 if (context
&& strcmp(ast_get_context_name(c
), context
))
3155 continue; /* skip this one, name doesn't match */
3157 dpc
->context_existence
= 1;
3159 ast_lock_context(c
);
3161 /* are we looking for exten too? if yes, we print context
3162 * only if we find our extension.
3163 * Otherwise print context even if empty ?
3164 * XXX i am not sure how the rinclude is handled.
3165 * I think it ought to go inside.
3168 dpc
->total_context
++;
3169 ast_cli(fd
, "[ Context '%s' created by '%s' ]\n",
3170 ast_get_context_name(c
), ast_get_context_registrar(c
));
3171 context_info_printed
= 1;
3174 /* walk extensions ... */
3176 while ( (e
= ast_walk_context_extensions(c
, e
)) ) {
3177 struct ast_exten
*p
;
3179 if (exten
&& !ast_extension_match(ast_get_extension_name(e
), exten
))
3180 continue; /* skip, extension match failed */
3182 dpc
->extension_existence
= 1;
3184 /* may we print context info? */
3185 if (!context_info_printed
) {
3186 dpc
->total_context
++;
3187 if (rinclude
) { /* TODO Print more info about rinclude */
3188 ast_cli(fd
, "[ Included context '%s' created by '%s' ]\n",
3189 ast_get_context_name(c
), ast_get_context_registrar(c
));
3191 ast_cli(fd
, "[ Context '%s' created by '%s' ]\n",
3192 ast_get_context_name(c
), ast_get_context_registrar(c
));
3194 context_info_printed
= 1;
3198 /* write extension name and first peer */
3199 snprintf(buf
, sizeof(buf
), "'%s' =>", ast_get_extension_name(e
));
3201 print_ext(e
, buf2
, sizeof(buf2
));
3203 ast_cli(fd
, " %-17s %-45s [%s]\n", buf
, buf2
,
3204 ast_get_extension_registrar(e
));
3207 /* walk next extension peers */
3208 p
= e
; /* skip the first one, we already got it */
3209 while ( (p
= ast_walk_extension_priorities(e
, p
)) ) {
3210 const char *el
= ast_get_extension_label(p
);
3213 snprintf(buf
, sizeof(buf
), " [%s]", el
);
3216 print_ext(p
, buf2
, sizeof(buf2
));
3218 ast_cli(fd
," %-17s %-45s [%s]\n", buf
, buf2
,
3219 ast_get_extension_registrar(p
));
3223 /* walk included and write info ... */
3225 while ( (i
= ast_walk_context_includes(c
, i
)) ) {
3226 snprintf(buf
, sizeof(buf
), "'%s'", ast_get_include_name(i
));
3228 /* Check all includes for the requested extension */
3229 if (includecount
>= AST_PBX_MAX_STACK
) {
3230 ast_log(LOG_NOTICE
, "Maximum include depth exceeded!\n");
3234 for (x
=0;x
<includecount
;x
++) {
3235 if (!strcasecmp(includes
[x
], ast_get_include_name(i
))) {
3241 includes
[includecount
] = ast_get_include_name(i
);
3242 show_dialplan_helper(fd
, ast_get_include_name(i
), exten
, dpc
, i
, includecount
+ 1, includes
);
3244 ast_log(LOG_WARNING
, "Avoiding circular include of %s within %s\n", ast_get_include_name(i
), context
);
3248 ast_cli(fd
, " Include => %-45s [%s]\n",
3249 buf
, ast_get_include_registrar(i
));
3253 /* walk ignore patterns and write info ... */
3255 while ( (ip
= ast_walk_context_ignorepats(c
, ip
)) ) {
3256 const char *ipname
= ast_get_ignorepat_name(ip
);
3257 char ignorepat
[AST_MAX_EXTENSION
];
3258 snprintf(buf
, sizeof(buf
), "'%s'", ipname
);
3259 snprintf(ignorepat
, sizeof(ignorepat
), "_%s.", ipname
);
3260 if (!exten
|| ast_extension_match(ignorepat
, exten
)) {
3261 ast_cli(fd
, " Ignore pattern => %-45s [%s]\n",
3262 buf
, ast_get_ignorepat_registrar(ip
));
3266 struct ast_sw
*sw
= NULL
;
3267 while ( (sw
= ast_walk_context_switches(c
, sw
)) ) {
3268 snprintf(buf
, sizeof(buf
), "'%s/%s'",
3269 ast_get_switch_name(sw
),
3270 ast_get_switch_data(sw
));
3271 ast_cli(fd
, " Alt. Switch => %-45s [%s]\n",
3272 buf
, ast_get_switch_registrar(sw
));
3276 ast_unlock_context(c
);
3278 /* if we print something in context, make an empty line */
3279 if (context_info_printed
)
3280 ast_cli(fd
, "\r\n");
3282 ast_unlock_contexts();
3284 return (dpc
->total_exten
== old_total_exten
) ? -1 : res
;
3287 static int handle_show_dialplan(int fd
, int argc
, char *argv
[])
3289 char *exten
= NULL
, *context
= NULL
;
3290 /* Variables used for different counters */
3291 struct dialplan_counters counters
;
3293 const char *incstack
[AST_PBX_MAX_STACK
];
3294 memset(&counters
, 0, sizeof(counters
));
3296 if (argc
!= 2 && argc
!= 3)
3297 return RESULT_SHOWUSAGE
;
3299 /* we obtain [exten@]context? if yes, split them ... */
3301 if (strchr(argv
[2], '@')) { /* split into exten & context */
3302 context
= ast_strdupa(argv
[2]);
3303 exten
= strsep(&context
, "@");
3304 /* change empty strings to NULL */
3305 if (ast_strlen_zero(exten
))
3307 } else { /* no '@' char, only context given */
3310 if (ast_strlen_zero(context
))
3313 /* else Show complete dial plan, context and exten are NULL */
3314 show_dialplan_helper(fd
, context
, exten
, &counters
, NULL
, 0, incstack
);
3316 /* check for input failure and throw some error messages */
3317 if (context
&& !counters
.context_existence
) {
3318 ast_cli(fd
, "There is no existence of '%s' context\n", context
);
3319 return RESULT_FAILURE
;
3322 if (exten
&& !counters
.extension_existence
) {
3324 ast_cli(fd
, "There is no existence of %s@%s extension\n",
3328 "There is no existence of '%s' extension in all contexts\n",
3330 return RESULT_FAILURE
;
3333 ast_cli(fd
,"-= %d %s (%d %s) in %d %s. =-\n",
3334 counters
.total_exten
, counters
.total_exten
== 1 ? "extension" : "extensions",
3335 counters
.total_prio
, counters
.total_prio
== 1 ? "priority" : "priorities",
3336 counters
.total_context
, counters
.total_context
== 1 ? "context" : "contexts");
3339 return RESULT_SUCCESS
;
3342 /*! \brief CLI support for listing global variables in a parseable way */
3343 static int handle_show_globals(int fd
, int argc
, char *argv
[])
3346 struct ast_var_t
*newvariable
;
3348 ast_mutex_lock(&globalslock
);
3349 AST_LIST_TRAVERSE (&globals
, newvariable
, entries
) {
3351 ast_cli(fd
, " %s=%s\n", ast_var_name(newvariable
), ast_var_value(newvariable
));
3353 ast_mutex_unlock(&globalslock
);
3354 ast_cli(fd
, "\n -- %d variables\n", i
);
3356 return RESULT_SUCCESS
;
3359 /*! \brief CLI support for setting global variables */
3360 static int handle_set_global(int fd
, int argc
, char *argv
[])
3363 return RESULT_SHOWUSAGE
;
3365 pbx_builtin_setvar_helper(NULL
, argv
[2], argv
[3]);
3366 ast_cli(fd
, "\n -- Global variable %s set to %s\n", argv
[2], argv
[3]);
3368 return RESULT_SUCCESS
;
3374 * CLI entries for upper commands ...
3376 static struct ast_cli_entry pbx_cli
[] = {
3377 { { "show", "applications", NULL
}, handle_show_applications
,
3378 "Shows registered dialplan applications", show_applications_help
, complete_show_applications
},
3379 { { "show", "functions", NULL
}, handle_show_functions
,
3380 "Shows registered dialplan functions", show_functions_help
},
3381 { { "show" , "function", NULL
}, handle_show_function
,
3382 "Describe a specific dialplan function", show_function_help
, complete_show_function
},
3383 { { "show", "application", NULL
}, handle_show_application
,
3384 "Describe a specific dialplan application", show_application_help
, complete_show_application
},
3385 { { "show", "dialplan", NULL
}, handle_show_dialplan
,
3386 "Show dialplan", show_dialplan_help
, complete_show_dialplan_context
},
3387 { { "show", "switches", NULL
}, handle_show_switches
,
3388 "Show alternative switches", show_switches_help
},
3389 { { "show", "hints", NULL
}, handle_show_hints
,
3390 "Show dialplan hints", show_hints_help
},
3391 { { "show", "globals", NULL
}, handle_show_globals
,
3392 "Show global dialplan variables", show_globals_help
},
3393 { { "set", "global", NULL
}, handle_set_global
,
3394 "Set global dialplan variable", set_global_help
},
3397 int ast_unregister_application(const char *app
)
3399 struct ast_app
*tmp
;
3401 AST_LIST_LOCK(&apps
);
3402 AST_LIST_TRAVERSE_SAFE_BEGIN(&apps
, tmp
, list
) {
3403 if (!strcasecmp(app
, tmp
->name
)) {
3404 AST_LIST_REMOVE_CURRENT(&apps
, list
);
3405 if (option_verbose
> 1)
3406 ast_verbose( VERBOSE_PREFIX_2
"Unregistered application '%s'\n", tmp
->name
);
3411 AST_LIST_TRAVERSE_SAFE_END
3412 AST_LIST_UNLOCK(&apps
);
3414 return tmp
? 0 : -1;
3417 struct ast_context
*ast_context_create(struct ast_context
**extcontexts
, const char *name
, const char *registrar
)
3419 struct ast_context
*tmp
, **local_contexts
;
3420 int length
= sizeof(struct ast_context
) + strlen(name
) + 1;
3423 ast_mutex_lock(&conlock
);
3424 local_contexts
= &contexts
;
3426 local_contexts
= extcontexts
;
3428 for (tmp
= *local_contexts
; tmp
; tmp
= tmp
->next
) {
3429 if (!strcasecmp(tmp
->name
, name
)) {
3430 ast_mutex_unlock(&conlock
);
3431 ast_log(LOG_WARNING
, "Tried to register context '%s', already in use\n", name
);
3433 ast_mutex_unlock(&conlock
);
3437 if ((tmp
= ast_calloc(1, length
))) {
3438 ast_mutex_init(&tmp
->lock
);
3439 strcpy(tmp
->name
, name
);
3441 tmp
->registrar
= registrar
;
3442 tmp
->next
= *local_contexts
;
3443 tmp
->includes
= NULL
;
3444 tmp
->ignorepats
= NULL
;
3445 *local_contexts
= tmp
;
3447 ast_log(LOG_DEBUG
, "Registered context '%s'\n", tmp
->name
);
3448 else if (option_verbose
> 2)
3449 ast_verbose( VERBOSE_PREFIX_3
"Registered extension context '%s'\n", tmp
->name
);
3453 ast_mutex_unlock(&conlock
);
3457 void __ast_context_destroy(struct ast_context
*con
, const char *registrar
);
3462 struct ast_state_cb
*callbacks
;
3464 AST_LIST_ENTRY(store_hint
) list
;
3468 AST_LIST_HEAD(store_hints
, store_hint
);
3470 /* XXX this does not check that multiple contexts are merged */
3471 void ast_merge_contexts_and_delete(struct ast_context
**extcontexts
, const char *registrar
)
3473 struct ast_context
*tmp
, *lasttmp
= NULL
;
3474 struct store_hints store
= AST_LIST_HEAD_INIT_VALUE
;
3475 struct store_hint
*this;
3476 struct ast_hint
*hint
;
3477 struct ast_exten
*exten
;
3479 struct ast_state_cb
*thiscb
, *prevcb
;
3481 /* it is very important that this function hold the hint list lock _and_ the conlock
3482 during its operation; not only do we need to ensure that the list of contexts
3483 and extensions does not change, but also that no hint callbacks (watchers) are
3484 added or removed during the merge/delete process
3486 in addition, the locks _must_ be taken in this order, because there are already
3487 other code paths that use this order
3489 ast_mutex_lock(&conlock
);
3490 AST_LIST_LOCK(&hints
);
3492 /* preserve all watchers for hints associated with this registrar */
3493 AST_LIST_TRAVERSE(&hints
, hint
, list
) {
3494 if (hint
->callbacks
&& !strcmp(registrar
, hint
->exten
->parent
->registrar
)) {
3495 length
= strlen(hint
->exten
->exten
) + strlen(hint
->exten
->parent
->name
) + 2 + sizeof(*this);
3496 if (!(this = ast_calloc(1, length
)))
3498 this->callbacks
= hint
->callbacks
;
3499 hint
->callbacks
= NULL
;
3500 this->laststate
= hint
->laststate
;
3501 this->context
= this->data
;
3502 strcpy(this->data
, hint
->exten
->parent
->name
);
3503 this->exten
= this->data
+ strlen(this->context
) + 1;
3504 strcpy(this->exten
, hint
->exten
->exten
);
3505 AST_LIST_INSERT_HEAD(&store
, this, list
);
3511 /* XXX remove previous contexts from same registrar */
3512 ast_log(LOG_DEBUG
, "must remove any reg %s\n", registrar
);
3513 __ast_context_destroy(NULL
,registrar
);
3519 /* XXX remove contexts with the same name */
3521 ast_log(LOG_WARNING
, "must remove %s reg %s\n", tmp
->name
, tmp
->registrar
);
3522 __ast_context_destroy(tmp
,tmp
->registrar
);
3528 lasttmp
->next
= contexts
;
3529 contexts
= *extcontexts
;
3530 *extcontexts
= NULL
;
3532 ast_log(LOG_WARNING
, "Requested contexts didn't get merged\n");
3534 /* restore the watchers for hints that can be found; notify those that
3537 while ((this = AST_LIST_REMOVE_HEAD(&store
, list
))) {
3538 exten
= ast_hint_extension(NULL
, this->context
, this->exten
);
3539 /* Find the hint in the list of hints */
3540 AST_LIST_TRAVERSE(&hints
, hint
, list
) {
3541 if (hint
->exten
== exten
)
3544 if (!exten
|| !hint
) {
3545 /* this hint has been removed, notify the watchers */
3547 thiscb
= this->callbacks
;
3550 thiscb
= thiscb
->next
;
3551 prevcb
->callback(this->context
, this->exten
, AST_EXTENSION_REMOVED
, prevcb
->data
);
3555 thiscb
= this->callbacks
;
3556 while (thiscb
->next
)
3557 thiscb
= thiscb
->next
;
3558 thiscb
->next
= hint
->callbacks
;
3559 hint
->callbacks
= this->callbacks
;
3560 hint
->laststate
= this->laststate
;
3565 AST_LIST_UNLOCK(&hints
);
3566 ast_mutex_unlock(&conlock
);
3573 * EBUSY - can't lock
3574 * ENOENT - no existence of context
3576 int ast_context_add_include(const char *context
, const char *include
, const char *registrar
)
3579 struct ast_context
*c
= find_context_locked(context
);
3582 ret
= ast_context_add_include2(c
, include
, registrar
);
3583 ast_unlock_contexts();
3588 /*! \brief Helper for get_range.
3589 * return the index of the matching entry, starting from 1.
3590 * If names is not supplied, try numeric values.
3592 static int lookup_name(const char *s
, char *const names
[], int max
)
3597 for (i
= 0; names
[i
]; i
++) {
3598 if (!strcasecmp(s
, names
[i
]))
3601 } else if (sscanf(s
, "%d", &i
) == 1 && i
>= 1 && i
<= max
) {
3604 return 0; /* error return */
3607 /*! \brief helper function to return a range up to max (7, 12, 31 respectively).
3608 * names, if supplied, is an array of names that should be mapped to numbers.
3610 static unsigned get_range(char *src
, int max
, char *const names
[], const char *msg
)
3612 int s
, e
; /* start and ending position */
3613 unsigned int mask
= 0;
3615 /* Check for whole range */
3616 if (ast_strlen_zero(src
) || !strcmp(src
, "*")) {
3620 /* Get start and ending position */
3621 char *c
= strchr(src
, '-');
3624 /* Find the start */
3625 s
= lookup_name(src
, names
, max
);
3627 ast_log(LOG_WARNING
, "Invalid %s '%s', assuming none\n", msg
, src
);
3631 if (c
) { /* find end of range */
3632 e
= lookup_name(c
, names
, max
);
3634 ast_log(LOG_WARNING
, "Invalid end %s '%s', assuming none\n", msg
, c
);
3641 /* Fill the mask. Remember that ranges are cyclic */
3642 mask
= 1 << e
; /* initialize with last element */
3655 /*! \brief store a bitmask of valid times, one bit each 2 minute */
3656 static void get_timerange(struct ast_timing
*i
, char *times
)
3664 /* start disabling all times, fill the fields with 0's, as they may contain garbage */
3665 memset(i
->minmask
, 0, sizeof(i
->minmask
));
3667 /* 2-minutes per bit, since the mask has only 32 bits :( */
3668 /* Star is all times */
3669 if (ast_strlen_zero(times
) || !strcmp(times
, "*")) {
3670 for (x
=0; x
<24; x
++)
3671 i
->minmask
[x
] = 0x3fffffff; /* 30 bits */
3674 /* Otherwise expect a range */
3675 e
= strchr(times
, '-');
3677 ast_log(LOG_WARNING
, "Time range is not valid. Assuming no restrictions based on time.\n");
3681 /* XXX why skip non digits ? */
3682 while (*e
&& !isdigit(*e
))
3685 ast_log(LOG_WARNING
, "Invalid time range. Assuming no restrictions based on time.\n");
3688 if (sscanf(times
, "%d:%d", &s1
, &s2
) != 2) {
3689 ast_log(LOG_WARNING
, "%s isn't a time. Assuming no restrictions based on time.\n", times
);
3692 if (sscanf(e
, "%d:%d", &e1
, &e2
) != 2) {
3693 ast_log(LOG_WARNING
, "%s isn't a time. Assuming no restrictions based on time.\n", e
);
3696 /* XXX this needs to be optimized */
3698 s1
= s1
* 30 + s2
/2;
3699 if ((s1
< 0) || (s1
>= 24*30)) {
3700 ast_log(LOG_WARNING
, "%s isn't a valid start time. Assuming no time.\n", times
);
3703 e1
= e1
* 30 + e2
/2;
3704 if ((e1
< 0) || (e1
>= 24*30)) {
3705 ast_log(LOG_WARNING
, "%s isn't a valid end time. Assuming no time.\n", e
);
3708 /* Go through the time and enable each appropriate bit */
3709 for (x
=s1
;x
!= e1
;x
= (x
+ 1) % (24 * 30)) {
3710 i
->minmask
[x
/30] |= (1 << (x
% 30));
3712 /* Do the last one */
3713 i
->minmask
[x
/30] |= (1 << (x
% 30));
3715 for (cth
=0; cth
<24; cth
++) {
3716 /* Initialize masks to blank */
3717 i
->minmask
[cth
] = 0;
3718 for (ctm
=0; ctm
<30; ctm
++) {
3720 /* First hour with more than one hour */
3721 (((cth
== s1
) && (ctm
>= s2
)) &&
3724 || (((cth
== s1
) && (ctm
>= s2
)) &&
3725 ((cth
== e1
) && (ctm
<= e2
)))
3726 /* In between first and last hours (more than 2 hours) */
3729 /* Last hour with more than one hour */
3731 ((cth
== e1
) && (ctm
<= e2
)))
3733 i
->minmask
[cth
] |= (1 << (ctm
/ 2));
3741 static char *days
[] =
3753 static char *months
[] =
3770 int ast_build_timing(struct ast_timing
*i
, const char *info_in
)
3772 char info_save
[256];
3775 /* Check for empty just in case */
3776 if (ast_strlen_zero(info_in
))
3778 /* make a copy just in case we were passed a static string */
3779 ast_copy_string(info_save
, info_in
, sizeof(info_save
));
3781 /* Assume everything except time */
3782 i
->monthmask
= 0xfff; /* 12 bits */
3783 i
->daymask
= 0x7fffffffU
; /* 31 bits */
3784 i
->dowmask
= 0x7f; /* 7 bits */
3785 /* on each call, use strsep() to move info to the next argument */
3786 get_timerange(i
, strsep(&info
, "|"));
3788 i
->dowmask
= get_range(strsep(&info
, "|"), 7, days
, "day of week");
3790 i
->daymask
= get_range(strsep(&info
, "|"), 31, NULL
, "day");
3792 i
->monthmask
= get_range(strsep(&info
, "|"), 12, months
, "month");
3796 int ast_check_timing(const struct ast_timing
*i
)
3799 time_t t
= time(NULL
);
3801 localtime_r(&t
,&tm
);
3803 /* If it's not the right month, return */
3804 if (!(i
->monthmask
& (1 << tm
.tm_mon
)))
3807 /* If it's not that time of the month.... */
3808 /* Warning, tm_mday has range 1..31! */
3809 if (!(i
->daymask
& (1 << (tm
.tm_mday
-1))))
3812 /* If it's not the right day of the week */
3813 if (!(i
->dowmask
& (1 << tm
.tm_wday
)))
3816 /* Sanity check the hour just to be safe */
3817 if ((tm
.tm_hour
< 0) || (tm
.tm_hour
> 23)) {
3818 ast_log(LOG_WARNING
, "Insane time...\n");
3822 /* Now the tough part, we calculate if it fits
3823 in the right time based on min/hour */
3824 if (!(i
->minmask
[tm
.tm_hour
] & (1 << (tm
.tm_min
/ 2))))
3827 /* If we got this far, then we're good */
3833 * ENOMEM - out of memory
3834 * EBUSY - can't lock
3835 * EEXIST - already included
3836 * EINVAL - there is no existence of context for inclusion
3838 int ast_context_add_include2(struct ast_context
*con
, const char *value
,
3839 const char *registrar
)
3841 struct ast_include
*new_include
;
3843 struct ast_include
*i
, *il
= NULL
; /* include, include_last */
3847 length
= sizeof(struct ast_include
);
3848 length
+= 2 * (strlen(value
) + 1);
3850 /* allocate new include structure ... */
3851 if (!(new_include
= ast_calloc(1, length
)))
3853 /* Fill in this structure. Use 'p' for assignments, as the fields
3854 * in the structure are 'const char *'
3856 p
= new_include
->stuff
;
3857 new_include
->name
= p
;
3859 p
+= strlen(value
) + 1;
3860 new_include
->rname
= p
;
3862 /* Strip off timing info, and process if it is there */
3863 if ( (c
= strchr(p
, '|')) ) {
3865 new_include
->hastime
= ast_build_timing(&(new_include
->timing
), c
);
3867 new_include
->next
= NULL
;
3868 new_include
->registrar
= registrar
;
3870 ast_mutex_lock(&con
->lock
);
3872 /* ... go to last include and check if context is already included too... */
3873 for (i
= con
->includes
; i
; i
= i
->next
) {
3874 if (!strcasecmp(i
->name
, new_include
->name
)) {
3876 ast_mutex_unlock(&con
->lock
);
3883 /* ... include new context into context list, unlock, return */
3885 il
->next
= new_include
;
3887 con
->includes
= new_include
;
3888 if (option_verbose
> 2)
3889 ast_verbose(VERBOSE_PREFIX_3
"Including context '%s' in context '%s'\n", new_include
->name
, ast_get_context_name(con
));
3890 ast_mutex_unlock(&con
->lock
);
3897 * EBUSY - can't lock
3898 * ENOENT - no existence of context
3900 int ast_context_add_switch(const char *context
, const char *sw
, const char *data
, int eval
, const char *registrar
)
3903 struct ast_context
*c
= find_context_locked(context
);
3905 if (c
) { /* found, add switch to this context */
3906 ret
= ast_context_add_switch2(c
, sw
, data
, eval
, registrar
);
3907 ast_unlock_contexts();
3914 * ENOMEM - out of memory
3915 * EBUSY - can't lock
3916 * EEXIST - already included
3917 * EINVAL - there is no existence of context for inclusion
3919 int ast_context_add_switch2(struct ast_context
*con
, const char *value
,
3920 const char *data
, int eval
, const char *registrar
)
3922 struct ast_sw
*new_sw
;
3927 length
= sizeof(struct ast_sw
);
3928 length
+= strlen(value
) + 1;
3930 length
+= strlen(data
);
3933 /* Create buffer for evaluation of variables */
3934 length
+= SWITCH_DATA_LENGTH
;
3938 /* allocate new sw structure ... */
3939 if (!(new_sw
= ast_calloc(1, length
)))
3941 /* ... fill in this structure ... */
3944 strcpy(new_sw
->name
, value
);
3945 p
+= strlen(value
) + 1;
3948 strcpy(new_sw
->data
, data
);
3949 p
+= strlen(data
) + 1;
3951 strcpy(new_sw
->data
, "");
3955 new_sw
->tmpdata
= p
;
3956 new_sw
->eval
= eval
;
3957 new_sw
->registrar
= registrar
;
3959 /* ... try to lock this context ... */
3960 ast_mutex_lock(&con
->lock
);
3962 /* ... go to last sw and check if context is already swd too... */
3963 AST_LIST_TRAVERSE(&con
->alts
, i
, list
) {
3964 if (!strcasecmp(i
->name
, new_sw
->name
) && !strcasecmp(i
->data
, new_sw
->data
)) {
3966 ast_mutex_unlock(&con
->lock
);
3972 /* ... sw new context into context list, unlock, return */
3973 AST_LIST_INSERT_TAIL(&con
->alts
, new_sw
, list
);
3975 if (option_verbose
> 2)
3976 ast_verbose(VERBOSE_PREFIX_3
"Including switch '%s/%s' in context '%s'\n", new_sw
->name
, new_sw
->data
, ast_get_context_name(con
));
3978 ast_mutex_unlock(&con
->lock
);
3984 * EBUSY - can't lock
3985 * ENOENT - there is not context existence
3987 int ast_context_remove_ignorepat(const char *context
, const char *ignorepat
, const char *registrar
)
3990 struct ast_context
*c
= find_context_locked(context
);
3993 ret
= ast_context_remove_ignorepat2(c
, ignorepat
, registrar
);
3994 ast_unlock_contexts();
3999 int ast_context_remove_ignorepat2(struct ast_context
*con
, const char *ignorepat
, const char *registrar
)
4001 struct ast_ignorepat
*ip
, *ipl
= NULL
;
4003 ast_mutex_lock(&con
->lock
);
4005 for (ip
= con
->ignorepats
; ip
; ip
= ip
->next
) {
4006 if (!strcmp(ip
->pattern
, ignorepat
) &&
4007 (!registrar
|| (registrar
== ip
->registrar
))) {
4009 ipl
->next
= ip
->next
;
4012 con
->ignorepats
= ip
->next
;
4015 ast_mutex_unlock(&con
->lock
);
4021 ast_mutex_unlock(&con
->lock
);
4027 * EBUSY - can't lock
4028 * ENOENT - there is no existence of context
4030 int ast_context_add_ignorepat(const char *context
, const char *value
, const char *registrar
)
4033 struct ast_context
*c
= find_context_locked(context
);
4036 ret
= ast_context_add_ignorepat2(c
, value
, registrar
);
4037 ast_unlock_contexts();
4042 int ast_context_add_ignorepat2(struct ast_context
*con
, const char *value
, const char *registrar
)
4044 struct ast_ignorepat
*ignorepat
, *ignorepatc
, *ignorepatl
= NULL
;
4046 length
= sizeof(struct ast_ignorepat
);
4047 length
+= strlen(value
) + 1;
4048 if (!(ignorepat
= ast_calloc(1, length
)))
4050 /* The cast to char * is because we need to write the initial value.
4051 * The field is not supposed to be modified otherwise
4053 strcpy((char *)ignorepat
->pattern
, value
);
4054 ignorepat
->next
= NULL
;
4055 ignorepat
->registrar
= registrar
;
4056 ast_mutex_lock(&con
->lock
);
4057 for (ignorepatc
= con
->ignorepats
; ignorepatc
; ignorepatc
= ignorepatc
->next
) {
4058 ignorepatl
= ignorepatc
;
4059 if (!strcasecmp(ignorepatc
->pattern
, value
)) {
4061 ast_mutex_unlock(&con
->lock
);
4067 ignorepatl
->next
= ignorepat
;
4069 con
->ignorepats
= ignorepat
;
4070 ast_mutex_unlock(&con
->lock
);
4075 int ast_ignore_pattern(const char *context
, const char *pattern
)
4077 struct ast_context
*con
= ast_context_find(context
);
4079 struct ast_ignorepat
*pat
;
4080 for (pat
= con
->ignorepats
; pat
; pat
= pat
->next
) {
4081 if (ast_extension_match(pat
->pattern
, pattern
))
4090 * EBUSY - can't lock
4091 * ENOENT - no existence of context
4094 int ast_add_extension(const char *context
, int replace
, const char *extension
,
4095 int priority
, const char *label
, const char *callerid
,
4096 const char *application
, void *data
, void (*datad
)(void *), const char *registrar
)
4099 struct ast_context
*c
= find_context_locked(context
);
4102 ret
= ast_add_extension2(c
, replace
, extension
, priority
, label
, callerid
,
4103 application
, data
, datad
, registrar
);
4104 ast_unlock_contexts();
4109 int ast_explicit_goto(struct ast_channel
*chan
, const char *context
, const char *exten
, int priority
)
4114 if (!ast_strlen_zero(context
))
4115 ast_copy_string(chan
->context
, context
, sizeof(chan
->context
));
4116 if (!ast_strlen_zero(exten
))
4117 ast_copy_string(chan
->exten
, exten
, sizeof(chan
->exten
));
4118 if (priority
> -1) {
4119 chan
->priority
= priority
;
4120 /* see flag description in channel.h for explanation */
4121 if (ast_test_flag(chan
, AST_FLAG_IN_AUTOLOOP
))
4128 int ast_async_goto(struct ast_channel
*chan
, const char *context
, const char *exten
, int priority
)
4132 ast_channel_lock(chan
);
4134 if (chan
->pbx
) { /* This channel is currently in the PBX */
4135 ast_explicit_goto(chan
, context
, exten
, priority
);
4136 ast_softhangup_nolock(chan
, AST_SOFTHANGUP_ASYNCGOTO
);
4138 /* In order to do it when the channel doesn't really exist within
4139 the PBX, we have to make a new channel, masquerade, and start the PBX
4140 at the new location */
4141 struct ast_channel
*tmpchan
= ast_channel_alloc(0);
4145 ast_string_field_build(tmpchan
, name
, "AsyncGoto/%s", chan
->name
);
4146 ast_setstate(tmpchan
, chan
->_state
);
4147 /* Make formats okay */
4148 tmpchan
->readformat
= chan
->readformat
;
4149 tmpchan
->writeformat
= chan
->writeformat
;
4150 /* Setup proper location */
4151 ast_explicit_goto(tmpchan
,
4152 S_OR(context
, chan
->context
), S_OR(exten
, chan
->exten
), priority
);
4154 /* Masquerade into temp channel */
4155 ast_channel_masquerade(tmpchan
, chan
);
4157 /* Grab the locks and get going */
4158 ast_channel_lock(tmpchan
);
4159 ast_do_masquerade(tmpchan
);
4160 ast_channel_unlock(tmpchan
);
4161 /* Start the PBX going on our stolen channel */
4162 if (ast_pbx_start(tmpchan
)) {
4163 ast_log(LOG_WARNING
, "Unable to start PBX on %s\n", tmpchan
->name
);
4164 ast_hangup(tmpchan
);
4169 ast_channel_unlock(chan
);
4173 int ast_async_goto_by_name(const char *channame
, const char *context
, const char *exten
, int priority
)
4175 struct ast_channel
*chan
;
4178 chan
= ast_get_channel_by_name_locked(channame
);
4180 res
= ast_async_goto(chan
, context
, exten
, priority
);
4181 ast_channel_unlock(chan
);
4186 /*! \brief copy a string skipping whitespace */
4187 static int ext_strncpy(char *dst
, const char *src
, int len
)
4191 while (*src
&& (count
< len
- 1)) {
4194 /* otherwise exten => [a-b],1,... doesn't work */
4210 static void null_datad(void *foo
)
4214 /*! \brief add the extension in the priority chain.
4215 * returns 0 on success, -1 on failure
4217 static int add_pri(struct ast_context
*con
, struct ast_exten
*tmp
,
4218 struct ast_exten
*el
, struct ast_exten
*e
, int replace
)
4220 struct ast_exten
*ep
;
4222 for (ep
= NULL
; e
; ep
= e
, e
= e
->peer
) {
4223 if (e
->priority
>= tmp
->priority
)
4226 if (!e
) { /* go at the end, and ep is surely set because the list is not empty */
4228 return 0; /* success */
4230 if (e
->priority
== tmp
->priority
) {
4231 /* Can't have something exactly the same. Is this a
4232 replacement? If so, replace, otherwise, bonk. */
4234 ast_log(LOG_WARNING
, "Unable to register extension '%s', priority %d in '%s', already in use\n", tmp
->exten
, tmp
->priority
, con
->name
);
4235 tmp
->datad(tmp
->data
);
4239 /* we are replacing e, so copy the link fields and then update
4240 * whoever pointed to e to point to us
4242 tmp
->next
= e
->next
; /* not meaningful if we are not first in the peer list */
4243 tmp
->peer
= e
->peer
; /* always meaningful */
4244 if (ep
) /* We're in the peer list, just insert ourselves */
4246 else if (el
) /* We're the first extension. Take over e's functions */
4248 else /* We're the very first extension. */
4250 if (tmp
->priority
== PRIORITY_HINT
)
4251 ast_change_hint(e
,tmp
);
4252 /* Destroy the old one */
4255 } else { /* Slip ourselves in just before e */
4257 tmp
->next
= e
->next
; /* extension chain, or NULL if e is not the first extension */
4258 if (ep
) /* Easy enough, we're just in the peer list */
4260 else { /* we are the first in some peer list, so link in the ext list */
4262 el
->next
= tmp
; /* in the middle... */
4264 con
->root
= tmp
; /* ... or at the head */
4265 e
->next
= NULL
; /* e is no more at the head, so e->next must be reset */
4267 /* And immediately return success. */
4268 if (tmp
->priority
== PRIORITY_HINT
)
4275 * Main interface to add extensions to the list for out context.
4277 * We sort extensions in order of matching preference, so that we can
4278 * stop the search as soon as we find a suitable match.
4279 * This ordering also takes care of wildcards such as '.' (meaning
4280 * "one or more of any character") and '!' (which is 'earlymatch',
4281 * meaning "zero or more of any character" but also impacts the
4282 * return value from CANMATCH and EARLYMATCH.
4284 * The extension match rules defined in the devmeeting 2006.05.05 are
4285 * quite simple: WE SELECT THE LONGEST MATCH.
4286 * In detail, "longest" means the number of matched characters in
4287 * the extension. In case of ties (e.g. _XXX and 333) in the length
4288 * of a pattern, we give priority to entries with the smallest cardinality
4289 * (e.g, [5-9] comes before [2-8] before the former has only 5 elements,
4290 * while the latter has 7, etc.
4291 * In case of same cardinality, the first element in the range counts.
4292 * If we still have a tie, any final '!' will make this as a possibly
4293 * less specific pattern.
4295 * EBUSY - can't lock
4296 * EEXIST - extension with the same priority exist and no replace is set
4299 int ast_add_extension2(struct ast_context
*con
,
4300 int replace
, const char *extension
, int priority
, const char *label
, const char *callerid
,
4301 const char *application
, void *data
, void (*datad
)(void *),
4302 const char *registrar
)
4305 * Sort extensions (or patterns) according to the rules indicated above.
4306 * These are implemented by the function ext_cmp()).
4307 * All priorities for the same ext/pattern/cid are kept in a list,
4308 * using the 'peer' field as a link field..
4310 struct ast_exten
*tmp
, *e
, *el
= NULL
;
4314 char expand_buf
[VAR_BUF_SIZE
] = { 0, };
4316 /* if we are adding a hint, and there are global variables, and the hint
4317 contains variable references, then expand them
4319 ast_mutex_lock(&globalslock
);
4320 if (priority
== PRIORITY_HINT
&& AST_LIST_FIRST(&globals
) && strstr(application
, "${")) {
4321 pbx_substitute_variables_varshead(&globals
, application
, expand_buf
, sizeof(expand_buf
));
4322 application
= expand_buf
;
4324 ast_mutex_unlock(&globalslock
);
4326 length
= sizeof(struct ast_exten
);
4327 length
+= strlen(extension
) + 1;
4328 length
+= strlen(application
) + 1;
4330 length
+= strlen(label
) + 1;
4332 length
+= strlen(callerid
) + 1;
4334 length
++; /* just the '\0' */
4336 /* Be optimistic: Build the extension structure first */
4339 if (!(tmp
= ast_calloc(1, length
)))
4342 /* use p as dst in assignments, as the fields are const char * */
4347 p
+= strlen(label
) + 1;
4350 p
+= ext_strncpy(p
, extension
, strlen(extension
) + 1) + 1;
4351 tmp
->priority
= priority
;
4352 tmp
->cidmatch
= p
; /* but use p for assignments below */
4354 p
+= ext_strncpy(p
, callerid
, strlen(callerid
) + 1) + 1;
4361 strcpy(p
, application
);
4365 tmp
->registrar
= registrar
;
4367 ast_mutex_lock(&con
->lock
);
4368 res
= 0; /* some compilers will think it is uninitialized otherwise */
4369 for (e
= con
->root
; e
; el
= e
, e
= e
->next
) { /* scan the extension list */
4370 res
= ext_cmp(e
->exten
, extension
);
4371 if (res
== 0) { /* extension match, now look at cidmatch */
4372 if (!e
->matchcid
&& !tmp
->matchcid
)
4374 else if (tmp
->matchcid
&& !e
->matchcid
)
4376 else if (e
->matchcid
&& !tmp
->matchcid
)
4379 res
= strcasecmp(e
->cidmatch
, tmp
->cidmatch
);
4384 if (e
&& res
== 0) { /* exact match, insert in the pri chain */
4385 res
= add_pri(con
, tmp
, el
, e
, replace
);
4386 ast_mutex_unlock(&con
->lock
);
4388 errno
= EEXIST
; /* XXX do we care ? */
4389 return 0; /* XXX should we return -1 maybe ? */
4393 * not an exact match, this is the first entry with this pattern,
4394 * so insert in the main list right before 'e' (if any)
4401 ast_mutex_unlock(&con
->lock
);
4402 if (tmp
->priority
== PRIORITY_HINT
)
4406 if (tmp
->matchcid
) {
4407 ast_log(LOG_DEBUG
, "Added extension '%s' priority %d (CID match '%s') to %s\n",
4408 tmp
->exten
, tmp
->priority
, tmp
->cidmatch
, con
->name
);
4410 ast_log(LOG_DEBUG
, "Added extension '%s' priority %d to %s\n",
4411 tmp
->exten
, tmp
->priority
, con
->name
);
4413 } else if (option_verbose
> 2) {
4414 if (tmp
->matchcid
) {
4415 ast_verbose( VERBOSE_PREFIX_3
"Added extension '%s' priority %d (CID match '%s')to %s\n",
4416 tmp
->exten
, tmp
->priority
, tmp
->cidmatch
, con
->name
);
4418 ast_verbose( VERBOSE_PREFIX_3
"Added extension '%s' priority %d to %s\n",
4419 tmp
->exten
, tmp
->priority
, con
->name
);
4427 struct ast_channel
*chan
;
4428 char context
[AST_MAX_CONTEXT
];
4429 char exten
[AST_MAX_EXTENSION
];
4432 char app
[AST_MAX_EXTENSION
];
4436 static void *async_wait(void *data
)
4438 struct async_stat
*as
= data
;
4439 struct ast_channel
*chan
= as
->chan
;
4440 int timeout
= as
->timeout
;
4442 struct ast_frame
*f
;
4443 struct ast_app
*app
;
4445 while (timeout
&& (chan
->_state
!= AST_STATE_UP
)) {
4446 res
= ast_waitfor(chan
, timeout
);
4454 if (f
->frametype
== AST_FRAME_CONTROL
) {
4455 if ((f
->subclass
== AST_CONTROL_BUSY
) ||
4456 (f
->subclass
== AST_CONTROL_CONGESTION
) )
4461 if (chan
->_state
== AST_STATE_UP
) {
4462 if (!ast_strlen_zero(as
->app
)) {
4463 app
= pbx_findapp(as
->app
);
4465 if (option_verbose
> 2)
4466 ast_verbose(VERBOSE_PREFIX_3
"Launching %s(%s) on %s\n", as
->app
, as
->appdata
, chan
->name
);
4467 pbx_exec(chan
, app
, as
->appdata
);
4469 ast_log(LOG_WARNING
, "No such application '%s'\n", as
->app
);
4471 if (!ast_strlen_zero(as
->context
))
4472 ast_copy_string(chan
->context
, as
->context
, sizeof(chan
->context
));
4473 if (!ast_strlen_zero(as
->exten
))
4474 ast_copy_string(chan
->exten
, as
->exten
, sizeof(chan
->exten
));
4475 if (as
->priority
> 0)
4476 chan
->priority
= as
->priority
;
4478 if (ast_pbx_run(chan
)) {
4479 ast_log(LOG_ERROR
, "Failed to start PBX on %s\n", chan
->name
);
4481 /* PBX will have taken care of this */
4492 /*! Function to post an empty cdr after a spool call fails.
4494 * This function posts an empty cdr for a failed spool call
4497 int ast_pbx_outgoing_cdr_failed(void)
4499 /* allocate a channel */
4500 struct ast_channel
*chan
= ast_channel_alloc(0);
4503 return -1; /* failure */
4505 chan
->cdr
= ast_cdr_alloc(); /* allocate a cdr for the channel */
4508 /* allocation of the cdr failed */
4509 ast_channel_free(chan
); /* free the channel */
4510 return -1; /* return failure */
4513 /* allocation of the cdr was successful */
4514 ast_cdr_init(chan
->cdr
, chan
); /* initilize our channel's cdr */
4515 ast_cdr_start(chan
->cdr
); /* record the start and stop time */
4516 ast_cdr_end(chan
->cdr
);
4517 ast_cdr_failed(chan
->cdr
); /* set the status to failed */
4518 ast_cdr_detach(chan
->cdr
); /* post and free the record */
4519 ast_channel_free(chan
); /* free the channel */
4521 return 0; /* success */
4524 int ast_pbx_outgoing_exten(const char *type
, int format
, void *data
, int timeout
, const char *context
, const char *exten
, int priority
, int *reason
, int sync
, const char *cid_num
, const char *cid_name
, struct ast_variable
*vars
, const char *account
, struct ast_channel
**channel
)
4526 struct ast_channel
*chan
;
4527 struct async_stat
*as
;
4528 int res
= -1, cdr_res
= -1;
4529 struct outgoing_helper oh
;
4530 pthread_attr_t attr
;
4534 chan
= __ast_request_and_dial(type
, format
, data
, timeout
, reason
, cid_num
, cid_name
, &oh
);
4538 ast_channel_lock(chan
);
4541 if (chan
->cdr
) { /* check if the channel already has a cdr record, if not give it one */
4542 ast_log(LOG_WARNING
, "%s already has a call record??\n", chan
->name
);
4544 chan
->cdr
= ast_cdr_alloc(); /* allocate a cdr for the channel */
4546 /* allocation of the cdr failed */
4549 goto outgoing_exten_cleanup
;
4551 /* allocation of the cdr was successful */
4552 ast_cdr_init(chan
->cdr
, chan
); /* initilize our channel's cdr */
4553 ast_cdr_start(chan
->cdr
);
4555 if (chan
->_state
== AST_STATE_UP
) {
4557 if (option_verbose
> 3)
4558 ast_verbose(VERBOSE_PREFIX_4
"Channel %s was answered.\n", chan
->name
);
4562 ast_channel_unlock(chan
);
4563 if (ast_pbx_run(chan
)) {
4564 ast_log(LOG_ERROR
, "Unable to run PBX on %s\n", chan
->name
);
4571 if (ast_pbx_start(chan
)) {
4572 ast_log(LOG_ERROR
, "Unable to start PBX on %s\n", chan
->name
);
4575 ast_channel_unlock(chan
);
4582 if (option_verbose
> 3)
4583 ast_verbose(VERBOSE_PREFIX_4
"Channel %s was never answered.\n", chan
->name
);
4585 if(chan
->cdr
) { /* update the cdr */
4586 /* here we update the status of the call, which sould be busy.
4587 * if that fails then we set the status to failed */
4588 if (ast_cdr_disposition(chan
->cdr
, chan
->hangupcause
))
4589 ast_cdr_failed(chan
->cdr
);
4594 ast_channel_unlock(chan
);
4600 if (res
< 0) { /* the call failed for some reason */
4601 if (*reason
== 0) { /* if the call failed (not busy or no answer)
4602 * update the cdr with the failed message */
4603 cdr_res
= ast_pbx_outgoing_cdr_failed();
4606 goto outgoing_exten_cleanup
;
4610 /* create a fake channel and execute the "failed" extension (if it exists) within the requested context */
4611 /* check if "failed" exists */
4612 if (ast_exists_extension(chan
, context
, "failed", 1, NULL
)) {
4613 chan
= ast_channel_alloc(0);
4615 ast_string_field_set(chan
, name
, "OutgoingSpoolFailed");
4616 if (!ast_strlen_zero(context
))
4617 ast_copy_string(chan
->context
, context
, sizeof(chan
->context
));
4618 set_ext_pri(chan
, "failed", 1);
4619 ast_set_variables(chan
, vars
);
4621 ast_cdr_setaccount(chan
, account
);
4627 if (!(as
= ast_calloc(1, sizeof(*as
)))) {
4629 goto outgoing_exten_cleanup
;
4631 chan
= ast_request_and_dial(type
, format
, data
, timeout
, reason
, cid_num
, cid_name
);
4635 ast_channel_lock(chan
);
4640 goto outgoing_exten_cleanup
;
4643 ast_copy_string(as
->context
, context
, sizeof(as
->context
));
4644 set_ext_pri(as
->chan
, exten
, priority
);
4645 as
->timeout
= timeout
;
4646 ast_set_variables(chan
, vars
);
4648 ast_cdr_setaccount(chan
, account
);
4649 pthread_attr_init(&attr
);
4650 pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
4651 if (ast_pthread_create(&as
->p
, &attr
, async_wait
, as
)) {
4652 ast_log(LOG_WARNING
, "Failed to start async wait\n");
4656 ast_channel_unlock(chan
);
4660 goto outgoing_exten_cleanup
;
4664 outgoing_exten_cleanup
:
4665 ast_variables_destroy(vars
);
4672 struct ast_channel
*chan
;
4676 /*! \brief run the application and free the descriptor once done */
4677 static void *ast_pbx_run_app(void *data
)
4679 struct app_tmp
*tmp
= data
;
4680 struct ast_app
*app
;
4681 app
= pbx_findapp(tmp
->app
);
4683 if (option_verbose
> 3)
4684 ast_verbose(VERBOSE_PREFIX_4
"Launching %s(%s) on %s\n", tmp
->app
, tmp
->data
, tmp
->chan
->name
);
4685 pbx_exec(tmp
->chan
, app
, tmp
->data
);
4687 ast_log(LOG_WARNING
, "No such application '%s'\n", tmp
->app
);
4688 ast_hangup(tmp
->chan
);
4693 int ast_pbx_outgoing_app(const char *type
, int format
, void *data
, int timeout
, const char *app
, const char *appdata
, int *reason
, int sync
, const char *cid_num
, const char *cid_name
, struct ast_variable
*vars
, const char *account
, struct ast_channel
**locked_channel
)
4695 struct ast_channel
*chan
;
4696 struct app_tmp
*tmp
;
4697 int res
= -1, cdr_res
= -1;
4698 struct outgoing_helper oh
;
4699 pthread_attr_t attr
;
4701 memset(&oh
, 0, sizeof(oh
));
4703 oh
.account
= account
;
4706 *locked_channel
= NULL
;
4707 if (ast_strlen_zero(app
)) {
4709 goto outgoing_app_cleanup
;
4712 chan
= __ast_request_and_dial(type
, format
, data
, timeout
, reason
, cid_num
, cid_name
, &oh
);
4714 if (chan
->cdr
) { /* check if the channel already has a cdr record, if not give it one */
4715 ast_log(LOG_WARNING
, "%s already has a call record??\n", chan
->name
);
4717 chan
->cdr
= ast_cdr_alloc(); /* allocate a cdr for the channel */
4719 /* allocation of the cdr failed */
4722 goto outgoing_app_cleanup
;
4724 /* allocation of the cdr was successful */
4725 ast_cdr_init(chan
->cdr
, chan
); /* initilize our channel's cdr */
4726 ast_cdr_start(chan
->cdr
);
4728 ast_set_variables(chan
, vars
);
4730 ast_cdr_setaccount(chan
, account
);
4731 if (chan
->_state
== AST_STATE_UP
) {
4733 if (option_verbose
> 3)
4734 ast_verbose(VERBOSE_PREFIX_4
"Channel %s was answered.\n", chan
->name
);
4735 tmp
= ast_calloc(1, sizeof(*tmp
));
4739 ast_copy_string(tmp
->app
, app
, sizeof(tmp
->app
));
4741 ast_copy_string(tmp
->data
, appdata
, sizeof(tmp
->data
));
4745 ast_channel_unlock(chan
);
4746 ast_pbx_run_app(tmp
);
4748 pthread_attr_init(&attr
);
4749 pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
4751 ast_channel_lock(chan
);
4752 if (ast_pthread_create(&tmp
->t
, &attr
, ast_pbx_run_app
, tmp
)) {
4753 ast_log(LOG_WARNING
, "Unable to spawn execute thread on %s: %s\n", chan
->name
, strerror(errno
));
4756 ast_channel_unlock(chan
);
4761 *locked_channel
= chan
;
4766 if (option_verbose
> 3)
4767 ast_verbose(VERBOSE_PREFIX_4
"Channel %s was never answered.\n", chan
->name
);
4768 if (chan
->cdr
) { /* update the cdr */
4769 /* here we update the status of the call, which sould be busy.
4770 * if that fails then we set the status to failed */
4771 if (ast_cdr_disposition(chan
->cdr
, chan
->hangupcause
))
4772 ast_cdr_failed(chan
->cdr
);
4778 if (res
< 0) { /* the call failed for some reason */
4779 if (*reason
== 0) { /* if the call failed (not busy or no answer)
4780 * update the cdr with the failed message */
4781 cdr_res
= ast_pbx_outgoing_cdr_failed();
4784 goto outgoing_app_cleanup
;
4790 struct async_stat
*as
;
4791 if (!(as
= ast_calloc(1, sizeof(*as
)))) {
4793 goto outgoing_app_cleanup
;
4795 chan
= __ast_request_and_dial(type
, format
, data
, timeout
, reason
, cid_num
, cid_name
, &oh
);
4799 goto outgoing_app_cleanup
;
4802 ast_copy_string(as
->app
, app
, sizeof(as
->app
));
4804 ast_copy_string(as
->appdata
, appdata
, sizeof(as
->appdata
));
4805 as
->timeout
= timeout
;
4806 ast_set_variables(chan
, vars
);
4808 ast_cdr_setaccount(chan
, account
);
4809 /* Start a new thread, and get something handling this channel. */
4810 pthread_attr_init(&attr
);
4811 pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
4813 ast_channel_lock(chan
);
4814 if (ast_pthread_create(&as
->p
, &attr
, async_wait
, as
)) {
4815 ast_log(LOG_WARNING
, "Failed to start async wait\n");
4818 ast_channel_unlock(chan
);
4821 goto outgoing_app_cleanup
;
4824 *locked_channel
= chan
;
4828 outgoing_app_cleanup
:
4829 ast_variables_destroy(vars
);
4833 void __ast_context_destroy(struct ast_context
*con
, const char *registrar
)
4835 struct ast_context
*tmp
, *tmpl
=NULL
;
4836 struct ast_include
*tmpi
;
4838 struct ast_exten
*e
, *el
, *en
;
4839 struct ast_ignorepat
*ipi
;
4841 ast_mutex_lock(&conlock
);
4842 for (tmp
= contexts
; tmp
; ) {
4843 struct ast_context
*next
; /* next starting point */
4844 for (; tmp
; tmpl
= tmp
, tmp
= tmp
->next
) {
4845 ast_log(LOG_DEBUG
, "check ctx %s %s\n", tmp
->name
, tmp
->registrar
);
4846 if ( (!registrar
|| !strcasecmp(registrar
, tmp
->registrar
)) &&
4847 (!con
|| !strcasecmp(tmp
->name
, con
->name
)) )
4848 break; /* found it */
4850 if (!tmp
) /* not found, we are done */
4852 ast_mutex_lock(&tmp
->lock
);
4853 ast_log(LOG_DEBUG
, "delete ctx %s %s\n", tmp
->name
, tmp
->registrar
);
4859 /* Okay, now we're safe to let it go -- in a sense, we were
4860 ready to let it go as soon as we locked it. */
4861 ast_mutex_unlock(&tmp
->lock
);
4862 for (tmpi
= tmp
->includes
; tmpi
; ) { /* Free includes */
4863 struct ast_include
*tmpil
= tmpi
;
4867 for (ipi
= tmp
->ignorepats
; ipi
; ) { /* Free ignorepats */
4868 struct ast_ignorepat
*ipl
= ipi
;
4872 while ((sw
= AST_LIST_REMOVE_HEAD(&tmp
->alts
, list
)))
4874 for (e
= tmp
->root
; e
;) {
4875 for (en
= e
->peer
; en
;) {
4884 ast_mutex_destroy(&tmp
->lock
);
4886 /* if we have a specific match, we are done, otherwise continue */
4887 tmp
= con
? NULL
: next
;
4889 ast_mutex_unlock(&conlock
);
4892 void ast_context_destroy(struct ast_context
*con
, const char *registrar
)
4894 __ast_context_destroy(con
,registrar
);
4897 static void wait_for_hangup(struct ast_channel
*chan
, void *data
)
4900 struct ast_frame
*f
;
4903 if (ast_strlen_zero(data
) || (sscanf(data
, "%d", &waittime
) != 1) || (waittime
< 0))
4905 if (waittime
> -1) {
4906 ast_safe_sleep(chan
, waittime
* 1000);
4908 res
= ast_waitfor(chan
, -1);
4918 * \ingroup applications
4920 static int pbx_builtin_progress(struct ast_channel
*chan
, void *data
)
4922 ast_indicate(chan
, AST_CONTROL_PROGRESS
);
4927 * \ingroup applications
4929 static int pbx_builtin_ringing(struct ast_channel
*chan
, void *data
)
4931 ast_indicate(chan
, AST_CONTROL_RINGING
);
4936 * \ingroup applications
4938 static int pbx_builtin_busy(struct ast_channel
*chan
, void *data
)
4940 ast_indicate(chan
, AST_CONTROL_BUSY
);
4941 ast_setstate(chan
, AST_STATE_BUSY
);
4942 wait_for_hangup(chan
, data
);
4947 * \ingroup applications
4949 static int pbx_builtin_congestion(struct ast_channel
*chan
, void *data
)
4951 ast_indicate(chan
, AST_CONTROL_CONGESTION
);
4952 ast_setstate(chan
, AST_STATE_BUSY
);
4953 wait_for_hangup(chan
, data
);
4958 * \ingroup applications
4960 static int pbx_builtin_answer(struct ast_channel
*chan
, void *data
)
4965 if (chan
->_state
== AST_STATE_UP
)
4967 else if (!ast_strlen_zero(data
))
4970 res
= ast_answer(chan
);
4975 res
= ast_safe_sleep(chan
, delay
);
4980 AST_APP_OPTIONS(resetcdr_opts
, {
4981 AST_APP_OPTION('w', AST_CDR_FLAG_POSTED
),
4982 AST_APP_OPTION('a', AST_CDR_FLAG_LOCKED
),
4983 AST_APP_OPTION('v', AST_CDR_FLAG_KEEP_VARS
),
4987 * \ingroup applications
4989 static int pbx_builtin_resetcdr(struct ast_channel
*chan
, void *data
)
4992 struct ast_flags flags
= { 0 };
4994 if (!ast_strlen_zero(data
)) {
4995 args
= ast_strdupa(data
);
4996 ast_app_parse_options(resetcdr_opts
, &flags
, NULL
, args
);
4999 ast_cdr_reset(chan
->cdr
, &flags
);
5005 * \ingroup applications
5007 static int pbx_builtin_setamaflags(struct ast_channel
*chan
, void *data
)
5009 /* Copy the AMA Flags as specified */
5010 ast_cdr_setamaflags(chan
, data
? data
: "");
5015 * \ingroup applications
5017 static int pbx_builtin_hangup(struct ast_channel
*chan
, void *data
)
5019 if (!ast_strlen_zero(data
)) {
5023 if ((cause
= ast_str2cause(data
)) > -1) {
5024 chan
->hangupcause
= cause
;
5028 cause
= strtol((const char *) data
, &endptr
, 10);
5029 if (cause
!= 0 || (data
!= endptr
)) {
5030 chan
->hangupcause
= cause
;
5034 ast_log(LOG_NOTICE
, "Invalid cause given to Hangup(): \"%s\"\n", (char *) data
);
5037 if (!chan
->hangupcause
) {
5038 chan
->hangupcause
= AST_CAUSE_NORMAL_CLEARING
;
5045 * \ingroup applications
5047 static int pbx_builtin_gotoiftime(struct ast_channel
*chan
, void *data
)
5051 struct ast_timing timing
;
5053 if (ast_strlen_zero(data
)) {
5054 ast_log(LOG_WARNING
, "GotoIfTime requires an argument:\n <time range>|<days of week>|<days of month>|<months>?[[context|]extension|]priority\n");
5058 ts
= s
= ast_strdupa(data
);
5060 /* Separate the Goto path */
5063 /* struct ast_include include contained garbage here, fixed by zeroing it on get_timerange */
5064 if (ast_build_timing(&timing
, s
) && ast_check_timing(&timing
))
5065 res
= pbx_builtin_goto(chan
, ts
);
5071 * \ingroup applications
5073 static int pbx_builtin_execiftime(struct ast_channel
*chan
, void *data
)
5076 struct ast_timing timing
;
5077 struct ast_app
*app
;
5078 static const char *usage
= "ExecIfTime requires an argument:\n <time range>|<days of week>|<days of month>|<months>?<appname>[|<appargs>]";
5080 if (ast_strlen_zero(data
)) {
5081 ast_log(LOG_WARNING
, "%s\n", usage
);
5085 appname
= ast_strdupa(data
);
5087 s
= strsep(&appname
,"?"); /* Separate the timerange and application name/data */
5088 if (!appname
) { /* missing application */
5089 ast_log(LOG_WARNING
, "%s\n", usage
);
5093 if (!ast_build_timing(&timing
, s
)) {
5094 ast_log(LOG_WARNING
, "Invalid Time Spec: %s\nCorrect usage: %s\n", s
, usage
);
5098 if (!ast_check_timing(&timing
)) /* outside the valid time window, just return */
5101 /* now split appname|appargs */
5102 if ((s
= strchr(appname
, '|')))
5105 if ((app
= pbx_findapp(appname
))) {
5106 return pbx_exec(chan
, app
, S_OR(s
, ""));
5108 ast_log(LOG_WARNING
, "Cannot locate application %s\n", appname
);
5114 * \ingroup applications
5116 static int pbx_builtin_wait(struct ast_channel
*chan
, void *data
)
5120 /* Wait for "n" seconds */
5121 if (data
&& (ms
= atof(data
)) > 0) {
5123 return ast_safe_sleep(chan
, ms
);
5129 * \ingroup applications
5131 static int pbx_builtin_waitexten(struct ast_channel
*chan
, void *data
)
5134 struct ast_flags flags
= {0};
5135 char *opts
[1] = { NULL
};
5137 AST_DECLARE_APP_ARGS(args
,
5138 AST_APP_ARG(timeout
);
5139 AST_APP_ARG(options
);
5142 if (!ast_strlen_zero(data
)) {
5143 parse
= ast_strdupa(data
);
5144 AST_STANDARD_APP_ARGS(args
, parse
);
5146 memset(&args
, 0, sizeof(args
));
5149 ast_app_parse_options(waitexten_opts
, &flags
, opts
, args
.options
);
5151 if (ast_test_flag(&flags
, WAITEXTEN_MOH
))
5152 ast_moh_start(chan
, opts
[0]);
5154 /* Wait for "n" seconds */
5155 if (args
.timeout
&& (ms
= atof(args
.timeout
)) > 0)
5158 ms
= chan
->pbx
->rtimeout
* 1000;
5161 res
= ast_waitfordigit(chan
, ms
);
5163 if (ast_exists_extension(chan
, chan
->context
, chan
->exten
, chan
->priority
+ 1, chan
->cid
.cid_num
)) {
5164 if (option_verbose
> 2)
5165 ast_verbose(VERBOSE_PREFIX_3
"Timeout on %s, continuing...\n", chan
->name
);
5166 } else if (ast_exists_extension(chan
, chan
->context
, "t", 1, chan
->cid
.cid_num
)) {
5167 if (option_verbose
> 2)
5168 ast_verbose(VERBOSE_PREFIX_3
"Timeout on %s, going to 't'\n", chan
->name
);
5169 set_ext_pri(chan
, "t", 0); /* XXX is the 0 correct ? */
5171 ast_log(LOG_WARNING
, "Timeout but no rule 't' in context '%s'\n", chan
->context
);
5176 if (ast_test_flag(&flags
, WAITEXTEN_MOH
))
5183 * \ingroup applications
5185 static int pbx_builtin_background(struct ast_channel
*chan
, void *data
)
5188 struct ast_flags flags
= {0};
5190 AST_DECLARE_APP_ARGS(args
,
5191 AST_APP_ARG(filename
);
5192 AST_APP_ARG(options
);
5194 AST_APP_ARG(context
);
5197 if (ast_strlen_zero(data
))
5198 ast_log(LOG_WARNING
, "Background requires an argument (filename)\n");
5200 parse
= ast_strdupa(data
);
5202 AST_STANDARD_APP_ARGS(args
, parse
);
5205 args
.lang
= (char *)chan
->language
; /* XXX this is const */
5208 args
.context
= chan
->context
;
5211 if (!strcasecmp(args
.options
, "skip"))
5212 flags
.flags
= BACKGROUND_SKIP
;
5213 else if (!strcasecmp(args
.options
, "noanswer"))
5214 flags
.flags
= BACKGROUND_NOANSWER
;
5216 ast_app_parse_options(background_opts
, &flags
, NULL
, args
.options
);
5219 /* Answer if need be */
5220 if (chan
->_state
!= AST_STATE_UP
) {
5221 if (ast_test_flag(&flags
, BACKGROUND_SKIP
)) {
5223 } else if (!ast_test_flag(&flags
, BACKGROUND_NOANSWER
)) {
5224 res
= ast_answer(chan
);
5229 char *back
= args
.filename
;
5231 ast_stopstream(chan
); /* Stop anything playing */
5232 /* Stream the list of files */
5233 while (!res
&& (front
= strsep(&back
, "&")) ) {
5234 if ( (res
= ast_streamfile(chan
, front
, args
.lang
)) ) {
5235 ast_log(LOG_WARNING
, "ast_streamfile failed on %s for %s\n", chan
->name
, (char*)data
);
5239 if (ast_test_flag(&flags
, BACKGROUND_PLAYBACK
)) {
5240 res
= ast_waitstream(chan
, "");
5241 } else if (ast_test_flag(&flags
, BACKGROUND_MATCHEXTEN
)) {
5242 res
= ast_waitstream_exten(chan
, args
.context
);
5244 res
= ast_waitstream(chan
, AST_DIGIT_ANY
);
5246 ast_stopstream(chan
);
5249 if (args
.context
!= chan
->context
&& res
) {
5250 snprintf(chan
->exten
, sizeof(chan
->exten
), "%c", res
);
5251 ast_copy_string(chan
->context
, args
.context
, sizeof(chan
->context
));
5259 * \ingroup applications
5261 static int pbx_builtin_goto(struct ast_channel
*chan
, void *data
)
5263 int res
= ast_parseable_goto(chan
, data
);
5264 if (!res
&& (option_verbose
> 2))
5265 ast_verbose( VERBOSE_PREFIX_3
"Goto (%s,%s,%d)\n", chan
->context
,chan
->exten
, chan
->priority
+1);
5270 int pbx_builtin_serialize_variables(struct ast_channel
*chan
, char *buf
, size_t size
)
5272 struct ast_var_t
*variables
;
5273 const char *var
, *val
;
5279 memset(buf
, 0, size
);
5281 AST_LIST_TRAVERSE(&chan
->varshead
, variables
, entries
) {
5283 (var
=ast_var_name(variables
)) && (val
=ast_var_value(variables
)) &&
5284 !ast_strlen_zero(var
) && !ast_strlen_zero(val
)) {
5285 if (ast_build_string(&buf
, &size
, "%s=%s\n", var
, val
)) {
5286 ast_log(LOG_ERROR
, "Data Buffer Size Exceeded!\n");
5297 const char *pbx_builtin_getvar_helper(struct ast_channel
*chan
, const char *name
)
5299 struct ast_var_t
*variables
;
5300 const char *ret
= NULL
;
5302 struct varshead
*places
[2] = { NULL
, &globals
};
5307 places
[0] = &chan
->varshead
;
5309 for (i
= 0; i
< 2; i
++) {
5312 if (places
[i
] == &globals
)
5313 ast_mutex_lock(&globalslock
);
5314 AST_LIST_TRAVERSE(places
[i
], variables
, entries
) {
5315 if (!strcmp(name
, ast_var_name(variables
))) {
5316 ret
= ast_var_value(variables
);
5320 if (places
[i
] == &globals
)
5321 ast_mutex_unlock(&globalslock
);
5329 void pbx_builtin_pushvar_helper(struct ast_channel
*chan
, const char *name
, const char *value
)
5331 struct ast_var_t
*newvariable
;
5332 struct varshead
*headp
;
5334 if (name
[strlen(name
)-1] == ')') {
5335 char *function
= ast_strdupa(name
);
5337 ast_log(LOG_WARNING
, "Cannot push a value onto a function\n");
5338 ast_func_write(chan
, function
, value
);
5342 headp
= (chan
) ? &chan
->varshead
: &globals
;
5345 if ((option_verbose
> 1) && (headp
== &globals
))
5346 ast_verbose(VERBOSE_PREFIX_2
"Setting global variable '%s' to '%s'\n", name
, value
);
5347 newvariable
= ast_var_assign(name
, value
);
5348 if (headp
== &globals
)
5349 ast_mutex_lock(&globalslock
);
5350 AST_LIST_INSERT_HEAD(headp
, newvariable
, entries
);
5351 if (headp
== &globals
)
5352 ast_mutex_unlock(&globalslock
);
5356 void pbx_builtin_setvar_helper(struct ast_channel
*chan
, const char *name
, const char *value
)
5358 struct ast_var_t
*newvariable
;
5359 struct varshead
*headp
;
5360 const char *nametail
= name
;
5362 /* XXX may need locking on the channel ? */
5363 if (name
[strlen(name
)-1] == ')') {
5364 char *function
= ast_strdupa(name
);
5366 ast_func_write(chan
, function
, value
);
5370 headp
= (chan
) ? &chan
->varshead
: &globals
;
5372 /* For comparison purposes, we have to strip leading underscores */
5373 if (*nametail
== '_') {
5375 if (*nametail
== '_')
5379 if (headp
== &globals
)
5380 ast_mutex_lock(&globalslock
);
5381 AST_LIST_TRAVERSE (headp
, newvariable
, entries
) {
5382 if (strcasecmp(ast_var_name(newvariable
), nametail
) == 0) {
5383 /* there is already such a variable, delete it */
5384 AST_LIST_REMOVE(headp
, newvariable
, entries
);
5385 ast_var_delete(newvariable
);
5391 if ((option_verbose
> 1) && (headp
== &globals
))
5392 ast_verbose(VERBOSE_PREFIX_2
"Setting global variable '%s' to '%s'\n", name
, value
);
5393 newvariable
= ast_var_assign(name
, value
);
5394 AST_LIST_INSERT_HEAD(headp
, newvariable
, entries
);
5397 if (headp
== &globals
)
5398 ast_mutex_unlock(&globalslock
);
5401 int pbx_builtin_setvar(struct ast_channel
*chan
, void *data
)
5403 char *name
, *value
, *mydata
;
5405 char *argv
[24]; /* this will only support a maximum of 24 variables being set in a single operation */
5409 if (ast_strlen_zero(data
)) {
5410 ast_log(LOG_WARNING
, "Set requires at least one variable name/value pair.\n");
5414 mydata
= ast_strdupa(data
);
5415 argc
= ast_app_separate_args(mydata
, '|', argv
, sizeof(argv
) / sizeof(argv
[0]));
5417 /* check for a trailing flags argument */
5418 if ((argc
> 1) && !strchr(argv
[argc
-1], '=')) {
5420 if (strchr(argv
[argc
], 'g'))
5424 for (x
= 0; x
< argc
; x
++) {
5426 if ((value
= strchr(name
, '='))) {
5428 pbx_builtin_setvar_helper((global
) ? NULL
: chan
, name
, value
);
5430 ast_log(LOG_WARNING
, "Ignoring entry '%s' with no = (and not last 'options' entry)\n", name
);
5436 int pbx_builtin_importvar(struct ast_channel
*chan
, void *data
)
5441 char tmp
[VAR_BUF_SIZE
]="";
5443 if (ast_strlen_zero(data
)) {
5444 ast_log(LOG_WARNING
, "Ignoring, since there is no variable to set\n");
5448 value
= ast_strdupa(data
);
5449 name
= strsep(&value
,"=");
5450 channel
= strsep(&value
,"|");
5451 if (channel
&& value
&& name
) { /*! \todo XXX should do !ast_strlen_zero(..) of the args ? */
5452 struct ast_channel
*chan2
= ast_get_channel_by_name_locked(channel
);
5454 char *s
= alloca(strlen(value
) + 4);
5456 sprintf(s
, "${%s}", value
);
5457 pbx_substitute_variables_helper(chan2
, s
, tmp
, sizeof(tmp
) - 1);
5459 ast_channel_unlock(chan2
);
5461 pbx_builtin_setvar_helper(chan
, name
, tmp
);
5467 /*! \todo XXX overwrites data ? */
5468 static int pbx_builtin_setglobalvar(struct ast_channel
*chan
, void *data
)
5471 char *stringp
= data
;
5472 static int dep_warning
= 0;
5474 if (ast_strlen_zero(data
)) {
5475 ast_log(LOG_WARNING
, "Ignoring, since there is no variable to set\n");
5479 name
= strsep(&stringp
, "=");
5483 ast_log(LOG_WARNING
, "SetGlobalVar is deprecated. Please use Set(GLOBAL(%s)=%s) instead.\n", name
, stringp
);
5486 /*! \todo XXX watch out, leading whitespace ? */
5487 pbx_builtin_setvar_helper(NULL
, name
, stringp
);
5492 static int pbx_builtin_noop(struct ast_channel
*chan
, void *data
)
5497 void pbx_builtin_clear_globals(void)
5499 struct ast_var_t
*vardata
;
5501 ast_mutex_lock(&globalslock
);
5502 while ((vardata
= AST_LIST_REMOVE_HEAD(&globals
, entries
)))
5503 ast_var_delete(vardata
);
5504 ast_mutex_unlock(&globalslock
);
5507 int pbx_checkcondition(const char *condition
)
5509 if (ast_strlen_zero(condition
)) /* NULL or empty strings are false */
5511 else if (*condition
>= '0' && *condition
<= '9') /* Numbers are evaluated for truth */
5512 return atoi(condition
);
5513 else /* Strings are true */
5517 static int pbx_builtin_gotoif(struct ast_channel
*chan
, void *data
)
5519 char *condition
, *branch1
, *branch2
, *branch
;
5523 if (ast_strlen_zero(data
)) {
5524 ast_log(LOG_WARNING
, "Ignoring, since there is no variable to check\n");
5528 stringp
= ast_strdupa(data
);
5529 condition
= strsep(&stringp
,"?");
5530 branch1
= strsep(&stringp
,":");
5531 branch2
= strsep(&stringp
,"");
5532 branch
= pbx_checkcondition(condition
) ? branch1
: branch2
;
5534 if (ast_strlen_zero(branch
)) {
5535 ast_log(LOG_DEBUG
, "Not taking any branch\n");
5539 rc
= pbx_builtin_goto(chan
, branch
);
5544 static int pbx_builtin_saynumber(struct ast_channel
*chan
, void *data
)
5550 if (ast_strlen_zero(data
)) {
5551 ast_log(LOG_WARNING
, "SayNumber requires an argument (number)\n");
5554 ast_copy_string(tmp
, data
, sizeof(tmp
));
5555 strsep(&number
, "|");
5556 options
= strsep(&number
, "|");
5558 if ( strcasecmp(options
, "f") && strcasecmp(options
,"m") &&
5559 strcasecmp(options
, "c") && strcasecmp(options
, "n") ) {
5560 ast_log(LOG_WARNING
, "SayNumber gender option is either 'f', 'm', 'c' or 'n'\n");
5564 return ast_say_number(chan
, atoi(tmp
), "", chan
->language
, options
);
5567 static int pbx_builtin_saydigits(struct ast_channel
*chan
, void *data
)
5572 res
= ast_say_digit_str(chan
, data
, "", chan
->language
);
5576 static int pbx_builtin_saycharacters(struct ast_channel
*chan
, void *data
)
5581 res
= ast_say_character_str(chan
, data
, "", chan
->language
);
5585 static int pbx_builtin_sayphonetic(struct ast_channel
*chan
, void *data
)
5590 res
= ast_say_phonetic_str(chan
, data
, "", chan
->language
);
5598 /* Initialize the PBX */
5599 if (option_verbose
) {
5600 ast_verbose( "Asterisk PBX Core Initializing\n");
5601 ast_verbose( "Registering builtin applications:\n");
5603 AST_LIST_HEAD_INIT_NOLOCK(&globals
);
5604 ast_cli_register_multiple(pbx_cli
, sizeof(pbx_cli
) / sizeof(pbx_cli
[0]));
5606 /* Register builtin applications */
5607 for (x
=0; x
<sizeof(builtins
) / sizeof(struct pbx_builtin
); x
++) {
5609 ast_verbose( VERBOSE_PREFIX_1
"[%s]\n", builtins
[x
].name
);
5610 if (ast_register_application(builtins
[x
].name
, builtins
[x
].execute
, builtins
[x
].synopsis
, builtins
[x
].description
)) {
5611 ast_log(LOG_ERROR
, "Unable to register builtin application '%s'\n", builtins
[x
].name
);
5619 * Lock context list functions ...
5621 int ast_lock_contexts()
5623 return ast_mutex_lock(&conlock
);
5626 int ast_unlock_contexts()
5628 return ast_mutex_unlock(&conlock
);
5634 int ast_lock_context(struct ast_context
*con
)
5636 return ast_mutex_lock(&con
->lock
);
5639 int ast_unlock_context(struct ast_context
*con
)
5641 return ast_mutex_unlock(&con
->lock
);
5645 * Name functions ...
5647 const char *ast_get_context_name(struct ast_context
*con
)
5649 return con
? con
->name
: NULL
;
5652 struct ast_context
*ast_get_extension_context(struct ast_exten
*exten
)
5654 return exten
? exten
->parent
: NULL
;
5657 const char *ast_get_extension_name(struct ast_exten
*exten
)
5659 return exten
? exten
->exten
: NULL
;
5662 const char *ast_get_extension_label(struct ast_exten
*exten
)
5664 return exten
? exten
->label
: NULL
;
5667 const char *ast_get_include_name(struct ast_include
*inc
)
5669 return inc
? inc
->name
: NULL
;
5672 const char *ast_get_ignorepat_name(struct ast_ignorepat
*ip
)
5674 return ip
? ip
->pattern
: NULL
;
5677 int ast_get_extension_priority(struct ast_exten
*exten
)
5679 return exten
? exten
->priority
: -1;
5683 * Registrar info functions ...
5685 const char *ast_get_context_registrar(struct ast_context
*c
)
5687 return c
? c
->registrar
: NULL
;
5690 const char *ast_get_extension_registrar(struct ast_exten
*e
)
5692 return e
? e
->registrar
: NULL
;
5695 const char *ast_get_include_registrar(struct ast_include
*i
)
5697 return i
? i
->registrar
: NULL
;
5700 const char *ast_get_ignorepat_registrar(struct ast_ignorepat
*ip
)
5702 return ip
? ip
->registrar
: NULL
;
5705 int ast_get_extension_matchcid(struct ast_exten
*e
)
5707 return e
? e
->matchcid
: 0;
5710 const char *ast_get_extension_cidmatch(struct ast_exten
*e
)
5712 return e
? e
->cidmatch
: NULL
;
5715 const char *ast_get_extension_app(struct ast_exten
*e
)
5717 return e
? e
->app
: NULL
;
5720 void *ast_get_extension_app_data(struct ast_exten
*e
)
5722 return e
? e
->data
: NULL
;
5725 const char *ast_get_switch_name(struct ast_sw
*sw
)
5727 return sw
? sw
->name
: NULL
;
5730 const char *ast_get_switch_data(struct ast_sw
*sw
)
5732 return sw
? sw
->data
: NULL
;
5735 const char *ast_get_switch_registrar(struct ast_sw
*sw
)
5737 return sw
? sw
->registrar
: NULL
;
5741 * Walking functions ...
5743 struct ast_context
*ast_walk_contexts(struct ast_context
*con
)
5745 return con
? con
->next
: contexts
;
5748 struct ast_exten
*ast_walk_context_extensions(struct ast_context
*con
,
5749 struct ast_exten
*exten
)
5752 return con
? con
->root
: NULL
;
5757 struct ast_sw
*ast_walk_context_switches(struct ast_context
*con
,
5761 return con
? AST_LIST_FIRST(&con
->alts
) : NULL
;
5763 return AST_LIST_NEXT(sw
, list
);
5766 struct ast_exten
*ast_walk_extension_priorities(struct ast_exten
*exten
,
5767 struct ast_exten
*priority
)
5769 return priority
? priority
->peer
: exten
;
5772 struct ast_include
*ast_walk_context_includes(struct ast_context
*con
,
5773 struct ast_include
*inc
)
5776 return con
? con
->includes
: NULL
;
5781 struct ast_ignorepat
*ast_walk_context_ignorepats(struct ast_context
*con
,
5782 struct ast_ignorepat
*ip
)
5785 return con
? con
->ignorepats
: NULL
;
5790 int ast_context_verify_includes(struct ast_context
*con
)
5792 struct ast_include
*inc
= NULL
;
5795 while ( (inc
= ast_walk_context_includes(con
, inc
)) )
5796 if (!ast_context_find(inc
->rname
)) {
5798 ast_log(LOG_WARNING
, "Context '%s' tries includes nonexistent context '%s'\n",
5799 ast_get_context_name(con
), inc
->rname
);
5805 static int __ast_goto_if_exists(struct ast_channel
*chan
, const char *context
, const char *exten
, int priority
, int async
)
5807 int (*goto_func
)(struct ast_channel
*chan
, const char *context
, const char *exten
, int priority
);
5812 if (context
== NULL
)
5813 context
= chan
->context
;
5815 exten
= chan
->exten
;
5817 goto_func
= (async
) ? ast_async_goto
: ast_explicit_goto
;
5818 if (ast_exists_extension(chan
, context
, exten
, priority
, chan
->cid
.cid_num
))
5819 return goto_func(chan
, context
, exten
, priority
);
5824 int ast_goto_if_exists(struct ast_channel
*chan
, const char* context
, const char *exten
, int priority
)
5826 return __ast_goto_if_exists(chan
, context
, exten
, priority
, 0);
5829 int ast_async_goto_if_exists(struct ast_channel
*chan
, const char * context
, const char *exten
, int priority
)
5831 return __ast_goto_if_exists(chan
, context
, exten
, priority
, 1);
5834 int ast_parseable_goto(struct ast_channel
*chan
, const char *goto_string
)
5836 char *exten
, *pri
, *context
;
5841 if (ast_strlen_zero(goto_string
)) {
5842 ast_log(LOG_WARNING
, "Goto requires an argument (optional context|optional extension|priority)\n");
5845 stringp
= ast_strdupa(goto_string
);
5846 context
= strsep(&stringp
, "|"); /* guaranteed non-null */
5847 exten
= strsep(&stringp
, "|");
5848 pri
= strsep(&stringp
, "|");
5849 if (!exten
) { /* Only a priority in this one */
5853 } else if (!pri
) { /* Only an extension and priority in this one */
5861 } else if (*pri
== '-') {
5865 if (sscanf(pri
, "%d", &ipri
) != 1) {
5866 if ((ipri
= ast_findlabel_extension(chan
, context
? context
: chan
->context
, exten
? exten
: chan
->exten
,
5867 pri
, chan
->cid
.cid_num
)) < 1) {
5868 ast_log(LOG_WARNING
, "Priority '%s' must be a number > 0, or valid label\n", pri
);
5873 /* At this point we have a priority and maybe an extension and a context */
5876 ipri
= chan
->priority
+ (ipri
* mode
);
5878 ast_explicit_goto(chan
, context
, exten
, ipri
);
5879 ast_cdr_update(chan
);