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>
28 ASTERISK_FILE_VERSION(__FILE__
, "$Revision$")
30 #include <sys/types.h>
40 #include "asterisk/lock.h"
41 #include "asterisk/cli.h"
42 #include "asterisk/pbx.h"
43 #include "asterisk/channel.h"
44 #include "asterisk/options.h"
45 #include "asterisk/logger.h"
46 #include "asterisk/file.h"
47 #include "asterisk/callerid.h"
48 #include "asterisk/cdr.h"
49 #include "asterisk/config.h"
50 #include "asterisk/term.h"
51 #include "asterisk/manager.h"
52 #include "asterisk/ast_expr.h"
53 #include "asterisk/linkedlists.h"
54 #define SAY_STUBS /* generate declarations and stubs for say methods */
55 #include "asterisk/say.h"
56 #include "asterisk/utils.h"
57 #include "asterisk/causes.h"
58 #include "asterisk/musiconhold.h"
59 #include "asterisk/app.h"
60 #include "asterisk/devicestate.h"
61 #include "asterisk/stringfields.h"
64 * \note I M P O R T A N T :
66 * The speed of extension handling will likely be among the most important
67 * aspects of this PBX. The switching scheme as it exists right now isn't
68 * terribly bad (it's O(N+M), where N is the # of extensions and M is the avg #
69 * of priorities, but a constant search time here would be great ;-)
74 #define EXT_DATA_SIZE 256
76 #define EXT_DATA_SIZE 8192
79 #define SWITCH_DATA_LENGTH 256
81 #define VAR_BUF_SIZE 4096
84 #define VAR_SOFTTRAN 2
85 #define VAR_HARDTRAN 3
87 #define BACKGROUND_SKIP (1 << 0)
88 #define BACKGROUND_NOANSWER (1 << 1)
89 #define BACKGROUND_MATCHEXTEN (1 << 2)
90 #define BACKGROUND_PLAYBACK (1 << 3)
92 AST_APP_OPTIONS(background_opts
, {
93 AST_APP_OPTION('s', BACKGROUND_SKIP
),
94 AST_APP_OPTION('n', BACKGROUND_NOANSWER
),
95 AST_APP_OPTION('m', BACKGROUND_MATCHEXTEN
),
96 AST_APP_OPTION('p', BACKGROUND_PLAYBACK
),
99 #define WAITEXTEN_MOH (1 << 0)
101 AST_APP_OPTIONS(waitexten_opts
, {
102 AST_APP_OPTION_ARG('m', WAITEXTEN_MOH
, 1),
108 \brief ast_exten: An extension
109 The dialplan is saved as a linked list with each context
110 having it's own linked list of extensions - one item per
114 char *exten
; /*!< Extension name */
115 int matchcid
; /*!< Match caller id ? */
116 const char *cidmatch
; /*!< Caller id to match for this extension */
117 int priority
; /*!< Priority */
118 const char *label
; /*!< Label */
119 struct ast_context
*parent
; /*!< The context this extension belongs to */
120 const char *app
; /*!< Application to execute */
121 void *data
; /*!< Data to use (arguments) */
122 void (*datad
)(void *); /*!< Data destructor */
123 struct ast_exten
*peer
; /*!< Next higher priority with our extension */
124 const char *registrar
; /*!< Registrar */
125 struct ast_exten
*next
; /*!< Extension with a greater ID */
129 /*! \brief ast_include: include= support in extensions.conf */
132 const char *rname
; /*!< Context to include */
133 const char *registrar
; /*!< Registrar */
134 int hastime
; /*!< If time construct exists */
135 struct ast_timing timing
; /*!< time construct */
136 struct ast_include
*next
; /*!< Link them together */
140 /*! \brief ast_sw: Switch statement in extensions.conf */
143 const char *registrar
; /*!< Registrar */
144 char *data
; /*!< Data load */
146 AST_LIST_ENTRY(ast_sw
) list
;
151 /*! \brief ast_ignorepat: Ignore patterns in dial plan */
152 struct ast_ignorepat
{
153 const char *registrar
;
154 struct ast_ignorepat
*next
;
155 const char pattern
[0];
158 /*! \brief ast_context: An extension context */
160 ast_mutex_t lock
; /*!< A lock to prevent multiple threads from clobbering the context */
161 struct ast_exten
*root
; /*!< The root of the list of extensions */
162 struct ast_context
*next
; /*!< Link them together */
163 struct ast_include
*includes
; /*!< Include other contexts */
164 struct ast_ignorepat
*ignorepats
; /*!< Patterns for which to continue playing dialtone */
165 const char *registrar
; /*!< Registrar */
166 AST_LIST_HEAD_NOLOCK(, ast_sw
) alts
; /*!< Alternative switches */
167 char name
[0]; /*!< Name of the context */
171 /*! \brief ast_app: A registered application */
173 int (*execute
)(struct ast_channel
*chan
, void *data
);
174 const char *synopsis
; /*!< Synopsis text for 'show applications' */
175 const char *description
; /*!< Description (help text) for 'show application <name>' */
176 AST_LIST_ENTRY(ast_app
) list
; /*!< Next app in list */
177 struct module
*module
; /*!< Module this app belongs to */
178 char name
[0]; /*!< Name of the application */
181 /*! \brief ast_state_cb: An extension state notify register item */
182 struct ast_state_cb
{
185 ast_state_cb_type callback
;
186 struct ast_state_cb
*next
;
189 /*! \brief Structure for dial plan hints
191 \note Hints are pointers from an extension in the dialplan to one or
192 more devices (tech/name) */
194 struct ast_exten
*exten
; /*!< Extension */
195 int laststate
; /*!< Last known state */
196 struct ast_state_cb
*callbacks
; /*!< Callback list for this extension */
197 AST_LIST_ENTRY(ast_hint
) list
; /*!< Pointer to next hint in list */
200 static const struct cfextension_states
{
202 const char * const text
;
203 } extension_states
[] = {
204 { AST_EXTENSION_NOT_INUSE
, "Idle" },
205 { AST_EXTENSION_INUSE
, "InUse" },
206 { AST_EXTENSION_BUSY
, "Busy" },
207 { AST_EXTENSION_UNAVAILABLE
, "Unavailable" },
208 { AST_EXTENSION_RINGING
, "Ringing" },
209 { AST_EXTENSION_INUSE
| AST_EXTENSION_RINGING
, "InUse&Ringing" },
210 { AST_EXTENSION_ONHOLD
, "Hold" },
211 { AST_EXTENSION_INUSE
| AST_EXTENSION_ONHOLD
, "InUse&Hold" }
214 static int pbx_builtin_answer(struct ast_channel
*, void *);
215 static int pbx_builtin_goto(struct ast_channel
*, void *);
216 static int pbx_builtin_hangup(struct ast_channel
*, void *);
217 static int pbx_builtin_background(struct ast_channel
*, void *);
218 static int pbx_builtin_wait(struct ast_channel
*, void *);
219 static int pbx_builtin_waitexten(struct ast_channel
*, void *);
220 static int pbx_builtin_resetcdr(struct ast_channel
*, void *);
221 static int pbx_builtin_setamaflags(struct ast_channel
*, void *);
222 static int pbx_builtin_ringing(struct ast_channel
*, void *);
223 static int pbx_builtin_progress(struct ast_channel
*, void *);
224 static int pbx_builtin_congestion(struct ast_channel
*, void *);
225 static int pbx_builtin_busy(struct ast_channel
*, void *);
226 static int pbx_builtin_setglobalvar(struct ast_channel
*, void *);
227 static int pbx_builtin_noop(struct ast_channel
*, void *);
228 static int pbx_builtin_gotoif(struct ast_channel
*, void *);
229 static int pbx_builtin_gotoiftime(struct ast_channel
*, void *);
230 static int pbx_builtin_execiftime(struct ast_channel
*, void *);
231 static int pbx_builtin_saynumber(struct ast_channel
*, void *);
232 static int pbx_builtin_saydigits(struct ast_channel
*, void *);
233 static int pbx_builtin_saycharacters(struct ast_channel
*, void *);
234 static int pbx_builtin_sayphonetic(struct ast_channel
*, void *);
235 int pbx_builtin_setvar(struct ast_channel
*, void *);
236 static int pbx_builtin_importvar(struct ast_channel
*, void *);
238 AST_MUTEX_DEFINE_STATIC(globalslock
);
239 static struct varshead globals
;
241 static int autofallthrough
= 0;
243 AST_MUTEX_DEFINE_STATIC(maxcalllock
);
244 static int countcalls
= 0;
246 static AST_LIST_HEAD_STATIC(acf_root
, ast_custom_function
);
248 /*! \brief Declaration of builtin applications */
249 static struct pbx_builtin
{
250 char name
[AST_MAX_APP
];
251 int (*execute
)(struct ast_channel
*chan
, void *data
);
256 /* These applications are built into the PBX core and do not
257 need separate modules */
259 { "Answer", pbx_builtin_answer
,
260 "Answer a channel if ringing",
261 " Answer([delay]): If the call has not been answered, this application will\n"
262 "answer it. Otherwise, it has no effect on the call. If a delay is specified,\n"
263 "Asterisk will wait this number of milliseconds before answering the call.\n"
266 { "BackGround", pbx_builtin_background
,
267 "Play an audio file while waiting for digits of an extension to go to.",
268 " Background(filename1[&filename2...][|options[|langoverride][|context]]):\n"
269 "This application will play the given list of files while waiting for an\n"
270 "extension to be dialed by the calling channel. To continue waiting for digits\n"
271 "after this application has finished playing files, the WaitExten application\n"
272 "should be used. The 'langoverride' option explicitly specifies which language\n"
273 "to attempt to use for the requested sound files. If a 'context' is specified,\n"
274 "this is the dialplan context that this application will use when exiting to a\n"
276 " If one of the requested sound files does not exist, call processing will be\n"
279 " s - Causes the playback of the message to be skipped\n"
280 " if the channel is not in the 'up' state (i.e. it\n"
281 " hasn't been answered yet). If this happens, the\n"
282 " application will return immediately.\n"
283 " n - Don't answer the channel before playing the files.\n"
284 " m - Only break if a digit hit matches a one digit\n"
285 " extension in the destination context.\n"
288 { "Busy", pbx_builtin_busy
,
289 "Indicate the Busy condition",
290 " Busy([timeout]): This application will indicate the busy condition to\n"
291 "the calling channel. If the optional timeout is specified, the calling channel\n"
292 "will be hung up after the specified number of seconds. Otherwise, this\n"
293 "application will wait until the calling channel hangs up.\n"
296 { "Congestion", pbx_builtin_congestion
,
297 "Indicate the Congestion condition",
298 " Congestion([timeout]): This application will indicate the congestion\n"
299 "condition to the calling channel. If the optional timeout is specified, the\n"
300 "calling channel will be hung up after the specified number of seconds.\n"
301 "Otherwise, this application will wait until the calling channel hangs up.\n"
304 { "Goto", pbx_builtin_goto
,
305 "Jump to a particular priority, extension, or context",
306 " Goto([[context|]extension|]priority): This application will cause the\n"
307 "calling channel to continue dialplan execution at the specified priority.\n"
308 "If no specific extension, or extension and context, are specified, then this\n"
309 "application will jump to the specified priority of the current extension.\n"
310 " If the attempt to jump to another location in the dialplan is not successful,\n"
311 "then the channel will continue at the next priority of the current extension.\n"
314 { "GotoIf", pbx_builtin_gotoif
,
316 " GotoIf(condition?[labeliftrue]:[labeliffalse]): This application will cause\n"
317 "the calling channel to jump to the specified location in the dialplan based on\n"
318 "the evaluation of the given condition. The channel will continue at\n"
319 "'labeliftrue' if the condition is true, or 'labeliffalse' if the condition is\n"
320 "false. The labels are specified with the same syntax as used within the Goto\n"
321 "application. If the label chosen by the condition is omitted, no jump is\n"
322 "performed, but execution continues with the next priority in the dialplan.\n"
325 { "GotoIfTime", pbx_builtin_gotoiftime
,
326 "Conditional Goto based on the current time",
327 " GotoIfTime(<times>|<weekdays>|<mdays>|<months>?[[context|]exten|]priority):\n"
328 "This application will have the calling channel jump to the specified location\n"
329 "in the dialplan if the current time matches the given time specification.\n"
332 { "ExecIfTime", pbx_builtin_execiftime
,
333 "Conditional application execution based on the current time",
334 " ExecIfTime(<times>|<weekdays>|<mdays>|<months>?appname[|appargs]):\n"
335 "This application will execute the specified dialplan application, with optional\n"
336 "arguments, if the current time matches the given time specification.\n"
339 { "Hangup", pbx_builtin_hangup
,
340 "Hang up the calling channel",
341 " Hangup([causecode]): This application will hang up the calling channel.\n"
342 "If a causecode is given the channel's hangup cause will be set to the given\n"
346 { "NoOp", pbx_builtin_noop
,
348 " NoOp(): This applicatiion does nothing. However, it is useful for debugging\n"
349 "purposes. Any text that is provided as arguments to this application can be\n"
350 "viewed at the Asterisk CLI. This method can be used to see the evaluations of\n"
351 "variables or functions without having any effect."
354 { "Progress", pbx_builtin_progress
,
356 " Progress(): This application will request that in-band progress information\n"
357 "be provided to the calling channel.\n"
360 { "ResetCDR", pbx_builtin_resetcdr
,
361 "Resets the Call Data Record",
362 " ResetCDR([options]): This application causes the Call Data Record to be\n"
365 " w -- Store the current CDR record before resetting it.\n"
366 " a -- Store any stacked records.\n"
367 " v -- Save CDR variables.\n"
370 { "Ringing", pbx_builtin_ringing
,
371 "Indicate ringing tone",
372 " Ringing(): This application will request that the channel indicate a ringing\n"
373 "tone to the user.\n"
376 { "SayNumber", pbx_builtin_saynumber
,
378 " SayNumber(digits[,gender]): This application will play the sounds that\n"
379 "correspond to the given number. Optionally, a gender may be specified.\n"
380 "This will use the language that is currently set for the channel. See the\n"
381 "LANGUAGE function for more information on setting the language for the channel.\n"
384 { "SayDigits", pbx_builtin_saydigits
,
386 " SayDigits(digits): This application will play the sounds that correspond\n"
387 "to the digits of the given number. This will use the language that is currently\n"
388 "set for the channel. See the LANGUAGE function for more information on setting\n"
389 "the language for the channel.\n"
392 { "SayAlpha", pbx_builtin_saycharacters
,
394 " SayAlpha(string): This application will play the sounds that correspond to\n"
395 "the letters of the given string.\n"
398 { "SayPhonetic", pbx_builtin_sayphonetic
,
400 " SayPhonetic(string): This application will play the sounds from the phonetic\n"
401 "alphabet that correspond to the letters in the given string.\n"
404 { "SetAMAFlags", pbx_builtin_setamaflags
,
406 " SetAMAFlags([flag]): This application will set the channel's AMA Flags for\n"
407 " billing purposes.\n"
410 { "SetGlobalVar", pbx_builtin_setglobalvar
,
411 "Set a global variable to a given value",
412 " SetGlobalVar(variable=value): This application sets a given global variable to\n"
413 "the specified value.\n"
416 { "Set", pbx_builtin_setvar
,
417 "Set channel variable(s) or function value(s)",
418 " Set(name1=value1|name2=value2|..[|options])\n"
419 "This function can be used to set the value of channel variables or dialplan\n"
420 "functions. It will accept up to 24 name/value pairs. When setting variables,\n"
421 "if the variable name is prefixed with _, the variable will be inherited into\n"
422 "channels created from the current channel. If the variable name is prefixed\n"
423 "with __, the variable will be inherited into channels created from the current\n"
424 "channel and all children channels.\n"
426 " g - Set variable globally instead of on the channel\n"
427 " (applies only to variables, not functions)\n"
430 { "ImportVar", pbx_builtin_importvar
,
431 "Import a variable from a channel into a new variable",
432 " ImportVar(newvar=channelname|variable): This application imports a variable\n"
433 "from the specified channel (as opposed to the current one) and stores it as\n"
434 "a variable in the current channel (the channel that is calling this\n"
435 "application). Variables created by this application have the same inheritance\n"
436 "properties as those created with the Set application. See the documentation for\n"
437 "Set for more information.\n"
440 { "Wait", pbx_builtin_wait
,
441 "Waits for some time",
442 " Wait(seconds): This application waits for a specified number of seconds.\n"
443 "Then, dialplan execution will continue at the next priority.\n"
444 " Note that the seconds can be passed with fractions of a second. For example,\n"
445 "'1.5' will ask the application to wait for 1.5 seconds.\n"
448 { "WaitExten", pbx_builtin_waitexten
,
449 "Waits for an extension to be entered",
450 " WaitExten([seconds][|options]): This application waits for the user to enter\n"
451 "a new extension for a specified number of seconds.\n"
452 " Note that the seconds can be passed with fractions of a second. For example,\n"
453 "'1.5' will ask the application to wait for 1.5 seconds.\n"
455 " m[(x)] - Provide music on hold to the caller while waiting for an extension.\n"
456 " Optionally, specify the class for music on hold within parenthesis.\n"
461 static struct ast_context
*contexts
= NULL
;
462 AST_MUTEX_DEFINE_STATIC(conlock
); /*!< Lock for the ast_context list */
464 static AST_LIST_HEAD_STATIC(apps
, ast_app
);
466 static AST_LIST_HEAD_STATIC(switches
, ast_switch
);
468 static int stateid
= 1;
470 When holding this list's lock, do _not_ do anything that will cause conlock
471 to be taken, unless you _already_ hold it. The ast_merge_contexts_and_delete
472 function will take the locks in conlock/hints order, so any other
473 paths that require both locks must also take them in that order.
475 static AST_LIST_HEAD_STATIC(hints
, ast_hint
);
476 struct ast_state_cb
*statecbs
= NULL
;
479 \note This function is special. It saves the stack so that no matter
480 how many times it is called, it returns to the same place */
481 int pbx_exec(struct ast_channel
*c
, /*!< Channel */
482 struct ast_app
*app
, /*!< Application */
483 void *data
) /*!< Data for execution */
487 const char *saved_c_appl
;
488 const char *saved_c_data
;
491 ast_cdr_setapp(c
->cdr
, app
->name
, data
);
493 /* save channel values */
494 saved_c_appl
= c
->appl
;
495 saved_c_data
= c
->data
;
499 /* XXX remember what to to when we have linked apps to modules */
501 /* XXX LOCAL_USER_ADD(app->module) */
503 res
= app
->execute(c
, data
);
505 /* XXX LOCAL_USER_REMOVE(app->module) */
507 /* restore channel values */
508 c
->appl
= saved_c_appl
;
509 c
->data
= saved_c_data
;
514 /*! Go no deeper than this through includes (not counting loops) */
515 #define AST_PBX_MAX_STACK 128
517 /*! \brief Find application handle in linked list
519 struct ast_app
*pbx_findapp(const char *app
)
523 AST_LIST_LOCK(&apps
);
524 AST_LIST_TRAVERSE(&apps
, tmp
, list
) {
525 if (!strcasecmp(tmp
->name
, app
))
528 AST_LIST_UNLOCK(&apps
);
533 static struct ast_switch
*pbx_findswitch(const char *sw
)
535 struct ast_switch
*asw
;
537 AST_LIST_LOCK(&switches
);
538 AST_LIST_TRAVERSE(&switches
, asw
, list
) {
539 if (!strcasecmp(asw
->name
, sw
))
542 AST_LIST_UNLOCK(&switches
);
547 static inline int include_valid(struct ast_include
*i
)
552 return ast_check_timing(&(i
->timing
));
555 static void pbx_destroy(struct ast_pbx
*p
)
561 * Special characters used in patterns:
562 * '_' underscore is the leading character of a pattern.
563 * In other position it is treated as a regular char.
564 * ' ' '-' space and '-' are separator and ignored.
565 * . one or more of any character. Only allowed at the end of
567 * ! zero or more of anything. Also impacts the result of CANMATCH
568 * and MATCHMORE. Only allowed at the end of a pattern.
569 * In the core routine, ! causes a match with a return code of 2.
570 * In turn, depending on the search mode: (XXX check if it is implemented)
571 * - E_MATCH retuns 1 (does match)
572 * - E_MATCHMORE returns 0 (no match)
573 * - E_CANMATCH returns 1 (does match)
575 * / should not appear as it is considered the separator of the CID info.
576 * XXX at the moment we may stop on this char.
578 * X Z N match ranges 0-9, 1-9, 2-9 respectively.
579 * [ denotes the start of a set of character. Everything inside
580 * is considered literally. We can have ranges a-d and individual
581 * characters. A '[' and '-' can be considered literally if they
582 * are just before ']'.
583 * XXX currently there is no way to specify ']' in a range, nor \ is
584 * considered specially.
586 * When we compare a pattern with a specific extension, all characters in the extension
587 * itself are considered literally with the only exception of '-' which is considered
588 * as a separator and thus ignored.
589 * XXX do we want to consider space as a separator as well ?
590 * XXX do we want to consider the separators in non-patterns as well ?
594 * \brief helper functions to sort extensions and patterns in the desired way,
595 * so that more specific patterns appear first.
597 * ext_cmp1 compares individual characters (or sets of), returning
598 * an int where bits 0-7 are the ASCII code of the first char in the set,
599 * while bit 8-15 are the cardinality of the set minus 1.
600 * This way more specific patterns (smaller cardinality) appear first.
601 * Wildcards have a special value, so that we can directly compare them to
602 * sets by subtracting the two values. In particular:
603 * 0x000xx one character, xx
604 * 0x0yyxx yy character set starting with xx
605 * 0x10000 '.' (one or more of anything)
606 * 0x20000 '!' (zero or more of anything)
607 * 0x30000 NUL (end of string)
608 * 0x40000 error in set.
609 * The pointer to the string is advanced according to needs.
611 * 1. the empty set is equivalent to NUL.
612 * 2. given that a full set has always 0 as the first element,
613 * we could encode the special cases as 0xffXX where XX
614 * is 1, 2, 3, 4 as used above.
616 static int ext_cmp1(const char **p
)
619 int c
, cmin
= 0xff, count
= 0;
622 /* load, sign extend and advance pointer until we find
625 while ( (c
= *(*p
)++) && (c
== ' ' || c
== '-') )
626 ; /* ignore some characters */
628 /* always return unless we have a set of chars */
630 default: /* ordinary character */
631 return 0x0000 | (c
& 0xff);
634 return 0x0700 | '2' ;
642 case '.': /* wildcard */
645 case '!': /* earlymatch */
646 return 0x20000; /* less specific than NULL */
648 case '\0': /* empty string */
652 case '[': /* pattern */
655 /* locate end of set */
656 end
= strchr(*p
, ']');
659 ast_log(LOG_WARNING
, "Wrong usage of [] in the extension\n");
660 return 0x40000; /* XXX make this entry go last... */
663 bzero(chars
, sizeof(chars
)); /* clear all chars in the set */
664 for (; *p
< end
; (*p
)++) {
665 unsigned char c1
, c2
; /* first-last char in range */
666 c1
= (unsigned char)((*p
)[0]);
667 if (*p
+ 2 < end
&& (*p
)[1] == '-') { /* this is a range */
668 c2
= (unsigned char)((*p
)[2]);
669 *p
+= 2; /* skip a total of 3 chars */
670 } else /* individual character */
674 for (; c1
<= c2
; c1
++) {
675 uint32_t mask
= 1 << (c1
% 32);
676 if ( (chars
[ c1
/ 32 ] & mask
) == 0)
678 chars
[ c1
/ 32 ] |= mask
;
682 return count
== 0 ? 0x30000 : (count
| cmin
);
686 * \brief the full routine to compare extensions in rules.
688 static int ext_cmp(const char *a
, const char *b
)
690 /* make sure non-patterns come first.
691 * If a is not a pattern, it either comes first or
692 * we use strcmp to compare the strings.
697 return (b
[0] == '_') ? -1 : strcmp(a
, b
);
699 /* Now we know a is a pattern; if b is not, a comes first */
702 #if 0 /* old mode for ext matching */
705 /* ok we need full pattern sorting routine */
706 while (!ret
&& a
&& b
)
707 ret
= ext_cmp1(&a
) - ext_cmp1(&b
);
711 return (ret
> 0) ? 1 : -1;
715 * When looking up extensions, we can have different requests
716 * identified by the 'action' argument, as follows.
717 * Note that the coding is such that the low 4 bits are the
718 * third argument to extension_match_core.
721 E_MATCHMORE
= 0x00, /* extension can match but only with more 'digits' */
722 E_CANMATCH
= 0x01, /* extension can match with or without more 'digits' */
723 E_MATCH
= 0x02, /* extension is an exact match */
724 E_MATCH_MASK
= 0x03, /* mask for the argument to extension_match_core() */
725 E_SPAWN
= 0x12, /* want to spawn an extension. Requires exact match */
726 E_FINDLABEL
= 0x22 /* returns the priority for a given label. Requires exact match */
730 * Internal function for ast_extension_{match|close}
731 * return 0 on no-match, 1 on match, 2 on early match.
732 * mode is as follows:
733 * E_MATCH success only on exact match
734 * E_MATCHMORE success only on partial match (i.e. leftover digits in pattern)
735 * E_CANMATCH either of the above.
737 static int _extension_match_core(const char *pattern
, const char *data
, enum ext_match_t mode
)
739 mode
&= E_MATCH_MASK
; /* only consider the relevant bits */
741 if (pattern
[0] != '_') { /* not a pattern, try exact or partial match */
742 int ld
= strlen(data
), lp
= strlen(pattern
);
744 if (lp
< ld
) /* pattern too short, cannot match */
746 /* depending on the mode, accept full or partial match or both */
748 return !strcmp(pattern
, data
); /* 1 on match, 0 on fail */
749 if (ld
== 0 || !strncasecmp(pattern
, data
, ld
)) /* partial or full match */
750 return (mode
== E_MATCHMORE
) ? lp
> ld
: 1; /* XXX should consider '!' and '/' ? */
754 pattern
++; /* skip leading _ */
756 * XXX below we stop at '/' which is a separator for the CID info. However we should
757 * not store '/' in the pattern at all. When we insure it, we can remove the checks.
759 while (*data
&& *pattern
&& *pattern
!= '/') {
762 if (*data
== '-') { /* skip '-' in data (just a separator) */
766 switch (toupper(*pattern
)) {
767 case '[': /* a range */
768 end
= strchr(pattern
+1, ']'); /* XXX should deal with escapes ? */
770 ast_log(LOG_WARNING
, "Wrong usage of [] in the extension\n");
771 return 0; /* unconditional failure */
773 for (pattern
++; pattern
!= end
; pattern
++) {
774 if (pattern
+2 < end
&& pattern
[1] == '-') { /* this is a range */
775 if (*data
>= pattern
[0] && *data
<= pattern
[2])
776 break; /* match found */
778 pattern
+= 2; /* skip a total of 3 chars */
781 } else if (*data
== pattern
[0])
782 break; /* match found */
786 pattern
= end
; /* skip and continue */
789 if (*data
< '2' || *data
> '9')
793 if (*data
< '0' || *data
> '9')
797 if (*data
< '1' || *data
> '9')
800 case '.': /* Must match, even with more digits */
802 case '!': /* Early match */
805 case '-': /* Ignore these in patterns */
806 data
--; /* compensate the final data++ */
809 if (*data
!= *pattern
)
815 if (*data
) /* data longer than pattern, no match */
818 * match so far, but ran off the end of the data.
819 * Depending on what is next, determine match or not.
821 if (*pattern
== '\0' || *pattern
== '/') /* exact match */
822 return (mode
== E_MATCHMORE
) ? 0 : 1; /* this is a failure for E_MATCHMORE */
823 else if (*pattern
== '!') /* early match */
825 else /* partial match */
826 return (mode
== E_MATCH
) ? 0 : 1; /* this is a failure for E_MATCH */
830 * Wrapper around _extension_match_core() to do performance measurement
831 * using the profiling code.
833 static int extension_match_core(const char *pattern
, const char *data
, enum ext_match_t mode
)
836 static int prof_id
= -2; /* marker for 'unallocated' id */
838 prof_id
= ast_add_profile("ext_match", 0);
839 ast_mark(prof_id
, 1);
840 i
= _extension_match_core(pattern
, data
, mode
);
841 ast_mark(prof_id
, 0);
845 int ast_extension_match(const char *pattern
, const char *data
)
847 return extension_match_core(pattern
, data
, E_MATCH
);
850 int ast_extension_close(const char *pattern
, const char *data
, int needmore
)
852 if (needmore
!= E_MATCHMORE
&& needmore
!= E_CANMATCH
)
853 ast_log(LOG_WARNING
, "invalid argument %d\n", needmore
);
854 return extension_match_core(pattern
, data
, needmore
);
857 struct ast_context
*ast_context_find(const char *name
)
859 struct ast_context
*tmp
= NULL
;
860 ast_mutex_lock(&conlock
);
861 while ( (tmp
= ast_walk_contexts(tmp
)) ) {
862 if (!name
|| !strcasecmp(name
, tmp
->name
))
865 ast_mutex_unlock(&conlock
);
869 #define STATUS_NO_CONTEXT 1
870 #define STATUS_NO_EXTENSION 2
871 #define STATUS_NO_PRIORITY 3
872 #define STATUS_NO_LABEL 4
873 #define STATUS_SUCCESS 5
875 static int matchcid(const char *cidpattern
, const char *callerid
)
877 /* If the Caller*ID pattern is empty, then we're matching NO Caller*ID, so
878 failing to get a number should count as a match, otherwise not */
880 if (ast_strlen_zero(callerid
))
881 return ast_strlen_zero(cidpattern
) ? 1 : 0;
883 return ast_extension_match(cidpattern
, callerid
);
886 /* request and result for pbx_find_extension */
887 struct pbx_find_info
{
894 char *incstack
[AST_PBX_MAX_STACK
]; /* filled during the search */
895 int stacklen
; /* modified during the search */
896 int status
; /* set on return */
897 struct ast_switch
*swo
; /* set on return */
898 const char *data
; /* set on return */
899 const char *foundcontext
; /* set on return */
902 static struct ast_exten
*pbx_find_extension(struct ast_channel
*chan
,
903 struct ast_context
*bypass
, struct pbx_find_info
*q
,
904 const char *context
, const char *exten
, int priority
,
905 const char *label
, const char *callerid
, enum ext_match_t action
)
908 struct ast_context
*tmp
;
909 struct ast_exten
*e
, *eroot
;
910 struct ast_include
*i
;
913 /* Initialize status if appropriate */
914 if (q
->stacklen
== 0) {
915 q
->status
= STATUS_NO_CONTEXT
;
918 q
->foundcontext
= NULL
;
920 /* Check for stack overflow */
921 if (q
->stacklen
>= AST_PBX_MAX_STACK
) {
922 ast_log(LOG_WARNING
, "Maximum PBX stack exceeded\n");
925 /* Check first to see if we've already been checked */
926 for (x
= 0; x
< q
->stacklen
; x
++) {
927 if (!strcasecmp(q
->incstack
[x
], context
))
930 if (bypass
) /* bypass means we only look there */
932 else { /* look in contexts */
934 while ((tmp
= ast_walk_contexts(tmp
)) ) {
935 if (!strcmp(tmp
->name
, context
))
941 if (q
->status
< STATUS_NO_EXTENSION
)
942 q
->status
= STATUS_NO_EXTENSION
;
944 /* scan the list trying to match extension and CID */
946 while ( (eroot
= ast_walk_context_extensions(tmp
, eroot
)) ) {
947 int match
= extension_match_core(eroot
->exten
, exten
, action
);
948 /* 0 on fail, 1 on match, 2 on earlymatch */
950 if (!match
|| (eroot
->matchcid
&& !matchcid(eroot
->cidmatch
, callerid
)))
951 continue; /* keep trying */
952 if (match
== 2 && action
== E_MATCHMORE
) {
953 /* We match an extension ending in '!'.
954 * The decision in this case is final and is NULL (no match).
958 /* found entry, now look for the right priority */
959 if (q
->status
< STATUS_NO_PRIORITY
)
960 q
->status
= STATUS_NO_PRIORITY
;
962 while ( (e
= ast_walk_extension_priorities(eroot
, e
)) ) {
963 /* Match label or priority */
964 if (action
== E_FINDLABEL
) {
965 if (q
->status
< STATUS_NO_LABEL
)
966 q
->status
= STATUS_NO_LABEL
;
967 if (label
&& e
->label
&& !strcmp(label
, e
->label
))
968 break; /* found it */
969 } else if (e
->priority
== priority
) {
970 break; /* found it */
971 } /* else keep searching */
973 if (e
) { /* found a valid match */
974 q
->status
= STATUS_SUCCESS
;
975 q
->foundcontext
= context
;
979 /* Check alternative switches */
980 AST_LIST_TRAVERSE(&tmp
->alts
, sw
, list
) {
981 struct ast_switch
*asw
= pbx_findswitch(sw
->name
);
982 ast_switch_f
*aswf
= NULL
;
986 ast_log(LOG_WARNING
, "No such switch '%s'\n", sw
->name
);
989 /* Substitute variables now */
991 pbx_substitute_variables_helper(chan
, sw
->data
, sw
->tmpdata
, SWITCH_DATA_LENGTH
- 1);
993 /* equivalent of extension_match_core() at the switch level */
994 if (action
== E_CANMATCH
)
995 aswf
= asw
->canmatch
;
996 else if (action
== E_MATCHMORE
)
997 aswf
= asw
->matchmore
;
998 else /* action == E_MATCH */
1000 datap
= sw
->eval
? sw
->tmpdata
: sw
->data
;
1001 res
= !aswf
? 0 : aswf(chan
, context
, exten
, priority
, callerid
, datap
);
1002 if (res
) { /* Got a match */
1005 q
->foundcontext
= context
;
1006 /* XXX keep status = STATUS_NO_CONTEXT ? */
1010 q
->incstack
[q
->stacklen
++] = tmp
->name
; /* Setup the stack */
1011 /* Now try any includes we have in this context */
1012 for (i
= tmp
->includes
; i
; i
= i
->next
) {
1013 if (include_valid(i
)) {
1014 if ((e
= pbx_find_extension(chan
, bypass
, q
, i
->rname
, exten
, priority
, label
, callerid
, action
)))
1023 /* Note that it's negative -- that's important later. */
1024 #define DONT_HAVE_LENGTH 0x80000000
1026 /*! \brief extract offset:length from variable name.
1027 * Returns 1 if there is a offset:length part, which is
1028 * trimmed off (values go into variables)
1030 static int parse_variable_name(char *var
, int *offset
, int *length
, int *isfunc
)
1035 *length
= DONT_HAVE_LENGTH
;
1037 for (; *var
; var
++) {
1041 } else if (*var
== ')') {
1043 } else if (*var
== ':' && parens
== 0) {
1045 sscanf(var
, "%d:%d", offset
, length
);
1046 return 1; /* offset:length valid */
1052 /*! \brief takes a substring. It is ok to call with value == workspace.
1054 * offset < 0 means start from the end of the string and set the beginning
1055 * to be that many characters back.
1056 * length is the length of the substring, -1 means unlimited
1057 * (we take any negative value).
1058 * Always return a copy in workspace.
1060 static char *substring(const char *value
, int offset
, int length
, char *workspace
, size_t workspace_len
)
1062 char *ret
= workspace
;
1063 int lr
; /* length of the input string after the copy */
1065 ast_copy_string(workspace
, value
, workspace_len
); /* always make a copy */
1067 /* Quick check if no need to do anything */
1068 if (offset
== 0 && length
< 0) /* take the whole string */
1071 lr
= strlen(ret
); /* compute length after copy, so we never go out of the workspace */
1073 if (offset
< 0) { /* translate negative offset into positive ones */
1074 offset
= lr
+ offset
;
1075 if (offset
< 0) /* If the negative offset was greater than the length of the string, just start at the beginning */
1079 /* too large offset result in empty string so we know what to return */
1081 return ret
+ lr
; /* the final '\0' */
1083 ret
+= offset
; /* move to the start position */
1084 if (length
>= 0 && length
< lr
- offset
) /* truncate if necessary */
1090 /*! \brief pbx_retrieve_variable: Support for Asterisk built-in variables and
1091 functions in the dialplan
1093 void pbx_retrieve_variable(struct ast_channel
*c
, const char *var
, char **ret
, char *workspace
, int workspacelen
, struct varshead
*headp
)
1095 const char not_found
= '\0';
1097 const char *s
; /* the result */
1099 int i
, need_substring
;
1100 struct varshead
*places
[2] = { headp
, &globals
}; /* list of places where we may look */
1103 places
[0] = &c
->varshead
;
1106 * Make a copy of var because parse_variable_name() modifies the string.
1107 * Then if called directly, we might need to run substring() on the result;
1108 * remember this for later in 'need_substring', 'offset' and 'length'
1110 tmpvar
= ast_strdupa(var
); /* parse_variable_name modifies the string */
1111 need_substring
= parse_variable_name(tmpvar
, &offset
, &length
, &i
/* ignored */);
1114 * Look first into predefined variables, then into variable lists.
1115 * Variable 's' points to the result, according to the following rules:
1116 * s == ¬_found (set at the beginning) means that we did not find a
1117 * matching variable and need to look into more places.
1118 * If s != ¬_found, s is a valid result string as follows:
1119 * s = NULL if the variable does not have a value;
1120 * you typically do this when looking for an unset predefined variable.
1121 * s = workspace if the result has been assembled there;
1122 * typically done when the result is built e.g. with an snprintf(),
1123 * so we don't need to do an additional copy.
1124 * s != workspace in case we have a string, that needs to be copied
1125 * (the ast_copy_string is done once for all at the end).
1126 * Typically done when the result is already available in some string.
1128 s
= ¬_found
; /* default value */
1129 if (c
) { /* This group requires a valid channel */
1130 /* Names with common parts are looked up a piece at a time using strncmp. */
1131 if (!strncmp(var
, "CALL", 4)) {
1132 if (!strncmp(var
+ 4, "ING", 3)) {
1133 if (!strcmp(var
+ 7, "PRES")) { /* CALLINGPRES */
1134 snprintf(workspace
, workspacelen
, "%d", c
->cid
.cid_pres
);
1136 } else if (!strcmp(var
+ 7, "ANI2")) { /* CALLINGANI2 */
1137 snprintf(workspace
, workspacelen
, "%d", c
->cid
.cid_ani2
);
1139 } else if (!strcmp(var
+ 7, "TON")) { /* CALLINGTON */
1140 snprintf(workspace
, workspacelen
, "%d", c
->cid
.cid_ton
);
1142 } else if (!strcmp(var
+ 7, "TNS")) { /* CALLINGTNS */
1143 snprintf(workspace
, workspacelen
, "%d", c
->cid
.cid_tns
);
1147 } else if (!strcmp(var
, "HINT")) {
1148 s
= ast_get_hint(workspace
, workspacelen
, NULL
, 0, c
, c
->context
, c
->exten
) ? workspace
: NULL
;
1149 } else if (!strcmp(var
, "HINTNAME")) {
1150 s
= ast_get_hint(NULL
, 0, workspace
, workspacelen
, c
, c
->context
, c
->exten
) ? workspace
: NULL
;
1151 } else if (!strcmp(var
, "EXTEN")) {
1153 } else if (!strcmp(var
, "CONTEXT")) {
1155 } else if (!strcmp(var
, "PRIORITY")) {
1156 snprintf(workspace
, workspacelen
, "%d", c
->priority
);
1158 } else if (!strcmp(var
, "CHANNEL")) {
1160 } else if (!strcmp(var
, "UNIQUEID")) {
1162 } else if (!strcmp(var
, "HANGUPCAUSE")) {
1163 snprintf(workspace
, workspacelen
, "%d", c
->hangupcause
);
1167 if (s
== ¬_found
) { /* look for more */
1168 if (!strcmp(var
, "EPOCH")) {
1169 snprintf(workspace
, workspacelen
, "%u",(int)time(NULL
));
1171 } else if (!strcmp(var
, "SYSTEMNAME")) {
1172 s
= ast_config_AST_SYSTEM_NAME
;
1175 /* if not found, look into chanvars or global vars */
1176 for (i
= 0; s
== ¬_found
&& i
< (sizeof(places
) / sizeof(places
[0])); i
++) {
1177 struct ast_var_t
*variables
;
1180 if (places
[i
] == &globals
)
1181 ast_mutex_lock(&globalslock
);
1182 AST_LIST_TRAVERSE(places
[i
], variables
, entries
) {
1183 if (strcasecmp(ast_var_name(variables
), var
)==0) {
1184 s
= ast_var_value(variables
);
1188 if (places
[i
] == &globals
)
1189 ast_mutex_unlock(&globalslock
);
1191 if (s
== ¬_found
|| s
== NULL
)
1195 ast_copy_string(workspace
, s
, workspacelen
);
1198 *ret
= substring(*ret
, offset
, length
, workspace
, workspacelen
);
1202 /*! \brief CLI function to show installed custom functions
1203 \addtogroup CLI_functions
1205 static int handle_show_functions(int fd
, int argc
, char *argv
[])
1207 struct ast_custom_function
*acf
;
1211 if (argc
== 4 && (!strcmp(argv
[2], "like")) ) {
1213 } else if (argc
!= 2) {
1214 return RESULT_SHOWUSAGE
;
1217 ast_cli(fd
, "%s Custom Functions:\n--------------------------------------------------------------------------------\n", like
? "Matching" : "Installed");
1219 AST_LIST_LOCK(&acf_root
);
1220 AST_LIST_TRAVERSE(&acf_root
, acf
, acflist
) {
1221 if (!like
|| strstr(acf
->name
, argv
[3])) {
1223 ast_cli(fd
, "%-20.20s %-35.35s %s\n", acf
->name
, acf
->syntax
, acf
->synopsis
);
1226 AST_LIST_UNLOCK(&acf_root
);
1228 ast_cli(fd
, "%d %scustom functions installed.\n", count_acf
, like
? "matching " : "");
1230 return RESULT_SUCCESS
;
1233 static int handle_show_function(int fd
, int argc
, char *argv
[])
1235 struct ast_custom_function
*acf
;
1236 /* Maximum number of characters added by terminal coloring is 22 */
1237 char infotitle
[64 + AST_MAX_APP
+ 22], syntitle
[40], destitle
[40];
1238 char info
[64 + AST_MAX_APP
], *synopsis
= NULL
, *description
= NULL
;
1239 char stxtitle
[40], *syntax
= NULL
;
1240 int synopsis_size
, description_size
, syntax_size
;
1243 return RESULT_SHOWUSAGE
;
1245 if (!(acf
= ast_custom_function_find(argv
[2]))) {
1246 ast_cli(fd
, "No function by that name registered.\n");
1247 return RESULT_FAILURE
;
1252 synopsis_size
= strlen(acf
->synopsis
) + 23;
1254 synopsis_size
= strlen("Not available") + 23;
1255 synopsis
= alloca(synopsis_size
);
1258 description_size
= strlen(acf
->desc
) + 23;
1260 description_size
= strlen("Not available") + 23;
1261 description
= alloca(description_size
);
1264 syntax_size
= strlen(acf
->syntax
) + 23;
1266 syntax_size
= strlen("Not available") + 23;
1267 syntax
= alloca(syntax_size
);
1269 snprintf(info
, 64 + AST_MAX_APP
, "\n -= Info about function '%s' =- \n\n", acf
->name
);
1270 term_color(infotitle
, info
, COLOR_MAGENTA
, 0, 64 + AST_MAX_APP
+ 22);
1271 term_color(stxtitle
, "[Syntax]\n", COLOR_MAGENTA
, 0, 40);
1272 term_color(syntitle
, "[Synopsis]\n", COLOR_MAGENTA
, 0, 40);
1273 term_color(destitle
, "[Description]\n", COLOR_MAGENTA
, 0, 40);
1275 acf
->syntax
? acf
->syntax
: "Not available",
1276 COLOR_CYAN
, 0, syntax_size
);
1277 term_color(synopsis
,
1278 acf
->synopsis
? acf
->synopsis
: "Not available",
1279 COLOR_CYAN
, 0, synopsis_size
);
1280 term_color(description
,
1281 acf
->desc
? acf
->desc
: "Not available",
1282 COLOR_CYAN
, 0, description_size
);
1284 ast_cli(fd
,"%s%s%s\n\n%s%s\n\n%s%s\n", infotitle
, stxtitle
, syntax
, syntitle
, synopsis
, destitle
, description
);
1286 return RESULT_SUCCESS
;
1289 static char *complete_show_function(const char *line
, const char *word
, int pos
, int state
)
1291 struct ast_custom_function
*acf
;
1294 int wordlen
= strlen(word
);
1296 /* case-insensitive for convenience in this 'complete' function */
1297 AST_LIST_LOCK(&acf_root
);
1298 AST_LIST_TRAVERSE(&acf_root
, acf
, acflist
) {
1299 if (!strncasecmp(word
, acf
->name
, wordlen
) && ++which
> state
) {
1300 ret
= strdup(acf
->name
);
1304 AST_LIST_UNLOCK(&acf_root
);
1309 struct ast_custom_function
*ast_custom_function_find(const char *name
)
1311 struct ast_custom_function
*acf
= NULL
;
1313 AST_LIST_LOCK(&acf_root
);
1314 AST_LIST_TRAVERSE(&acf_root
, acf
, acflist
) {
1315 if (!strcmp(name
, acf
->name
))
1318 AST_LIST_UNLOCK(&acf_root
);
1323 int ast_custom_function_unregister(struct ast_custom_function
*acf
)
1325 struct ast_custom_function
*cur
;
1330 AST_LIST_LOCK(&acf_root
);
1331 AST_LIST_TRAVERSE_SAFE_BEGIN(&acf_root
, cur
, acflist
) {
1333 AST_LIST_REMOVE_CURRENT(&acf_root
, acflist
);
1334 if (option_verbose
> 1)
1335 ast_verbose(VERBOSE_PREFIX_2
"Unregistered custom function %s\n", acf
->name
);
1339 AST_LIST_TRAVERSE_SAFE_END
1340 AST_LIST_UNLOCK(&acf_root
);
1342 return acf
? 0 : -1;
1345 int ast_custom_function_register(struct ast_custom_function
*acf
)
1347 struct ast_custom_function
*cur
;
1352 AST_LIST_LOCK(&acf_root
);
1354 if (ast_custom_function_find(acf
->name
)) {
1355 ast_log(LOG_ERROR
, "Function %s already registered.\n", acf
->name
);
1356 AST_LIST_UNLOCK(&acf_root
);
1360 /* Store in alphabetical order */
1361 AST_LIST_TRAVERSE_SAFE_BEGIN(&acf_root
, cur
, acflist
) {
1362 if (strcasecmp(acf
->name
, cur
->name
) < 0) {
1363 AST_LIST_INSERT_BEFORE_CURRENT(&acf_root
, acf
, acflist
);
1367 AST_LIST_TRAVERSE_SAFE_END
1369 AST_LIST_INSERT_TAIL(&acf_root
, acf
, acflist
);
1371 AST_LIST_UNLOCK(&acf_root
);
1373 if (option_verbose
> 1)
1374 ast_verbose(VERBOSE_PREFIX_2
"Registered custom function %s\n", acf
->name
);
1379 /*! \brief return a pointer to the arguments of the function,
1380 * and terminates the function name with '\\0'
1382 static char *func_args(char *function
)
1384 char *args
= strchr(function
, '(');
1387 ast_log(LOG_WARNING
, "Function doesn't contain parentheses. Assuming null argument.\n");
1391 if ((p
= strrchr(args
, ')')) )
1394 ast_log(LOG_WARNING
, "Can't find trailing parenthesis?\n");
1399 int ast_func_read(struct ast_channel
*chan
, char *function
, char *workspace
, size_t len
)
1401 char *args
= func_args(function
);
1402 struct ast_custom_function
*acfptr
= ast_custom_function_find(function
);
1405 ast_log(LOG_ERROR
, "Function %s not registered\n", function
);
1406 else if (!acfptr
->read
)
1407 ast_log(LOG_ERROR
, "Function %s cannot be read\n", function
);
1409 return acfptr
->read(chan
, function
, args
, workspace
, len
);
1413 int ast_func_write(struct ast_channel
*chan
, char *function
, const char *value
)
1415 char *args
= func_args(function
);
1416 struct ast_custom_function
*acfptr
= ast_custom_function_find(function
);
1419 ast_log(LOG_ERROR
, "Function %s not registered\n", function
);
1420 else if (!acfptr
->write
)
1421 ast_log(LOG_ERROR
, "Function %s cannot be written to\n", function
);
1423 return acfptr
->write(chan
, function
, args
, value
);
1428 static void pbx_substitute_variables_helper_full(struct ast_channel
*c
, struct varshead
*headp
, const char *cp1
, char *cp2
, int count
)
1430 /* Substitutes variables into cp2, based on string cp1, and assuming cp2 to be
1433 const char *tmp
, *whereweare
;
1434 int length
, offset
, offset2
, isfunction
;
1435 char *workspace
= NULL
;
1436 char *ltmp
= NULL
, *var
= NULL
;
1437 char *nextvar
, *nextexp
, *nextthing
;
1439 int pos
, brackets
, needsub
, len
;
1442 while (!ast_strlen_zero(whereweare
) && count
) {
1443 /* Assume we're copying the whole remaining string */
1444 pos
= strlen(whereweare
);
1447 nextthing
= strchr(whereweare
, '$');
1449 switch(nextthing
[1]) {
1451 nextvar
= nextthing
;
1452 pos
= nextvar
- whereweare
;
1455 nextexp
= nextthing
;
1456 pos
= nextexp
- whereweare
;
1462 /* Can't copy more than 'count' bytes */
1466 /* Copy that many bytes */
1467 memcpy(cp2
, whereweare
, pos
);
1475 /* We have a variable. Find the start and end, and determine
1476 if we are going to have to recursively call ourselves on the
1478 vars
= vare
= nextvar
+ 2;
1482 /* Find the end of it */
1483 while (brackets
&& *vare
) {
1484 if ((vare
[0] == '$') && (vare
[1] == '{')) {
1486 } else if (vare
[0] == '{') {
1488 } else if (vare
[0] == '}') {
1490 } else if ((vare
[0] == '$') && (vare
[1] == '['))
1495 ast_log(LOG_NOTICE
, "Error in extension logic (missing '}')\n");
1496 len
= vare
- vars
- 1;
1498 /* Skip totally over variable string */
1499 whereweare
+= (len
+ 3);
1502 var
= alloca(VAR_BUF_SIZE
);
1504 /* Store variable name (and truncate) */
1505 ast_copy_string(var
, vars
, len
+ 1);
1507 /* Substitute if necessary */
1510 ltmp
= alloca(VAR_BUF_SIZE
);
1512 memset(ltmp
, 0, VAR_BUF_SIZE
);
1513 pbx_substitute_variables_helper_full(c
, headp
, var
, ltmp
, VAR_BUF_SIZE
- 1);
1520 workspace
= alloca(VAR_BUF_SIZE
);
1522 workspace
[0] = '\0';
1524 parse_variable_name(vars
, &offset
, &offset2
, &isfunction
);
1526 /* Evaluate function */
1527 cp4
= ast_func_read(c
, vars
, workspace
, VAR_BUF_SIZE
) ? NULL
: workspace
;
1529 ast_log(LOG_DEBUG
, "Function result is '%s'\n", cp4
? cp4
: "(null)");
1531 /* Retrieve variable value */
1532 pbx_retrieve_variable(c
, vars
, &cp4
, workspace
, VAR_BUF_SIZE
, headp
);
1535 cp4
= substring(cp4
, offset
, offset2
, workspace
, VAR_BUF_SIZE
);
1537 length
= strlen(cp4
);
1540 memcpy(cp2
, cp4
, length
);
1544 } else if (nextexp
) {
1545 /* We have an expression. Find the start and end, and determine
1546 if we are going to have to recursively call ourselves on the
1548 vars
= vare
= nextexp
+ 2;
1552 /* Find the end of it */
1553 while(brackets
&& *vare
) {
1554 if ((vare
[0] == '$') && (vare
[1] == '[')) {
1558 } else if (vare
[0] == '[') {
1560 } else if (vare
[0] == ']') {
1562 } else if ((vare
[0] == '$') && (vare
[1] == '{')) {
1569 ast_log(LOG_NOTICE
, "Error in extension logic (missing ']')\n");
1570 len
= vare
- vars
- 1;
1572 /* Skip totally over expression */
1573 whereweare
+= (len
+ 3);
1576 var
= alloca(VAR_BUF_SIZE
);
1578 /* Store variable name (and truncate) */
1579 ast_copy_string(var
, vars
, len
+ 1);
1581 /* Substitute if necessary */
1584 ltmp
= alloca(VAR_BUF_SIZE
);
1586 memset(ltmp
, 0, VAR_BUF_SIZE
);
1587 pbx_substitute_variables_helper_full(c
, headp
, var
, ltmp
, VAR_BUF_SIZE
- 1);
1593 length
= ast_expr(vars
, cp2
, count
);
1596 ast_log(LOG_DEBUG
, "Expression result is '%s'\n", cp2
);
1605 void pbx_substitute_variables_helper(struct ast_channel
*c
, const char *cp1
, char *cp2
, int count
)
1607 pbx_substitute_variables_helper_full(c
, (c
) ? &c
->varshead
: NULL
, cp1
, cp2
, count
);
1610 void pbx_substitute_variables_varshead(struct varshead
*headp
, const char *cp1
, char *cp2
, int count
)
1612 pbx_substitute_variables_helper_full(NULL
, headp
, cp1
, cp2
, count
);
1615 static void pbx_substitute_variables(char *passdata
, int datalen
, struct ast_channel
*c
, struct ast_exten
*e
)
1617 memset(passdata
, 0, datalen
);
1619 /* No variables or expressions in e->data, so why scan it? */
1620 if (!strchr(e
->data
, '$') && !strstr(e
->data
,"${") && !strstr(e
->data
,"$[") && !strstr(e
->data
,"$(")) {
1621 ast_copy_string(passdata
, e
->data
, datalen
);
1625 pbx_substitute_variables_helper(c
, e
->data
, passdata
, datalen
- 1);
1628 /*! \brief The return value depends on the action:
1630 * E_MATCH, E_CANMATCH, E_MATCHMORE require a real match,
1631 * and return 0 on failure, -1 on match;
1632 * E_FINDLABEL maps the label to a priority, and returns
1633 * the priority on success, ... XXX
1634 * E_SPAWN, spawn an application,
1635 * and return 0 on success, -1 on failure.
1637 static int pbx_extension_helper(struct ast_channel
*c
, struct ast_context
*con
,
1638 const char *context
, const char *exten
, int priority
,
1639 const char *label
, const char *callerid
, enum ext_match_t action
)
1641 struct ast_exten
*e
;
1642 struct ast_app
*app
;
1644 struct pbx_find_info q
= { .stacklen
= 0 }; /* the rest is reset in pbx_find_extension */
1645 char passdata
[EXT_DATA_SIZE
];
1647 int matching_action
= (action
== E_MATCH
|| action
== E_CANMATCH
|| action
== E_MATCHMORE
);
1649 ast_mutex_lock(&conlock
);
1650 e
= pbx_find_extension(c
, con
, &q
, context
, exten
, priority
, label
, callerid
, action
);
1652 if (matching_action
) {
1653 ast_mutex_unlock(&conlock
);
1654 return -1; /* success, we found it */
1655 } else if (action
== E_FINDLABEL
) { /* map the label to a priority */
1657 ast_mutex_unlock(&conlock
);
1658 return res
; /* the priority we were looking for */
1659 } else { /* spawn */
1660 app
= pbx_findapp(e
->app
);
1661 ast_mutex_unlock(&conlock
);
1663 ast_log(LOG_WARNING
, "No application '%s' for extension (%s, %s, %d)\n", e
->app
, context
, exten
, priority
);
1666 if (c
->context
!= context
)
1667 ast_copy_string(c
->context
, context
, sizeof(c
->context
));
1668 if (c
->exten
!= exten
)
1669 ast_copy_string(c
->exten
, exten
, sizeof(c
->exten
));
1670 c
->priority
= priority
;
1671 pbx_substitute_variables(passdata
, sizeof(passdata
), c
, e
);
1674 char atmp2
[EXT_DATA_SIZE
+100];
1675 ast_log(LOG_DEBUG
, "Launching '%s'\n", app
->name
);
1676 snprintf(atmp
, sizeof(atmp
), "STACK-%s-%s-%d", context
, exten
, priority
);
1677 snprintf(atmp2
, sizeof(atmp2
), "%s(\"%s\", \"%s\") %s",
1678 app
->name
, c
->name
, passdata
, "in new stack");
1679 pbx_builtin_setvar_helper(c
, atmp
, atmp2
);
1681 if (option_verbose
> 2) {
1682 char tmp
[80], tmp2
[80], tmp3
[EXT_DATA_SIZE
];
1683 ast_verbose( VERBOSE_PREFIX_3
"Executing [%s@%s:%d] %s(\"%s\", \"%s\") %s\n",
1684 exten
, context
, priority
,
1685 term_color(tmp
, app
->name
, COLOR_BRCYAN
, 0, sizeof(tmp
)),
1686 term_color(tmp2
, c
->name
, COLOR_BRMAGENTA
, 0, sizeof(tmp2
)),
1687 term_color(tmp3
, passdata
, COLOR_BRMAGENTA
, 0, sizeof(tmp3
)),
1690 manager_event(EVENT_FLAG_CALL
, "Newexten",
1695 "Application: %s\r\n"
1698 c
->name
, c
->context
, c
->exten
, c
->priority
, app
->name
, passdata
, c
->uniqueid
);
1699 return pbx_exec(c
, app
, passdata
); /* 0 on success, -1 on failure */
1701 } else if (q
.swo
) { /* not found here, but in another switch */
1702 ast_mutex_unlock(&conlock
);
1703 if (matching_action
)
1707 ast_log(LOG_WARNING
, "No execution engine for switch %s\n", q
.swo
->name
);
1710 return q
.swo
->exec(c
, q
.foundcontext
? q
.foundcontext
: context
, exten
, priority
, callerid
, q
.data
);
1712 } else { /* not found anywhere, see what happened */
1713 ast_mutex_unlock(&conlock
);
1715 case STATUS_NO_CONTEXT
:
1716 if (!matching_action
)
1717 ast_log(LOG_NOTICE
, "Cannot find extension context '%s'\n", context
);
1719 case STATUS_NO_EXTENSION
:
1720 if (!matching_action
)
1721 ast_log(LOG_NOTICE
, "Cannot find extension '%s' in context '%s'\n", exten
, context
);
1723 case STATUS_NO_PRIORITY
:
1724 if (!matching_action
)
1725 ast_log(LOG_NOTICE
, "No such priority %d in extension '%s' in context '%s'\n", priority
, exten
, context
);
1727 case STATUS_NO_LABEL
:
1729 ast_log(LOG_NOTICE
, "No such label '%s' in extension '%s' in context '%s'\n", label
, exten
, context
);
1732 ast_log(LOG_DEBUG
, "Shouldn't happen!\n");
1735 return (matching_action
) ? 0 : -1;
1739 /*! \brief ast_hint_extension: Find hint for given extension in context */
1740 static struct ast_exten
*ast_hint_extension(struct ast_channel
*c
, const char *context
, const char *exten
)
1742 struct ast_exten
*e
;
1743 struct pbx_find_info q
= { .stacklen
= 0 }; /* the rest is set in pbx_find_context */
1745 ast_mutex_lock(&conlock
);
1746 e
= pbx_find_extension(c
, NULL
, &q
, context
, exten
, PRIORITY_HINT
, NULL
, "", E_MATCH
);
1747 ast_mutex_unlock(&conlock
);
1752 /*! \brief ast_extensions_state2: Check state of extension by using hints */
1753 static int ast_extension_state2(struct ast_exten
*e
)
1755 char hint
[AST_MAX_EXTENSION
];
1757 int allunavailable
= 1, allbusy
= 1, allfree
= 1, allonhold
= 1;
1758 int busy
= 0, inuse
= 0, ring
= 0;
1763 ast_copy_string(hint
, ast_get_extension_app(e
), sizeof(hint
));
1765 rest
= hint
; /* One or more devices separated with a & character */
1766 while ( (cur
= strsep(&rest
, "&")) ) {
1767 int res
= ast_device_state(cur
);
1769 case AST_DEVICE_NOT_INUSE
:
1774 case AST_DEVICE_INUSE
:
1780 case AST_DEVICE_RINGING
:
1786 case AST_DEVICE_RINGINUSE
:
1793 case AST_DEVICE_ONHOLD
:
1797 case AST_DEVICE_BUSY
:
1803 case AST_DEVICE_UNAVAILABLE
:
1804 case AST_DEVICE_INVALID
:
1818 return AST_EXTENSION_RINGING
;
1820 return (AST_EXTENSION_INUSE
| AST_EXTENSION_RINGING
);
1822 return AST_EXTENSION_INUSE
;
1824 return AST_EXTENSION_NOT_INUSE
;
1826 return AST_EXTENSION_ONHOLD
;
1828 return AST_EXTENSION_BUSY
;
1830 return AST_EXTENSION_UNAVAILABLE
;
1832 return AST_EXTENSION_INUSE
;
1834 return AST_EXTENSION_NOT_INUSE
;
1837 /*! \brief ast_extension_state2str: Return extension_state as string */
1838 const char *ast_extension_state2str(int extension_state
)
1842 for (i
= 0; (i
< (sizeof(extension_states
) / sizeof(extension_states
[0]))); i
++) {
1843 if (extension_states
[i
].extension_state
== extension_state
)
1844 return extension_states
[i
].text
;
1849 /*! \brief ast_extension_state: Check extension state for an extension by using hint */
1850 int ast_extension_state(struct ast_channel
*c
, const char *context
, const char *exten
)
1852 struct ast_exten
*e
;
1854 e
= ast_hint_extension(c
, context
, exten
); /* Do we have a hint for this extension ? */
1856 return -1; /* No hint, return -1 */
1858 return ast_extension_state2(e
); /* Check all devices in the hint */
1861 void ast_hint_state_changed(const char *device
)
1863 struct ast_hint
*hint
;
1865 AST_LIST_LOCK(&hints
);
1867 AST_LIST_TRAVERSE(&hints
, hint
, list
) {
1868 struct ast_state_cb
*cblist
;
1869 char buf
[AST_MAX_EXTENSION
];
1874 ast_copy_string(buf
, ast_get_extension_app(hint
->exten
), sizeof(buf
));
1875 while ( (cur
= strsep(&parse
, "&")) ) {
1876 if (!strcasecmp(cur
, device
))
1882 /* Get device state for this hint */
1883 state
= ast_extension_state2(hint
->exten
);
1885 if ((state
== -1) || (state
== hint
->laststate
))
1888 /* Device state changed since last check - notify the watchers */
1890 /* For general callbacks */
1891 for (cblist
= statecbs
; cblist
; cblist
= cblist
->next
)
1892 cblist
->callback(hint
->exten
->parent
->name
, hint
->exten
->exten
, state
, cblist
->data
);
1894 /* For extension callbacks */
1895 for (cblist
= hint
->callbacks
; cblist
; cblist
= cblist
->next
)
1896 cblist
->callback(hint
->exten
->parent
->name
, hint
->exten
->exten
, state
, cblist
->data
);
1898 hint
->laststate
= state
; /* record we saw the change */
1901 AST_LIST_UNLOCK(&hints
);
1904 /*! \brief ast_extension_state_add: Add watcher for extension states */
1905 int ast_extension_state_add(const char *context
, const char *exten
,
1906 ast_state_cb_type callback
, void *data
)
1908 struct ast_hint
*hint
;
1909 struct ast_state_cb
*cblist
;
1910 struct ast_exten
*e
;
1912 /* If there's no context and extension: add callback to statecbs list */
1913 if (!context
&& !exten
) {
1914 AST_LIST_LOCK(&hints
);
1916 for (cblist
= statecbs
; cblist
; cblist
= cblist
->next
) {
1917 if (cblist
->callback
== callback
) {
1918 cblist
->data
= data
;
1919 AST_LIST_UNLOCK(&hints
);
1924 /* Now insert the callback */
1925 if (!(cblist
= ast_calloc(1, sizeof(*cblist
)))) {
1926 AST_LIST_UNLOCK(&hints
);
1930 cblist
->callback
= callback
;
1931 cblist
->data
= data
;
1933 cblist
->next
= statecbs
;
1936 AST_LIST_UNLOCK(&hints
);
1940 if (!context
|| !exten
)
1943 /* This callback type is for only one hint, so get the hint */
1944 e
= ast_hint_extension(NULL
, context
, exten
);
1949 /* Find the hint in the list of hints */
1950 AST_LIST_LOCK(&hints
);
1952 AST_LIST_TRAVERSE(&hints
, hint
, list
) {
1953 if (hint
->exten
== e
)
1958 /* We have no hint, sorry */
1959 AST_LIST_UNLOCK(&hints
);
1963 /* Now insert the callback in the callback list */
1964 if (!(cblist
= ast_calloc(1, sizeof(*cblist
)))) {
1965 AST_LIST_UNLOCK(&hints
);
1968 cblist
->id
= stateid
++; /* Unique ID for this callback */
1969 cblist
->callback
= callback
; /* Pointer to callback routine */
1970 cblist
->data
= data
; /* Data for the callback */
1972 cblist
->next
= hint
->callbacks
;
1973 hint
->callbacks
= cblist
;
1975 AST_LIST_UNLOCK(&hints
);
1979 /*! \brief ast_extension_state_del: Remove a watcher from the callback list */
1980 int ast_extension_state_del(int id
, ast_state_cb_type callback
)
1982 struct ast_state_cb
**p_cur
= NULL
; /* address of pointer to us */
1985 if (!id
&& !callback
)
1988 AST_LIST_LOCK(&hints
);
1990 if (!id
) { /* id == 0 is a callback without extension */
1991 for (p_cur
= &statecbs
; *p_cur
; p_cur
= &(*p_cur
)->next
) {
1992 if ((*p_cur
)->callback
== callback
)
1995 } else { /* callback with extension, find the callback based on ID */
1996 struct ast_hint
*hint
;
1997 AST_LIST_TRAVERSE(&hints
, hint
, list
) {
1998 for (p_cur
= &hint
->callbacks
; *p_cur
; p_cur
= &(*p_cur
)->next
) {
1999 if ((*p_cur
)->id
== id
)
2002 if (*p_cur
) /* found in the inner loop */
2006 if (p_cur
&& *p_cur
) {
2007 struct ast_state_cb
*cur
= *p_cur
;
2012 AST_LIST_UNLOCK(&hints
);
2016 /*! \brief ast_add_hint: Add hint to hint list, check initial extension state */
2017 static int ast_add_hint(struct ast_exten
*e
)
2019 struct ast_hint
*hint
;
2024 AST_LIST_LOCK(&hints
);
2026 /* Search if hint exists, do nothing */
2027 AST_LIST_TRAVERSE(&hints
, hint
, list
) {
2028 if (hint
->exten
== e
) {
2029 AST_LIST_UNLOCK(&hints
);
2030 if (option_debug
> 1)
2031 ast_log(LOG_DEBUG
, "HINTS: Not re-adding existing hint %s: %s\n", ast_get_extension_name(e
), ast_get_extension_app(e
));
2036 if (option_debug
> 1)
2037 ast_log(LOG_DEBUG
, "HINTS: Adding hint %s: %s\n", ast_get_extension_name(e
), ast_get_extension_app(e
));
2039 if (!(hint
= ast_calloc(1, sizeof(*hint
)))) {
2040 AST_LIST_UNLOCK(&hints
);
2043 /* Initialize and insert new item at the top */
2045 hint
->laststate
= ast_extension_state2(e
);
2046 AST_LIST_INSERT_HEAD(&hints
, hint
, list
);
2048 AST_LIST_UNLOCK(&hints
);
2052 /*! \brief ast_change_hint: Change hint for an extension */
2053 static int ast_change_hint(struct ast_exten
*oe
, struct ast_exten
*ne
)
2055 struct ast_hint
*hint
;
2058 AST_LIST_LOCK(&hints
);
2059 AST_LIST_TRAVERSE(&hints
, hint
, list
) {
2060 if (hint
->exten
== oe
) {
2066 AST_LIST_UNLOCK(&hints
);
2071 /*! \brief ast_remove_hint: Remove hint from extension */
2072 static int ast_remove_hint(struct ast_exten
*e
)
2074 /* Cleanup the Notifys if hint is removed */
2075 struct ast_hint
*hint
;
2076 struct ast_state_cb
*cblist
, *cbprev
;
2082 AST_LIST_LOCK(&hints
);
2083 AST_LIST_TRAVERSE_SAFE_BEGIN(&hints
, hint
, list
) {
2084 if (hint
->exten
== e
) {
2086 cblist
= hint
->callbacks
;
2088 /* Notify with -1 and remove all callbacks */
2090 cblist
= cblist
->next
;
2091 cbprev
->callback(hint
->exten
->parent
->name
, hint
->exten
->exten
, AST_EXTENSION_DEACTIVATED
, cbprev
->data
);
2094 hint
->callbacks
= NULL
;
2095 AST_LIST_REMOVE_CURRENT(&hints
, list
);
2101 AST_LIST_TRAVERSE_SAFE_END
2102 AST_LIST_UNLOCK(&hints
);
2108 /*! \brief ast_get_hint: Get hint for channel */
2109 int ast_get_hint(char *hint
, int hintsize
, char *name
, int namesize
, struct ast_channel
*c
, const char *context
, const char *exten
)
2111 struct ast_exten
*e
= ast_hint_extension(c
, context
, exten
);
2115 ast_copy_string(hint
, ast_get_extension_app(e
), hintsize
);
2117 const char *tmp
= ast_get_extension_app_data(e
);
2119 ast_copy_string(name
, tmp
, namesize
);
2126 int ast_exists_extension(struct ast_channel
*c
, const char *context
, const char *exten
, int priority
, const char *callerid
)
2128 return pbx_extension_helper(c
, NULL
, context
, exten
, priority
, NULL
, callerid
, E_MATCH
);
2131 int ast_findlabel_extension(struct ast_channel
*c
, const char *context
, const char *exten
, const char *label
, const char *callerid
)
2133 return pbx_extension_helper(c
, NULL
, context
, exten
, 0, label
, callerid
, E_FINDLABEL
);
2136 int ast_findlabel_extension2(struct ast_channel
*c
, struct ast_context
*con
, const char *exten
, const char *label
, const char *callerid
)
2138 return pbx_extension_helper(c
, con
, NULL
, exten
, 0, label
, callerid
, E_FINDLABEL
);
2141 int ast_canmatch_extension(struct ast_channel
*c
, const char *context
, const char *exten
, int priority
, const char *callerid
)
2143 return pbx_extension_helper(c
, NULL
, context
, exten
, priority
, NULL
, callerid
, E_CANMATCH
);
2146 int ast_matchmore_extension(struct ast_channel
*c
, const char *context
, const char *exten
, int priority
, const char *callerid
)
2148 return pbx_extension_helper(c
, NULL
, context
, exten
, priority
, NULL
, callerid
, E_MATCHMORE
);
2151 int ast_spawn_extension(struct ast_channel
*c
, const char *context
, const char *exten
, int priority
, const char *callerid
)
2153 return pbx_extension_helper(c
, NULL
, context
, exten
, priority
, NULL
, callerid
, E_SPAWN
);
2156 /* helper function to set extension and priority */
2157 static void set_ext_pri(struct ast_channel
*c
, const char *exten
, int pri
)
2159 ast_copy_string(c
->exten
, exten
, sizeof(c
->exten
));
2164 * \brief collect digits from the channel into the buffer,
2165 * return -1 on error, 0 on timeout or done.
2167 static int collect_digits(struct ast_channel
*c
, int waittime
, char *buf
, int buflen
, int pos
)
2171 buf
[pos
] = '\0'; /* make sure it is properly terminated */
2172 while (ast_matchmore_extension(c
, c
->context
, buf
, 1, c
->cid
.cid_num
)) {
2173 /* As long as we're willing to wait, and as long as it's not defined,
2174 keep reading digits until we can't possibly get a right answer anymore. */
2175 digit
= ast_waitfordigit(c
, waittime
* 1000);
2176 if (c
->_softhangup
== AST_SOFTHANGUP_ASYNCGOTO
) {
2179 if (!digit
) /* No entry */
2181 if (digit
< 0) /* Error, maybe a hangup */
2183 if (pos
< buflen
- 1) { /* XXX maybe error otherwise ? */
2187 waittime
= c
->pbx
->dtimeout
;
2193 static int __ast_pbx_run(struct ast_channel
*c
)
2195 int found
= 0; /* set if we find at least one match */
2198 int error
= 0; /* set an error conditions */
2200 /* A little initial setup here */
2202 ast_log(LOG_WARNING
, "%s already has PBX structure??\n", c
->name
);
2203 /* XXX and now what ? */
2206 if (!(c
->pbx
= ast_calloc(1, sizeof(*c
->pbx
))))
2210 c
->cdr
= ast_cdr_alloc();
2212 ast_log(LOG_WARNING
, "Unable to create Call Detail Record\n");
2216 ast_cdr_init(c
->cdr
, c
);
2219 /* Set reasonable defaults */
2220 c
->pbx
->rtimeout
= 10;
2221 c
->pbx
->dtimeout
= 5;
2223 autoloopflag
= ast_test_flag(c
, AST_FLAG_IN_AUTOLOOP
); /* save value to restore at the end */
2224 ast_set_flag(c
, AST_FLAG_IN_AUTOLOOP
);
2226 /* Start by trying whatever the channel is set to */
2227 if (!ast_exists_extension(c
, c
->context
, c
->exten
, c
->priority
, c
->cid
.cid_num
)) {
2228 /* If not successful fall back to 's' */
2229 if (option_verbose
> 1)
2230 ast_verbose( VERBOSE_PREFIX_2
"Starting %s at %s,%s,%d failed so falling back to exten 's'\n", c
->name
, c
->context
, c
->exten
, c
->priority
);
2231 /* XXX the original code used the existing priority in the call to
2232 * ast_exists_extension(), and reset it to 1 afterwards.
2233 * I believe the correct thing is to set it to 1 immediately.
2235 set_ext_pri(c
, "s", 1);
2236 if (!ast_exists_extension(c
, c
->context
, c
->exten
, c
->priority
, c
->cid
.cid_num
)) {
2237 /* JK02: And finally back to default if everything else failed */
2238 if (option_verbose
> 1)
2239 ast_verbose( VERBOSE_PREFIX_2
"Starting %s at %s,%s,%d still failed so falling back to context 'default'\n", c
->name
, c
->context
, c
->exten
, c
->priority
);
2240 ast_copy_string(c
->context
, "default", sizeof(c
->context
));
2243 if (c
->cdr
&& ast_tvzero(c
->cdr
->start
))
2244 ast_cdr_start(c
->cdr
);
2246 char dst_exten
[256]; /* buffer to accumulate digits */
2247 int pos
= 0; /* XXX should check bounds */
2250 /* loop on priorities in this context/exten */
2251 while (ast_exists_extension(c
, c
->context
, c
->exten
, c
->priority
, c
->cid
.cid_num
)) {
2253 if ((res
= ast_spawn_extension(c
, c
->context
, c
->exten
, c
->priority
, c
->cid
.cid_num
))) {
2254 /* Something bad happened, or a hangup has been requested. */
2255 if (strchr("0123456789ABCDEF*#", res
)) {
2256 ast_log(LOG_DEBUG
, "Oooh, got something to jump out with ('%c')!\n", res
);
2258 dst_exten
[pos
++] = digit
= res
;
2259 dst_exten
[pos
] = '\0';
2262 if (res
== AST_PBX_KEEPALIVE
) {
2264 ast_log(LOG_DEBUG
, "Spawn extension (%s,%s,%d) exited KEEPALIVE on '%s'\n", c
->context
, c
->exten
, c
->priority
, c
->name
);
2265 else if (option_verbose
> 1)
2266 ast_verbose( VERBOSE_PREFIX_2
"Spawn extension (%s, %s, %d) exited KEEPALIVE on '%s'\n", c
->context
, c
->exten
, c
->priority
, c
->name
);
2271 ast_log(LOG_DEBUG
, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c
->context
, c
->exten
, c
->priority
, c
->name
);
2272 else if (option_verbose
> 1)
2273 ast_verbose( VERBOSE_PREFIX_2
"Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c
->context
, c
->exten
, c
->priority
, c
->name
);
2274 if (c
->_softhangup
== AST_SOFTHANGUP_ASYNCGOTO
) {
2276 } else if (c
->_softhangup
== AST_SOFTHANGUP_TIMEOUT
) {
2277 /* atimeout, nothing bad */
2285 if (c
->_softhangup
== AST_SOFTHANGUP_TIMEOUT
&& ast_exists_extension(c
,c
->context
,"T",1,c
->cid
.cid_num
)) {
2286 set_ext_pri(c
, "T", 0); /* 0 will become 1 with the c->priority++; at the end */
2287 /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
2288 c
->whentohangup
= 0;
2289 c
->_softhangup
&= ~AST_SOFTHANGUP_TIMEOUT
;
2290 } else if (c
->_softhangup
) {
2291 ast_log(LOG_DEBUG
, "Extension %s, priority %d returned normally even though call was hung up\n",
2292 c
->exten
, c
->priority
);
2297 } /* end while - from here on we can use 'break' to go out */
2301 /* XXX we get here on non-existing extension or a keypress or hangup ? */
2303 if (!ast_exists_extension(c
, c
->context
, c
->exten
, 1, c
->cid
.cid_num
)) {
2304 /* If there is no match at priority 1, it is not a valid extension anymore.
2305 * Try to continue at "i", 1 or exit if the latter does not exist.
2307 if (ast_exists_extension(c
, c
->context
, "i", 1, c
->cid
.cid_num
)) {
2308 if (option_verbose
> 2)
2309 ast_verbose(VERBOSE_PREFIX_3
"Sent into invalid extension '%s' in context '%s' on %s\n", c
->exten
, c
->context
, c
->name
);
2310 pbx_builtin_setvar_helper(c
, "INVALID_EXTEN", c
->exten
);
2311 set_ext_pri(c
, "i", 1);
2313 ast_log(LOG_WARNING
, "Channel '%s' sent into invalid extension '%s' in context '%s', but no invalid handler\n",
2314 c
->name
, c
->exten
, c
->context
);
2315 error
= 1; /* we know what to do with it */
2318 } else if (c
->_softhangup
== AST_SOFTHANGUP_TIMEOUT
) {
2319 /* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */
2321 } else { /* keypress received, get more digits for a full extension */
2324 waittime
= c
->pbx
->dtimeout
;
2325 else if (!autofallthrough
)
2326 waittime
= c
->pbx
->rtimeout
;
2328 const char *status
= pbx_builtin_getvar_helper(c
, "DIALSTATUS");
2331 if (option_verbose
> 2)
2332 ast_verbose(VERBOSE_PREFIX_2
"Auto fallthrough, channel '%s' status is '%s'\n", c
->name
, status
);
2333 if (!strcasecmp(status
, "CONGESTION"))
2334 res
= pbx_builtin_congestion(c
, "10");
2335 else if (!strcasecmp(status
, "CHANUNAVAIL"))
2336 res
= pbx_builtin_congestion(c
, "10");
2337 else if (!strcasecmp(status
, "BUSY"))
2338 res
= pbx_builtin_busy(c
, "10");
2339 error
= 1; /* XXX disable message */
2340 break; /* exit from the 'for' loop */
2343 if (collect_digits(c
, waittime
, dst_exten
, sizeof(dst_exten
), pos
))
2345 if (ast_exists_extension(c
, c
->context
, dst_exten
, 1, c
->cid
.cid_num
)) /* Prepare the next cycle */
2346 set_ext_pri(c
, dst_exten
, 1);
2348 /* No such extension */
2349 if (!ast_strlen_zero(dst_exten
)) {
2350 /* An invalid extension */
2351 if (ast_exists_extension(c
, c
->context
, "i", 1, c
->cid
.cid_num
)) {
2352 if (option_verbose
> 2)
2353 ast_verbose( VERBOSE_PREFIX_3
"Invalid extension '%s' in context '%s' on %s\n", dst_exten
, c
->context
, c
->name
);
2354 pbx_builtin_setvar_helper(c
, "INVALID_EXTEN", dst_exten
);
2355 set_ext_pri(c
, "i", 1);
2357 ast_log(LOG_WARNING
, "Invalid extension '%s', but no rule 'i' in context '%s'\n", dst_exten
, c
->context
);
2358 found
= 1; /* XXX disable message */
2362 /* A simple timeout */
2363 if (ast_exists_extension(c
, c
->context
, "t", 1, c
->cid
.cid_num
)) {
2364 if (option_verbose
> 2)
2365 ast_verbose( VERBOSE_PREFIX_3
"Timeout on %s\n", c
->name
);
2366 set_ext_pri(c
, "t", 1);
2368 ast_log(LOG_WARNING
, "Timeout, but no rule 't' in context '%s'\n", c
->context
);
2369 found
= 1; /* XXX disable message */
2375 if (option_verbose
> 2)
2376 ast_verbose(VERBOSE_PREFIX_2
"CDR updated on %s\n",c
->name
);
2381 if (!found
&& !error
)
2382 ast_log(LOG_WARNING
, "Don't know what to do with '%s'\n", c
->name
);
2383 if ((res
!= AST_PBX_KEEPALIVE
) && ast_exists_extension(c
, c
->context
, "h", 1, c
->cid
.cid_num
)) {
2384 if (c
->cdr
&& ast_opt_end_cdr_before_h_exten
)
2385 ast_cdr_end(c
->cdr
);
2386 set_ext_pri(c
, "h", 1);
2387 while(ast_exists_extension(c
, c
->context
, c
->exten
, c
->priority
, c
->cid
.cid_num
)) {
2388 if ((res
= ast_spawn_extension(c
, c
->context
, c
->exten
, c
->priority
, c
->cid
.cid_num
))) {
2389 /* Something bad happened, or a hangup has been requested. */
2391 ast_log(LOG_DEBUG
, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c
->context
, c
->exten
, c
->priority
, c
->name
);
2392 else if (option_verbose
> 1)
2393 ast_verbose( VERBOSE_PREFIX_2
"Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c
->context
, c
->exten
, c
->priority
, c
->name
);
2399 ast_set2_flag(c
, autoloopflag
, AST_FLAG_IN_AUTOLOOP
);
2401 pbx_destroy(c
->pbx
);
2403 if (res
!= AST_PBX_KEEPALIVE
)
2408 /* Returns 0 on success, non-zero if call limit was reached */
2409 static int increase_call_count(const struct ast_channel
*c
)
2413 ast_mutex_lock(&maxcalllock
);
2414 if (option_maxcalls
) {
2415 if (countcalls
>= option_maxcalls
) {
2416 ast_log(LOG_NOTICE
, "Maximum call limit of %d calls exceeded by '%s'!\n", option_maxcalls
, c
->name
);
2420 if (option_maxload
) {
2421 getloadavg(&curloadavg
, 1);
2422 if (curloadavg
>= option_maxload
) {
2423 ast_log(LOG_NOTICE
, "Maximum loadavg limit of %f load exceeded by '%s' (currently %f)!\n", option_maxload
, c
->name
, curloadavg
);
2429 ast_mutex_unlock(&maxcalllock
);
2434 static void decrease_call_count(void)
2436 ast_mutex_lock(&maxcalllock
);
2439 ast_mutex_unlock(&maxcalllock
);
2442 static void destroy_exten(struct ast_exten
*e
)
2444 if (e
->priority
== PRIORITY_HINT
)
2452 static void *pbx_thread(void *data
)
2454 /* Oh joyeous kernel, we're a new thread, with nothing to do but
2455 answer this channel and get it going.
2458 The launcher of this function _MUST_ increment 'countcalls'
2459 before invoking the function; it will be decremented when the
2460 PBX has finished running on the channel
2462 struct ast_channel
*c
= data
;
2465 decrease_call_count();
2472 enum ast_pbx_result
ast_pbx_start(struct ast_channel
*c
)
2475 pthread_attr_t attr
;
2478 ast_log(LOG_WARNING
, "Asked to start thread on NULL channel?\n");
2479 return AST_PBX_FAILED
;
2482 if (increase_call_count(c
))
2483 return AST_PBX_CALL_LIMIT
;
2485 /* Start a new thread, and get something handling this channel. */
2486 pthread_attr_init(&attr
);
2487 pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
2488 if (ast_pthread_create(&t
, &attr
, pbx_thread
, c
)) {
2489 ast_log(LOG_WARNING
, "Failed to create new channel thread\n");
2490 return AST_PBX_FAILED
;
2493 return AST_PBX_SUCCESS
;
2496 enum ast_pbx_result
ast_pbx_run(struct ast_channel
*c
)
2498 enum ast_pbx_result res
= AST_PBX_SUCCESS
;
2500 if (increase_call_count(c
))
2501 return AST_PBX_CALL_LIMIT
;
2503 res
= __ast_pbx_run(c
);
2504 decrease_call_count();
2509 int ast_active_calls(void)
2514 int pbx_set_autofallthrough(int newval
)
2516 int oldval
= autofallthrough
;
2517 autofallthrough
= newval
;
2521 /* lookup for a context with a given name,
2522 * return with conlock held if found, NULL if not found
2524 static struct ast_context
*find_context_locked(const char *context
)
2526 struct ast_context
*c
= NULL
;
2528 ast_lock_contexts();
2529 while ( (c
= ast_walk_contexts(c
)) ) {
2530 if (!strcmp(ast_get_context_name(c
), context
))
2533 ast_unlock_contexts();
2539 * This function locks contexts list by &conlist, search for the right context
2540 * structure, leave context list locked and call ast_context_remove_include2
2541 * which removes include, unlock contexts list and return ...
2543 int ast_context_remove_include(const char *context
, const char *include
, const char *registrar
)
2546 struct ast_context
*c
= find_context_locked(context
);
2549 /* found, remove include from this context ... */
2550 ret
= ast_context_remove_include2(c
, include
, registrar
);
2551 ast_unlock_contexts();
2557 * When we call this function, &conlock lock must be locked, because when
2558 * we giving *con argument, some process can remove/change this context
2559 * and after that there can be segfault.
2561 * This function locks given context, removes include, unlock context and
2564 int ast_context_remove_include2(struct ast_context
*con
, const char *include
, const char *registrar
)
2566 struct ast_include
*i
, *pi
= NULL
;
2569 ast_mutex_lock(&con
->lock
);
2571 /* find our include */
2572 for (i
= con
->includes
; i
; pi
= i
, i
= i
->next
) {
2573 if (!strcmp(i
->name
, include
) &&
2574 (!registrar
|| !strcmp(i
->registrar
, registrar
))) {
2575 /* remove from list */
2579 con
->includes
= i
->next
;
2580 /* free include and return */
2587 ast_mutex_unlock(&con
->lock
);
2592 * \note This function locks contexts list by &conlist, search for the rigt context
2593 * structure, leave context list locked and call ast_context_remove_switch2
2594 * which removes switch, unlock contexts list and return ...
2596 int ast_context_remove_switch(const char *context
, const char *sw
, const char *data
, const char *registrar
)
2598 int ret
= -1; /* default error return */
2599 struct ast_context
*c
= find_context_locked(context
);
2602 /* remove switch from this context ... */
2603 ret
= ast_context_remove_switch2(c
, sw
, data
, registrar
);
2604 ast_unlock_contexts();
2610 * \brief This function locks given context, removes switch, unlock context and
2612 * \note When we call this function, &conlock lock must be locked, because when
2613 * we giving *con argument, some process can remove/change this context
2614 * and after that there can be segfault.
2617 int ast_context_remove_switch2(struct ast_context
*con
, const char *sw
, const char *data
, const char *registrar
)
2622 ast_mutex_lock(&con
->lock
);
2625 AST_LIST_TRAVERSE_SAFE_BEGIN(&con
->alts
, i
, list
) {
2626 if (!strcmp(i
->name
, sw
) && !strcmp(i
->data
, data
) &&
2627 (!registrar
|| !strcmp(i
->registrar
, registrar
))) {
2628 /* found, remove from list */
2629 AST_LIST_REMOVE_CURRENT(&con
->alts
, list
);
2630 free(i
); /* free switch and return */
2635 AST_LIST_TRAVERSE_SAFE_END
2637 ast_mutex_unlock(&con
->lock
);
2643 * \note This functions lock contexts list, search for the right context,
2644 * call ast_context_remove_extension2, unlock contexts list and return.
2645 * In this function we are using
2647 int ast_context_remove_extension(const char *context
, const char *extension
, int priority
, const char *registrar
)
2649 int ret
= -1; /* default error return */
2650 struct ast_context
*c
= find_context_locked(context
);
2652 if (c
) { /* ... remove extension ... */
2653 ret
= ast_context_remove_extension2(c
, extension
, priority
, registrar
);
2654 ast_unlock_contexts();
2660 * \brief This functionc locks given context, search for the right extension and
2661 * fires out all peer in this extensions with given priority. If priority
2662 * is set to 0, all peers are removed. After that, unlock context and
2664 * \note When do you want to call this function, make sure that &conlock is locked,
2665 * because some process can handle with your *con context before you lock
2669 int ast_context_remove_extension2(struct ast_context
*con
, const char *extension
, int priority
, const char *registrar
)
2671 struct ast_exten
*exten
, *prev_exten
= NULL
;
2672 struct ast_exten
*peer
;
2674 ast_mutex_lock(&con
->lock
);
2676 /* scan the extension list to find matching extension-registrar */
2677 for (exten
= con
->root
; exten
; prev_exten
= exten
, exten
= exten
->next
) {
2678 if (!strcmp(exten
->exten
, extension
) &&
2679 (!registrar
|| !strcmp(exten
->registrar
, registrar
)))
2683 /* we can't find right extension */
2684 ast_mutex_unlock(&con
->lock
);
2688 /* should we free all peers in this extension? (priority == 0)? */
2689 if (priority
== 0) {
2690 /* remove this extension from context list */
2692 prev_exten
->next
= exten
->next
;
2694 con
->root
= exten
->next
;
2696 /* fire out all peers */
2697 while ( (peer
= exten
) ) {
2698 exten
= peer
->peer
; /* prepare for next entry */
2699 destroy_exten(peer
);
2702 /* scan the priority list to remove extension with exten->priority == priority */
2703 struct ast_exten
*previous_peer
= NULL
;
2705 for (peer
= exten
; peer
; previous_peer
= peer
, peer
= peer
->peer
) {
2706 if (peer
->priority
== priority
&&
2707 (!registrar
|| !strcmp(peer
->registrar
, registrar
) ))
2708 break; /* found our priority */
2710 if (!peer
) { /* not found */
2711 ast_mutex_unlock(&con
->lock
);
2714 /* we are first priority extension? */
2715 if (!previous_peer
) {
2717 * We are first in the priority chain, so must update the extension chain.
2718 * The next node is either the next priority or the next extension
2720 struct ast_exten
*next_node
= peer
->peer
? peer
->peer
: peer
->next
;
2722 if (!prev_exten
) /* change the root... */
2723 con
->root
= next_node
;
2725 prev_exten
->next
= next_node
; /* unlink */
2726 if (peer
->peer
) /* XXX update the new head of the pri list */
2727 peer
->peer
->next
= peer
->next
;
2728 } else { /* easy, we are not first priority in extension */
2729 previous_peer
->peer
= peer
->peer
;
2732 /* now, free whole priority extension */
2733 destroy_exten(peer
);
2734 /* XXX should we return -1 ? */
2736 ast_mutex_unlock(&con
->lock
);
2741 /*! \brief Dynamically register a new dial plan application */
2742 int ast_register_application(const char *app
, int (*execute
)(struct ast_channel
*, void *), const char *synopsis
, const char *description
)
2744 struct ast_app
*tmp
, *cur
= NULL
;
2748 AST_LIST_LOCK(&apps
);
2749 AST_LIST_TRAVERSE(&apps
, tmp
, list
) {
2750 if (!strcasecmp(app
, tmp
->name
)) {
2751 ast_log(LOG_WARNING
, "Already have an application '%s'\n", app
);
2752 AST_LIST_UNLOCK(&apps
);
2757 length
= sizeof(*tmp
) + strlen(app
) + 1;
2759 if (!(tmp
= ast_calloc(1, length
))) {
2760 AST_LIST_UNLOCK(&apps
);
2764 strcpy(tmp
->name
, app
);
2765 tmp
->execute
= execute
;
2766 tmp
->synopsis
= synopsis
;
2767 tmp
->description
= description
;
2769 /* Store in alphabetical order */
2770 AST_LIST_TRAVERSE_SAFE_BEGIN(&apps
, cur
, list
) {
2771 if (strcasecmp(tmp
->name
, cur
->name
) < 0) {
2772 AST_LIST_INSERT_BEFORE_CURRENT(&apps
, tmp
, list
);
2776 AST_LIST_TRAVERSE_SAFE_END
2778 AST_LIST_INSERT_TAIL(&apps
, tmp
, list
);
2780 if (option_verbose
> 1)
2781 ast_verbose( VERBOSE_PREFIX_2
"Registered application '%s'\n", term_color(tmps
, tmp
->name
, COLOR_BRCYAN
, 0, sizeof(tmps
)));
2783 AST_LIST_UNLOCK(&apps
);
2789 * Append to the list. We don't have a tail pointer because we need
2790 * to scan the list anyways to check for duplicates during insertion.
2792 int ast_register_switch(struct ast_switch
*sw
)
2794 struct ast_switch
*tmp
;
2796 AST_LIST_LOCK(&switches
);
2797 AST_LIST_TRAVERSE(&switches
, tmp
, list
) {
2798 if (!strcasecmp(tmp
->name
, sw
->name
)) {
2799 AST_LIST_UNLOCK(&switches
);
2800 ast_log(LOG_WARNING
, "Switch '%s' already found\n", sw
->name
);
2804 AST_LIST_INSERT_TAIL(&switches
, sw
, list
);
2805 AST_LIST_UNLOCK(&switches
);
2810 void ast_unregister_switch(struct ast_switch
*sw
)
2812 AST_LIST_LOCK(&switches
);
2813 AST_LIST_REMOVE(&switches
, sw
, list
);
2814 AST_LIST_UNLOCK(&switches
);
2818 * Help for CLI commands ...
2820 static char show_application_help
[] =
2821 "Usage: show application <application> [<application> [<application> [...]]]\n"
2822 " Describes a particular application.\n";
2824 static char show_functions_help
[] =
2825 "Usage: show functions [like <text>]\n"
2826 " List builtin functions, optionally only those matching a given string\n";
2828 static char show_function_help
[] =
2829 "Usage: show function <function>\n"
2830 " Describe a particular dialplan function.\n";
2832 static char show_applications_help
[] =
2833 "Usage: show applications [{like|describing} <text>]\n"
2834 " List applications which are currently available.\n"
2835 " If 'like', <text> will be a substring of the app name\n"
2836 " If 'describing', <text> will be a substring of the description\n";
2838 static char show_dialplan_help
[] =
2839 "Usage: show dialplan [exten@][context]\n"
2842 static char show_switches_help
[] =
2843 "Usage: show switches\n"
2844 " Show registered switches\n";
2846 static char show_hints_help
[] =
2847 "Usage: show hints\n"
2848 " Show registered hints\n";
2850 static char show_globals_help
[] =
2851 "Usage: show globals\n"
2852 " Show current global dialplan variables and their values\n";
2854 static char set_global_help
[] =
2855 "Usage: set global <name> <value>\n"
2856 " Set global dialplan variable <name> to <value>\n";
2860 * IMPLEMENTATION OF CLI FUNCTIONS IS IN THE SAME ORDER AS COMMANDS HELPS
2865 * \brief 'show application' CLI command implementation functions ...
2869 * There is a possibility to show informations about more than one
2870 * application at one time. You can type 'show application Dial Echo' and
2871 * you will see informations about these two applications ...
2873 static char *complete_show_application(const char *line
, const char *word
, int pos
, int state
)
2878 int wordlen
= strlen(word
);
2880 /* return the n-th [partial] matching entry */
2881 AST_LIST_LOCK(&apps
);
2882 AST_LIST_TRAVERSE(&apps
, a
, list
) {
2883 if (!strncasecmp(word
, a
->name
, wordlen
) && ++which
> state
) {
2884 ret
= strdup(a
->name
);
2888 AST_LIST_UNLOCK(&apps
);
2893 static int handle_show_application(int fd
, int argc
, char *argv
[])
2896 int app
, no_registered_app
= 1;
2899 return RESULT_SHOWUSAGE
;
2901 /* ... go through all applications ... */
2902 AST_LIST_LOCK(&apps
);
2903 AST_LIST_TRAVERSE(&apps
, a
, list
) {
2904 /* ... compare this application name with all arguments given
2905 * to 'show application' command ... */
2906 for (app
= 2; app
< argc
; app
++) {
2907 if (!strcasecmp(a
->name
, argv
[app
])) {
2908 /* Maximum number of characters added by terminal coloring is 22 */
2909 char infotitle
[64 + AST_MAX_APP
+ 22], syntitle
[40], destitle
[40];
2910 char info
[64 + AST_MAX_APP
], *synopsis
= NULL
, *description
= NULL
;
2911 int synopsis_size
, description_size
;
2913 no_registered_app
= 0;
2916 synopsis_size
= strlen(a
->synopsis
) + 23;
2918 synopsis_size
= strlen("Not available") + 23;
2919 synopsis
= alloca(synopsis_size
);
2922 description_size
= strlen(a
->description
) + 23;
2924 description_size
= strlen("Not available") + 23;
2925 description
= alloca(description_size
);
2927 if (synopsis
&& description
) {
2928 snprintf(info
, 64 + AST_MAX_APP
, "\n -= Info about application '%s' =- \n\n", a
->name
);
2929 term_color(infotitle
, info
, COLOR_MAGENTA
, 0, 64 + AST_MAX_APP
+ 22);
2930 term_color(syntitle
, "[Synopsis]\n", COLOR_MAGENTA
, 0, 40);
2931 term_color(destitle
, "[Description]\n", COLOR_MAGENTA
, 0, 40);
2932 term_color(synopsis
,
2933 a
->synopsis
? a
->synopsis
: "Not available",
2934 COLOR_CYAN
, 0, synopsis_size
);
2935 term_color(description
,
2936 a
->description
? a
->description
: "Not available",
2937 COLOR_CYAN
, 0, description_size
);
2939 ast_cli(fd
,"%s%s%s\n\n%s%s\n", infotitle
, syntitle
, synopsis
, destitle
, description
);
2941 /* ... one of our applications, show info ...*/
2942 ast_cli(fd
,"\n -= Info about application '%s' =- \n\n"
2943 "[Synopsis]\n %s\n\n"
2944 "[Description]\n%s\n",
2946 a
->synopsis
? a
->synopsis
: "Not available",
2947 a
->description
? a
->description
: "Not available");
2952 AST_LIST_UNLOCK(&apps
);
2954 /* we found at least one app? no? */
2955 if (no_registered_app
) {
2956 ast_cli(fd
, "Your application(s) is (are) not registered\n");
2957 return RESULT_FAILURE
;
2960 return RESULT_SUCCESS
;
2963 /*! \brief handle_show_hints: CLI support for listing registred dial plan hints */
2964 static int handle_show_hints(int fd
, int argc
, char *argv
[])
2966 struct ast_hint
*hint
;
2969 struct ast_state_cb
*watcher
;
2971 if (AST_LIST_EMPTY(&hints
)) {
2972 ast_cli(fd
, "There are no registered dialplan hints\n");
2973 return RESULT_SUCCESS
;
2975 /* ... we have hints ... */
2976 ast_cli(fd
, "\n -= Registered Asterisk Dial Plan Hints =-\n");
2977 AST_LIST_LOCK(&hints
);
2978 AST_LIST_TRAVERSE(&hints
, hint
, list
) {
2980 for (watcher
= hint
->callbacks
; watcher
; watcher
= watcher
->next
)
2982 ast_cli(fd
, " %20s@%-20.20s: %-20.20s State:%-15.15s Watchers %2d\n",
2983 ast_get_extension_name(hint
->exten
),
2984 ast_get_context_name(ast_get_extension_context(hint
->exten
)),
2985 ast_get_extension_app(hint
->exten
),
2986 ast_extension_state2str(hint
->laststate
), watchers
);
2989 ast_cli(fd
, "----------------\n");
2990 ast_cli(fd
, "- %d hints registered\n", num
);
2991 AST_LIST_UNLOCK(&hints
);
2992 return RESULT_SUCCESS
;
2995 /*! \brief handle_show_switches: CLI support for listing registred dial plan switches */
2996 static int handle_show_switches(int fd
, int argc
, char *argv
[])
2998 struct ast_switch
*sw
;
3000 AST_LIST_LOCK(&switches
);
3002 if (AST_LIST_EMPTY(&switches
)) {
3003 AST_LIST_UNLOCK(&switches
);
3004 ast_cli(fd
, "There are no registered alternative switches\n");
3005 return RESULT_SUCCESS
;
3008 ast_cli(fd
, "\n -= Registered Asterisk Alternative Switches =-\n");
3009 AST_LIST_TRAVERSE(&switches
, sw
, list
)
3010 ast_cli(fd
, "%s: %s\n", sw
->name
, sw
->description
);
3012 AST_LIST_UNLOCK(&switches
);
3014 return RESULT_SUCCESS
;
3018 * 'show applications' CLI command implementation functions ...
3020 static int handle_show_applications(int fd
, int argc
, char *argv
[])
3023 int like
= 0, describing
= 0;
3024 int total_match
= 0; /* Number of matches in like clause */
3025 int total_apps
= 0; /* Number of apps registered */
3027 AST_LIST_LOCK(&apps
);
3029 if (AST_LIST_EMPTY(&apps
)) {
3030 ast_cli(fd
, "There are no registered applications\n");
3031 AST_LIST_UNLOCK(&apps
);
3035 /* show applications like <keyword> */
3036 if ((argc
== 4) && (!strcmp(argv
[2], "like"))) {
3038 } else if ((argc
> 3) && (!strcmp(argv
[2], "describing"))) {
3042 /* show applications describing <keyword1> [<keyword2>] [...] */
3043 if ((!like
) && (!describing
)) {
3044 ast_cli(fd
, " -= Registered Asterisk Applications =-\n");
3046 ast_cli(fd
, " -= Matching Asterisk Applications =-\n");
3049 AST_LIST_TRAVERSE(&apps
, a
, list
) {
3053 if (strcasestr(a
->name
, argv
[3])) {
3057 } else if (describing
) {
3058 if (a
->description
) {
3059 /* Match all words on command line */
3062 for (i
= 3; i
< argc
; i
++) {
3063 if (!strcasestr(a
->description
, argv
[i
])) {
3075 ast_cli(fd
," %20s: %s\n", a
->name
, a
->synopsis
? a
->synopsis
: "<Synopsis not available>");
3078 if ((!like
) && (!describing
)) {
3079 ast_cli(fd
, " -= %d Applications Registered =-\n",total_apps
);
3081 ast_cli(fd
, " -= %d Applications Matching =-\n",total_match
);
3084 AST_LIST_UNLOCK(&apps
);
3086 return RESULT_SUCCESS
;
3089 static char *complete_show_applications(const char *line
, const char *word
, int pos
, int state
)
3091 static char* choices
[] = { "like", "describing", NULL
};
3093 return (pos
!= 2) ? NULL
: ast_cli_complete(word
, choices
, state
);
3097 * 'show dialplan' CLI command implementation functions ...
3099 static char *complete_show_dialplan_context(const char *line
, const char *word
, int pos
,
3102 struct ast_context
*c
= NULL
;
3107 /* we are do completion of [exten@]context on second position only */
3111 ast_lock_contexts();
3113 wordlen
= strlen(word
);
3115 /* walk through all contexts and return the n-th match */
3116 while ( (c
= ast_walk_contexts(c
)) ) {
3117 if (!strncasecmp(word
, ast_get_context_name(c
), wordlen
) && ++which
> state
) {
3118 ret
= ast_strdup(ast_get_context_name(c
));
3123 ast_unlock_contexts();
3128 struct dialplan_counters
{
3132 int context_existence
;
3133 int extension_existence
;
3136 /*! \brief helper function to print an extension */
3137 static void print_ext(struct ast_exten
*e
, char * buf
, int buflen
)
3139 int prio
= ast_get_extension_priority(e
);
3140 if (prio
== PRIORITY_HINT
) {
3141 snprintf(buf
, buflen
, "hint: %s",
3142 ast_get_extension_app(e
));
3144 snprintf(buf
, buflen
, "%d. %s(%s)",
3145 prio
, ast_get_extension_app(e
),
3146 (char *)ast_get_extension_app_data(e
));
3150 /* XXX not verified */
3151 static int show_dialplan_helper(int fd
, const char *context
, const char *exten
, struct dialplan_counters
*dpc
, struct ast_include
*rinclude
, int includecount
, const char *includes
[])
3153 struct ast_context
*c
= NULL
;
3154 int res
= 0, old_total_exten
= dpc
->total_exten
;
3156 ast_lock_contexts();
3158 /* walk all contexts ... */
3159 while ( (c
= ast_walk_contexts(c
)) ) {
3160 struct ast_exten
*e
;
3161 struct ast_include
*i
;
3162 struct ast_ignorepat
*ip
;
3163 char buf
[256], buf2
[256];
3164 int context_info_printed
= 0;
3166 if (context
&& strcmp(ast_get_context_name(c
), context
))
3167 continue; /* skip this one, name doesn't match */
3169 dpc
->context_existence
= 1;
3171 ast_lock_context(c
);
3173 /* are we looking for exten too? if yes, we print context
3174 * only if we find our extension.
3175 * Otherwise print context even if empty ?
3176 * XXX i am not sure how the rinclude is handled.
3177 * I think it ought to go inside.
3180 dpc
->total_context
++;
3181 ast_cli(fd
, "[ Context '%s' created by '%s' ]\n",
3182 ast_get_context_name(c
), ast_get_context_registrar(c
));
3183 context_info_printed
= 1;
3186 /* walk extensions ... */
3188 while ( (e
= ast_walk_context_extensions(c
, e
)) ) {
3189 struct ast_exten
*p
;
3191 if (exten
&& !ast_extension_match(ast_get_extension_name(e
), exten
))
3192 continue; /* skip, extension match failed */
3194 dpc
->extension_existence
= 1;
3196 /* may we print context info? */
3197 if (!context_info_printed
) {
3198 dpc
->total_context
++;
3199 if (rinclude
) { /* TODO Print more info about rinclude */
3200 ast_cli(fd
, "[ Included context '%s' created by '%s' ]\n",
3201 ast_get_context_name(c
), ast_get_context_registrar(c
));
3203 ast_cli(fd
, "[ Context '%s' created by '%s' ]\n",
3204 ast_get_context_name(c
), ast_get_context_registrar(c
));
3206 context_info_printed
= 1;
3210 /* write extension name and first peer */
3211 snprintf(buf
, sizeof(buf
), "'%s' =>", ast_get_extension_name(e
));
3213 print_ext(e
, buf2
, sizeof(buf2
));
3215 ast_cli(fd
, " %-17s %-45s [%s]\n", buf
, buf2
,
3216 ast_get_extension_registrar(e
));
3219 /* walk next extension peers */
3220 p
= e
; /* skip the first one, we already got it */
3221 while ( (p
= ast_walk_extension_priorities(e
, p
)) ) {
3222 const char *el
= ast_get_extension_label(p
);
3225 snprintf(buf
, sizeof(buf
), " [%s]", el
);
3228 print_ext(p
, buf2
, sizeof(buf2
));
3230 ast_cli(fd
," %-17s %-45s [%s]\n", buf
, buf2
,
3231 ast_get_extension_registrar(p
));
3235 /* walk included and write info ... */
3237 while ( (i
= ast_walk_context_includes(c
, i
)) ) {
3238 snprintf(buf
, sizeof(buf
), "'%s'", ast_get_include_name(i
));
3240 /* Check all includes for the requested extension */
3241 if (includecount
>= AST_PBX_MAX_STACK
) {
3242 ast_log(LOG_NOTICE
, "Maximum include depth exceeded!\n");
3246 for (x
=0;x
<includecount
;x
++) {
3247 if (!strcasecmp(includes
[x
], ast_get_include_name(i
))) {
3253 includes
[includecount
] = ast_get_include_name(i
);
3254 show_dialplan_helper(fd
, ast_get_include_name(i
), exten
, dpc
, i
, includecount
+ 1, includes
);
3256 ast_log(LOG_WARNING
, "Avoiding circular include of %s within %s\n", ast_get_include_name(i
), context
);
3260 ast_cli(fd
, " Include => %-45s [%s]\n",
3261 buf
, ast_get_include_registrar(i
));
3265 /* walk ignore patterns and write info ... */
3267 while ( (ip
= ast_walk_context_ignorepats(c
, ip
)) ) {
3268 const char *ipname
= ast_get_ignorepat_name(ip
);
3269 char ignorepat
[AST_MAX_EXTENSION
];
3270 snprintf(buf
, sizeof(buf
), "'%s'", ipname
);
3271 snprintf(ignorepat
, sizeof(ignorepat
), "_%s.", ipname
);
3272 if (!exten
|| ast_extension_match(ignorepat
, exten
)) {
3273 ast_cli(fd
, " Ignore pattern => %-45s [%s]\n",
3274 buf
, ast_get_ignorepat_registrar(ip
));
3278 struct ast_sw
*sw
= NULL
;
3279 while ( (sw
= ast_walk_context_switches(c
, sw
)) ) {
3280 snprintf(buf
, sizeof(buf
), "'%s/%s'",
3281 ast_get_switch_name(sw
),
3282 ast_get_switch_data(sw
));
3283 ast_cli(fd
, " Alt. Switch => %-45s [%s]\n",
3284 buf
, ast_get_switch_registrar(sw
));
3288 ast_unlock_context(c
);
3290 /* if we print something in context, make an empty line */
3291 if (context_info_printed
)
3292 ast_cli(fd
, "\r\n");
3294 ast_unlock_contexts();
3296 return (dpc
->total_exten
== old_total_exten
) ? -1 : res
;
3299 static int handle_show_dialplan(int fd
, int argc
, char *argv
[])
3301 char *exten
= NULL
, *context
= NULL
;
3302 /* Variables used for different counters */
3303 struct dialplan_counters counters
;
3305 const char *incstack
[AST_PBX_MAX_STACK
];
3306 memset(&counters
, 0, sizeof(counters
));
3308 if (argc
!= 2 && argc
!= 3)
3309 return RESULT_SHOWUSAGE
;
3311 /* we obtain [exten@]context? if yes, split them ... */
3313 if (strchr(argv
[2], '@')) { /* split into exten & context */
3314 context
= ast_strdupa(argv
[2]);
3315 exten
= strsep(&context
, "@");
3316 /* change empty strings to NULL */
3317 if (ast_strlen_zero(exten
))
3319 } else { /* no '@' char, only context given */
3322 if (ast_strlen_zero(context
))
3325 /* else Show complete dial plan, context and exten are NULL */
3326 show_dialplan_helper(fd
, context
, exten
, &counters
, NULL
, 0, incstack
);
3328 /* check for input failure and throw some error messages */
3329 if (context
&& !counters
.context_existence
) {
3330 ast_cli(fd
, "There is no existence of '%s' context\n", context
);
3331 return RESULT_FAILURE
;
3334 if (exten
&& !counters
.extension_existence
) {
3336 ast_cli(fd
, "There is no existence of %s@%s extension\n",
3340 "There is no existence of '%s' extension in all contexts\n",
3342 return RESULT_FAILURE
;
3345 ast_cli(fd
,"-= %d %s (%d %s) in %d %s. =-\n",
3346 counters
.total_exten
, counters
.total_exten
== 1 ? "extension" : "extensions",
3347 counters
.total_prio
, counters
.total_prio
== 1 ? "priority" : "priorities",
3348 counters
.total_context
, counters
.total_context
== 1 ? "context" : "contexts");
3351 return RESULT_SUCCESS
;
3354 /*! \brief CLI support for listing global variables in a parseable way */
3355 static int handle_show_globals(int fd
, int argc
, char *argv
[])
3358 struct ast_var_t
*newvariable
;
3360 ast_mutex_lock(&globalslock
);
3361 AST_LIST_TRAVERSE (&globals
, newvariable
, entries
) {
3363 ast_cli(fd
, " %s=%s\n", ast_var_name(newvariable
), ast_var_value(newvariable
));
3365 ast_mutex_unlock(&globalslock
);
3366 ast_cli(fd
, "\n -- %d variables\n", i
);
3368 return RESULT_SUCCESS
;
3371 /*! \brief CLI support for setting global variables */
3372 static int handle_set_global(int fd
, int argc
, char *argv
[])
3375 return RESULT_SHOWUSAGE
;
3377 pbx_builtin_setvar_helper(NULL
, argv
[2], argv
[3]);
3378 ast_cli(fd
, "\n -- Global variable %s set to %s\n", argv
[2], argv
[3]);
3380 return RESULT_SUCCESS
;
3386 * CLI entries for upper commands ...
3388 static struct ast_cli_entry pbx_cli
[] = {
3389 { { "show", "applications", NULL
}, handle_show_applications
,
3390 "Shows registered dialplan applications", show_applications_help
, complete_show_applications
},
3391 { { "show", "functions", NULL
}, handle_show_functions
,
3392 "Shows registered dialplan functions", show_functions_help
},
3393 { { "show" , "function", NULL
}, handle_show_function
,
3394 "Describe a specific dialplan function", show_function_help
, complete_show_function
},
3395 { { "show", "application", NULL
}, handle_show_application
,
3396 "Describe a specific dialplan application", show_application_help
, complete_show_application
},
3397 { { "show", "dialplan", NULL
}, handle_show_dialplan
,
3398 "Show dialplan", show_dialplan_help
, complete_show_dialplan_context
},
3399 { { "show", "switches", NULL
}, handle_show_switches
,
3400 "Show alternative switches", show_switches_help
},
3401 { { "show", "hints", NULL
}, handle_show_hints
,
3402 "Show dialplan hints", show_hints_help
},
3403 { { "show", "globals", NULL
}, handle_show_globals
,
3404 "Show global dialplan variables", show_globals_help
},
3405 { { "set", "global", NULL
}, handle_set_global
,
3406 "Set global dialplan variable", set_global_help
},
3409 int ast_unregister_application(const char *app
)
3411 struct ast_app
*tmp
;
3413 AST_LIST_LOCK(&apps
);
3414 AST_LIST_TRAVERSE_SAFE_BEGIN(&apps
, tmp
, list
) {
3415 if (!strcasecmp(app
, tmp
->name
)) {
3416 AST_LIST_REMOVE_CURRENT(&apps
, list
);
3417 if (option_verbose
> 1)
3418 ast_verbose( VERBOSE_PREFIX_2
"Unregistered application '%s'\n", tmp
->name
);
3423 AST_LIST_TRAVERSE_SAFE_END
3424 AST_LIST_UNLOCK(&apps
);
3426 return tmp
? 0 : -1;
3429 struct ast_context
*ast_context_create(struct ast_context
**extcontexts
, const char *name
, const char *registrar
)
3431 struct ast_context
*tmp
, **local_contexts
;
3432 int length
= sizeof(struct ast_context
) + strlen(name
) + 1;
3435 ast_mutex_lock(&conlock
);
3436 local_contexts
= &contexts
;
3438 local_contexts
= extcontexts
;
3440 for (tmp
= *local_contexts
; tmp
; tmp
= tmp
->next
) {
3441 if (!strcasecmp(tmp
->name
, name
)) {
3442 ast_log(LOG_WARNING
, "Tried to register context '%s', already in use\n", name
);
3444 ast_mutex_unlock(&conlock
);
3448 if ((tmp
= ast_calloc(1, length
))) {
3449 ast_mutex_init(&tmp
->lock
);
3450 strcpy(tmp
->name
, name
);
3452 tmp
->registrar
= registrar
;
3453 tmp
->next
= *local_contexts
;
3454 tmp
->includes
= NULL
;
3455 tmp
->ignorepats
= NULL
;
3456 *local_contexts
= tmp
;
3458 ast_log(LOG_DEBUG
, "Registered context '%s'\n", tmp
->name
);
3459 else if (option_verbose
> 2)
3460 ast_verbose( VERBOSE_PREFIX_3
"Registered extension context '%s'\n", tmp
->name
);
3464 ast_mutex_unlock(&conlock
);
3468 void __ast_context_destroy(struct ast_context
*con
, const char *registrar
);
3473 struct ast_state_cb
*callbacks
;
3475 AST_LIST_ENTRY(store_hint
) list
;
3479 AST_LIST_HEAD(store_hints
, store_hint
);
3481 /* XXX this does not check that multiple contexts are merged */
3482 void ast_merge_contexts_and_delete(struct ast_context
**extcontexts
, const char *registrar
)
3484 struct ast_context
*tmp
, *lasttmp
= NULL
;
3485 struct store_hints store
= AST_LIST_HEAD_INIT_VALUE
;
3486 struct store_hint
*this;
3487 struct ast_hint
*hint
;
3488 struct ast_exten
*exten
;
3490 struct ast_state_cb
*thiscb
, *prevcb
;
3492 /* it is very important that this function hold the hint list lock _and_ the conlock
3493 during its operation; not only do we need to ensure that the list of contexts
3494 and extensions does not change, but also that no hint callbacks (watchers) are
3495 added or removed during the merge/delete process
3497 in addition, the locks _must_ be taken in this order, because there are already
3498 other code paths that use this order
3500 ast_mutex_lock(&conlock
);
3501 AST_LIST_LOCK(&hints
);
3503 /* preserve all watchers for hints associated with this registrar */
3504 AST_LIST_TRAVERSE(&hints
, hint
, list
) {
3505 if (hint
->callbacks
&& !strcmp(registrar
, hint
->exten
->parent
->registrar
)) {
3506 length
= strlen(hint
->exten
->exten
) + strlen(hint
->exten
->parent
->name
) + 2 + sizeof(*this);
3507 if (!(this = ast_calloc(1, length
)))
3509 this->callbacks
= hint
->callbacks
;
3510 hint
->callbacks
= NULL
;
3511 this->laststate
= hint
->laststate
;
3512 this->context
= this->data
;
3513 strcpy(this->data
, hint
->exten
->parent
->name
);
3514 this->exten
= this->data
+ strlen(this->context
) + 1;
3515 strcpy(this->exten
, hint
->exten
->exten
);
3516 AST_LIST_INSERT_HEAD(&store
, this, list
);
3522 /* XXX remove previous contexts from same registrar */
3523 ast_log(LOG_DEBUG
, "must remove any reg %s\n", registrar
);
3524 __ast_context_destroy(NULL
,registrar
);
3530 /* XXX remove contexts with the same name */
3532 ast_log(LOG_WARNING
, "must remove %s reg %s\n", tmp
->name
, tmp
->registrar
);
3533 __ast_context_destroy(tmp
,tmp
->registrar
);
3539 lasttmp
->next
= contexts
;
3540 contexts
= *extcontexts
;
3541 *extcontexts
= NULL
;
3543 ast_log(LOG_WARNING
, "Requested contexts didn't get merged\n");
3545 /* restore the watchers for hints that can be found; notify those that
3548 while ((this = AST_LIST_REMOVE_HEAD(&store
, list
))) {
3549 exten
= ast_hint_extension(NULL
, this->context
, this->exten
);
3550 /* Find the hint in the list of hints */
3551 AST_LIST_TRAVERSE(&hints
, hint
, list
) {
3552 if (hint
->exten
== exten
)
3555 if (!exten
|| !hint
) {
3556 /* this hint has been removed, notify the watchers */
3558 thiscb
= this->callbacks
;
3561 thiscb
= thiscb
->next
;
3562 prevcb
->callback(this->context
, this->exten
, AST_EXTENSION_REMOVED
, prevcb
->data
);
3566 thiscb
= this->callbacks
;
3567 while (thiscb
->next
)
3568 thiscb
= thiscb
->next
;
3569 thiscb
->next
= hint
->callbacks
;
3570 hint
->callbacks
= this->callbacks
;
3571 hint
->laststate
= this->laststate
;
3576 AST_LIST_UNLOCK(&hints
);
3577 ast_mutex_unlock(&conlock
);
3584 * EBUSY - can't lock
3585 * ENOENT - no existence of context
3587 int ast_context_add_include(const char *context
, const char *include
, const char *registrar
)
3590 struct ast_context
*c
= find_context_locked(context
);
3593 ret
= ast_context_add_include2(c
, include
, registrar
);
3594 ast_unlock_contexts();
3599 /*! \brief Helper for get_range.
3600 * return the index of the matching entry, starting from 1.
3601 * If names is not supplied, try numeric values.
3603 static int lookup_name(const char *s
, char *const names
[], int max
)
3608 for (i
= 0; names
[i
]; i
++) {
3609 if (!strcasecmp(s
, names
[i
]))
3612 } else if (sscanf(s
, "%d", &i
) == 1 && i
>= 1 && i
<= max
) {
3615 return 0; /* error return */
3618 /*! \brief helper function to return a range up to max (7, 12, 31 respectively).
3619 * names, if supplied, is an array of names that should be mapped to numbers.
3621 static unsigned get_range(char *src
, int max
, char *const names
[], const char *msg
)
3623 int s
, e
; /* start and ending position */
3624 unsigned int mask
= 0;
3626 /* Check for whole range */
3627 if (ast_strlen_zero(src
) || !strcmp(src
, "*")) {
3631 /* Get start and ending position */
3632 char *c
= strchr(src
, '-');
3635 /* Find the start */
3636 s
= lookup_name(src
, names
, max
);
3638 ast_log(LOG_WARNING
, "Invalid %s '%s', assuming none\n", msg
, src
);
3642 if (c
) { /* find end of range */
3643 e
= lookup_name(c
, names
, max
);
3645 ast_log(LOG_WARNING
, "Invalid end %s '%s', assuming none\n", msg
, c
);
3652 /* Fill the mask. Remember that ranges are cyclic */
3653 mask
= 1 << e
; /* initialize with last element */
3666 /*! \brief store a bitmask of valid times, one bit each 2 minute */
3667 static void get_timerange(struct ast_timing
*i
, char *times
)
3675 /* start disabling all times, fill the fields with 0's, as they may contain garbage */
3676 memset(i
->minmask
, 0, sizeof(i
->minmask
));
3678 /* 2-minutes per bit, since the mask has only 32 bits :( */
3679 /* Star is all times */
3680 if (ast_strlen_zero(times
) || !strcmp(times
, "*")) {
3681 for (x
=0; x
<24; x
++)
3682 i
->minmask
[x
] = 0x3fffffff; /* 30 bits */
3685 /* Otherwise expect a range */
3686 e
= strchr(times
, '-');
3688 ast_log(LOG_WARNING
, "Time range is not valid. Assuming no restrictions based on time.\n");
3692 /* XXX why skip non digits ? */
3693 while (*e
&& !isdigit(*e
))
3696 ast_log(LOG_WARNING
, "Invalid time range. Assuming no restrictions based on time.\n");
3699 if (sscanf(times
, "%d:%d", &s1
, &s2
) != 2) {
3700 ast_log(LOG_WARNING
, "%s isn't a time. Assuming no restrictions based on time.\n", times
);
3703 if (sscanf(e
, "%d:%d", &e1
, &e2
) != 2) {
3704 ast_log(LOG_WARNING
, "%s isn't a time. Assuming no restrictions based on time.\n", e
);
3707 /* XXX this needs to be optimized */
3709 s1
= s1
* 30 + s2
/2;
3710 if ((s1
< 0) || (s1
>= 24*30)) {
3711 ast_log(LOG_WARNING
, "%s isn't a valid start time. Assuming no time.\n", times
);
3714 e1
= e1
* 30 + e2
/2;
3715 if ((e1
< 0) || (e1
>= 24*30)) {
3716 ast_log(LOG_WARNING
, "%s isn't a valid end time. Assuming no time.\n", e
);
3719 /* Go through the time and enable each appropriate bit */
3720 for (x
=s1
;x
!= e1
;x
= (x
+ 1) % (24 * 30)) {
3721 i
->minmask
[x
/30] |= (1 << (x
% 30));
3723 /* Do the last one */
3724 i
->minmask
[x
/30] |= (1 << (x
% 30));
3726 for (cth
=0; cth
<24; cth
++) {
3727 /* Initialize masks to blank */
3728 i
->minmask
[cth
] = 0;
3729 for (ctm
=0; ctm
<30; ctm
++) {
3731 /* First hour with more than one hour */
3732 (((cth
== s1
) && (ctm
>= s2
)) &&
3735 || (((cth
== s1
) && (ctm
>= s2
)) &&
3736 ((cth
== e1
) && (ctm
<= e2
)))
3737 /* In between first and last hours (more than 2 hours) */
3740 /* Last hour with more than one hour */
3742 ((cth
== e1
) && (ctm
<= e2
)))
3744 i
->minmask
[cth
] |= (1 << (ctm
/ 2));
3752 static char *days
[] =
3764 static char *months
[] =
3781 int ast_build_timing(struct ast_timing
*i
, const char *info_in
)
3783 char info_save
[256];
3786 /* Check for empty just in case */
3787 if (ast_strlen_zero(info_in
))
3789 /* make a copy just in case we were passed a static string */
3790 ast_copy_string(info_save
, info_in
, sizeof(info_save
));
3792 /* Assume everything except time */
3793 i
->monthmask
= 0xfff; /* 12 bits */
3794 i
->daymask
= 0x7fffffffU
; /* 31 bits */
3795 i
->dowmask
= 0x7f; /* 7 bits */
3796 /* on each call, use strsep() to move info to the next argument */
3797 get_timerange(i
, strsep(&info
, "|"));
3799 i
->dowmask
= get_range(strsep(&info
, "|"), 7, days
, "day of week");
3801 i
->daymask
= get_range(strsep(&info
, "|"), 31, NULL
, "day");
3803 i
->monthmask
= get_range(strsep(&info
, "|"), 12, months
, "month");
3807 int ast_check_timing(const struct ast_timing
*i
)
3810 time_t t
= time(NULL
);
3812 localtime_r(&t
,&tm
);
3814 /* If it's not the right month, return */
3815 if (!(i
->monthmask
& (1 << tm
.tm_mon
)))
3818 /* If it's not that time of the month.... */
3819 /* Warning, tm_mday has range 1..31! */
3820 if (!(i
->daymask
& (1 << (tm
.tm_mday
-1))))
3823 /* If it's not the right day of the week */
3824 if (!(i
->dowmask
& (1 << tm
.tm_wday
)))
3827 /* Sanity check the hour just to be safe */
3828 if ((tm
.tm_hour
< 0) || (tm
.tm_hour
> 23)) {
3829 ast_log(LOG_WARNING
, "Insane time...\n");
3833 /* Now the tough part, we calculate if it fits
3834 in the right time based on min/hour */
3835 if (!(i
->minmask
[tm
.tm_hour
] & (1 << (tm
.tm_min
/ 2))))
3838 /* If we got this far, then we're good */
3844 * ENOMEM - out of memory
3845 * EBUSY - can't lock
3846 * EEXIST - already included
3847 * EINVAL - there is no existence of context for inclusion
3849 int ast_context_add_include2(struct ast_context
*con
, const char *value
,
3850 const char *registrar
)
3852 struct ast_include
*new_include
;
3854 struct ast_include
*i
, *il
= NULL
; /* include, include_last */
3858 length
= sizeof(struct ast_include
);
3859 length
+= 2 * (strlen(value
) + 1);
3861 /* allocate new include structure ... */
3862 if (!(new_include
= ast_calloc(1, length
)))
3864 /* Fill in this structure. Use 'p' for assignments, as the fields
3865 * in the structure are 'const char *'
3867 p
= new_include
->stuff
;
3868 new_include
->name
= p
;
3870 p
+= strlen(value
) + 1;
3871 new_include
->rname
= p
;
3873 /* Strip off timing info, and process if it is there */
3874 if ( (c
= strchr(p
, '|')) ) {
3876 new_include
->hastime
= ast_build_timing(&(new_include
->timing
), c
);
3878 new_include
->next
= NULL
;
3879 new_include
->registrar
= registrar
;
3881 ast_mutex_lock(&con
->lock
);
3883 /* ... go to last include and check if context is already included too... */
3884 for (i
= con
->includes
; i
; i
= i
->next
) {
3885 if (!strcasecmp(i
->name
, new_include
->name
)) {
3887 ast_mutex_unlock(&con
->lock
);
3894 /* ... include new context into context list, unlock, return */
3896 il
->next
= new_include
;
3898 con
->includes
= new_include
;
3899 if (option_verbose
> 2)
3900 ast_verbose(VERBOSE_PREFIX_3
"Including context '%s' in context '%s'\n", new_include
->name
, ast_get_context_name(con
));
3901 ast_mutex_unlock(&con
->lock
);
3908 * EBUSY - can't lock
3909 * ENOENT - no existence of context
3911 int ast_context_add_switch(const char *context
, const char *sw
, const char *data
, int eval
, const char *registrar
)
3914 struct ast_context
*c
= find_context_locked(context
);
3916 if (c
) { /* found, add switch to this context */
3917 ret
= ast_context_add_switch2(c
, sw
, data
, eval
, registrar
);
3918 ast_unlock_contexts();
3925 * ENOMEM - out of memory
3926 * EBUSY - can't lock
3927 * EEXIST - already included
3928 * EINVAL - there is no existence of context for inclusion
3930 int ast_context_add_switch2(struct ast_context
*con
, const char *value
,
3931 const char *data
, int eval
, const char *registrar
)
3933 struct ast_sw
*new_sw
;
3938 length
= sizeof(struct ast_sw
);
3939 length
+= strlen(value
) + 1;
3941 length
+= strlen(data
);
3944 /* Create buffer for evaluation of variables */
3945 length
+= SWITCH_DATA_LENGTH
;
3949 /* allocate new sw structure ... */
3950 if (!(new_sw
= ast_calloc(1, length
)))
3952 /* ... fill in this structure ... */
3955 strcpy(new_sw
->name
, value
);
3956 p
+= strlen(value
) + 1;
3959 strcpy(new_sw
->data
, data
);
3960 p
+= strlen(data
) + 1;
3962 strcpy(new_sw
->data
, "");
3966 new_sw
->tmpdata
= p
;
3967 new_sw
->eval
= eval
;
3968 new_sw
->registrar
= registrar
;
3970 /* ... try to lock this context ... */
3971 ast_mutex_lock(&con
->lock
);
3973 /* ... go to last sw and check if context is already swd too... */
3974 AST_LIST_TRAVERSE(&con
->alts
, i
, list
) {
3975 if (!strcasecmp(i
->name
, new_sw
->name
) && !strcasecmp(i
->data
, new_sw
->data
)) {
3977 ast_mutex_unlock(&con
->lock
);
3983 /* ... sw new context into context list, unlock, return */
3984 AST_LIST_INSERT_TAIL(&con
->alts
, new_sw
, list
);
3986 if (option_verbose
> 2)
3987 ast_verbose(VERBOSE_PREFIX_3
"Including switch '%s/%s' in context '%s'\n", new_sw
->name
, new_sw
->data
, ast_get_context_name(con
));
3989 ast_mutex_unlock(&con
->lock
);
3995 * EBUSY - can't lock
3996 * ENOENT - there is not context existence
3998 int ast_context_remove_ignorepat(const char *context
, const char *ignorepat
, const char *registrar
)
4001 struct ast_context
*c
= find_context_locked(context
);
4004 ret
= ast_context_remove_ignorepat2(c
, ignorepat
, registrar
);
4005 ast_unlock_contexts();
4010 int ast_context_remove_ignorepat2(struct ast_context
*con
, const char *ignorepat
, const char *registrar
)
4012 struct ast_ignorepat
*ip
, *ipl
= NULL
;
4014 ast_mutex_lock(&con
->lock
);
4016 for (ip
= con
->ignorepats
; ip
; ip
= ip
->next
) {
4017 if (!strcmp(ip
->pattern
, ignorepat
) &&
4018 (!registrar
|| (registrar
== ip
->registrar
))) {
4020 ipl
->next
= ip
->next
;
4023 con
->ignorepats
= ip
->next
;
4026 ast_mutex_unlock(&con
->lock
);
4032 ast_mutex_unlock(&con
->lock
);
4038 * EBUSY - can't lock
4039 * ENOENT - there is no existence of context
4041 int ast_context_add_ignorepat(const char *context
, const char *value
, const char *registrar
)
4044 struct ast_context
*c
= find_context_locked(context
);
4047 ret
= ast_context_add_ignorepat2(c
, value
, registrar
);
4048 ast_unlock_contexts();
4053 int ast_context_add_ignorepat2(struct ast_context
*con
, const char *value
, const char *registrar
)
4055 struct ast_ignorepat
*ignorepat
, *ignorepatc
, *ignorepatl
= NULL
;
4057 length
= sizeof(struct ast_ignorepat
);
4058 length
+= strlen(value
) + 1;
4059 if (!(ignorepat
= ast_calloc(1, length
)))
4061 /* The cast to char * is because we need to write the initial value.
4062 * The field is not supposed to be modified otherwise
4064 strcpy((char *)ignorepat
->pattern
, value
);
4065 ignorepat
->next
= NULL
;
4066 ignorepat
->registrar
= registrar
;
4067 ast_mutex_lock(&con
->lock
);
4068 for (ignorepatc
= con
->ignorepats
; ignorepatc
; ignorepatc
= ignorepatc
->next
) {
4069 ignorepatl
= ignorepatc
;
4070 if (!strcasecmp(ignorepatc
->pattern
, value
)) {
4072 ast_mutex_unlock(&con
->lock
);
4078 ignorepatl
->next
= ignorepat
;
4080 con
->ignorepats
= ignorepat
;
4081 ast_mutex_unlock(&con
->lock
);
4086 int ast_ignore_pattern(const char *context
, const char *pattern
)
4088 struct ast_context
*con
= ast_context_find(context
);
4090 struct ast_ignorepat
*pat
;
4091 for (pat
= con
->ignorepats
; pat
; pat
= pat
->next
) {
4092 if (ast_extension_match(pat
->pattern
, pattern
))
4101 * EBUSY - can't lock
4102 * ENOENT - no existence of context
4105 int ast_add_extension(const char *context
, int replace
, const char *extension
,
4106 int priority
, const char *label
, const char *callerid
,
4107 const char *application
, void *data
, void (*datad
)(void *), const char *registrar
)
4110 struct ast_context
*c
= find_context_locked(context
);
4113 ret
= ast_add_extension2(c
, replace
, extension
, priority
, label
, callerid
,
4114 application
, data
, datad
, registrar
);
4115 ast_unlock_contexts();
4120 int ast_explicit_goto(struct ast_channel
*chan
, const char *context
, const char *exten
, int priority
)
4125 if (!ast_strlen_zero(context
))
4126 ast_copy_string(chan
->context
, context
, sizeof(chan
->context
));
4127 if (!ast_strlen_zero(exten
))
4128 ast_copy_string(chan
->exten
, exten
, sizeof(chan
->exten
));
4129 if (priority
> -1) {
4130 chan
->priority
= priority
;
4131 /* see flag description in channel.h for explanation */
4132 if (ast_test_flag(chan
, AST_FLAG_IN_AUTOLOOP
))
4139 int ast_async_goto(struct ast_channel
*chan
, const char *context
, const char *exten
, int priority
)
4143 ast_channel_lock(chan
);
4145 if (chan
->pbx
) { /* This channel is currently in the PBX */
4146 ast_explicit_goto(chan
, context
, exten
, priority
);
4147 ast_softhangup_nolock(chan
, AST_SOFTHANGUP_ASYNCGOTO
);
4149 /* In order to do it when the channel doesn't really exist within
4150 the PBX, we have to make a new channel, masquerade, and start the PBX
4151 at the new location */
4152 struct ast_channel
*tmpchan
= ast_channel_alloc(0);
4156 ast_string_field_build(tmpchan
, name
, "AsyncGoto/%s", chan
->name
);
4157 ast_setstate(tmpchan
, chan
->_state
);
4158 /* Make formats okay */
4159 tmpchan
->readformat
= chan
->readformat
;
4160 tmpchan
->writeformat
= chan
->writeformat
;
4161 /* Setup proper location */
4162 ast_explicit_goto(tmpchan
,
4163 S_OR(context
, chan
->context
), S_OR(exten
, chan
->exten
), priority
);
4165 /* Masquerade into temp channel */
4166 ast_channel_masquerade(tmpchan
, chan
);
4168 /* Grab the locks and get going */
4169 ast_channel_lock(tmpchan
);
4170 ast_do_masquerade(tmpchan
);
4171 ast_channel_unlock(tmpchan
);
4172 /* Start the PBX going on our stolen channel */
4173 if (ast_pbx_start(tmpchan
)) {
4174 ast_log(LOG_WARNING
, "Unable to start PBX on %s\n", tmpchan
->name
);
4175 ast_hangup(tmpchan
);
4180 ast_channel_unlock(chan
);
4184 int ast_async_goto_by_name(const char *channame
, const char *context
, const char *exten
, int priority
)
4186 struct ast_channel
*chan
;
4189 chan
= ast_get_channel_by_name_locked(channame
);
4191 res
= ast_async_goto(chan
, context
, exten
, priority
);
4192 ast_channel_unlock(chan
);
4197 /*! \brief copy a string skipping whitespace */
4198 static int ext_strncpy(char *dst
, const char *src
, int len
)
4202 while (*src
&& (count
< len
- 1)) {
4205 /* otherwise exten => [a-b],1,... doesn't work */
4221 static void null_datad(void *foo
)
4225 /*! \brief add the extension in the priority chain.
4226 * returns 0 on success, -1 on failure
4228 static int add_pri(struct ast_context
*con
, struct ast_exten
*tmp
,
4229 struct ast_exten
*el
, struct ast_exten
*e
, int replace
)
4231 struct ast_exten
*ep
;
4233 for (ep
= NULL
; e
; ep
= e
, e
= e
->peer
) {
4234 if (e
->priority
>= tmp
->priority
)
4237 if (!e
) { /* go at the end, and ep is surely set because the list is not empty */
4239 return 0; /* success */
4241 if (e
->priority
== tmp
->priority
) {
4242 /* Can't have something exactly the same. Is this a
4243 replacement? If so, replace, otherwise, bonk. */
4245 ast_log(LOG_WARNING
, "Unable to register extension '%s', priority %d in '%s', already in use\n", tmp
->exten
, tmp
->priority
, con
->name
);
4246 tmp
->datad(tmp
->data
);
4250 /* we are replacing e, so copy the link fields and then update
4251 * whoever pointed to e to point to us
4253 tmp
->next
= e
->next
; /* not meaningful if we are not first in the peer list */
4254 tmp
->peer
= e
->peer
; /* always meaningful */
4255 if (ep
) /* We're in the peer list, just insert ourselves */
4257 else if (el
) /* We're the first extension. Take over e's functions */
4259 else /* We're the very first extension. */
4261 if (tmp
->priority
== PRIORITY_HINT
)
4262 ast_change_hint(e
,tmp
);
4263 /* Destroy the old one */
4266 } else { /* Slip ourselves in just before e */
4268 tmp
->next
= e
->next
; /* extension chain, or NULL if e is not the first extension */
4269 if (ep
) /* Easy enough, we're just in the peer list */
4271 else { /* we are the first in some peer list, so link in the ext list */
4273 el
->next
= tmp
; /* in the middle... */
4275 con
->root
= tmp
; /* ... or at the head */
4276 e
->next
= NULL
; /* e is no more at the head, so e->next must be reset */
4278 /* And immediately return success. */
4279 if (tmp
->priority
== PRIORITY_HINT
)
4286 * Main interface to add extensions to the list for out context.
4288 * We sort extensions in order of matching preference, so that we can
4289 * stop the search as soon as we find a suitable match.
4290 * This ordering also takes care of wildcards such as '.' (meaning
4291 * "one or more of any character") and '!' (which is 'earlymatch',
4292 * meaning "zero or more of any character" but also impacts the
4293 * return value from CANMATCH and EARLYMATCH.
4295 * The extension match rules defined in the devmeeting 2006.05.05 are
4296 * quite simple: WE SELECT THE LONGEST MATCH.
4297 * In detail, "longest" means the number of matched characters in
4298 * the extension. In case of ties (e.g. _XXX and 333) in the length
4299 * of a pattern, we give priority to entries with the smallest cardinality
4300 * (e.g, [5-9] comes before [2-8] before the former has only 5 elements,
4301 * while the latter has 7, etc.
4302 * In case of same cardinality, the first element in the range counts.
4303 * If we still have a tie, any final '!' will make this as a possibly
4304 * less specific pattern.
4306 * EBUSY - can't lock
4307 * EEXIST - extension with the same priority exist and no replace is set
4310 int ast_add_extension2(struct ast_context
*con
,
4311 int replace
, const char *extension
, int priority
, const char *label
, const char *callerid
,
4312 const char *application
, void *data
, void (*datad
)(void *),
4313 const char *registrar
)
4316 * Sort extensions (or patterns) according to the rules indicated above.
4317 * These are implemented by the function ext_cmp()).
4318 * All priorities for the same ext/pattern/cid are kept in a list,
4319 * using the 'peer' field as a link field..
4321 struct ast_exten
*tmp
, *e
, *el
= NULL
;
4325 char expand_buf
[VAR_BUF_SIZE
] = { 0, };
4327 /* if we are adding a hint, and there are global variables, and the hint
4328 contains variable references, then expand them
4330 ast_mutex_lock(&globalslock
);
4331 if (priority
== PRIORITY_HINT
&& AST_LIST_FIRST(&globals
) && strstr(application
, "${")) {
4332 pbx_substitute_variables_varshead(&globals
, application
, expand_buf
, sizeof(expand_buf
));
4333 application
= expand_buf
;
4335 ast_mutex_unlock(&globalslock
);
4337 length
= sizeof(struct ast_exten
);
4338 length
+= strlen(extension
) + 1;
4339 length
+= strlen(application
) + 1;
4341 length
+= strlen(label
) + 1;
4343 length
+= strlen(callerid
) + 1;
4345 length
++; /* just the '\0' */
4347 /* Be optimistic: Build the extension structure first */
4350 if (!(tmp
= ast_calloc(1, length
)))
4353 /* use p as dst in assignments, as the fields are const char * */
4358 p
+= strlen(label
) + 1;
4361 p
+= ext_strncpy(p
, extension
, strlen(extension
) + 1) + 1;
4362 tmp
->priority
= priority
;
4363 tmp
->cidmatch
= p
; /* but use p for assignments below */
4365 p
+= ext_strncpy(p
, callerid
, strlen(callerid
) + 1) + 1;
4372 strcpy(p
, application
);
4376 tmp
->registrar
= registrar
;
4378 ast_mutex_lock(&con
->lock
);
4379 res
= 0; /* some compilers will think it is uninitialized otherwise */
4380 for (e
= con
->root
; e
; el
= e
, e
= e
->next
) { /* scan the extension list */
4381 res
= ext_cmp(e
->exten
, extension
);
4382 if (res
== 0) { /* extension match, now look at cidmatch */
4383 if (!e
->matchcid
&& !tmp
->matchcid
)
4385 else if (tmp
->matchcid
&& !e
->matchcid
)
4387 else if (e
->matchcid
&& !tmp
->matchcid
)
4390 res
= strcasecmp(e
->cidmatch
, tmp
->cidmatch
);
4395 if (e
&& res
== 0) { /* exact match, insert in the pri chain */
4396 res
= add_pri(con
, tmp
, el
, e
, replace
);
4397 ast_mutex_unlock(&con
->lock
);
4399 errno
= EEXIST
; /* XXX do we care ? */
4400 return 0; /* XXX should we return -1 maybe ? */
4404 * not an exact match, this is the first entry with this pattern,
4405 * so insert in the main list right before 'e' (if any)
4412 ast_mutex_unlock(&con
->lock
);
4413 if (tmp
->priority
== PRIORITY_HINT
)
4417 if (tmp
->matchcid
) {
4418 ast_log(LOG_DEBUG
, "Added extension '%s' priority %d (CID match '%s') to %s\n",
4419 tmp
->exten
, tmp
->priority
, tmp
->cidmatch
, con
->name
);
4421 ast_log(LOG_DEBUG
, "Added extension '%s' priority %d to %s\n",
4422 tmp
->exten
, tmp
->priority
, con
->name
);
4424 } else if (option_verbose
> 2) {
4425 if (tmp
->matchcid
) {
4426 ast_verbose( VERBOSE_PREFIX_3
"Added extension '%s' priority %d (CID match '%s')to %s\n",
4427 tmp
->exten
, tmp
->priority
, tmp
->cidmatch
, con
->name
);
4429 ast_verbose( VERBOSE_PREFIX_3
"Added extension '%s' priority %d to %s\n",
4430 tmp
->exten
, tmp
->priority
, con
->name
);
4438 struct ast_channel
*chan
;
4439 char context
[AST_MAX_CONTEXT
];
4440 char exten
[AST_MAX_EXTENSION
];
4443 char app
[AST_MAX_EXTENSION
];
4447 static void *async_wait(void *data
)
4449 struct async_stat
*as
= data
;
4450 struct ast_channel
*chan
= as
->chan
;
4451 int timeout
= as
->timeout
;
4453 struct ast_frame
*f
;
4454 struct ast_app
*app
;
4456 while (timeout
&& (chan
->_state
!= AST_STATE_UP
)) {
4457 res
= ast_waitfor(chan
, timeout
);
4465 if (f
->frametype
== AST_FRAME_CONTROL
) {
4466 if ((f
->subclass
== AST_CONTROL_BUSY
) ||
4467 (f
->subclass
== AST_CONTROL_CONGESTION
) ) {
4474 if (chan
->_state
== AST_STATE_UP
) {
4475 if (!ast_strlen_zero(as
->app
)) {
4476 app
= pbx_findapp(as
->app
);
4478 if (option_verbose
> 2)
4479 ast_verbose(VERBOSE_PREFIX_3
"Launching %s(%s) on %s\n", as
->app
, as
->appdata
, chan
->name
);
4480 pbx_exec(chan
, app
, as
->appdata
);
4482 ast_log(LOG_WARNING
, "No such application '%s'\n", as
->app
);
4484 if (!ast_strlen_zero(as
->context
))
4485 ast_copy_string(chan
->context
, as
->context
, sizeof(chan
->context
));
4486 if (!ast_strlen_zero(as
->exten
))
4487 ast_copy_string(chan
->exten
, as
->exten
, sizeof(chan
->exten
));
4488 if (as
->priority
> 0)
4489 chan
->priority
= as
->priority
;
4491 if (ast_pbx_run(chan
)) {
4492 ast_log(LOG_ERROR
, "Failed to start PBX on %s\n", chan
->name
);
4494 /* PBX will have taken care of this */
4505 /*! Function to post an empty cdr after a spool call fails.
4507 * This function posts an empty cdr for a failed spool call
4510 static int ast_pbx_outgoing_cdr_failed(void)
4512 /* allocate a channel */
4513 struct ast_channel
*chan
= ast_channel_alloc(0);
4516 return -1; /* failure */
4518 chan
->cdr
= ast_cdr_alloc(); /* allocate a cdr for the channel */
4521 /* allocation of the cdr failed */
4522 ast_channel_free(chan
); /* free the channel */
4523 return -1; /* return failure */
4526 /* allocation of the cdr was successful */
4527 ast_cdr_init(chan
->cdr
, chan
); /* initilize our channel's cdr */
4528 ast_cdr_start(chan
->cdr
); /* record the start and stop time */
4529 ast_cdr_end(chan
->cdr
);
4530 ast_cdr_failed(chan
->cdr
); /* set the status to failed */
4531 ast_cdr_detach(chan
->cdr
); /* post and free the record */
4532 ast_channel_free(chan
); /* free the channel */
4534 return 0; /* success */
4537 int ast_pbx_outgoing_exten(const char *type
, int format
, void *data
, int timeout
, const char *context
, const char *exten
, int priority
, int *reason
, int sync
, const char *cid_num
, const char *cid_name
, struct ast_variable
*vars
, const char *account
, struct ast_channel
**channel
)
4539 struct ast_channel
*chan
;
4540 struct async_stat
*as
;
4541 int res
= -1, cdr_res
= -1;
4542 struct outgoing_helper oh
;
4543 pthread_attr_t attr
;
4547 chan
= __ast_request_and_dial(type
, format
, data
, timeout
, reason
, cid_num
, cid_name
, &oh
);
4551 ast_channel_lock(chan
);
4554 if (chan
->cdr
) { /* check if the channel already has a cdr record, if not give it one */
4555 ast_log(LOG_WARNING
, "%s already has a call record??\n", chan
->name
);
4557 chan
->cdr
= ast_cdr_alloc(); /* allocate a cdr for the channel */
4559 /* allocation of the cdr failed */
4562 goto outgoing_exten_cleanup
;
4564 /* allocation of the cdr was successful */
4565 ast_cdr_init(chan
->cdr
, chan
); /* initilize our channel's cdr */
4566 ast_cdr_start(chan
->cdr
);
4568 if (chan
->_state
== AST_STATE_UP
) {
4570 if (option_verbose
> 3)
4571 ast_verbose(VERBOSE_PREFIX_4
"Channel %s was answered.\n", chan
->name
);
4575 ast_channel_unlock(chan
);
4576 if (ast_pbx_run(chan
)) {
4577 ast_log(LOG_ERROR
, "Unable to run PBX on %s\n", chan
->name
);
4584 if (ast_pbx_start(chan
)) {
4585 ast_log(LOG_ERROR
, "Unable to start PBX on %s\n", chan
->name
);
4588 ast_channel_unlock(chan
);
4595 if (option_verbose
> 3)
4596 ast_verbose(VERBOSE_PREFIX_4
"Channel %s was never answered.\n", chan
->name
);
4598 if(chan
->cdr
) { /* update the cdr */
4599 /* here we update the status of the call, which sould be busy.
4600 * if that fails then we set the status to failed */
4601 if (ast_cdr_disposition(chan
->cdr
, chan
->hangupcause
))
4602 ast_cdr_failed(chan
->cdr
);
4607 ast_channel_unlock(chan
);
4613 if (res
< 0) { /* the call failed for some reason */
4614 if (*reason
== 0) { /* if the call failed (not busy or no answer)
4615 * update the cdr with the failed message */
4616 cdr_res
= ast_pbx_outgoing_cdr_failed();
4619 goto outgoing_exten_cleanup
;
4623 /* create a fake channel and execute the "failed" extension (if it exists) within the requested context */
4624 /* check if "failed" exists */
4625 if (ast_exists_extension(chan
, context
, "failed", 1, NULL
)) {
4626 chan
= ast_channel_alloc(0);
4628 ast_string_field_set(chan
, name
, "OutgoingSpoolFailed");
4629 if (!ast_strlen_zero(context
))
4630 ast_copy_string(chan
->context
, context
, sizeof(chan
->context
));
4631 set_ext_pri(chan
, "failed", 1);
4632 ast_set_variables(chan
, vars
);
4634 ast_cdr_setaccount(chan
, account
);
4640 if (!(as
= ast_calloc(1, sizeof(*as
)))) {
4642 goto outgoing_exten_cleanup
;
4644 chan
= ast_request_and_dial(type
, format
, data
, timeout
, reason
, cid_num
, cid_name
);
4648 ast_channel_lock(chan
);
4653 goto outgoing_exten_cleanup
;
4656 ast_copy_string(as
->context
, context
, sizeof(as
->context
));
4657 set_ext_pri(as
->chan
, exten
, priority
);
4658 as
->timeout
= timeout
;
4659 ast_set_variables(chan
, vars
);
4661 ast_cdr_setaccount(chan
, account
);
4662 pthread_attr_init(&attr
);
4663 pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
4664 if (ast_pthread_create(&as
->p
, &attr
, async_wait
, as
)) {
4665 ast_log(LOG_WARNING
, "Failed to start async wait\n");
4669 ast_channel_unlock(chan
);
4673 goto outgoing_exten_cleanup
;
4677 outgoing_exten_cleanup
:
4678 ast_variables_destroy(vars
);
4685 struct ast_channel
*chan
;
4689 /*! \brief run the application and free the descriptor once done */
4690 static void *ast_pbx_run_app(void *data
)
4692 struct app_tmp
*tmp
= data
;
4693 struct ast_app
*app
;
4694 app
= pbx_findapp(tmp
->app
);
4696 if (option_verbose
> 3)
4697 ast_verbose(VERBOSE_PREFIX_4
"Launching %s(%s) on %s\n", tmp
->app
, tmp
->data
, tmp
->chan
->name
);
4698 pbx_exec(tmp
->chan
, app
, tmp
->data
);
4700 ast_log(LOG_WARNING
, "No such application '%s'\n", tmp
->app
);
4701 ast_hangup(tmp
->chan
);
4706 int ast_pbx_outgoing_app(const char *type
, int format
, void *data
, int timeout
, const char *app
, const char *appdata
, int *reason
, int sync
, const char *cid_num
, const char *cid_name
, struct ast_variable
*vars
, const char *account
, struct ast_channel
**locked_channel
)
4708 struct ast_channel
*chan
;
4709 struct app_tmp
*tmp
;
4710 int res
= -1, cdr_res
= -1;
4711 struct outgoing_helper oh
;
4712 pthread_attr_t attr
;
4714 memset(&oh
, 0, sizeof(oh
));
4716 oh
.account
= account
;
4719 *locked_channel
= NULL
;
4720 if (ast_strlen_zero(app
)) {
4722 goto outgoing_app_cleanup
;
4725 chan
= __ast_request_and_dial(type
, format
, data
, timeout
, reason
, cid_num
, cid_name
, &oh
);
4727 if (chan
->cdr
) { /* check if the channel already has a cdr record, if not give it one */
4728 ast_log(LOG_WARNING
, "%s already has a call record??\n", chan
->name
);
4730 chan
->cdr
= ast_cdr_alloc(); /* allocate a cdr for the channel */
4732 /* allocation of the cdr failed */
4735 goto outgoing_app_cleanup
;
4737 /* allocation of the cdr was successful */
4738 ast_cdr_init(chan
->cdr
, chan
); /* initilize our channel's cdr */
4739 ast_cdr_start(chan
->cdr
);
4741 ast_set_variables(chan
, vars
);
4743 ast_cdr_setaccount(chan
, account
);
4744 if (chan
->_state
== AST_STATE_UP
) {
4746 if (option_verbose
> 3)
4747 ast_verbose(VERBOSE_PREFIX_4
"Channel %s was answered.\n", chan
->name
);
4748 tmp
= ast_calloc(1, sizeof(*tmp
));
4752 ast_copy_string(tmp
->app
, app
, sizeof(tmp
->app
));
4754 ast_copy_string(tmp
->data
, appdata
, sizeof(tmp
->data
));
4758 ast_channel_unlock(chan
);
4759 ast_pbx_run_app(tmp
);
4761 pthread_attr_init(&attr
);
4762 pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
4764 ast_channel_lock(chan
);
4765 if (ast_pthread_create(&tmp
->t
, &attr
, ast_pbx_run_app
, tmp
)) {
4766 ast_log(LOG_WARNING
, "Unable to spawn execute thread on %s: %s\n", chan
->name
, strerror(errno
));
4769 ast_channel_unlock(chan
);
4774 *locked_channel
= chan
;
4779 if (option_verbose
> 3)
4780 ast_verbose(VERBOSE_PREFIX_4
"Channel %s was never answered.\n", chan
->name
);
4781 if (chan
->cdr
) { /* update the cdr */
4782 /* here we update the status of the call, which sould be busy.
4783 * if that fails then we set the status to failed */
4784 if (ast_cdr_disposition(chan
->cdr
, chan
->hangupcause
))
4785 ast_cdr_failed(chan
->cdr
);
4791 if (res
< 0) { /* the call failed for some reason */
4792 if (*reason
== 0) { /* if the call failed (not busy or no answer)
4793 * update the cdr with the failed message */
4794 cdr_res
= ast_pbx_outgoing_cdr_failed();
4797 goto outgoing_app_cleanup
;
4803 struct async_stat
*as
;
4804 if (!(as
= ast_calloc(1, sizeof(*as
)))) {
4806 goto outgoing_app_cleanup
;
4808 chan
= __ast_request_and_dial(type
, format
, data
, timeout
, reason
, cid_num
, cid_name
, &oh
);
4812 goto outgoing_app_cleanup
;
4815 ast_copy_string(as
->app
, app
, sizeof(as
->app
));
4817 ast_copy_string(as
->appdata
, appdata
, sizeof(as
->appdata
));
4818 as
->timeout
= timeout
;
4819 ast_set_variables(chan
, vars
);
4821 ast_cdr_setaccount(chan
, account
);
4822 /* Start a new thread, and get something handling this channel. */
4823 pthread_attr_init(&attr
);
4824 pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
4826 ast_channel_lock(chan
);
4827 if (ast_pthread_create(&as
->p
, &attr
, async_wait
, as
)) {
4828 ast_log(LOG_WARNING
, "Failed to start async wait\n");
4831 ast_channel_unlock(chan
);
4834 goto outgoing_app_cleanup
;
4837 *locked_channel
= chan
;
4841 outgoing_app_cleanup
:
4842 ast_variables_destroy(vars
);
4846 void __ast_context_destroy(struct ast_context
*con
, const char *registrar
)
4848 struct ast_context
*tmp
, *tmpl
=NULL
;
4849 struct ast_include
*tmpi
;
4851 struct ast_exten
*e
, *el
, *en
;
4852 struct ast_ignorepat
*ipi
;
4854 ast_mutex_lock(&conlock
);
4855 for (tmp
= contexts
; tmp
; ) {
4856 struct ast_context
*next
; /* next starting point */
4857 for (; tmp
; tmpl
= tmp
, tmp
= tmp
->next
) {
4858 ast_log(LOG_DEBUG
, "check ctx %s %s\n", tmp
->name
, tmp
->registrar
);
4859 if ( (!registrar
|| !strcasecmp(registrar
, tmp
->registrar
)) &&
4860 (!con
|| !strcasecmp(tmp
->name
, con
->name
)) )
4861 break; /* found it */
4863 if (!tmp
) /* not found, we are done */
4865 ast_mutex_lock(&tmp
->lock
);
4866 ast_log(LOG_DEBUG
, "delete ctx %s %s\n", tmp
->name
, tmp
->registrar
);
4872 /* Okay, now we're safe to let it go -- in a sense, we were
4873 ready to let it go as soon as we locked it. */
4874 ast_mutex_unlock(&tmp
->lock
);
4875 for (tmpi
= tmp
->includes
; tmpi
; ) { /* Free includes */
4876 struct ast_include
*tmpil
= tmpi
;
4880 for (ipi
= tmp
->ignorepats
; ipi
; ) { /* Free ignorepats */
4881 struct ast_ignorepat
*ipl
= ipi
;
4885 while ((sw
= AST_LIST_REMOVE_HEAD(&tmp
->alts
, list
)))
4887 for (e
= tmp
->root
; e
;) {
4888 for (en
= e
->peer
; en
;) {
4897 ast_mutex_destroy(&tmp
->lock
);
4899 /* if we have a specific match, we are done, otherwise continue */
4900 tmp
= con
? NULL
: next
;
4902 ast_mutex_unlock(&conlock
);
4905 void ast_context_destroy(struct ast_context
*con
, const char *registrar
)
4907 __ast_context_destroy(con
,registrar
);
4910 static void wait_for_hangup(struct ast_channel
*chan
, void *data
)
4913 struct ast_frame
*f
;
4916 if (ast_strlen_zero(data
) || (sscanf(data
, "%d", &waittime
) != 1) || (waittime
< 0))
4918 if (waittime
> -1) {
4919 ast_safe_sleep(chan
, waittime
* 1000);
4921 res
= ast_waitfor(chan
, -1);
4931 * \ingroup applications
4933 static int pbx_builtin_progress(struct ast_channel
*chan
, void *data
)
4935 ast_indicate(chan
, AST_CONTROL_PROGRESS
);
4940 * \ingroup applications
4942 static int pbx_builtin_ringing(struct ast_channel
*chan
, void *data
)
4944 ast_indicate(chan
, AST_CONTROL_RINGING
);
4949 * \ingroup applications
4951 static int pbx_builtin_busy(struct ast_channel
*chan
, void *data
)
4953 ast_indicate(chan
, AST_CONTROL_BUSY
);
4954 /* Don't change state of an UP channel, just indicate
4956 if (chan
->_state
!= AST_STATE_UP
)
4957 ast_setstate(chan
, AST_STATE_BUSY
);
4958 wait_for_hangup(chan
, data
);
4963 * \ingroup applications
4965 static int pbx_builtin_congestion(struct ast_channel
*chan
, void *data
)
4967 ast_indicate(chan
, AST_CONTROL_CONGESTION
);
4968 /* Don't change state of an UP channel, just indicate
4969 congestion in audio */
4970 if (chan
->_state
!= AST_STATE_UP
)
4971 ast_setstate(chan
, AST_STATE_BUSY
);
4972 wait_for_hangup(chan
, data
);
4977 * \ingroup applications
4979 static int pbx_builtin_answer(struct ast_channel
*chan
, void *data
)
4984 if (chan
->_state
== AST_STATE_UP
)
4986 else if (!ast_strlen_zero(data
))
4989 res
= ast_answer(chan
);
4994 res
= ast_safe_sleep(chan
, delay
);
4999 AST_APP_OPTIONS(resetcdr_opts
, {
5000 AST_APP_OPTION('w', AST_CDR_FLAG_POSTED
),
5001 AST_APP_OPTION('a', AST_CDR_FLAG_LOCKED
),
5002 AST_APP_OPTION('v', AST_CDR_FLAG_KEEP_VARS
),
5006 * \ingroup applications
5008 static int pbx_builtin_resetcdr(struct ast_channel
*chan
, void *data
)
5011 struct ast_flags flags
= { 0 };
5013 if (!ast_strlen_zero(data
)) {
5014 args
= ast_strdupa(data
);
5015 ast_app_parse_options(resetcdr_opts
, &flags
, NULL
, args
);
5018 ast_cdr_reset(chan
->cdr
, &flags
);
5024 * \ingroup applications
5026 static int pbx_builtin_setamaflags(struct ast_channel
*chan
, void *data
)
5028 /* Copy the AMA Flags as specified */
5029 ast_cdr_setamaflags(chan
, data
? data
: "");
5034 * \ingroup applications
5036 static int pbx_builtin_hangup(struct ast_channel
*chan
, void *data
)
5038 if (!ast_strlen_zero(data
)) {
5042 if ((cause
= ast_str2cause(data
)) > -1) {
5043 chan
->hangupcause
= cause
;
5047 cause
= strtol((const char *) data
, &endptr
, 10);
5048 if (cause
!= 0 || (data
!= endptr
)) {
5049 chan
->hangupcause
= cause
;
5053 ast_log(LOG_NOTICE
, "Invalid cause given to Hangup(): \"%s\"\n", (char *) data
);
5056 if (!chan
->hangupcause
) {
5057 chan
->hangupcause
= AST_CAUSE_NORMAL_CLEARING
;
5064 * \ingroup applications
5066 static int pbx_builtin_gotoiftime(struct ast_channel
*chan
, void *data
)
5070 struct ast_timing timing
;
5072 if (ast_strlen_zero(data
)) {
5073 ast_log(LOG_WARNING
, "GotoIfTime requires an argument:\n <time range>|<days of week>|<days of month>|<months>?[[context|]extension|]priority\n");
5077 ts
= s
= ast_strdupa(data
);
5079 /* Separate the Goto path */
5082 /* struct ast_include include contained garbage here, fixed by zeroing it on get_timerange */
5083 if (ast_build_timing(&timing
, s
) && ast_check_timing(&timing
))
5084 res
= pbx_builtin_goto(chan
, ts
);
5090 * \ingroup applications
5092 static int pbx_builtin_execiftime(struct ast_channel
*chan
, void *data
)
5095 struct ast_timing timing
;
5096 struct ast_app
*app
;
5097 static const char *usage
= "ExecIfTime requires an argument:\n <time range>|<days of week>|<days of month>|<months>?<appname>[|<appargs>]";
5099 if (ast_strlen_zero(data
)) {
5100 ast_log(LOG_WARNING
, "%s\n", usage
);
5104 appname
= ast_strdupa(data
);
5106 s
= strsep(&appname
,"?"); /* Separate the timerange and application name/data */
5107 if (!appname
) { /* missing application */
5108 ast_log(LOG_WARNING
, "%s\n", usage
);
5112 if (!ast_build_timing(&timing
, s
)) {
5113 ast_log(LOG_WARNING
, "Invalid Time Spec: %s\nCorrect usage: %s\n", s
, usage
);
5117 if (!ast_check_timing(&timing
)) /* outside the valid time window, just return */
5120 /* now split appname|appargs */
5121 if ((s
= strchr(appname
, '|')))
5124 if ((app
= pbx_findapp(appname
))) {
5125 return pbx_exec(chan
, app
, S_OR(s
, ""));
5127 ast_log(LOG_WARNING
, "Cannot locate application %s\n", appname
);
5133 * \ingroup applications
5135 static int pbx_builtin_wait(struct ast_channel
*chan
, void *data
)
5139 /* Wait for "n" seconds */
5140 if (data
&& (ms
= atof(data
)) > 0) {
5142 return ast_safe_sleep(chan
, ms
);
5148 * \ingroup applications
5150 static int pbx_builtin_waitexten(struct ast_channel
*chan
, void *data
)
5153 struct ast_flags flags
= {0};
5154 char *opts
[1] = { NULL
};
5156 AST_DECLARE_APP_ARGS(args
,
5157 AST_APP_ARG(timeout
);
5158 AST_APP_ARG(options
);
5161 if (!ast_strlen_zero(data
)) {
5162 parse
= ast_strdupa(data
);
5163 AST_STANDARD_APP_ARGS(args
, parse
);
5165 memset(&args
, 0, sizeof(args
));
5168 ast_app_parse_options(waitexten_opts
, &flags
, opts
, args
.options
);
5170 if (ast_test_flag(&flags
, WAITEXTEN_MOH
))
5171 ast_indicate_data(chan
, AST_CONTROL_HOLD
, opts
[0], strlen(opts
[0]));
5173 /* Wait for "n" seconds */
5174 if (args
.timeout
&& (ms
= atof(args
.timeout
)) > 0)
5177 ms
= chan
->pbx
->rtimeout
* 1000;
5180 res
= ast_waitfordigit(chan
, ms
);
5182 if (ast_exists_extension(chan
, chan
->context
, chan
->exten
, chan
->priority
+ 1, chan
->cid
.cid_num
)) {
5183 if (option_verbose
> 2)
5184 ast_verbose(VERBOSE_PREFIX_3
"Timeout on %s, continuing...\n", chan
->name
);
5185 } else if (ast_exists_extension(chan
, chan
->context
, "t", 1, chan
->cid
.cid_num
)) {
5186 if (option_verbose
> 2)
5187 ast_verbose(VERBOSE_PREFIX_3
"Timeout on %s, going to 't'\n", chan
->name
);
5188 set_ext_pri(chan
, "t", 0); /* XXX is the 0 correct ? */
5190 ast_log(LOG_WARNING
, "Timeout but no rule 't' in context '%s'\n", chan
->context
);
5195 if (ast_test_flag(&flags
, WAITEXTEN_MOH
))
5196 ast_indicate(chan
, AST_CONTROL_UNHOLD
);
5202 * \ingroup applications
5204 static int pbx_builtin_background(struct ast_channel
*chan
, void *data
)
5207 struct ast_flags flags
= {0};
5209 AST_DECLARE_APP_ARGS(args
,
5210 AST_APP_ARG(filename
);
5211 AST_APP_ARG(options
);
5213 AST_APP_ARG(context
);
5216 if (ast_strlen_zero(data
))
5217 ast_log(LOG_WARNING
, "Background requires an argument (filename)\n");
5219 parse
= ast_strdupa(data
);
5221 AST_STANDARD_APP_ARGS(args
, parse
);
5224 args
.lang
= (char *)chan
->language
; /* XXX this is const */
5227 args
.context
= chan
->context
;
5230 if (!strcasecmp(args
.options
, "skip"))
5231 flags
.flags
= BACKGROUND_SKIP
;
5232 else if (!strcasecmp(args
.options
, "noanswer"))
5233 flags
.flags
= BACKGROUND_NOANSWER
;
5235 ast_app_parse_options(background_opts
, &flags
, NULL
, args
.options
);
5238 /* Answer if need be */
5239 if (chan
->_state
!= AST_STATE_UP
) {
5240 if (ast_test_flag(&flags
, BACKGROUND_SKIP
)) {
5242 } else if (!ast_test_flag(&flags
, BACKGROUND_NOANSWER
)) {
5243 res
= ast_answer(chan
);
5248 char *back
= args
.filename
;
5250 ast_stopstream(chan
); /* Stop anything playing */
5251 /* Stream the list of files */
5252 while (!res
&& (front
= strsep(&back
, "&")) ) {
5253 if ( (res
= ast_streamfile(chan
, front
, args
.lang
)) ) {
5254 ast_log(LOG_WARNING
, "ast_streamfile failed on %s for %s\n", chan
->name
, (char*)data
);
5258 if (ast_test_flag(&flags
, BACKGROUND_PLAYBACK
)) {
5259 res
= ast_waitstream(chan
, "");
5260 } else if (ast_test_flag(&flags
, BACKGROUND_MATCHEXTEN
)) {
5261 res
= ast_waitstream_exten(chan
, args
.context
);
5263 res
= ast_waitstream(chan
, AST_DIGIT_ANY
);
5265 ast_stopstream(chan
);
5268 if (args
.context
!= chan
->context
&& res
) {
5269 snprintf(chan
->exten
, sizeof(chan
->exten
), "%c", res
);
5270 ast_copy_string(chan
->context
, args
.context
, sizeof(chan
->context
));
5278 * \ingroup applications
5280 static int pbx_builtin_goto(struct ast_channel
*chan
, void *data
)
5282 int res
= ast_parseable_goto(chan
, data
);
5283 if (!res
&& (option_verbose
> 2))
5284 ast_verbose( VERBOSE_PREFIX_3
"Goto (%s,%s,%d)\n", chan
->context
,chan
->exten
, chan
->priority
+1);
5289 int pbx_builtin_serialize_variables(struct ast_channel
*chan
, char *buf
, size_t size
)
5291 struct ast_var_t
*variables
;
5292 const char *var
, *val
;
5298 memset(buf
, 0, size
);
5300 AST_LIST_TRAVERSE(&chan
->varshead
, variables
, entries
) {
5302 (var
=ast_var_name(variables
)) && (val
=ast_var_value(variables
)) &&
5303 !ast_strlen_zero(var
) && !ast_strlen_zero(val
)) {
5304 if (ast_build_string(&buf
, &size
, "%s=%s\n", var
, val
)) {
5305 ast_log(LOG_ERROR
, "Data Buffer Size Exceeded!\n");
5316 const char *pbx_builtin_getvar_helper(struct ast_channel
*chan
, const char *name
)
5318 struct ast_var_t
*variables
;
5319 const char *ret
= NULL
;
5321 struct varshead
*places
[2] = { NULL
, &globals
};
5326 places
[0] = &chan
->varshead
;
5328 for (i
= 0; i
< 2; i
++) {
5331 if (places
[i
] == &globals
)
5332 ast_mutex_lock(&globalslock
);
5333 AST_LIST_TRAVERSE(places
[i
], variables
, entries
) {
5334 if (!strcmp(name
, ast_var_name(variables
))) {
5335 ret
= ast_var_value(variables
);
5339 if (places
[i
] == &globals
)
5340 ast_mutex_unlock(&globalslock
);
5348 void pbx_builtin_pushvar_helper(struct ast_channel
*chan
, const char *name
, const char *value
)
5350 struct ast_var_t
*newvariable
;
5351 struct varshead
*headp
;
5353 if (name
[strlen(name
)-1] == ')') {
5354 char *function
= ast_strdupa(name
);
5356 ast_log(LOG_WARNING
, "Cannot push a value onto a function\n");
5357 ast_func_write(chan
, function
, value
);
5361 headp
= (chan
) ? &chan
->varshead
: &globals
;
5364 if ((option_verbose
> 1) && (headp
== &globals
))
5365 ast_verbose(VERBOSE_PREFIX_2
"Setting global variable '%s' to '%s'\n", name
, value
);
5366 newvariable
= ast_var_assign(name
, value
);
5367 if (headp
== &globals
)
5368 ast_mutex_lock(&globalslock
);
5369 AST_LIST_INSERT_HEAD(headp
, newvariable
, entries
);
5370 if (headp
== &globals
)
5371 ast_mutex_unlock(&globalslock
);
5375 void pbx_builtin_setvar_helper(struct ast_channel
*chan
, const char *name
, const char *value
)
5377 struct ast_var_t
*newvariable
;
5378 struct varshead
*headp
;
5379 const char *nametail
= name
;
5381 /* XXX may need locking on the channel ? */
5382 if (name
[strlen(name
)-1] == ')') {
5383 char *function
= ast_strdupa(name
);
5385 ast_func_write(chan
, function
, value
);
5389 headp
= (chan
) ? &chan
->varshead
: &globals
;
5391 /* For comparison purposes, we have to strip leading underscores */
5392 if (*nametail
== '_') {
5394 if (*nametail
== '_')
5398 if (headp
== &globals
)
5399 ast_mutex_lock(&globalslock
);
5400 AST_LIST_TRAVERSE (headp
, newvariable
, entries
) {
5401 if (strcasecmp(ast_var_name(newvariable
), nametail
) == 0) {
5402 /* there is already such a variable, delete it */
5403 AST_LIST_REMOVE(headp
, newvariable
, entries
);
5404 ast_var_delete(newvariable
);
5410 if ((option_verbose
> 1) && (headp
== &globals
))
5411 ast_verbose(VERBOSE_PREFIX_2
"Setting global variable '%s' to '%s'\n", name
, value
);
5412 newvariable
= ast_var_assign(name
, value
);
5413 AST_LIST_INSERT_HEAD(headp
, newvariable
, entries
);
5416 if (headp
== &globals
)
5417 ast_mutex_unlock(&globalslock
);
5420 int pbx_builtin_setvar(struct ast_channel
*chan
, void *data
)
5422 char *name
, *value
, *mydata
;
5424 char *argv
[24]; /* this will only support a maximum of 24 variables being set in a single operation */
5428 if (ast_strlen_zero(data
)) {
5429 ast_log(LOG_WARNING
, "Set requires at least one variable name/value pair.\n");
5433 mydata
= ast_strdupa(data
);
5434 argc
= ast_app_separate_args(mydata
, '|', argv
, sizeof(argv
) / sizeof(argv
[0]));
5436 /* check for a trailing flags argument */
5437 if ((argc
> 1) && !strchr(argv
[argc
-1], '=')) {
5439 if (strchr(argv
[argc
], 'g'))
5443 for (x
= 0; x
< argc
; x
++) {
5445 if ((value
= strchr(name
, '='))) {
5447 pbx_builtin_setvar_helper((global
) ? NULL
: chan
, name
, value
);
5449 ast_log(LOG_WARNING
, "Ignoring entry '%s' with no = (and not last 'options' entry)\n", name
);
5455 int pbx_builtin_importvar(struct ast_channel
*chan
, void *data
)
5460 char tmp
[VAR_BUF_SIZE
]="";
5462 if (ast_strlen_zero(data
)) {
5463 ast_log(LOG_WARNING
, "Ignoring, since there is no variable to set\n");
5467 value
= ast_strdupa(data
);
5468 name
= strsep(&value
,"=");
5469 channel
= strsep(&value
,"|");
5470 if (channel
&& value
&& name
) { /*! \todo XXX should do !ast_strlen_zero(..) of the args ? */
5471 struct ast_channel
*chan2
= ast_get_channel_by_name_locked(channel
);
5473 char *s
= alloca(strlen(value
) + 4);
5475 sprintf(s
, "${%s}", value
);
5476 pbx_substitute_variables_helper(chan2
, s
, tmp
, sizeof(tmp
) - 1);
5478 ast_channel_unlock(chan2
);
5480 pbx_builtin_setvar_helper(chan
, name
, tmp
);
5486 /*! \todo XXX overwrites data ? */
5487 static int pbx_builtin_setglobalvar(struct ast_channel
*chan
, void *data
)
5490 char *stringp
= data
;
5491 static int dep_warning
= 0;
5493 if (ast_strlen_zero(data
)) {
5494 ast_log(LOG_WARNING
, "Ignoring, since there is no variable to set\n");
5498 name
= strsep(&stringp
, "=");
5502 ast_log(LOG_WARNING
, "SetGlobalVar is deprecated. Please use Set(GLOBAL(%s)=%s) instead.\n", name
, stringp
);
5505 /*! \todo XXX watch out, leading whitespace ? */
5506 pbx_builtin_setvar_helper(NULL
, name
, stringp
);
5511 static int pbx_builtin_noop(struct ast_channel
*chan
, void *data
)
5516 void pbx_builtin_clear_globals(void)
5518 struct ast_var_t
*vardata
;
5520 ast_mutex_lock(&globalslock
);
5521 while ((vardata
= AST_LIST_REMOVE_HEAD(&globals
, entries
)))
5522 ast_var_delete(vardata
);
5523 ast_mutex_unlock(&globalslock
);
5526 int pbx_checkcondition(const char *condition
)
5528 if (ast_strlen_zero(condition
)) /* NULL or empty strings are false */
5530 else if (*condition
>= '0' && *condition
<= '9') /* Numbers are evaluated for truth */
5531 return atoi(condition
);
5532 else /* Strings are true */
5536 static int pbx_builtin_gotoif(struct ast_channel
*chan
, void *data
)
5538 char *condition
, *branch1
, *branch2
, *branch
;
5542 if (ast_strlen_zero(data
)) {
5543 ast_log(LOG_WARNING
, "Ignoring, since there is no variable to check\n");
5547 stringp
= ast_strdupa(data
);
5548 condition
= strsep(&stringp
,"?");
5549 branch1
= strsep(&stringp
,":");
5550 branch2
= strsep(&stringp
,"");
5551 branch
= pbx_checkcondition(condition
) ? branch1
: branch2
;
5553 if (ast_strlen_zero(branch
)) {
5554 ast_log(LOG_DEBUG
, "Not taking any branch\n");
5558 rc
= pbx_builtin_goto(chan
, branch
);
5563 static int pbx_builtin_saynumber(struct ast_channel
*chan
, void *data
)
5569 if (ast_strlen_zero(data
)) {
5570 ast_log(LOG_WARNING
, "SayNumber requires an argument (number)\n");
5573 ast_copy_string(tmp
, data
, sizeof(tmp
));
5574 strsep(&number
, "|");
5575 options
= strsep(&number
, "|");
5577 if ( strcasecmp(options
, "f") && strcasecmp(options
,"m") &&
5578 strcasecmp(options
, "c") && strcasecmp(options
, "n") ) {
5579 ast_log(LOG_WARNING
, "SayNumber gender option is either 'f', 'm', 'c' or 'n'\n");
5583 return ast_say_number(chan
, atoi(tmp
), "", chan
->language
, options
);
5586 static int pbx_builtin_saydigits(struct ast_channel
*chan
, void *data
)
5591 res
= ast_say_digit_str(chan
, data
, "", chan
->language
);
5595 static int pbx_builtin_saycharacters(struct ast_channel
*chan
, void *data
)
5600 res
= ast_say_character_str(chan
, data
, "", chan
->language
);
5604 static int pbx_builtin_sayphonetic(struct ast_channel
*chan
, void *data
)
5609 res
= ast_say_phonetic_str(chan
, data
, "", chan
->language
);
5617 /* Initialize the PBX */
5618 if (option_verbose
) {
5619 ast_verbose( "Asterisk PBX Core Initializing\n");
5620 ast_verbose( "Registering builtin applications:\n");
5622 AST_LIST_HEAD_INIT_NOLOCK(&globals
);
5623 ast_cli_register_multiple(pbx_cli
, sizeof(pbx_cli
) / sizeof(pbx_cli
[0]));
5625 /* Register builtin applications */
5626 for (x
=0; x
<sizeof(builtins
) / sizeof(struct pbx_builtin
); x
++) {
5628 ast_verbose( VERBOSE_PREFIX_1
"[%s]\n", builtins
[x
].name
);
5629 if (ast_register_application(builtins
[x
].name
, builtins
[x
].execute
, builtins
[x
].synopsis
, builtins
[x
].description
)) {
5630 ast_log(LOG_ERROR
, "Unable to register builtin application '%s'\n", builtins
[x
].name
);
5638 * Lock context list functions ...
5640 int ast_lock_contexts()
5642 return ast_mutex_lock(&conlock
);
5645 int ast_unlock_contexts()
5647 return ast_mutex_unlock(&conlock
);
5653 int ast_lock_context(struct ast_context
*con
)
5655 return ast_mutex_lock(&con
->lock
);
5658 int ast_unlock_context(struct ast_context
*con
)
5660 return ast_mutex_unlock(&con
->lock
);
5664 * Name functions ...
5666 const char *ast_get_context_name(struct ast_context
*con
)
5668 return con
? con
->name
: NULL
;
5671 struct ast_context
*ast_get_extension_context(struct ast_exten
*exten
)
5673 return exten
? exten
->parent
: NULL
;
5676 const char *ast_get_extension_name(struct ast_exten
*exten
)
5678 return exten
? exten
->exten
: NULL
;
5681 const char *ast_get_extension_label(struct ast_exten
*exten
)
5683 return exten
? exten
->label
: NULL
;
5686 const char *ast_get_include_name(struct ast_include
*inc
)
5688 return inc
? inc
->name
: NULL
;
5691 const char *ast_get_ignorepat_name(struct ast_ignorepat
*ip
)
5693 return ip
? ip
->pattern
: NULL
;
5696 int ast_get_extension_priority(struct ast_exten
*exten
)
5698 return exten
? exten
->priority
: -1;
5702 * Registrar info functions ...
5704 const char *ast_get_context_registrar(struct ast_context
*c
)
5706 return c
? c
->registrar
: NULL
;
5709 const char *ast_get_extension_registrar(struct ast_exten
*e
)
5711 return e
? e
->registrar
: NULL
;
5714 const char *ast_get_include_registrar(struct ast_include
*i
)
5716 return i
? i
->registrar
: NULL
;
5719 const char *ast_get_ignorepat_registrar(struct ast_ignorepat
*ip
)
5721 return ip
? ip
->registrar
: NULL
;
5724 int ast_get_extension_matchcid(struct ast_exten
*e
)
5726 return e
? e
->matchcid
: 0;
5729 const char *ast_get_extension_cidmatch(struct ast_exten
*e
)
5731 return e
? e
->cidmatch
: NULL
;
5734 const char *ast_get_extension_app(struct ast_exten
*e
)
5736 return e
? e
->app
: NULL
;
5739 void *ast_get_extension_app_data(struct ast_exten
*e
)
5741 return e
? e
->data
: NULL
;
5744 const char *ast_get_switch_name(struct ast_sw
*sw
)
5746 return sw
? sw
->name
: NULL
;
5749 const char *ast_get_switch_data(struct ast_sw
*sw
)
5751 return sw
? sw
->data
: NULL
;
5754 const char *ast_get_switch_registrar(struct ast_sw
*sw
)
5756 return sw
? sw
->registrar
: NULL
;
5760 * Walking functions ...
5762 struct ast_context
*ast_walk_contexts(struct ast_context
*con
)
5764 return con
? con
->next
: contexts
;
5767 struct ast_exten
*ast_walk_context_extensions(struct ast_context
*con
,
5768 struct ast_exten
*exten
)
5771 return con
? con
->root
: NULL
;
5776 struct ast_sw
*ast_walk_context_switches(struct ast_context
*con
,
5780 return con
? AST_LIST_FIRST(&con
->alts
) : NULL
;
5782 return AST_LIST_NEXT(sw
, list
);
5785 struct ast_exten
*ast_walk_extension_priorities(struct ast_exten
*exten
,
5786 struct ast_exten
*priority
)
5788 return priority
? priority
->peer
: exten
;
5791 struct ast_include
*ast_walk_context_includes(struct ast_context
*con
,
5792 struct ast_include
*inc
)
5795 return con
? con
->includes
: NULL
;
5800 struct ast_ignorepat
*ast_walk_context_ignorepats(struct ast_context
*con
,
5801 struct ast_ignorepat
*ip
)
5804 return con
? con
->ignorepats
: NULL
;
5809 int ast_context_verify_includes(struct ast_context
*con
)
5811 struct ast_include
*inc
= NULL
;
5814 while ( (inc
= ast_walk_context_includes(con
, inc
)) )
5815 if (!ast_context_find(inc
->rname
)) {
5817 ast_log(LOG_WARNING
, "Context '%s' tries includes nonexistent context '%s'\n",
5818 ast_get_context_name(con
), inc
->rname
);
5824 static int __ast_goto_if_exists(struct ast_channel
*chan
, const char *context
, const char *exten
, int priority
, int async
)
5826 int (*goto_func
)(struct ast_channel
*chan
, const char *context
, const char *exten
, int priority
);
5831 if (context
== NULL
)
5832 context
= chan
->context
;
5834 exten
= chan
->exten
;
5836 goto_func
= (async
) ? ast_async_goto
: ast_explicit_goto
;
5837 if (ast_exists_extension(chan
, context
, exten
, priority
, chan
->cid
.cid_num
))
5838 return goto_func(chan
, context
, exten
, priority
);
5843 int ast_goto_if_exists(struct ast_channel
*chan
, const char* context
, const char *exten
, int priority
)
5845 return __ast_goto_if_exists(chan
, context
, exten
, priority
, 0);
5848 int ast_async_goto_if_exists(struct ast_channel
*chan
, const char * context
, const char *exten
, int priority
)
5850 return __ast_goto_if_exists(chan
, context
, exten
, priority
, 1);
5853 int ast_parseable_goto(struct ast_channel
*chan
, const char *goto_string
)
5855 char *exten
, *pri
, *context
;
5860 if (ast_strlen_zero(goto_string
)) {
5861 ast_log(LOG_WARNING
, "Goto requires an argument (optional context|optional extension|priority)\n");
5864 stringp
= ast_strdupa(goto_string
);
5865 context
= strsep(&stringp
, "|"); /* guaranteed non-null */
5866 exten
= strsep(&stringp
, "|");
5867 pri
= strsep(&stringp
, "|");
5868 if (!exten
) { /* Only a priority in this one */
5872 } else if (!pri
) { /* Only an extension and priority in this one */
5880 } else if (*pri
== '-') {
5884 if (sscanf(pri
, "%d", &ipri
) != 1) {
5885 if ((ipri
= ast_findlabel_extension(chan
, context
? context
: chan
->context
, exten
? exten
: chan
->exten
,
5886 pri
, chan
->cid
.cid_num
)) < 1) {
5887 ast_log(LOG_WARNING
, "Priority '%s' must be a number > 0, or valid label\n", pri
);
5892 /* At this point we have a priority and maybe an extension and a context */
5895 ipri
= chan
->priority
+ (ipri
* mode
);
5897 ast_explicit_goto(chan
, context
, exten
, ipri
);
5898 ast_cdr_update(chan
);