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>
41 #include "asterisk/lock.h"
42 #include "asterisk/cli.h"
43 #include "asterisk/pbx.h"
44 #include "asterisk/channel.h"
45 #include "asterisk/options.h"
46 #include "asterisk/logger.h"
47 #include "asterisk/file.h"
48 #include "asterisk/callerid.h"
49 #include "asterisk/cdr.h"
50 #include "asterisk/config.h"
51 #include "asterisk/term.h"
52 #include "asterisk/manager.h"
53 #include "asterisk/ast_expr.h"
54 #include "asterisk/linkedlists.h"
55 #define SAY_STUBS /* generate declarations and stubs for say methods */
56 #include "asterisk/say.h"
57 #include "asterisk/utils.h"
58 #include "asterisk/causes.h"
59 #include "asterisk/musiconhold.h"
60 #include "asterisk/app.h"
61 #include "asterisk/devicestate.h"
62 #include "asterisk/stringfields.h"
63 #include "asterisk/threadstorage.h"
66 * \note I M P O R T A N T :
68 * The speed of extension handling will likely be among the most important
69 * aspects of this PBX. The switching scheme as it exists right now isn't
70 * terribly bad (it's O(N+M), where N is the # of extensions and M is the avg #
71 * of priorities, but a constant search time here would be great ;-)
76 #define EXT_DATA_SIZE 256
78 #define EXT_DATA_SIZE 8192
81 #define SWITCH_DATA_LENGTH 256
83 #define VAR_BUF_SIZE 4096
86 #define VAR_SOFTTRAN 2
87 #define VAR_HARDTRAN 3
89 #define BACKGROUND_SKIP (1 << 0)
90 #define BACKGROUND_NOANSWER (1 << 1)
91 #define BACKGROUND_MATCHEXTEN (1 << 2)
92 #define BACKGROUND_PLAYBACK (1 << 3)
94 AST_APP_OPTIONS(background_opts
, {
95 AST_APP_OPTION('s', BACKGROUND_SKIP
),
96 AST_APP_OPTION('n', BACKGROUND_NOANSWER
),
97 AST_APP_OPTION('m', BACKGROUND_MATCHEXTEN
),
98 AST_APP_OPTION('p', BACKGROUND_PLAYBACK
),
101 #define WAITEXTEN_MOH (1 << 0)
103 AST_APP_OPTIONS(waitexten_opts
, {
104 AST_APP_OPTION_ARG('m', WAITEXTEN_MOH
, 0),
109 AST_THREADSTORAGE(switch_data
, switch_data_init
);
112 \brief ast_exten: An extension
113 The dialplan is saved as a linked list with each context
114 having it's own linked list of extensions - one item per
118 char *exten
; /*!< Extension name */
119 int matchcid
; /*!< Match caller id ? */
120 const char *cidmatch
; /*!< Caller id to match for this extension */
121 int priority
; /*!< Priority */
122 const char *label
; /*!< Label */
123 struct ast_context
*parent
; /*!< The context this extension belongs to */
124 const char *app
; /*!< Application to execute */
125 void *data
; /*!< Data to use (arguments) */
126 void (*datad
)(void *); /*!< Data destructor */
127 struct ast_exten
*peer
; /*!< Next higher priority with our extension */
128 const char *registrar
; /*!< Registrar */
129 struct ast_exten
*next
; /*!< Extension with a greater ID */
133 /*! \brief ast_include: include= support in extensions.conf */
136 const char *rname
; /*!< Context to include */
137 const char *registrar
; /*!< Registrar */
138 int hastime
; /*!< If time construct exists */
139 struct ast_timing timing
; /*!< time construct */
140 struct ast_include
*next
; /*!< Link them together */
144 /*! \brief ast_sw: Switch statement in extensions.conf */
147 const char *registrar
; /*!< Registrar */
148 char *data
; /*!< Data load */
150 AST_LIST_ENTRY(ast_sw
) list
;
154 /*! \brief ast_ignorepat: Ignore patterns in dial plan */
155 struct ast_ignorepat
{
156 const char *registrar
;
157 struct ast_ignorepat
*next
;
158 const char pattern
[0];
161 /*! \brief ast_context: An extension context */
163 ast_mutex_t lock
; /*!< A lock to prevent multiple threads from clobbering the context */
164 struct ast_exten
*root
; /*!< The root of the list of extensions */
165 struct ast_context
*next
; /*!< Link them together */
166 struct ast_include
*includes
; /*!< Include other contexts */
167 struct ast_ignorepat
*ignorepats
; /*!< Patterns for which to continue playing dialtone */
168 const char *registrar
; /*!< Registrar */
169 AST_LIST_HEAD_NOLOCK(, ast_sw
) alts
; /*!< Alternative switches */
170 ast_mutex_t macrolock
; /*!< A lock to implement "exclusive" macros - held whilst a call is executing in the macro */
171 char name
[0]; /*!< Name of the context */
175 /*! \brief ast_app: A registered application */
177 int (*execute
)(struct ast_channel
*chan
, void *data
);
178 const char *synopsis
; /*!< Synopsis text for 'show applications' */
179 const char *description
; /*!< Description (help text) for 'show application <name>' */
180 AST_LIST_ENTRY(ast_app
) list
; /*!< Next app in list */
181 struct module
*module
; /*!< Module this app belongs to */
182 char name
[0]; /*!< Name of the application */
185 /*! \brief ast_state_cb: An extension state notify register item */
186 struct ast_state_cb
{
189 ast_state_cb_type callback
;
190 struct ast_state_cb
*next
;
193 /*! \brief Structure for dial plan hints
195 \note Hints are pointers from an extension in the dialplan to one or
196 more devices (tech/name) */
198 struct ast_exten
*exten
; /*!< Extension */
199 int laststate
; /*!< Last known state */
200 struct ast_state_cb
*callbacks
; /*!< Callback list for this extension */
201 AST_LIST_ENTRY(ast_hint
) list
; /*!< Pointer to next hint in list */
204 static const struct cfextension_states
{
206 const char * const text
;
207 } extension_states
[] = {
208 { AST_EXTENSION_NOT_INUSE
, "Idle" },
209 { AST_EXTENSION_INUSE
, "InUse" },
210 { AST_EXTENSION_BUSY
, "Busy" },
211 { AST_EXTENSION_UNAVAILABLE
, "Unavailable" },
212 { AST_EXTENSION_RINGING
, "Ringing" },
213 { AST_EXTENSION_INUSE
| AST_EXTENSION_RINGING
, "InUse&Ringing" },
214 { AST_EXTENSION_ONHOLD
, "Hold" },
215 { AST_EXTENSION_INUSE
| AST_EXTENSION_ONHOLD
, "InUse&Hold" }
218 static int pbx_builtin_answer(struct ast_channel
*, void *);
219 static int pbx_builtin_goto(struct ast_channel
*, void *);
220 static int pbx_builtin_hangup(struct ast_channel
*, void *);
221 static int pbx_builtin_background(struct ast_channel
*, void *);
222 static int pbx_builtin_wait(struct ast_channel
*, void *);
223 static int pbx_builtin_waitexten(struct ast_channel
*, void *);
224 static int pbx_builtin_resetcdr(struct ast_channel
*, void *);
225 static int pbx_builtin_setamaflags(struct ast_channel
*, void *);
226 static int pbx_builtin_ringing(struct ast_channel
*, void *);
227 static int pbx_builtin_progress(struct ast_channel
*, void *);
228 static int pbx_builtin_congestion(struct ast_channel
*, void *);
229 static int pbx_builtin_busy(struct ast_channel
*, void *);
230 static int pbx_builtin_setglobalvar(struct ast_channel
*, void *);
231 static int pbx_builtin_noop(struct ast_channel
*, void *);
232 static int pbx_builtin_gotoif(struct ast_channel
*, void *);
233 static int pbx_builtin_gotoiftime(struct ast_channel
*, void *);
234 static int pbx_builtin_execiftime(struct ast_channel
*, void *);
235 static int pbx_builtin_saynumber(struct ast_channel
*, void *);
236 static int pbx_builtin_saydigits(struct ast_channel
*, void *);
237 static int pbx_builtin_saycharacters(struct ast_channel
*, void *);
238 static int pbx_builtin_sayphonetic(struct ast_channel
*, void *);
239 int pbx_builtin_setvar(struct ast_channel
*, void *);
240 static int pbx_builtin_importvar(struct ast_channel
*, void *);
242 AST_MUTEX_DEFINE_STATIC(globalslock
);
243 static struct varshead globals
= AST_LIST_HEAD_NOLOCK_INIT_VALUE
;
245 static int autofallthrough
= 1;
247 AST_MUTEX_DEFINE_STATIC(maxcalllock
);
248 static int countcalls
;
250 static AST_LIST_HEAD_STATIC(acf_root
, ast_custom_function
);
252 /*! \brief Declaration of builtin applications */
253 static struct pbx_builtin
{
254 char name
[AST_MAX_APP
];
255 int (*execute
)(struct ast_channel
*chan
, void *data
);
260 /* These applications are built into the PBX core and do not
261 need separate modules */
263 { "Answer", pbx_builtin_answer
,
264 "Answer a channel if ringing",
265 " Answer([delay]): If the call has not been answered, this application will\n"
266 "answer it. Otherwise, it has no effect on the call. If a delay is specified,\n"
267 "Asterisk will wait this number of milliseconds before returning to\n"
268 "the dialplan after answering the call.\n"
271 { "BackGround", pbx_builtin_background
,
272 "Play an audio file while waiting for digits of an extension to go to.",
273 " Background(filename1[&filename2...][|options[|langoverride][|context]]):\n"
274 "This application will play the given list of files (do not put extension)\n"
275 "while waiting for an extension to be dialed by the calling channel. To\n"
276 "continue waiting for digits after this application has finished playing\n"
277 "files, the WaitExten application should be used. The 'langoverride' option\n"
278 "explicitly specifies which language to attempt to use for the requested sound\n"
279 "files. If a 'context' is specified, this is the dialplan context that this\n"
280 "application will use when exiting to a dialed extension."
281 " If one of the requested sound files does not exist, call processing will be\n"
284 " s - Causes the playback of the message to be skipped\n"
285 " if the channel is not in the 'up' state (i.e. it\n"
286 " hasn't been answered yet). If this happens, the\n"
287 " application will return immediately.\n"
288 " n - Don't answer the channel before playing the files.\n"
289 " m - Only break if a digit hit matches a one digit\n"
290 " extension in the destination context.\n"
291 "See Also: Playback (application) -- Play sound file(s) to the channel,\n"
292 " that cannot be interrupted\n"
295 { "Busy", pbx_builtin_busy
,
296 "Indicate the Busy condition",
297 " Busy([timeout]): This application will indicate the busy condition to\n"
298 "the calling channel. If the optional timeout is specified, the calling channel\n"
299 "will be hung up after the specified number of seconds. Otherwise, this\n"
300 "application will wait until the calling channel hangs up.\n"
303 { "Congestion", pbx_builtin_congestion
,
304 "Indicate the Congestion condition",
305 " Congestion([timeout]): This application will indicate the congestion\n"
306 "condition to the calling channel. If the optional timeout is specified, the\n"
307 "calling channel will be hung up after the specified number of seconds.\n"
308 "Otherwise, this application will wait until the calling channel hangs up.\n"
311 { "Goto", pbx_builtin_goto
,
312 "Jump to a particular priority, extension, or context",
313 " Goto([[context|]extension|]priority): This application will set the current\n"
314 "context, extension, and priority in the channel structure. After it completes, the\n"
315 "pbx engine will continue dialplan execution at the specified location.\n"
316 "If no specific extension, or extension and context, are specified, then this\n"
317 "application will just set the specified priority of the current extension.\n"
318 " At least a priority is required as an argument, or the goto will return a -1,\n"
319 "and the channel and call will be terminated.\n"
320 " If the location that is put into the channel information is bogus, and asterisk cannot\n"
321 "find that location in the dialplan,\n"
322 "then the execution engine will try to find and execute the code in the 'i' (invalid)\n"
323 "extension in the current context. If that does not exist, it will try to execute the\n"
324 "'h' extension. If either or neither the 'h' or 'i' extensions have been defined, the\n"
325 "channel is hung up, and the execution of instructions on the channel is terminated.\n"
326 "What this means is that, for example, you specify a context that does not exist, then\n"
327 "it will not be possible to find the 'h' or 'i' extensions, and the call will terminate!\n"
330 { "GotoIf", pbx_builtin_gotoif
,
332 " GotoIf(condition?[labeliftrue]:[labeliffalse]): This application will set the current\n"
333 "context, extension, and priority in the channel structure based on the evaluation of\n"
334 "the given condition. After this application completes, the\n"
335 "pbx engine will continue dialplan execution at the specified location in the dialplan.\n"
336 "The channel will continue at\n"
337 "'labeliftrue' if the condition is true, or 'labeliffalse' if the condition is\n"
338 "false. The labels are specified with the same syntax as used within the Goto\n"
339 "application. If the label chosen by the condition is omitted, no jump is\n"
340 "performed, and the execution passes to the next instruction.\n"
341 "If the target location is bogus, and does not exist, the execution engine will try \n"
342 "to find and execute the code in the 'i' (invalid)\n"
343 "extension in the current context. If that does not exist, it will try to execute the\n"
344 "'h' extension. If either or neither the 'h' or 'i' extensions have been defined, the\n"
345 "channel is hung up, and the execution of instructions on the channel is terminated.\n"
346 "Remember that this command can set the current context, and if the context specified\n"
347 "does not exist, then it will not be able to find any 'h' or 'i' extensions there, and\n"
348 "the channel and call will both be terminated!\n"
351 { "GotoIfTime", pbx_builtin_gotoiftime
,
352 "Conditional Goto based on the current time",
353 " GotoIfTime(<times>|<weekdays>|<mdays>|<months>?[[context|]exten|]priority):\n"
354 "This application will set the context, extension, and priority in the channel structure\n"
355 "if the current time matches the given time specification. Otherwise, nothing is done.\n"
356 "Further information on the time specification can be found in examples\n"
357 "illustrating how to do time-based context includes in the dialplan.\n"
358 "If the target jump location is bogus, the same actions would be taken as for Goto.\n"
361 { "ExecIfTime", pbx_builtin_execiftime
,
362 "Conditional application execution based on the current time",
363 " ExecIfTime(<times>|<weekdays>|<mdays>|<months>?appname[|appargs]):\n"
364 "This application will execute the specified dialplan application, with optional\n"
365 "arguments, if the current time matches the given time specification.\n"
368 { "Hangup", pbx_builtin_hangup
,
369 "Hang up the calling channel",
370 " Hangup([causecode]): This application will hang up the calling channel.\n"
371 "If a causecode is given the channel's hangup cause will be set to the given\n"
375 { "NoOp", pbx_builtin_noop
,
377 " NoOp(): This applicatiion does nothing. However, it is useful for debugging\n"
378 "purposes. Any text that is provided as arguments to this application can be\n"
379 "viewed at the Asterisk CLI. This method can be used to see the evaluations of\n"
380 "variables or functions without having any effect."
383 { "Progress", pbx_builtin_progress
,
385 " Progress(): This application will request that in-band progress information\n"
386 "be provided to the calling channel.\n"
389 { "ResetCDR", pbx_builtin_resetcdr
,
390 "Resets the Call Data Record",
391 " ResetCDR([options]): This application causes the Call Data Record to be\n"
394 " w -- Store the current CDR record before resetting it.\n"
395 " a -- Store any stacked records.\n"
396 " v -- Save CDR variables.\n"
399 { "Ringing", pbx_builtin_ringing
,
400 "Indicate ringing tone",
401 " Ringing(): This application will request that the channel indicate a ringing\n"
402 "tone to the user.\n"
405 { "SayNumber", pbx_builtin_saynumber
,
407 " SayNumber(digits[,gender]): This application will play the sounds that\n"
408 "correspond to the given number. Optionally, a gender may be specified.\n"
409 "This will use the language that is currently set for the channel. See the\n"
410 "LANGUAGE function for more information on setting the language for the channel.\n"
413 { "SayDigits", pbx_builtin_saydigits
,
415 " SayDigits(digits): This application will play the sounds that correspond\n"
416 "to the digits of the given number. This will use the language that is currently\n"
417 "set for the channel. See the LANGUAGE function for more information on setting\n"
418 "the language for the channel.\n"
421 { "SayAlpha", pbx_builtin_saycharacters
,
423 " SayAlpha(string): This application will play the sounds that correspond to\n"
424 "the letters of the given string.\n"
427 { "SayPhonetic", pbx_builtin_sayphonetic
,
429 " SayPhonetic(string): This application will play the sounds from the phonetic\n"
430 "alphabet that correspond to the letters in the given string.\n"
433 { "SetAMAFlags", pbx_builtin_setamaflags
,
435 " SetAMAFlags([flag]): This application will set the channel's AMA Flags for\n"
436 " billing purposes.\n"
439 { "SetGlobalVar", pbx_builtin_setglobalvar
,
440 "Set a global variable to a given value",
441 " SetGlobalVar(variable=value): This application sets a given global variable to\n"
442 "the specified value.\n"
443 "\n\nThis application is deprecated in favor of Set(GLOBAL(var)=value)\n"
446 { "Set", pbx_builtin_setvar
,
447 "Set channel variable(s) or function value(s)",
448 " Set(name1=value1|name2=value2|..[|options])\n"
449 "This function can be used to set the value of channel variables or dialplan\n"
450 "functions. It will accept up to 24 name/value pairs. When setting variables,\n"
451 "if the variable name is prefixed with _, the variable will be inherited into\n"
452 "channels created from the current channel. If the variable name is prefixed\n"
453 "with __, the variable will be inherited into channels created from the current\n"
454 "channel and all children channels.\n"
456 " g - Set variable globally instead of on the channel\n"
457 " (applies only to variables, not functions)\n"
458 "\n\nThe use of Set to set multiple variables at once and the g flag have both\n"
459 "been deprecated. Please use multiple Set calls and the GLOBAL() dialplan\n"
460 "function instead.\n"
463 { "ImportVar", pbx_builtin_importvar
,
464 "Import a variable from a channel into a new variable",
465 " ImportVar(newvar=channelname|variable): This application imports a variable\n"
466 "from the specified channel (as opposed to the current one) and stores it as\n"
467 "a variable in the current channel (the channel that is calling this\n"
468 "application). Variables created by this application have the same inheritance\n"
469 "properties as those created with the Set application. See the documentation for\n"
470 "Set for more information.\n"
473 { "Wait", pbx_builtin_wait
,
474 "Waits for some time",
475 " Wait(seconds): This application waits for a specified number of seconds.\n"
476 "Then, dialplan execution will continue at the next priority.\n"
477 " Note that the seconds can be passed with fractions of a second. For example,\n"
478 "'1.5' will ask the application to wait for 1.5 seconds.\n"
481 { "WaitExten", pbx_builtin_waitexten
,
482 "Waits for an extension to be entered",
483 " WaitExten([seconds][|options]): This application waits for the user to enter\n"
484 "a new extension for a specified number of seconds.\n"
485 " Note that the seconds can be passed with fractions of a second. For example,\n"
486 "'1.5' will ask the application to wait for 1.5 seconds.\n"
488 " m[(x)] - Provide music on hold to the caller while waiting for an extension.\n"
489 " Optionally, specify the class for music on hold within parenthesis.\n"
490 "See Also: Playback(application), Background(application).\n"
495 static struct ast_context
*contexts
;
496 AST_RWLOCK_DEFINE_STATIC(conlock
); /*!< Lock for the ast_context list */
498 static AST_LIST_HEAD_STATIC(apps
, ast_app
);
500 static AST_LIST_HEAD_STATIC(switches
, ast_switch
);
502 static int stateid
= 1;
504 When holding this list's lock, do _not_ do anything that will cause conlock
505 to be taken, unless you _already_ hold it. The ast_merge_contexts_and_delete
506 function will take the locks in conlock/hints order, so any other
507 paths that require both locks must also take them in that order.
509 static AST_LIST_HEAD_STATIC(hints
, ast_hint
);
510 struct ast_state_cb
*statecbs
;
513 \note This function is special. It saves the stack so that no matter
514 how many times it is called, it returns to the same place */
515 int pbx_exec(struct ast_channel
*c
, /*!< Channel */
516 struct ast_app
*app
, /*!< Application */
517 void *data
) /*!< Data for execution */
521 const char *saved_c_appl
;
522 const char *saved_c_data
;
524 if (c
->cdr
&& !ast_check_hangup(c
))
525 ast_cdr_setapp(c
->cdr
, app
->name
, data
);
527 /* save channel values */
528 saved_c_appl
= c
->appl
;
529 saved_c_data
= c
->data
;
533 /* XXX remember what to to when we have linked apps to modules */
535 /* XXX LOCAL_USER_ADD(app->module) */
537 res
= app
->execute(c
, S_OR(data
, ""));
539 /* XXX LOCAL_USER_REMOVE(app->module) */
541 /* restore channel values */
542 c
->appl
= saved_c_appl
;
543 c
->data
= saved_c_data
;
548 /*! Go no deeper than this through includes (not counting loops) */
549 #define AST_PBX_MAX_STACK 128
551 /*! \brief Find application handle in linked list
553 struct ast_app
*pbx_findapp(const char *app
)
557 AST_LIST_LOCK(&apps
);
558 AST_LIST_TRAVERSE(&apps
, tmp
, list
) {
559 if (!strcasecmp(tmp
->name
, app
))
562 AST_LIST_UNLOCK(&apps
);
567 static struct ast_switch
*pbx_findswitch(const char *sw
)
569 struct ast_switch
*asw
;
571 AST_LIST_LOCK(&switches
);
572 AST_LIST_TRAVERSE(&switches
, asw
, list
) {
573 if (!strcasecmp(asw
->name
, sw
))
576 AST_LIST_UNLOCK(&switches
);
581 static inline int include_valid(struct ast_include
*i
)
586 return ast_check_timing(&(i
->timing
));
589 static void pbx_destroy(struct ast_pbx
*p
)
595 * Special characters used in patterns:
596 * '_' underscore is the leading character of a pattern.
597 * In other position it is treated as a regular char.
598 * ' ' '-' space and '-' are separator and ignored.
599 * . one or more of any character. Only allowed at the end of
601 * ! zero or more of anything. Also impacts the result of CANMATCH
602 * and MATCHMORE. Only allowed at the end of a pattern.
603 * In the core routine, ! causes a match with a return code of 2.
604 * In turn, depending on the search mode: (XXX check if it is implemented)
605 * - E_MATCH retuns 1 (does match)
606 * - E_MATCHMORE returns 0 (no match)
607 * - E_CANMATCH returns 1 (does match)
609 * / should not appear as it is considered the separator of the CID info.
610 * XXX at the moment we may stop on this char.
612 * X Z N match ranges 0-9, 1-9, 2-9 respectively.
613 * [ denotes the start of a set of character. Everything inside
614 * is considered literally. We can have ranges a-d and individual
615 * characters. A '[' and '-' can be considered literally if they
616 * are just before ']'.
617 * XXX currently there is no way to specify ']' in a range, nor \ is
618 * considered specially.
620 * When we compare a pattern with a specific extension, all characters in the extension
621 * itself are considered literally with the only exception of '-' which is considered
622 * as a separator and thus ignored.
623 * XXX do we want to consider space as a separator as well ?
624 * XXX do we want to consider the separators in non-patterns as well ?
628 * \brief helper functions to sort extensions and patterns in the desired way,
629 * so that more specific patterns appear first.
631 * ext_cmp1 compares individual characters (or sets of), returning
632 * an int where bits 0-7 are the ASCII code of the first char in the set,
633 * while bit 8-15 are the cardinality of the set minus 1.
634 * This way more specific patterns (smaller cardinality) appear first.
635 * Wildcards have a special value, so that we can directly compare them to
636 * sets by subtracting the two values. In particular:
637 * 0x000xx one character, xx
638 * 0x0yyxx yy character set starting with xx
639 * 0x10000 '.' (one or more of anything)
640 * 0x20000 '!' (zero or more of anything)
641 * 0x30000 NUL (end of string)
642 * 0x40000 error in set.
643 * The pointer to the string is advanced according to needs.
645 * 1. the empty set is equivalent to NUL.
646 * 2. given that a full set has always 0 as the first element,
647 * we could encode the special cases as 0xffXX where XX
648 * is 1, 2, 3, 4 as used above.
650 static int ext_cmp1(const char **p
)
653 int c
, cmin
= 0xff, count
= 0;
656 /* load, sign extend and advance pointer until we find
659 while ( (c
= *(*p
)++) && (c
== ' ' || c
== '-') )
660 ; /* ignore some characters */
662 /* always return unless we have a set of chars */
664 default: /* ordinary character */
665 return 0x0000 | (c
& 0xff);
668 return 0x0700 | '2' ;
676 case '.': /* wildcard */
679 case '!': /* earlymatch */
680 return 0x20000; /* less specific than NULL */
682 case '\0': /* empty string */
686 case '[': /* pattern */
689 /* locate end of set */
690 end
= strchr(*p
, ']');
693 ast_log(LOG_WARNING
, "Wrong usage of [] in the extension\n");
694 return 0x40000; /* XXX make this entry go last... */
697 bzero(chars
, sizeof(chars
)); /* clear all chars in the set */
698 for (; *p
< end
; (*p
)++) {
699 unsigned char c1
, c2
; /* first-last char in range */
700 c1
= (unsigned char)((*p
)[0]);
701 if (*p
+ 2 < end
&& (*p
)[1] == '-') { /* this is a range */
702 c2
= (unsigned char)((*p
)[2]);
703 *p
+= 2; /* skip a total of 3 chars */
704 } else /* individual character */
708 for (; c1
<= c2
; c1
++) {
709 uint32_t mask
= 1 << (c1
% 32);
710 if ( (chars
[ c1
/ 32 ] & mask
) == 0)
712 chars
[ c1
/ 32 ] |= mask
;
716 return count
== 0 ? 0x30000 : (count
| cmin
);
720 * \brief the full routine to compare extensions in rules.
722 static int ext_cmp(const char *a
, const char *b
)
724 /* make sure non-patterns come first.
725 * If a is not a pattern, it either comes first or
726 * we use strcmp to compare the strings.
731 return (b
[0] == '_') ? -1 : strcmp(a
, b
);
733 /* Now we know a is a pattern; if b is not, a comes first */
736 #if 0 /* old mode for ext matching */
739 /* ok we need full pattern sorting routine */
740 while (!ret
&& a
&& b
)
741 ret
= ext_cmp1(&a
) - ext_cmp1(&b
);
745 return (ret
> 0) ? 1 : -1;
749 * When looking up extensions, we can have different requests
750 * identified by the 'action' argument, as follows.
751 * Note that the coding is such that the low 4 bits are the
752 * third argument to extension_match_core.
755 E_MATCHMORE
= 0x00, /* extension can match but only with more 'digits' */
756 E_CANMATCH
= 0x01, /* extension can match with or without more 'digits' */
757 E_MATCH
= 0x02, /* extension is an exact match */
758 E_MATCH_MASK
= 0x03, /* mask for the argument to extension_match_core() */
759 E_SPAWN
= 0x12, /* want to spawn an extension. Requires exact match */
760 E_FINDLABEL
= 0x22 /* returns the priority for a given label. Requires exact match */
764 * Internal function for ast_extension_{match|close}
765 * return 0 on no-match, 1 on match, 2 on early match.
766 * mode is as follows:
767 * E_MATCH success only on exact match
768 * E_MATCHMORE success only on partial match (i.e. leftover digits in pattern)
769 * E_CANMATCH either of the above.
772 static int _extension_match_core(const char *pattern
, const char *data
, enum ext_match_t mode
)
774 mode
&= E_MATCH_MASK
; /* only consider the relevant bits */
776 if ( (mode
== E_MATCH
) && (pattern
[0] == '_') && (strcasecmp(pattern
,data
)==0) ) /* note: if this test is left out, then _x. will not match _x. !!! */
779 if (pattern
[0] != '_') { /* not a pattern, try exact or partial match */
780 int ld
= strlen(data
), lp
= strlen(pattern
);
782 if (lp
< ld
) /* pattern too short, cannot match */
784 /* depending on the mode, accept full or partial match or both */
786 return !strcmp(pattern
, data
); /* 1 on match, 0 on fail */
787 if (ld
== 0 || !strncasecmp(pattern
, data
, ld
)) /* partial or full match */
788 return (mode
== E_MATCHMORE
) ? lp
> ld
: 1; /* XXX should consider '!' and '/' ? */
792 pattern
++; /* skip leading _ */
794 * XXX below we stop at '/' which is a separator for the CID info. However we should
795 * not store '/' in the pattern at all. When we insure it, we can remove the checks.
797 while (*data
&& *pattern
&& *pattern
!= '/') {
800 if (*data
== '-') { /* skip '-' in data (just a separator) */
804 switch (toupper(*pattern
)) {
805 case '[': /* a range */
806 end
= strchr(pattern
+1, ']'); /* XXX should deal with escapes ? */
808 ast_log(LOG_WARNING
, "Wrong usage of [] in the extension\n");
809 return 0; /* unconditional failure */
811 for (pattern
++; pattern
!= end
; pattern
++) {
812 if (pattern
+2 < end
&& pattern
[1] == '-') { /* this is a range */
813 if (*data
>= pattern
[0] && *data
<= pattern
[2])
814 break; /* match found */
816 pattern
+= 2; /* skip a total of 3 chars */
819 } else if (*data
== pattern
[0])
820 break; /* match found */
824 pattern
= end
; /* skip and continue */
827 if (*data
< '2' || *data
> '9')
831 if (*data
< '0' || *data
> '9')
835 if (*data
< '1' || *data
> '9')
838 case '.': /* Must match, even with more digits */
840 case '!': /* Early match */
843 case '-': /* Ignore these in patterns */
844 data
--; /* compensate the final data++ */
847 if (*data
!= *pattern
)
853 if (*data
) /* data longer than pattern, no match */
856 * match so far, but ran off the end of the data.
857 * Depending on what is next, determine match or not.
859 if (*pattern
== '\0' || *pattern
== '/') /* exact match */
860 return (mode
== E_MATCHMORE
) ? 0 : 1; /* this is a failure for E_MATCHMORE */
861 else if (*pattern
== '!') /* early match */
863 else /* partial match */
864 return (mode
== E_MATCH
) ? 0 : 1; /* this is a failure for E_MATCH */
868 * Wrapper around _extension_match_core() to do performance measurement
869 * using the profiling code.
871 static int extension_match_core(const char *pattern
, const char *data
, enum ext_match_t mode
)
874 static int prof_id
= -2; /* marker for 'unallocated' id */
876 prof_id
= ast_add_profile("ext_match", 0);
877 ast_mark(prof_id
, 1);
878 i
= _extension_match_core(pattern
, data
, mode
);
879 ast_mark(prof_id
, 0);
883 int ast_extension_match(const char *pattern
, const char *data
)
885 return extension_match_core(pattern
, data
, E_MATCH
);
888 int ast_extension_close(const char *pattern
, const char *data
, int needmore
)
890 if (needmore
!= E_MATCHMORE
&& needmore
!= E_CANMATCH
)
891 ast_log(LOG_WARNING
, "invalid argument %d\n", needmore
);
892 return extension_match_core(pattern
, data
, needmore
);
895 struct ast_context
*ast_context_find(const char *name
)
897 struct ast_context
*tmp
= NULL
;
899 ast_rdlock_contexts();
901 while ( (tmp
= ast_walk_contexts(tmp
)) ) {
902 if (!name
|| !strcasecmp(name
, tmp
->name
))
906 ast_unlock_contexts();
911 #define STATUS_NO_CONTEXT 1
912 #define STATUS_NO_EXTENSION 2
913 #define STATUS_NO_PRIORITY 3
914 #define STATUS_NO_LABEL 4
915 #define STATUS_SUCCESS 5
917 static int matchcid(const char *cidpattern
, const char *callerid
)
919 /* If the Caller*ID pattern is empty, then we're matching NO Caller*ID, so
920 failing to get a number should count as a match, otherwise not */
922 if (ast_strlen_zero(callerid
))
923 return ast_strlen_zero(cidpattern
) ? 1 : 0;
925 return ast_extension_match(cidpattern
, callerid
);
928 /* request and result for pbx_find_extension */
929 struct pbx_find_info
{
936 char *incstack
[AST_PBX_MAX_STACK
]; /* filled during the search */
937 int stacklen
; /* modified during the search */
938 int status
; /* set on return */
939 struct ast_switch
*swo
; /* set on return */
940 const char *data
; /* set on return */
941 const char *foundcontext
; /* set on return */
944 static struct ast_exten
*pbx_find_extension(struct ast_channel
*chan
,
945 struct ast_context
*bypass
, struct pbx_find_info
*q
,
946 const char *context
, const char *exten
, int priority
,
947 const char *label
, const char *callerid
, enum ext_match_t action
)
950 struct ast_context
*tmp
;
951 struct ast_exten
*e
, *eroot
;
952 struct ast_include
*i
;
954 char *tmpdata
= NULL
;
956 /* Initialize status if appropriate */
957 if (q
->stacklen
== 0) {
958 q
->status
= STATUS_NO_CONTEXT
;
961 q
->foundcontext
= NULL
;
963 /* Check for stack overflow */
964 if (q
->stacklen
>= AST_PBX_MAX_STACK
) {
965 ast_log(LOG_WARNING
, "Maximum PBX stack exceeded\n");
968 /* Check first to see if we've already been checked */
969 for (x
= 0; x
< q
->stacklen
; x
++) {
970 if (!strcasecmp(q
->incstack
[x
], context
))
973 if (bypass
) /* bypass means we only look there */
975 else { /* look in contexts */
977 while ((tmp
= ast_walk_contexts(tmp
)) ) {
978 if (!strcmp(tmp
->name
, context
))
984 if (q
->status
< STATUS_NO_EXTENSION
)
985 q
->status
= STATUS_NO_EXTENSION
;
987 /* scan the list trying to match extension and CID */
989 while ( (eroot
= ast_walk_context_extensions(tmp
, eroot
)) ) {
990 int match
= extension_match_core(eroot
->exten
, exten
, action
);
991 /* 0 on fail, 1 on match, 2 on earlymatch */
993 if (!match
|| (eroot
->matchcid
&& !matchcid(eroot
->cidmatch
, callerid
)))
994 continue; /* keep trying */
995 if (match
== 2 && action
== E_MATCHMORE
) {
996 /* We match an extension ending in '!'.
997 * The decision in this case is final and is NULL (no match).
1001 /* found entry, now look for the right priority */
1002 if (q
->status
< STATUS_NO_PRIORITY
)
1003 q
->status
= STATUS_NO_PRIORITY
;
1005 while ( (e
= ast_walk_extension_priorities(eroot
, e
)) ) {
1006 /* Match label or priority */
1007 if (action
== E_FINDLABEL
) {
1008 if (q
->status
< STATUS_NO_LABEL
)
1009 q
->status
= STATUS_NO_LABEL
;
1010 if (label
&& e
->label
&& !strcmp(label
, e
->label
))
1011 break; /* found it */
1012 } else if (e
->priority
== priority
) {
1013 break; /* found it */
1014 } /* else keep searching */
1016 if (e
) { /* found a valid match */
1017 q
->status
= STATUS_SUCCESS
;
1018 q
->foundcontext
= context
;
1022 /* Check alternative switches */
1023 AST_LIST_TRAVERSE(&tmp
->alts
, sw
, list
) {
1024 struct ast_switch
*asw
= pbx_findswitch(sw
->name
);
1025 ast_switch_f
*aswf
= NULL
;
1029 ast_log(LOG_WARNING
, "No such switch '%s'\n", sw
->name
);
1032 /* Substitute variables now */
1034 if (!(tmpdata
= ast_threadstorage_get(&switch_data
, 512))) {
1035 ast_log(LOG_WARNING
, "Can't evaluate switch?!");
1038 pbx_substitute_variables_helper(chan
, sw
->data
, tmpdata
, 512);
1041 /* equivalent of extension_match_core() at the switch level */
1042 if (action
== E_CANMATCH
)
1043 aswf
= asw
->canmatch
;
1044 else if (action
== E_MATCHMORE
)
1045 aswf
= asw
->matchmore
;
1046 else /* action == E_MATCH */
1048 datap
= sw
->eval
? tmpdata
: sw
->data
;
1053 ast_autoservice_start(chan
);
1054 res
= aswf(chan
, context
, exten
, priority
, callerid
, datap
);
1056 ast_autoservice_stop(chan
);
1058 if (res
) { /* Got a match */
1061 q
->foundcontext
= context
;
1062 /* XXX keep status = STATUS_NO_CONTEXT ? */
1066 q
->incstack
[q
->stacklen
++] = tmp
->name
; /* Setup the stack */
1067 /* Now try any includes we have in this context */
1068 for (i
= tmp
->includes
; i
; i
= i
->next
) {
1069 if (include_valid(i
)) {
1070 if ((e
= pbx_find_extension(chan
, bypass
, q
, i
->rname
, exten
, priority
, label
, callerid
, action
)))
1079 /*! \brief extract offset:length from variable name.
1080 * Returns 1 if there is a offset:length part, which is
1081 * trimmed off (values go into variables)
1083 static int parse_variable_name(char *var
, int *offset
, int *length
, int *isfunc
)
1090 for (; *var
; var
++) {
1094 } else if (*var
== ')') {
1096 } else if (*var
== ':' && parens
== 0) {
1098 sscanf(var
, "%d:%d", offset
, length
);
1099 return 1; /* offset:length valid */
1105 /*! \brief takes a substring. It is ok to call with value == workspace.
1107 * offset < 0 means start from the end of the string and set the beginning
1108 * to be that many characters back.
1109 * length is the length of the substring. A value less than 0 means to leave
1110 * that many off the end.
1111 * Always return a copy in workspace.
1113 static char *substring(const char *value
, int offset
, int length
, char *workspace
, size_t workspace_len
)
1115 char *ret
= workspace
;
1116 int lr
; /* length of the input string after the copy */
1118 ast_copy_string(workspace
, value
, workspace_len
); /* always make a copy */
1120 lr
= strlen(ret
); /* compute length after copy, so we never go out of the workspace */
1122 /* Quick check if no need to do anything */
1123 if (offset
== 0 && length
>= lr
) /* take the whole string */
1126 if (offset
< 0) { /* translate negative offset into positive ones */
1127 offset
= lr
+ offset
;
1128 if (offset
< 0) /* If the negative offset was greater than the length of the string, just start at the beginning */
1132 /* too large offset result in empty string so we know what to return */
1134 return ret
+ lr
; /* the final '\0' */
1136 ret
+= offset
; /* move to the start position */
1137 if (length
>= 0 && length
< lr
- offset
) /* truncate if necessary */
1139 else if (length
< 0) {
1140 if (lr
> offset
- length
) /* After we remove from the front and from the rear, is there anything left? */
1141 ret
[lr
+ length
- offset
] = '\0';
1149 /*! \brief pbx_retrieve_variable: Support for Asterisk built-in variables
1151 void pbx_retrieve_variable(struct ast_channel
*c
, const char *var
, char **ret
, char *workspace
, int workspacelen
, struct varshead
*headp
)
1153 const char not_found
= '\0';
1155 const char *s
; /* the result */
1157 int i
, need_substring
;
1158 struct varshead
*places
[2] = { headp
, &globals
}; /* list of places where we may look */
1161 ast_channel_lock(c
);
1162 places
[0] = &c
->varshead
;
1165 * Make a copy of var because parse_variable_name() modifies the string.
1166 * Then if called directly, we might need to run substring() on the result;
1167 * remember this for later in 'need_substring', 'offset' and 'length'
1169 tmpvar
= ast_strdupa(var
); /* parse_variable_name modifies the string */
1170 need_substring
= parse_variable_name(tmpvar
, &offset
, &length
, &i
/* ignored */);
1173 * Look first into predefined variables, then into variable lists.
1174 * Variable 's' points to the result, according to the following rules:
1175 * s == ¬_found (set at the beginning) means that we did not find a
1176 * matching variable and need to look into more places.
1177 * If s != ¬_found, s is a valid result string as follows:
1178 * s = NULL if the variable does not have a value;
1179 * you typically do this when looking for an unset predefined variable.
1180 * s = workspace if the result has been assembled there;
1181 * typically done when the result is built e.g. with an snprintf(),
1182 * so we don't need to do an additional copy.
1183 * s != workspace in case we have a string, that needs to be copied
1184 * (the ast_copy_string is done once for all at the end).
1185 * Typically done when the result is already available in some string.
1187 s
= ¬_found
; /* default value */
1188 if (c
) { /* This group requires a valid channel */
1189 /* Names with common parts are looked up a piece at a time using strncmp. */
1190 if (!strncmp(var
, "CALL", 4)) {
1191 if (!strncmp(var
+ 4, "ING", 3)) {
1192 if (!strcmp(var
+ 7, "PRES")) { /* CALLINGPRES */
1193 snprintf(workspace
, workspacelen
, "%d", c
->cid
.cid_pres
);
1195 } else if (!strcmp(var
+ 7, "ANI2")) { /* CALLINGANI2 */
1196 snprintf(workspace
, workspacelen
, "%d", c
->cid
.cid_ani2
);
1198 } else if (!strcmp(var
+ 7, "TON")) { /* CALLINGTON */
1199 snprintf(workspace
, workspacelen
, "%d", c
->cid
.cid_ton
);
1201 } else if (!strcmp(var
+ 7, "TNS")) { /* CALLINGTNS */
1202 snprintf(workspace
, workspacelen
, "%d", c
->cid
.cid_tns
);
1206 } else if (!strcmp(var
, "HINT")) {
1207 s
= ast_get_hint(workspace
, workspacelen
, NULL
, 0, c
, c
->context
, c
->exten
) ? workspace
: NULL
;
1208 } else if (!strcmp(var
, "HINTNAME")) {
1209 s
= ast_get_hint(NULL
, 0, workspace
, workspacelen
, c
, c
->context
, c
->exten
) ? workspace
: NULL
;
1210 } else if (!strcmp(var
, "EXTEN")) {
1212 } else if (!strcmp(var
, "CONTEXT")) {
1214 } else if (!strcmp(var
, "PRIORITY")) {
1215 snprintf(workspace
, workspacelen
, "%d", c
->priority
);
1217 } else if (!strcmp(var
, "CHANNEL")) {
1219 } else if (!strcmp(var
, "UNIQUEID")) {
1221 } else if (!strcmp(var
, "HANGUPCAUSE")) {
1222 snprintf(workspace
, workspacelen
, "%d", c
->hangupcause
);
1226 if (s
== ¬_found
) { /* look for more */
1227 if (!strcmp(var
, "EPOCH")) {
1228 snprintf(workspace
, workspacelen
, "%u",(int)time(NULL
));
1230 } else if (!strcmp(var
, "SYSTEMNAME")) {
1231 s
= ast_config_AST_SYSTEM_NAME
;
1234 /* if not found, look into chanvars or global vars */
1235 for (i
= 0; s
== ¬_found
&& i
< (sizeof(places
) / sizeof(places
[0])); i
++) {
1236 struct ast_var_t
*variables
;
1239 if (places
[i
] == &globals
)
1240 ast_mutex_lock(&globalslock
);
1241 AST_LIST_TRAVERSE(places
[i
], variables
, entries
) {
1242 if (strcasecmp(ast_var_name(variables
), var
)==0) {
1243 s
= ast_var_value(variables
);
1247 if (places
[i
] == &globals
)
1248 ast_mutex_unlock(&globalslock
);
1250 if (s
== ¬_found
|| s
== NULL
)
1254 ast_copy_string(workspace
, s
, workspacelen
);
1257 *ret
= substring(*ret
, offset
, length
, workspace
, workspacelen
);
1261 ast_channel_unlock(c
);
1264 /*! \brief CLI function to show installed custom functions
1265 \addtogroup CLI_functions
1267 static int handle_show_functions_deprecated(int fd
, int argc
, char *argv
[])
1269 struct ast_custom_function
*acf
;
1273 if (argc
== 4 && (!strcmp(argv
[2], "like")) ) {
1275 } else if (argc
!= 2) {
1276 return RESULT_SHOWUSAGE
;
1279 ast_cli(fd
, "%s Custom Functions:\n--------------------------------------------------------------------------------\n", like
? "Matching" : "Installed");
1281 AST_LIST_LOCK(&acf_root
);
1282 AST_LIST_TRAVERSE(&acf_root
, acf
, acflist
) {
1283 if (!like
|| strstr(acf
->name
, argv
[3])) {
1285 ast_cli(fd
, "%-20.20s %-35.35s %s\n", acf
->name
, acf
->syntax
, acf
->synopsis
);
1288 AST_LIST_UNLOCK(&acf_root
);
1290 ast_cli(fd
, "%d %scustom functions installed.\n", count_acf
, like
? "matching " : "");
1292 return RESULT_SUCCESS
;
1294 static int handle_show_functions(int fd
, int argc
, char *argv
[])
1296 struct ast_custom_function
*acf
;
1300 if (argc
== 5 && (!strcmp(argv
[3], "like")) ) {
1302 } else if (argc
!= 3) {
1303 return RESULT_SHOWUSAGE
;
1306 ast_cli(fd
, "%s Custom Functions:\n--------------------------------------------------------------------------------\n", like
? "Matching" : "Installed");
1308 AST_LIST_LOCK(&acf_root
);
1309 AST_LIST_TRAVERSE(&acf_root
, acf
, acflist
) {
1310 if (!like
|| strstr(acf
->name
, argv
[4])) {
1312 ast_cli(fd
, "%-20.20s %-35.35s %s\n", acf
->name
, acf
->syntax
, acf
->synopsis
);
1315 AST_LIST_UNLOCK(&acf_root
);
1317 ast_cli(fd
, "%d %scustom functions installed.\n", count_acf
, like
? "matching " : "");
1319 return RESULT_SUCCESS
;
1322 static int handle_show_function_deprecated(int fd
, int argc
, char *argv
[])
1324 struct ast_custom_function
*acf
;
1325 /* Maximum number of characters added by terminal coloring is 22 */
1326 char infotitle
[64 + AST_MAX_APP
+ 22], syntitle
[40], destitle
[40];
1327 char info
[64 + AST_MAX_APP
], *synopsis
= NULL
, *description
= NULL
;
1328 char stxtitle
[40], *syntax
= NULL
;
1329 int synopsis_size
, description_size
, syntax_size
;
1332 return RESULT_SHOWUSAGE
;
1334 if (!(acf
= ast_custom_function_find(argv
[2]))) {
1335 ast_cli(fd
, "No function by that name registered.\n");
1336 return RESULT_FAILURE
;
1341 synopsis_size
= strlen(acf
->synopsis
) + 23;
1343 synopsis_size
= strlen("Not available") + 23;
1344 synopsis
= alloca(synopsis_size
);
1347 description_size
= strlen(acf
->desc
) + 23;
1349 description_size
= strlen("Not available") + 23;
1350 description
= alloca(description_size
);
1353 syntax_size
= strlen(acf
->syntax
) + 23;
1355 syntax_size
= strlen("Not available") + 23;
1356 syntax
= alloca(syntax_size
);
1358 snprintf(info
, 64 + AST_MAX_APP
, "\n -= Info about function '%s' =- \n\n", acf
->name
);
1359 term_color(infotitle
, info
, COLOR_MAGENTA
, 0, 64 + AST_MAX_APP
+ 22);
1360 term_color(stxtitle
, "[Syntax]\n", COLOR_MAGENTA
, 0, 40);
1361 term_color(syntitle
, "[Synopsis]\n", COLOR_MAGENTA
, 0, 40);
1362 term_color(destitle
, "[Description]\n", COLOR_MAGENTA
, 0, 40);
1364 acf
->syntax
? acf
->syntax
: "Not available",
1365 COLOR_CYAN
, 0, syntax_size
);
1366 term_color(synopsis
,
1367 acf
->synopsis
? acf
->synopsis
: "Not available",
1368 COLOR_CYAN
, 0, synopsis_size
);
1369 term_color(description
,
1370 acf
->desc
? acf
->desc
: "Not available",
1371 COLOR_CYAN
, 0, description_size
);
1373 ast_cli(fd
,"%s%s%s\n\n%s%s\n\n%s%s\n", infotitle
, stxtitle
, syntax
, syntitle
, synopsis
, destitle
, description
);
1375 return RESULT_SUCCESS
;
1378 static int handle_show_function(int fd
, int argc
, char *argv
[])
1380 struct ast_custom_function
*acf
;
1381 /* Maximum number of characters added by terminal coloring is 22 */
1382 char infotitle
[64 + AST_MAX_APP
+ 22], syntitle
[40], destitle
[40];
1383 char info
[64 + AST_MAX_APP
], *synopsis
= NULL
, *description
= NULL
;
1384 char stxtitle
[40], *syntax
= NULL
;
1385 int synopsis_size
, description_size
, syntax_size
;
1388 return RESULT_SHOWUSAGE
;
1390 if (!(acf
= ast_custom_function_find(argv
[3]))) {
1391 ast_cli(fd
, "No function by that name registered.\n");
1392 return RESULT_FAILURE
;
1397 synopsis_size
= strlen(acf
->synopsis
) + 23;
1399 synopsis_size
= strlen("Not available") + 23;
1400 synopsis
= alloca(synopsis_size
);
1403 description_size
= strlen(acf
->desc
) + 23;
1405 description_size
= strlen("Not available") + 23;
1406 description
= alloca(description_size
);
1409 syntax_size
= strlen(acf
->syntax
) + 23;
1411 syntax_size
= strlen("Not available") + 23;
1412 syntax
= alloca(syntax_size
);
1414 snprintf(info
, 64 + AST_MAX_APP
, "\n -= Info about function '%s' =- \n\n", acf
->name
);
1415 term_color(infotitle
, info
, COLOR_MAGENTA
, 0, 64 + AST_MAX_APP
+ 22);
1416 term_color(stxtitle
, "[Syntax]\n", COLOR_MAGENTA
, 0, 40);
1417 term_color(syntitle
, "[Synopsis]\n", COLOR_MAGENTA
, 0, 40);
1418 term_color(destitle
, "[Description]\n", COLOR_MAGENTA
, 0, 40);
1420 acf
->syntax
? acf
->syntax
: "Not available",
1421 COLOR_CYAN
, 0, syntax_size
);
1422 term_color(synopsis
,
1423 acf
->synopsis
? acf
->synopsis
: "Not available",
1424 COLOR_CYAN
, 0, synopsis_size
);
1425 term_color(description
,
1426 acf
->desc
? acf
->desc
: "Not available",
1427 COLOR_CYAN
, 0, description_size
);
1429 ast_cli(fd
,"%s%s%s\n\n%s%s\n\n%s%s\n", infotitle
, stxtitle
, syntax
, syntitle
, synopsis
, destitle
, description
);
1431 return RESULT_SUCCESS
;
1434 static char *complete_show_function(const char *line
, const char *word
, int pos
, int state
)
1436 struct ast_custom_function
*acf
;
1439 int wordlen
= strlen(word
);
1441 /* case-insensitive for convenience in this 'complete' function */
1442 AST_LIST_LOCK(&acf_root
);
1443 AST_LIST_TRAVERSE(&acf_root
, acf
, acflist
) {
1444 if (!strncasecmp(word
, acf
->name
, wordlen
) && ++which
> state
) {
1445 ret
= strdup(acf
->name
);
1449 AST_LIST_UNLOCK(&acf_root
);
1454 struct ast_custom_function
*ast_custom_function_find(const char *name
)
1456 struct ast_custom_function
*acf
= NULL
;
1458 AST_LIST_LOCK(&acf_root
);
1459 AST_LIST_TRAVERSE(&acf_root
, acf
, acflist
) {
1460 if (!strcmp(name
, acf
->name
))
1463 AST_LIST_UNLOCK(&acf_root
);
1468 int ast_custom_function_unregister(struct ast_custom_function
*acf
)
1470 struct ast_custom_function
*cur
;
1475 AST_LIST_LOCK(&acf_root
);
1476 AST_LIST_TRAVERSE_SAFE_BEGIN(&acf_root
, cur
, acflist
) {
1478 AST_LIST_REMOVE_CURRENT(&acf_root
, acflist
);
1479 if (option_verbose
> 1)
1480 ast_verbose(VERBOSE_PREFIX_2
"Unregistered custom function %s\n", acf
->name
);
1484 AST_LIST_TRAVERSE_SAFE_END
1485 AST_LIST_UNLOCK(&acf_root
);
1487 return acf
? 0 : -1;
1490 int ast_custom_function_register(struct ast_custom_function
*acf
)
1492 struct ast_custom_function
*cur
;
1497 AST_LIST_LOCK(&acf_root
);
1499 if (ast_custom_function_find(acf
->name
)) {
1500 ast_log(LOG_ERROR
, "Function %s already registered.\n", acf
->name
);
1501 AST_LIST_UNLOCK(&acf_root
);
1505 /* Store in alphabetical order */
1506 AST_LIST_TRAVERSE_SAFE_BEGIN(&acf_root
, cur
, acflist
) {
1507 if (strcasecmp(acf
->name
, cur
->name
) < 0) {
1508 AST_LIST_INSERT_BEFORE_CURRENT(&acf_root
, acf
, acflist
);
1512 AST_LIST_TRAVERSE_SAFE_END
1514 AST_LIST_INSERT_TAIL(&acf_root
, acf
, acflist
);
1516 AST_LIST_UNLOCK(&acf_root
);
1518 if (option_verbose
> 1)
1519 ast_verbose(VERBOSE_PREFIX_2
"Registered custom function %s\n", acf
->name
);
1524 /*! \brief return a pointer to the arguments of the function,
1525 * and terminates the function name with '\\0'
1527 static char *func_args(char *function
)
1529 char *args
= strchr(function
, '(');
1532 ast_log(LOG_WARNING
, "Function doesn't contain parentheses. Assuming null argument.\n");
1536 if ((p
= strrchr(args
, ')')) )
1539 ast_log(LOG_WARNING
, "Can't find trailing parenthesis?\n");
1544 int ast_func_read(struct ast_channel
*chan
, char *function
, char *workspace
, size_t len
)
1546 char *args
= func_args(function
);
1547 struct ast_custom_function
*acfptr
= ast_custom_function_find(function
);
1550 ast_log(LOG_ERROR
, "Function %s not registered\n", function
);
1551 else if (!acfptr
->read
)
1552 ast_log(LOG_ERROR
, "Function %s cannot be read\n", function
);
1554 return acfptr
->read(chan
, function
, args
, workspace
, len
);
1558 int ast_func_write(struct ast_channel
*chan
, char *function
, const char *value
)
1560 char *args
= func_args(function
);
1561 struct ast_custom_function
*acfptr
= ast_custom_function_find(function
);
1564 ast_log(LOG_ERROR
, "Function %s not registered\n", function
);
1565 else if (!acfptr
->write
)
1566 ast_log(LOG_ERROR
, "Function %s cannot be written to\n", function
);
1568 return acfptr
->write(chan
, function
, args
, value
);
1573 static void pbx_substitute_variables_helper_full(struct ast_channel
*c
, struct varshead
*headp
, const char *cp1
, char *cp2
, int count
)
1575 /* Substitutes variables into cp2, based on string cp1, and assuming cp2 to be
1578 const char *tmp
, *whereweare
;
1579 int length
, offset
, offset2
, isfunction
;
1580 char *workspace
= NULL
;
1581 char *ltmp
= NULL
, *var
= NULL
;
1582 char *nextvar
, *nextexp
, *nextthing
;
1584 int pos
, brackets
, needsub
, len
;
1587 while (!ast_strlen_zero(whereweare
) && count
) {
1588 /* Assume we're copying the whole remaining string */
1589 pos
= strlen(whereweare
);
1592 nextthing
= strchr(whereweare
, '$');
1594 switch(nextthing
[1]) {
1596 nextvar
= nextthing
;
1597 pos
= nextvar
- whereweare
;
1600 nextexp
= nextthing
;
1601 pos
= nextexp
- whereweare
;
1609 /* Can't copy more than 'count' bytes */
1613 /* Copy that many bytes */
1614 memcpy(cp2
, whereweare
, pos
);
1622 /* We have a variable. Find the start and end, and determine
1623 if we are going to have to recursively call ourselves on the
1625 vars
= vare
= nextvar
+ 2;
1629 /* Find the end of it */
1630 while (brackets
&& *vare
) {
1631 if ((vare
[0] == '$') && (vare
[1] == '{')) {
1633 } else if (vare
[0] == '{') {
1635 } else if (vare
[0] == '}') {
1637 } else if ((vare
[0] == '$') && (vare
[1] == '['))
1642 ast_log(LOG_NOTICE
, "Error in extension logic (missing '}')\n");
1643 len
= vare
- vars
- 1;
1645 /* Skip totally over variable string */
1646 whereweare
+= (len
+ 3);
1649 var
= alloca(VAR_BUF_SIZE
);
1651 /* Store variable name (and truncate) */
1652 ast_copy_string(var
, vars
, len
+ 1);
1654 /* Substitute if necessary */
1657 ltmp
= alloca(VAR_BUF_SIZE
);
1659 memset(ltmp
, 0, VAR_BUF_SIZE
);
1660 pbx_substitute_variables_helper_full(c
, headp
, var
, ltmp
, VAR_BUF_SIZE
- 1);
1667 workspace
= alloca(VAR_BUF_SIZE
);
1669 workspace
[0] = '\0';
1671 parse_variable_name(vars
, &offset
, &offset2
, &isfunction
);
1673 /* Evaluate function */
1675 cp4
= ast_func_read(c
, vars
, workspace
, VAR_BUF_SIZE
) ? NULL
: workspace
;
1677 struct varshead old
;
1678 struct ast_channel
*c
= ast_channel_alloc(0, 0, "", "", "", "", "", 0, "Bogus/%p", vars
);
1680 memcpy(&old
, &c
->varshead
, sizeof(old
));
1681 memcpy(&c
->varshead
, headp
, sizeof(c
->varshead
));
1682 cp4
= ast_func_read(c
, vars
, workspace
, VAR_BUF_SIZE
) ? NULL
: workspace
;
1683 /* Don't deallocate the varshead that was passed in */
1684 memcpy(&c
->varshead
, &old
, sizeof(c
->varshead
));
1685 ast_channel_free(c
);
1687 ast_log(LOG_ERROR
, "Unable to allocate bogus channel for variable substitution. Function results may be blank.\n");
1691 ast_log(LOG_DEBUG
, "Function result is '%s'\n", cp4
? cp4
: "(null)");
1693 /* Retrieve variable value */
1694 pbx_retrieve_variable(c
, vars
, &cp4
, workspace
, VAR_BUF_SIZE
, headp
);
1697 cp4
= substring(cp4
, offset
, offset2
, workspace
, VAR_BUF_SIZE
);
1699 length
= strlen(cp4
);
1702 memcpy(cp2
, cp4
, length
);
1706 } else if (nextexp
) {
1707 /* We have an expression. Find the start and end, and determine
1708 if we are going to have to recursively call ourselves on the
1710 vars
= vare
= nextexp
+ 2;
1714 /* Find the end of it */
1715 while(brackets
&& *vare
) {
1716 if ((vare
[0] == '$') && (vare
[1] == '[')) {
1720 } else if (vare
[0] == '[') {
1722 } else if (vare
[0] == ']') {
1724 } else if ((vare
[0] == '$') && (vare
[1] == '{')) {
1731 ast_log(LOG_NOTICE
, "Error in extension logic (missing ']')\n");
1732 len
= vare
- vars
- 1;
1734 /* Skip totally over expression */
1735 whereweare
+= (len
+ 3);
1738 var
= alloca(VAR_BUF_SIZE
);
1740 /* Store variable name (and truncate) */
1741 ast_copy_string(var
, vars
, len
+ 1);
1743 /* Substitute if necessary */
1746 ltmp
= alloca(VAR_BUF_SIZE
);
1748 memset(ltmp
, 0, VAR_BUF_SIZE
);
1749 pbx_substitute_variables_helper_full(c
, headp
, var
, ltmp
, VAR_BUF_SIZE
- 1);
1755 length
= ast_expr(vars
, cp2
, count
);
1759 ast_log(LOG_DEBUG
, "Expression result is '%s'\n", cp2
);
1767 void pbx_substitute_variables_helper(struct ast_channel
*c
, const char *cp1
, char *cp2
, int count
)
1769 pbx_substitute_variables_helper_full(c
, (c
) ? &c
->varshead
: NULL
, cp1
, cp2
, count
);
1772 void pbx_substitute_variables_varshead(struct varshead
*headp
, const char *cp1
, char *cp2
, int count
)
1774 pbx_substitute_variables_helper_full(NULL
, headp
, cp1
, cp2
, count
);
1777 static void pbx_substitute_variables(char *passdata
, int datalen
, struct ast_channel
*c
, struct ast_exten
*e
)
1779 memset(passdata
, 0, datalen
);
1781 /* No variables or expressions in e->data, so why scan it? */
1782 if (e
->data
&& !strchr(e
->data
, '$') && !strstr(e
->data
,"${") && !strstr(e
->data
,"$[") && !strstr(e
->data
,"$(")) {
1783 ast_copy_string(passdata
, e
->data
, datalen
);
1787 pbx_substitute_variables_helper(c
, e
->data
, passdata
, datalen
- 1);
1791 * \brief The return value depends on the action:
1793 * E_MATCH, E_CANMATCH, E_MATCHMORE require a real match,
1794 * and return 0 on failure, -1 on match;
1795 * E_FINDLABEL maps the label to a priority, and returns
1796 * the priority on success, ... XXX
1797 * E_SPAWN, spawn an application,
1798 * and return 0 on success, -1 on failure.
1800 * \note The channel is auto-serviced in this function, because doing an extension
1801 * match may block for a long time. For example, if the lookup has to use a network
1802 * dialplan switch, such as DUNDi or IAX2, it may take a while. However, the channel
1803 * auto-service code will queue up any important signalling frames to be processed
1804 * after this is done.
1806 static int pbx_extension_helper(struct ast_channel
*c
, struct ast_context
*con
,
1807 const char *context
, const char *exten
, int priority
,
1808 const char *label
, const char *callerid
, enum ext_match_t action
)
1810 struct ast_exten
*e
;
1811 struct ast_app
*app
;
1813 struct pbx_find_info q
= { .stacklen
= 0 }; /* the rest is reset in pbx_find_extension */
1814 char passdata
[EXT_DATA_SIZE
];
1816 int matching_action
= (action
== E_MATCH
|| action
== E_CANMATCH
|| action
== E_MATCHMORE
);
1818 ast_rdlock_contexts();
1819 e
= pbx_find_extension(c
, con
, &q
, context
, exten
, priority
, label
, callerid
, action
);
1821 if (matching_action
) {
1822 ast_unlock_contexts();
1823 return -1; /* success, we found it */
1824 } else if (action
== E_FINDLABEL
) { /* map the label to a priority */
1826 ast_unlock_contexts();
1827 return res
; /* the priority we were looking for */
1828 } else { /* spawn */
1829 app
= pbx_findapp(e
->app
);
1830 ast_unlock_contexts();
1832 ast_log(LOG_WARNING
, "No application '%s' for extension (%s, %s, %d)\n", e
->app
, context
, exten
, priority
);
1835 if (c
->context
!= context
)
1836 ast_copy_string(c
->context
, context
, sizeof(c
->context
));
1837 if (c
->exten
!= exten
)
1838 ast_copy_string(c
->exten
, exten
, sizeof(c
->exten
));
1839 c
->priority
= priority
;
1840 pbx_substitute_variables(passdata
, sizeof(passdata
), c
, e
);
1842 ast_log(LOG_DEBUG
, "Launching '%s'\n", app
->name
);
1844 if (option_verbose
> 2) {
1845 char tmp
[80], tmp2
[80], tmp3
[EXT_DATA_SIZE
];
1846 ast_verbose( VERBOSE_PREFIX_3
"Executing [%s@%s:%d] %s(\"%s\", \"%s\") %s\n",
1847 exten
, context
, priority
,
1848 term_color(tmp
, app
->name
, COLOR_BRCYAN
, 0, sizeof(tmp
)),
1849 term_color(tmp2
, c
->name
, COLOR_BRMAGENTA
, 0, sizeof(tmp2
)),
1850 term_color(tmp3
, passdata
, COLOR_BRMAGENTA
, 0, sizeof(tmp3
)),
1853 manager_event(EVENT_FLAG_CALL
, "Newexten",
1858 "Application: %s\r\n"
1861 c
->name
, c
->context
, c
->exten
, c
->priority
, app
->name
, passdata
, c
->uniqueid
);
1862 return pbx_exec(c
, app
, passdata
); /* 0 on success, -1 on failure */
1864 } else if (q
.swo
) { /* not found here, but in another switch */
1865 ast_unlock_contexts();
1866 if (matching_action
) {
1870 ast_log(LOG_WARNING
, "No execution engine for switch %s\n", q
.swo
->name
);
1873 return q
.swo
->exec(c
, q
.foundcontext
? q
.foundcontext
: context
, exten
, priority
, callerid
, q
.data
);
1875 } else { /* not found anywhere, see what happened */
1876 ast_unlock_contexts();
1878 case STATUS_NO_CONTEXT
:
1879 if (!matching_action
)
1880 ast_log(LOG_NOTICE
, "Cannot find extension context '%s'\n", context
);
1882 case STATUS_NO_EXTENSION
:
1883 if (!matching_action
)
1884 ast_log(LOG_NOTICE
, "Cannot find extension '%s' in context '%s'\n", exten
, context
);
1886 case STATUS_NO_PRIORITY
:
1887 if (!matching_action
)
1888 ast_log(LOG_NOTICE
, "No such priority %d in extension '%s' in context '%s'\n", priority
, exten
, context
);
1890 case STATUS_NO_LABEL
:
1892 ast_log(LOG_NOTICE
, "No such label '%s' in extension '%s' in context '%s'\n", label
, exten
, context
);
1896 ast_log(LOG_DEBUG
, "Shouldn't happen!\n");
1899 return (matching_action
) ? 0 : -1;
1903 /*! \brief ast_hint_extension: Find hint for given extension in context */
1904 static struct ast_exten
*ast_hint_extension(struct ast_channel
*c
, const char *context
, const char *exten
)
1906 struct ast_exten
*e
;
1907 struct pbx_find_info q
= { .stacklen
= 0 }; /* the rest is set in pbx_find_context */
1909 ast_rdlock_contexts();
1910 e
= pbx_find_extension(c
, NULL
, &q
, context
, exten
, PRIORITY_HINT
, NULL
, "", E_MATCH
);
1911 ast_unlock_contexts();
1916 /*! \brief ast_extensions_state2: Check state of extension by using hints */
1917 static int ast_extension_state2(struct ast_exten
*e
)
1919 char hint
[AST_MAX_EXTENSION
];
1921 int allunavailable
= 1, allbusy
= 1, allfree
= 1, allonhold
= 1;
1922 int busy
= 0, inuse
= 0, ring
= 0;
1927 ast_copy_string(hint
, ast_get_extension_app(e
), sizeof(hint
));
1929 rest
= hint
; /* One or more devices separated with a & character */
1930 while ( (cur
= strsep(&rest
, "&")) ) {
1931 int res
= ast_device_state(cur
);
1933 case AST_DEVICE_NOT_INUSE
:
1938 case AST_DEVICE_INUSE
:
1944 case AST_DEVICE_RINGING
:
1950 case AST_DEVICE_RINGINUSE
:
1957 case AST_DEVICE_ONHOLD
:
1961 case AST_DEVICE_BUSY
:
1967 case AST_DEVICE_UNAVAILABLE
:
1968 case AST_DEVICE_INVALID
:
1982 return AST_EXTENSION_RINGING
;
1984 return (AST_EXTENSION_INUSE
| AST_EXTENSION_RINGING
);
1986 return AST_EXTENSION_INUSE
;
1988 return AST_EXTENSION_NOT_INUSE
;
1990 return AST_EXTENSION_ONHOLD
;
1992 return AST_EXTENSION_BUSY
;
1994 return AST_EXTENSION_UNAVAILABLE
;
1996 return AST_EXTENSION_INUSE
;
1998 return AST_EXTENSION_NOT_INUSE
;
2001 /*! \brief ast_extension_state2str: Return extension_state as string */
2002 const char *ast_extension_state2str(int extension_state
)
2006 for (i
= 0; (i
< (sizeof(extension_states
) / sizeof(extension_states
[0]))); i
++) {
2007 if (extension_states
[i
].extension_state
== extension_state
)
2008 return extension_states
[i
].text
;
2013 /*! \brief ast_extension_state: Check extension state for an extension by using hint */
2014 int ast_extension_state(struct ast_channel
*c
, const char *context
, const char *exten
)
2016 struct ast_exten
*e
;
2018 e
= ast_hint_extension(c
, context
, exten
); /* Do we have a hint for this extension ? */
2020 return -1; /* No hint, return -1 */
2022 return ast_extension_state2(e
); /* Check all devices in the hint */
2025 void ast_hint_state_changed(const char *device
)
2027 struct ast_hint
*hint
;
2029 AST_LIST_LOCK(&hints
);
2031 AST_LIST_TRAVERSE(&hints
, hint
, list
) {
2032 struct ast_state_cb
*cblist
;
2033 char buf
[AST_MAX_EXTENSION
];
2038 ast_copy_string(buf
, ast_get_extension_app(hint
->exten
), sizeof(buf
));
2039 while ( (cur
= strsep(&parse
, "&")) ) {
2040 if (!strcasecmp(cur
, device
))
2046 /* Get device state for this hint */
2047 state
= ast_extension_state2(hint
->exten
);
2049 if ((state
== -1) || (state
== hint
->laststate
))
2052 /* Device state changed since last check - notify the watchers */
2054 /* For general callbacks */
2055 for (cblist
= statecbs
; cblist
; cblist
= cblist
->next
)
2056 cblist
->callback(hint
->exten
->parent
->name
, hint
->exten
->exten
, state
, cblist
->data
);
2058 /* For extension callbacks */
2059 for (cblist
= hint
->callbacks
; cblist
; cblist
= cblist
->next
)
2060 cblist
->callback(hint
->exten
->parent
->name
, hint
->exten
->exten
, state
, cblist
->data
);
2062 hint
->laststate
= state
; /* record we saw the change */
2065 AST_LIST_UNLOCK(&hints
);
2068 /*! \brief ast_extension_state_add: Add watcher for extension states */
2069 int ast_extension_state_add(const char *context
, const char *exten
,
2070 ast_state_cb_type callback
, void *data
)
2072 struct ast_hint
*hint
;
2073 struct ast_state_cb
*cblist
;
2074 struct ast_exten
*e
;
2076 /* If there's no context and extension: add callback to statecbs list */
2077 if (!context
&& !exten
) {
2078 AST_LIST_LOCK(&hints
);
2080 for (cblist
= statecbs
; cblist
; cblist
= cblist
->next
) {
2081 if (cblist
->callback
== callback
) {
2082 cblist
->data
= data
;
2083 AST_LIST_UNLOCK(&hints
);
2088 /* Now insert the callback */
2089 if (!(cblist
= ast_calloc(1, sizeof(*cblist
)))) {
2090 AST_LIST_UNLOCK(&hints
);
2094 cblist
->callback
= callback
;
2095 cblist
->data
= data
;
2097 cblist
->next
= statecbs
;
2100 AST_LIST_UNLOCK(&hints
);
2104 if (!context
|| !exten
)
2107 /* This callback type is for only one hint, so get the hint */
2108 e
= ast_hint_extension(NULL
, context
, exten
);
2113 /* Find the hint in the list of hints */
2114 AST_LIST_LOCK(&hints
);
2116 AST_LIST_TRAVERSE(&hints
, hint
, list
) {
2117 if (hint
->exten
== e
)
2122 /* We have no hint, sorry */
2123 AST_LIST_UNLOCK(&hints
);
2127 /* Now insert the callback in the callback list */
2128 if (!(cblist
= ast_calloc(1, sizeof(*cblist
)))) {
2129 AST_LIST_UNLOCK(&hints
);
2132 cblist
->id
= stateid
++; /* Unique ID for this callback */
2133 cblist
->callback
= callback
; /* Pointer to callback routine */
2134 cblist
->data
= data
; /* Data for the callback */
2136 cblist
->next
= hint
->callbacks
;
2137 hint
->callbacks
= cblist
;
2139 AST_LIST_UNLOCK(&hints
);
2143 /*! \brief ast_extension_state_del: Remove a watcher from the callback list */
2144 int ast_extension_state_del(int id
, ast_state_cb_type callback
)
2146 struct ast_state_cb
**p_cur
= NULL
; /* address of pointer to us */
2149 if (!id
&& !callback
)
2152 AST_LIST_LOCK(&hints
);
2154 if (!id
) { /* id == 0 is a callback without extension */
2155 for (p_cur
= &statecbs
; *p_cur
; p_cur
= &(*p_cur
)->next
) {
2156 if ((*p_cur
)->callback
== callback
)
2159 } else { /* callback with extension, find the callback based on ID */
2160 struct ast_hint
*hint
;
2161 AST_LIST_TRAVERSE(&hints
, hint
, list
) {
2162 for (p_cur
= &hint
->callbacks
; *p_cur
; p_cur
= &(*p_cur
)->next
) {
2163 if ((*p_cur
)->id
== id
)
2166 if (*p_cur
) /* found in the inner loop */
2170 if (p_cur
&& *p_cur
) {
2171 struct ast_state_cb
*cur
= *p_cur
;
2176 AST_LIST_UNLOCK(&hints
);
2180 /*! \brief ast_add_hint: Add hint to hint list, check initial extension state */
2181 static int ast_add_hint(struct ast_exten
*e
)
2183 struct ast_hint
*hint
;
2188 AST_LIST_LOCK(&hints
);
2190 /* Search if hint exists, do nothing */
2191 AST_LIST_TRAVERSE(&hints
, hint
, list
) {
2192 if (hint
->exten
== e
) {
2193 AST_LIST_UNLOCK(&hints
);
2194 if (option_debug
> 1)
2195 ast_log(LOG_DEBUG
, "HINTS: Not re-adding existing hint %s: %s\n", ast_get_extension_name(e
), ast_get_extension_app(e
));
2200 if (option_debug
> 1)
2201 ast_log(LOG_DEBUG
, "HINTS: Adding hint %s: %s\n", ast_get_extension_name(e
), ast_get_extension_app(e
));
2203 if (!(hint
= ast_calloc(1, sizeof(*hint
)))) {
2204 AST_LIST_UNLOCK(&hints
);
2207 /* Initialize and insert new item at the top */
2209 hint
->laststate
= ast_extension_state2(e
);
2210 AST_LIST_INSERT_HEAD(&hints
, hint
, list
);
2212 AST_LIST_UNLOCK(&hints
);
2216 /*! \brief ast_change_hint: Change hint for an extension */
2217 static int ast_change_hint(struct ast_exten
*oe
, struct ast_exten
*ne
)
2219 struct ast_hint
*hint
;
2222 AST_LIST_LOCK(&hints
);
2223 AST_LIST_TRAVERSE(&hints
, hint
, list
) {
2224 if (hint
->exten
== oe
) {
2230 AST_LIST_UNLOCK(&hints
);
2235 /*! \brief ast_remove_hint: Remove hint from extension */
2236 static int ast_remove_hint(struct ast_exten
*e
)
2238 /* Cleanup the Notifys if hint is removed */
2239 struct ast_hint
*hint
;
2240 struct ast_state_cb
*cblist
, *cbprev
;
2246 AST_LIST_LOCK(&hints
);
2247 AST_LIST_TRAVERSE_SAFE_BEGIN(&hints
, hint
, list
) {
2248 if (hint
->exten
== e
) {
2250 cblist
= hint
->callbacks
;
2252 /* Notify with -1 and remove all callbacks */
2254 cblist
= cblist
->next
;
2255 cbprev
->callback(hint
->exten
->parent
->name
, hint
->exten
->exten
, AST_EXTENSION_DEACTIVATED
, cbprev
->data
);
2258 hint
->callbacks
= NULL
;
2259 AST_LIST_REMOVE_CURRENT(&hints
, list
);
2265 AST_LIST_TRAVERSE_SAFE_END
2266 AST_LIST_UNLOCK(&hints
);
2272 /*! \brief ast_get_hint: Get hint for channel */
2273 int ast_get_hint(char *hint
, int hintsize
, char *name
, int namesize
, struct ast_channel
*c
, const char *context
, const char *exten
)
2275 struct ast_exten
*e
= ast_hint_extension(c
, context
, exten
);
2279 ast_copy_string(hint
, ast_get_extension_app(e
), hintsize
);
2281 const char *tmp
= ast_get_extension_app_data(e
);
2283 ast_copy_string(name
, tmp
, namesize
);
2290 int ast_exists_extension(struct ast_channel
*c
, const char *context
, const char *exten
, int priority
, const char *callerid
)
2292 return pbx_extension_helper(c
, NULL
, context
, exten
, priority
, NULL
, callerid
, E_MATCH
);
2295 int ast_findlabel_extension(struct ast_channel
*c
, const char *context
, const char *exten
, const char *label
, const char *callerid
)
2297 return pbx_extension_helper(c
, NULL
, context
, exten
, 0, label
, callerid
, E_FINDLABEL
);
2300 int ast_findlabel_extension2(struct ast_channel
*c
, struct ast_context
*con
, const char *exten
, const char *label
, const char *callerid
)
2302 return pbx_extension_helper(c
, con
, NULL
, exten
, 0, label
, callerid
, E_FINDLABEL
);
2305 int ast_canmatch_extension(struct ast_channel
*c
, const char *context
, const char *exten
, int priority
, const char *callerid
)
2307 return pbx_extension_helper(c
, NULL
, context
, exten
, priority
, NULL
, callerid
, E_CANMATCH
);
2310 int ast_matchmore_extension(struct ast_channel
*c
, const char *context
, const char *exten
, int priority
, const char *callerid
)
2312 return pbx_extension_helper(c
, NULL
, context
, exten
, priority
, NULL
, callerid
, E_MATCHMORE
);
2315 int ast_spawn_extension(struct ast_channel
*c
, const char *context
, const char *exten
, int priority
, const char *callerid
)
2317 return pbx_extension_helper(c
, NULL
, context
, exten
, priority
, NULL
, callerid
, E_SPAWN
);
2320 /* helper function to set extension and priority */
2321 static void set_ext_pri(struct ast_channel
*c
, const char *exten
, int pri
)
2323 ast_channel_lock(c
);
2324 ast_copy_string(c
->exten
, exten
, sizeof(c
->exten
));
2326 ast_channel_unlock(c
);
2330 * \brief collect digits from the channel into the buffer,
2331 * return -1 on error, 0 on timeout or done.
2333 static int collect_digits(struct ast_channel
*c
, int waittime
, char *buf
, int buflen
, int pos
)
2337 buf
[pos
] = '\0'; /* make sure it is properly terminated */
2338 while (ast_matchmore_extension(c
, c
->context
, buf
, 1, c
->cid
.cid_num
)) {
2339 /* As long as we're willing to wait, and as long as it's not defined,
2340 keep reading digits until we can't possibly get a right answer anymore. */
2341 digit
= ast_waitfordigit(c
, waittime
* 1000);
2342 if (c
->_softhangup
== AST_SOFTHANGUP_ASYNCGOTO
) {
2345 if (!digit
) /* No entry */
2347 if (digit
< 0) /* Error, maybe a hangup */
2349 if (pos
< buflen
- 1) { /* XXX maybe error otherwise ? */
2353 waittime
= c
->pbx
->dtimeout
;
2359 static int __ast_pbx_run(struct ast_channel
*c
)
2361 int found
= 0; /* set if we find at least one match */
2364 int error
= 0; /* set an error conditions */
2366 /* A little initial setup here */
2368 ast_log(LOG_WARNING
, "%s already has PBX structure??\n", c
->name
);
2369 /* XXX and now what ? */
2372 if (!(c
->pbx
= ast_calloc(1, sizeof(*c
->pbx
))))
2376 c
->cdr
= ast_cdr_alloc();
2378 ast_log(LOG_WARNING
, "Unable to create Call Detail Record\n");
2382 ast_cdr_init(c
->cdr
, c
);
2385 /* Set reasonable defaults */
2386 c
->pbx
->rtimeout
= 10;
2387 c
->pbx
->dtimeout
= 5;
2389 autoloopflag
= ast_test_flag(c
, AST_FLAG_IN_AUTOLOOP
); /* save value to restore at the end */
2390 ast_set_flag(c
, AST_FLAG_IN_AUTOLOOP
);
2392 /* Start by trying whatever the channel is set to */
2393 if (!ast_exists_extension(c
, c
->context
, c
->exten
, c
->priority
, c
->cid
.cid_num
)) {
2394 /* If not successful fall back to 's' */
2395 if (option_verbose
> 1)
2396 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
);
2397 /* XXX the original code used the existing priority in the call to
2398 * ast_exists_extension(), and reset it to 1 afterwards.
2399 * I believe the correct thing is to set it to 1 immediately.
2401 set_ext_pri(c
, "s", 1);
2402 if (!ast_exists_extension(c
, c
->context
, c
->exten
, c
->priority
, c
->cid
.cid_num
)) {
2403 /* JK02: And finally back to default if everything else failed */
2404 if (option_verbose
> 1)
2405 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
);
2406 ast_copy_string(c
->context
, "default", sizeof(c
->context
));
2409 if (c
->cdr
&& ast_tvzero(c
->cdr
->start
))
2410 ast_cdr_start(c
->cdr
);
2412 char dst_exten
[256]; /* buffer to accumulate digits */
2413 int pos
= 0; /* XXX should check bounds */
2416 /* loop on priorities in this context/exten */
2417 while (ast_exists_extension(c
, c
->context
, c
->exten
, c
->priority
, c
->cid
.cid_num
)) {
2419 if ((res
= ast_spawn_extension(c
, c
->context
, c
->exten
, c
->priority
, c
->cid
.cid_num
))) {
2420 /* Something bad happened, or a hangup has been requested. */
2421 if (strchr("0123456789ABCDEF*#", res
)) {
2423 ast_log(LOG_DEBUG
, "Oooh, got something to jump out with ('%c')!\n", res
);
2425 dst_exten
[pos
++] = digit
= res
;
2426 dst_exten
[pos
] = '\0';
2429 if (res
== AST_PBX_KEEPALIVE
) {
2431 ast_log(LOG_DEBUG
, "Spawn extension (%s,%s,%d) exited KEEPALIVE on '%s'\n", c
->context
, c
->exten
, c
->priority
, c
->name
);
2432 if (option_verbose
> 1)
2433 ast_verbose( VERBOSE_PREFIX_2
"Spawn extension (%s, %s, %d) exited KEEPALIVE on '%s'\n", c
->context
, c
->exten
, c
->priority
, c
->name
);
2438 ast_log(LOG_DEBUG
, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c
->context
, c
->exten
, c
->priority
, c
->name
);
2439 if (option_verbose
> 1)
2440 ast_verbose( VERBOSE_PREFIX_2
"Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c
->context
, c
->exten
, c
->priority
, c
->name
);
2441 if (c
->_softhangup
== AST_SOFTHANGUP_ASYNCGOTO
) {
2443 } else if (c
->_softhangup
== AST_SOFTHANGUP_TIMEOUT
) {
2444 /* atimeout, nothing bad */
2452 if (c
->_softhangup
== AST_SOFTHANGUP_ASYNCGOTO
) {
2454 } else if (c
->_softhangup
== AST_SOFTHANGUP_TIMEOUT
&& ast_exists_extension(c
,c
->context
,"T",1,c
->cid
.cid_num
)) {
2455 set_ext_pri(c
, "T", 0); /* 0 will become 1 with the c->priority++; at the end */
2456 /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
2457 c
->whentohangup
= 0;
2458 c
->_softhangup
&= ~AST_SOFTHANGUP_TIMEOUT
;
2459 } else if (c
->_softhangup
) {
2461 ast_log(LOG_DEBUG
, "Extension %s, priority %d returned normally even though call was hung up\n",
2462 c
->exten
, c
->priority
);
2467 } /* end while - from here on we can use 'break' to go out */
2471 /* XXX we get here on non-existing extension or a keypress or hangup ? */
2473 if (!ast_exists_extension(c
, c
->context
, c
->exten
, 1, c
->cid
.cid_num
)) {
2474 /* If there is no match at priority 1, it is not a valid extension anymore.
2475 * Try to continue at "i", 1 or exit if the latter does not exist.
2477 if (ast_exists_extension(c
, c
->context
, "i", 1, c
->cid
.cid_num
)) {
2478 if (option_verbose
> 2)
2479 ast_verbose(VERBOSE_PREFIX_3
"Sent into invalid extension '%s' in context '%s' on %s\n", c
->exten
, c
->context
, c
->name
);
2480 pbx_builtin_setvar_helper(c
, "INVALID_EXTEN", c
->exten
);
2481 set_ext_pri(c
, "i", 1);
2483 ast_log(LOG_WARNING
, "Channel '%s' sent into invalid extension '%s' in context '%s', but no invalid handler\n",
2484 c
->name
, c
->exten
, c
->context
);
2485 error
= 1; /* we know what to do with it */
2488 } else if (c
->_softhangup
== AST_SOFTHANGUP_TIMEOUT
) {
2489 /* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */
2491 } else { /* keypress received, get more digits for a full extension */
2494 waittime
= c
->pbx
->dtimeout
;
2495 else if (!autofallthrough
)
2496 waittime
= c
->pbx
->rtimeout
;
2498 const char *status
= pbx_builtin_getvar_helper(c
, "DIALSTATUS");
2501 if (option_verbose
> 2)
2502 ast_verbose(VERBOSE_PREFIX_2
"Auto fallthrough, channel '%s' status is '%s'\n", c
->name
, status
);
2503 if (!strcasecmp(status
, "CONGESTION"))
2504 res
= pbx_builtin_congestion(c
, "10");
2505 else if (!strcasecmp(status
, "CHANUNAVAIL"))
2506 res
= pbx_builtin_congestion(c
, "10");
2507 else if (!strcasecmp(status
, "BUSY"))
2508 res
= pbx_builtin_busy(c
, "10");
2509 error
= 1; /* XXX disable message */
2510 break; /* exit from the 'for' loop */
2513 if (collect_digits(c
, waittime
, dst_exten
, sizeof(dst_exten
), pos
))
2515 if (ast_exists_extension(c
, c
->context
, dst_exten
, 1, c
->cid
.cid_num
)) /* Prepare the next cycle */
2516 set_ext_pri(c
, dst_exten
, 1);
2518 /* No such extension */
2519 if (!ast_strlen_zero(dst_exten
)) {
2520 /* An invalid extension */
2521 if (ast_exists_extension(c
, c
->context
, "i", 1, c
->cid
.cid_num
)) {
2522 if (option_verbose
> 2)
2523 ast_verbose( VERBOSE_PREFIX_3
"Invalid extension '%s' in context '%s' on %s\n", dst_exten
, c
->context
, c
->name
);
2524 pbx_builtin_setvar_helper(c
, "INVALID_EXTEN", dst_exten
);
2525 set_ext_pri(c
, "i", 1);
2527 ast_log(LOG_WARNING
, "Invalid extension '%s', but no rule 'i' in context '%s'\n", dst_exten
, c
->context
);
2528 found
= 1; /* XXX disable message */
2532 /* A simple timeout */
2533 if (ast_exists_extension(c
, c
->context
, "t", 1, c
->cid
.cid_num
)) {
2534 if (option_verbose
> 2)
2535 ast_verbose( VERBOSE_PREFIX_3
"Timeout on %s\n", c
->name
);
2536 set_ext_pri(c
, "t", 1);
2538 ast_log(LOG_WARNING
, "Timeout, but no rule 't' in context '%s'\n", c
->context
);
2539 found
= 1; /* XXX disable message */
2545 if (option_verbose
> 2)
2546 ast_verbose(VERBOSE_PREFIX_2
"CDR updated on %s\n",c
->name
);
2551 if (!found
&& !error
)
2552 ast_log(LOG_WARNING
, "Don't know what to do with '%s'\n", c
->name
);
2553 if (res
!= AST_PBX_KEEPALIVE
)
2554 ast_softhangup(c
, c
->hangupcause
? c
->hangupcause
: AST_CAUSE_NORMAL_CLEARING
);
2555 if ((res
!= AST_PBX_KEEPALIVE
) && ast_exists_extension(c
, c
->context
, "h", 1, c
->cid
.cid_num
)) {
2556 if (c
->cdr
&& ast_opt_end_cdr_before_h_exten
)
2557 ast_cdr_end(c
->cdr
);
2558 set_ext_pri(c
, "h", 1);
2559 while(ast_exists_extension(c
, c
->context
, c
->exten
, c
->priority
, c
->cid
.cid_num
)) {
2560 if ((res
= ast_spawn_extension(c
, c
->context
, c
->exten
, c
->priority
, c
->cid
.cid_num
))) {
2561 /* Something bad happened, or a hangup has been requested. */
2563 ast_log(LOG_DEBUG
, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c
->context
, c
->exten
, c
->priority
, c
->name
);
2564 if (option_verbose
> 1)
2565 ast_verbose( VERBOSE_PREFIX_2
"Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c
->context
, c
->exten
, c
->priority
, c
->name
);
2571 ast_set2_flag(c
, autoloopflag
, AST_FLAG_IN_AUTOLOOP
);
2573 pbx_destroy(c
->pbx
);
2575 if (res
!= AST_PBX_KEEPALIVE
)
2580 /* Returns 0 on success, non-zero if call limit was reached */
2581 static int increase_call_count(const struct ast_channel
*c
)
2585 ast_mutex_lock(&maxcalllock
);
2586 if (option_maxcalls
) {
2587 if (countcalls
>= option_maxcalls
) {
2588 ast_log(LOG_NOTICE
, "Maximum call limit of %d calls exceeded by '%s'!\n", option_maxcalls
, c
->name
);
2592 if (option_maxload
) {
2593 getloadavg(&curloadavg
, 1);
2594 if (curloadavg
>= option_maxload
) {
2595 ast_log(LOG_NOTICE
, "Maximum loadavg limit of %f load exceeded by '%s' (currently %f)!\n", option_maxload
, c
->name
, curloadavg
);
2601 ast_mutex_unlock(&maxcalllock
);
2606 static void decrease_call_count(void)
2608 ast_mutex_lock(&maxcalllock
);
2611 ast_mutex_unlock(&maxcalllock
);
2614 static void destroy_exten(struct ast_exten
*e
)
2616 if (e
->priority
== PRIORITY_HINT
)
2624 static void *pbx_thread(void *data
)
2626 /* Oh joyeous kernel, we're a new thread, with nothing to do but
2627 answer this channel and get it going.
2630 The launcher of this function _MUST_ increment 'countcalls'
2631 before invoking the function; it will be decremented when the
2632 PBX has finished running on the channel
2634 struct ast_channel
*c
= data
;
2637 decrease_call_count();
2644 enum ast_pbx_result
ast_pbx_start(struct ast_channel
*c
)
2647 pthread_attr_t attr
;
2650 ast_log(LOG_WARNING
, "Asked to start thread on NULL channel?\n");
2651 return AST_PBX_FAILED
;
2654 if (increase_call_count(c
))
2655 return AST_PBX_CALL_LIMIT
;
2657 /* Start a new thread, and get something handling this channel. */
2658 pthread_attr_init(&attr
);
2659 pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
2660 if (ast_pthread_create(&t
, &attr
, pbx_thread
, c
)) {
2661 ast_log(LOG_WARNING
, "Failed to create new channel thread\n");
2662 pthread_attr_destroy(&attr
);
2663 return AST_PBX_FAILED
;
2665 pthread_attr_destroy(&attr
);
2667 return AST_PBX_SUCCESS
;
2670 enum ast_pbx_result
ast_pbx_run(struct ast_channel
*c
)
2672 enum ast_pbx_result res
= AST_PBX_SUCCESS
;
2674 if (increase_call_count(c
))
2675 return AST_PBX_CALL_LIMIT
;
2677 res
= __ast_pbx_run(c
);
2678 decrease_call_count();
2683 int ast_active_calls(void)
2688 int pbx_set_autofallthrough(int newval
)
2690 int oldval
= autofallthrough
;
2691 autofallthrough
= newval
;
2695 /* lookup for a context with a given name,
2696 * return with conlock held if found, NULL if not found
2698 static struct ast_context
*find_context_locked(const char *context
)
2700 struct ast_context
*c
= NULL
;
2702 ast_rdlock_contexts();
2703 while ( (c
= ast_walk_contexts(c
)) ) {
2704 if (!strcmp(ast_get_context_name(c
), context
))
2707 ast_unlock_contexts();
2713 * This function locks contexts list by &conlist, search for the right context
2714 * structure, leave context list locked and call ast_context_remove_include2
2715 * which removes include, unlock contexts list and return ...
2717 int ast_context_remove_include(const char *context
, const char *include
, const char *registrar
)
2720 struct ast_context
*c
= find_context_locked(context
);
2723 /* found, remove include from this context ... */
2724 ret
= ast_context_remove_include2(c
, include
, registrar
);
2725 ast_unlock_contexts();
2731 * When we call this function, &conlock lock must be locked, because when
2732 * we giving *con argument, some process can remove/change this context
2733 * and after that there can be segfault.
2735 * This function locks given context, removes include, unlock context and
2738 int ast_context_remove_include2(struct ast_context
*con
, const char *include
, const char *registrar
)
2740 struct ast_include
*i
, *pi
= NULL
;
2743 ast_mutex_lock(&con
->lock
);
2745 /* find our include */
2746 for (i
= con
->includes
; i
; pi
= i
, i
= i
->next
) {
2747 if (!strcmp(i
->name
, include
) &&
2748 (!registrar
|| !strcmp(i
->registrar
, registrar
))) {
2749 /* remove from list */
2753 con
->includes
= i
->next
;
2754 /* free include and return */
2761 ast_mutex_unlock(&con
->lock
);
2766 * \note This function locks contexts list by &conlist, search for the rigt context
2767 * structure, leave context list locked and call ast_context_remove_switch2
2768 * which removes switch, unlock contexts list and return ...
2770 int ast_context_remove_switch(const char *context
, const char *sw
, const char *data
, const char *registrar
)
2772 int ret
= -1; /* default error return */
2773 struct ast_context
*c
= find_context_locked(context
);
2776 /* remove switch from this context ... */
2777 ret
= ast_context_remove_switch2(c
, sw
, data
, registrar
);
2778 ast_unlock_contexts();
2784 * \brief This function locks given context, removes switch, unlock context and
2786 * \note When we call this function, &conlock lock must be locked, because when
2787 * we giving *con argument, some process can remove/change this context
2788 * and after that there can be segfault.
2791 int ast_context_remove_switch2(struct ast_context
*con
, const char *sw
, const char *data
, const char *registrar
)
2796 ast_mutex_lock(&con
->lock
);
2799 AST_LIST_TRAVERSE_SAFE_BEGIN(&con
->alts
, i
, list
) {
2800 if (!strcmp(i
->name
, sw
) && !strcmp(i
->data
, data
) &&
2801 (!registrar
|| !strcmp(i
->registrar
, registrar
))) {
2802 /* found, remove from list */
2803 AST_LIST_REMOVE_CURRENT(&con
->alts
, list
);
2804 free(i
); /* free switch and return */
2809 AST_LIST_TRAVERSE_SAFE_END
2811 ast_mutex_unlock(&con
->lock
);
2817 * \note This functions lock contexts list, search for the right context,
2818 * call ast_context_remove_extension2, unlock contexts list and return.
2819 * In this function we are using
2821 int ast_context_remove_extension(const char *context
, const char *extension
, int priority
, const char *registrar
)
2823 int ret
= -1; /* default error return */
2824 struct ast_context
*c
= find_context_locked(context
);
2826 if (c
) { /* ... remove extension ... */
2827 ret
= ast_context_remove_extension2(c
, extension
, priority
, registrar
);
2828 ast_unlock_contexts();
2834 * \brief This functionc locks given context, search for the right extension and
2835 * fires out all peer in this extensions with given priority. If priority
2836 * is set to 0, all peers are removed. After that, unlock context and
2838 * \note When do you want to call this function, make sure that &conlock is locked,
2839 * because some process can handle with your *con context before you lock
2843 int ast_context_remove_extension2(struct ast_context
*con
, const char *extension
, int priority
, const char *registrar
)
2845 struct ast_exten
*exten
, *prev_exten
= NULL
;
2846 struct ast_exten
*peer
;
2848 ast_mutex_lock(&con
->lock
);
2850 /* scan the extension list to find matching extension-registrar */
2851 for (exten
= con
->root
; exten
; prev_exten
= exten
, exten
= exten
->next
) {
2852 if (!strcmp(exten
->exten
, extension
) &&
2853 (!registrar
|| !strcmp(exten
->registrar
, registrar
)))
2857 /* we can't find right extension */
2858 ast_mutex_unlock(&con
->lock
);
2862 /* should we free all peers in this extension? (priority == 0)? */
2863 if (priority
== 0) {
2864 /* remove this extension from context list */
2866 prev_exten
->next
= exten
->next
;
2868 con
->root
= exten
->next
;
2870 /* fire out all peers */
2871 while ( (peer
= exten
) ) {
2872 exten
= peer
->peer
; /* prepare for next entry */
2873 destroy_exten(peer
);
2876 /* scan the priority list to remove extension with exten->priority == priority */
2877 struct ast_exten
*previous_peer
= NULL
;
2879 for (peer
= exten
; peer
; previous_peer
= peer
, peer
= peer
->peer
) {
2880 if (peer
->priority
== priority
&&
2881 (!registrar
|| !strcmp(peer
->registrar
, registrar
) ))
2882 break; /* found our priority */
2884 if (!peer
) { /* not found */
2885 ast_mutex_unlock(&con
->lock
);
2888 /* we are first priority extension? */
2889 if (!previous_peer
) {
2891 * We are first in the priority chain, so must update the extension chain.
2892 * The next node is either the next priority or the next extension
2894 struct ast_exten
*next_node
= peer
->peer
? peer
->peer
: peer
->next
;
2896 if (!prev_exten
) /* change the root... */
2897 con
->root
= next_node
;
2899 prev_exten
->next
= next_node
; /* unlink */
2900 if (peer
->peer
) /* XXX update the new head of the pri list */
2901 peer
->peer
->next
= peer
->next
;
2902 } else { /* easy, we are not first priority in extension */
2903 previous_peer
->peer
= peer
->peer
;
2906 /* now, free whole priority extension */
2907 destroy_exten(peer
);
2908 /* XXX should we return -1 ? */
2910 ast_mutex_unlock(&con
->lock
);
2916 * \note This function locks contexts list by &conlist, searches for the right context
2917 * structure, and locks the macrolock mutex in that context.
2918 * macrolock is used to limit a macro to be executed by one call at a time.
2920 int ast_context_lockmacro(const char *context
)
2922 struct ast_context
*c
= NULL
;
2925 ast_rdlock_contexts();
2927 while ((c
= ast_walk_contexts(c
))) {
2928 if (!strcmp(ast_get_context_name(c
), context
)) {
2934 ast_unlock_contexts();
2936 /* if we found context, lock macrolock */
2938 ret
= ast_mutex_lock(&c
->macrolock
);
2944 * \note This function locks contexts list by &conlist, searches for the right context
2945 * structure, and unlocks the macrolock mutex in that context.
2946 * macrolock is used to limit a macro to be executed by one call at a time.
2948 int ast_context_unlockmacro(const char *context
)
2950 struct ast_context
*c
= NULL
;
2953 ast_rdlock_contexts();
2955 while ((c
= ast_walk_contexts(c
))) {
2956 if (!strcmp(ast_get_context_name(c
), context
)) {
2962 ast_unlock_contexts();
2964 /* if we found context, unlock macrolock */
2966 ret
= ast_mutex_unlock(&c
->macrolock
);
2971 /*! \brief Dynamically register a new dial plan application */
2972 int ast_register_application(const char *app
, int (*execute
)(struct ast_channel
*, void *), const char *synopsis
, const char *description
)
2974 struct ast_app
*tmp
, *cur
= NULL
;
2978 AST_LIST_LOCK(&apps
);
2979 AST_LIST_TRAVERSE(&apps
, tmp
, list
) {
2980 if (!strcasecmp(app
, tmp
->name
)) {
2981 ast_log(LOG_WARNING
, "Already have an application '%s'\n", app
);
2982 AST_LIST_UNLOCK(&apps
);
2987 length
= sizeof(*tmp
) + strlen(app
) + 1;
2989 if (!(tmp
= ast_calloc(1, length
))) {
2990 AST_LIST_UNLOCK(&apps
);
2994 strcpy(tmp
->name
, app
);
2995 tmp
->execute
= execute
;
2996 tmp
->synopsis
= synopsis
;
2997 tmp
->description
= description
;
2999 /* Store in alphabetical order */
3000 AST_LIST_TRAVERSE_SAFE_BEGIN(&apps
, cur
, list
) {
3001 if (strcasecmp(tmp
->name
, cur
->name
) < 0) {
3002 AST_LIST_INSERT_BEFORE_CURRENT(&apps
, tmp
, list
);
3006 AST_LIST_TRAVERSE_SAFE_END
3008 AST_LIST_INSERT_TAIL(&apps
, tmp
, list
);
3010 if (option_verbose
> 1)
3011 ast_verbose( VERBOSE_PREFIX_2
"Registered application '%s'\n", term_color(tmps
, tmp
->name
, COLOR_BRCYAN
, 0, sizeof(tmps
)));
3013 AST_LIST_UNLOCK(&apps
);
3019 * Append to the list. We don't have a tail pointer because we need
3020 * to scan the list anyways to check for duplicates during insertion.
3022 int ast_register_switch(struct ast_switch
*sw
)
3024 struct ast_switch
*tmp
;
3026 AST_LIST_LOCK(&switches
);
3027 AST_LIST_TRAVERSE(&switches
, tmp
, list
) {
3028 if (!strcasecmp(tmp
->name
, sw
->name
)) {
3029 AST_LIST_UNLOCK(&switches
);
3030 ast_log(LOG_WARNING
, "Switch '%s' already found\n", sw
->name
);
3034 AST_LIST_INSERT_TAIL(&switches
, sw
, list
);
3035 AST_LIST_UNLOCK(&switches
);
3040 void ast_unregister_switch(struct ast_switch
*sw
)
3042 AST_LIST_LOCK(&switches
);
3043 AST_LIST_REMOVE(&switches
, sw
, list
);
3044 AST_LIST_UNLOCK(&switches
);
3048 * Help for CLI commands ...
3050 static char show_applications_help
[] =
3051 "Usage: core show applications [{like|describing} <text>]\n"
3052 " List applications which are currently available.\n"
3053 " If 'like', <text> will be a substring of the app name\n"
3054 " If 'describing', <text> will be a substring of the description\n";
3056 static char show_functions_help
[] =
3057 "Usage: core show functions [like <text>]\n"
3058 " List builtin functions, optionally only those matching a given string\n";
3060 static char show_switches_help
[] =
3061 "Usage: core show switches\n"
3062 " List registered switches\n";
3064 static char show_hints_help
[] =
3065 "Usage: core show hints\n"
3066 " List registered hints\n";
3068 static char show_globals_help
[] =
3069 "Usage: core show globals\n"
3070 " List current global dialplan variables and their values\n";
3072 static char show_application_help
[] =
3073 "Usage: core show application <application> [<application> [<application> [...]]]\n"
3074 " Describes a particular application.\n";
3076 static char show_function_help
[] =
3077 "Usage: core show function <function>\n"
3078 " Describe a particular dialplan function.\n";
3080 static char show_dialplan_help
[] =
3081 "Usage: dialplan show [exten@][context]\n"
3084 static char set_global_help
[] =
3085 "Usage: core set global <name> <value>\n"
3086 " Set global dialplan variable <name> to <value>\n";
3090 * \brief 'show application' CLI command implementation functions ...
3094 * There is a possibility to show informations about more than one
3095 * application at one time. You can type 'show application Dial Echo' and
3096 * you will see informations about these two applications ...
3098 static char *complete_show_application(const char *line
, const char *word
, int pos
, int state
)
3103 int wordlen
= strlen(word
);
3105 /* return the n-th [partial] matching entry */
3106 AST_LIST_LOCK(&apps
);
3107 AST_LIST_TRAVERSE(&apps
, a
, list
) {
3108 if (!strncasecmp(word
, a
->name
, wordlen
) && ++which
> state
) {
3109 ret
= strdup(a
->name
);
3113 AST_LIST_UNLOCK(&apps
);
3118 static int handle_show_application_deprecated(int fd
, int argc
, char *argv
[])
3121 int app
, no_registered_app
= 1;
3124 return RESULT_SHOWUSAGE
;
3126 /* ... go through all applications ... */
3127 AST_LIST_LOCK(&apps
);
3128 AST_LIST_TRAVERSE(&apps
, a
, list
) {
3129 /* ... compare this application name with all arguments given
3130 * to 'show application' command ... */
3131 for (app
= 2; app
< argc
; app
++) {
3132 if (!strcasecmp(a
->name
, argv
[app
])) {
3133 /* Maximum number of characters added by terminal coloring is 22 */
3134 char infotitle
[64 + AST_MAX_APP
+ 22], syntitle
[40], destitle
[40];
3135 char info
[64 + AST_MAX_APP
], *synopsis
= NULL
, *description
= NULL
;
3136 int synopsis_size
, description_size
;
3138 no_registered_app
= 0;
3141 synopsis_size
= strlen(a
->synopsis
) + 23;
3143 synopsis_size
= strlen("Not available") + 23;
3144 synopsis
= alloca(synopsis_size
);
3147 description_size
= strlen(a
->description
) + 23;
3149 description_size
= strlen("Not available") + 23;
3150 description
= alloca(description_size
);
3152 if (synopsis
&& description
) {
3153 snprintf(info
, 64 + AST_MAX_APP
, "\n -= Info about application '%s' =- \n\n", a
->name
);
3154 term_color(infotitle
, info
, COLOR_MAGENTA
, 0, 64 + AST_MAX_APP
+ 22);
3155 term_color(syntitle
, "[Synopsis]\n", COLOR_MAGENTA
, 0, 40);
3156 term_color(destitle
, "[Description]\n", COLOR_MAGENTA
, 0, 40);
3157 term_color(synopsis
,
3158 a
->synopsis
? a
->synopsis
: "Not available",
3159 COLOR_CYAN
, 0, synopsis_size
);
3160 term_color(description
,
3161 a
->description
? a
->description
: "Not available",
3162 COLOR_CYAN
, 0, description_size
);
3164 ast_cli(fd
,"%s%s%s\n\n%s%s\n", infotitle
, syntitle
, synopsis
, destitle
, description
);
3166 /* ... one of our applications, show info ...*/
3167 ast_cli(fd
,"\n -= Info about application '%s' =- \n\n"
3168 "[Synopsis]\n %s\n\n"
3169 "[Description]\n%s\n",
3171 a
->synopsis
? a
->synopsis
: "Not available",
3172 a
->description
? a
->description
: "Not available");
3177 AST_LIST_UNLOCK(&apps
);
3179 /* we found at least one app? no? */
3180 if (no_registered_app
) {
3181 ast_cli(fd
, "Your application(s) is (are) not registered\n");
3182 return RESULT_FAILURE
;
3185 return RESULT_SUCCESS
;
3188 static int handle_show_application(int fd
, int argc
, char *argv
[])
3191 int app
, no_registered_app
= 1;
3194 return RESULT_SHOWUSAGE
;
3196 /* ... go through all applications ... */
3197 AST_LIST_LOCK(&apps
);
3198 AST_LIST_TRAVERSE(&apps
, a
, list
) {
3199 /* ... compare this application name with all arguments given
3200 * to 'show application' command ... */
3201 for (app
= 3; app
< argc
; app
++) {
3202 if (!strcasecmp(a
->name
, argv
[app
])) {
3203 /* Maximum number of characters added by terminal coloring is 22 */
3204 char infotitle
[64 + AST_MAX_APP
+ 22], syntitle
[40], destitle
[40];
3205 char info
[64 + AST_MAX_APP
], *synopsis
= NULL
, *description
= NULL
;
3206 int synopsis_size
, description_size
;
3208 no_registered_app
= 0;
3211 synopsis_size
= strlen(a
->synopsis
) + 23;
3213 synopsis_size
= strlen("Not available") + 23;
3214 synopsis
= alloca(synopsis_size
);
3217 description_size
= strlen(a
->description
) + 23;
3219 description_size
= strlen("Not available") + 23;
3220 description
= alloca(description_size
);
3222 if (synopsis
&& description
) {
3223 snprintf(info
, 64 + AST_MAX_APP
, "\n -= Info about application '%s' =- \n\n", a
->name
);
3224 term_color(infotitle
, info
, COLOR_MAGENTA
, 0, 64 + AST_MAX_APP
+ 22);
3225 term_color(syntitle
, "[Synopsis]\n", COLOR_MAGENTA
, 0, 40);
3226 term_color(destitle
, "[Description]\n", COLOR_MAGENTA
, 0, 40);
3227 term_color(synopsis
,
3228 a
->synopsis
? a
->synopsis
: "Not available",
3229 COLOR_CYAN
, 0, synopsis_size
);
3230 term_color(description
,
3231 a
->description
? a
->description
: "Not available",
3232 COLOR_CYAN
, 0, description_size
);
3234 ast_cli(fd
,"%s%s%s\n\n%s%s\n", infotitle
, syntitle
, synopsis
, destitle
, description
);
3236 /* ... one of our applications, show info ...*/
3237 ast_cli(fd
,"\n -= Info about application '%s' =- \n\n"
3238 "[Synopsis]\n %s\n\n"
3239 "[Description]\n%s\n",
3241 a
->synopsis
? a
->synopsis
: "Not available",
3242 a
->description
? a
->description
: "Not available");
3247 AST_LIST_UNLOCK(&apps
);
3249 /* we found at least one app? no? */
3250 if (no_registered_app
) {
3251 ast_cli(fd
, "Your application(s) is (are) not registered\n");
3252 return RESULT_FAILURE
;
3255 return RESULT_SUCCESS
;
3258 /*! \brief handle_show_hints: CLI support for listing registred dial plan hints */
3259 static int handle_show_hints(int fd
, int argc
, char *argv
[])
3261 struct ast_hint
*hint
;
3264 struct ast_state_cb
*watcher
;
3266 if (AST_LIST_EMPTY(&hints
)) {
3267 ast_cli(fd
, "There are no registered dialplan hints\n");
3268 return RESULT_SUCCESS
;
3270 /* ... we have hints ... */
3271 ast_cli(fd
, "\n -= Registered Asterisk Dial Plan Hints =-\n");
3272 AST_LIST_LOCK(&hints
);
3273 AST_LIST_TRAVERSE(&hints
, hint
, list
) {
3275 for (watcher
= hint
->callbacks
; watcher
; watcher
= watcher
->next
)
3277 ast_cli(fd
, " %20s@%-20.20s: %-20.20s State:%-15.15s Watchers %2d\n",
3278 ast_get_extension_name(hint
->exten
),
3279 ast_get_context_name(ast_get_extension_context(hint
->exten
)),
3280 ast_get_extension_app(hint
->exten
),
3281 ast_extension_state2str(hint
->laststate
), watchers
);
3284 ast_cli(fd
, "----------------\n");
3285 ast_cli(fd
, "- %d hints registered\n", num
);
3286 AST_LIST_UNLOCK(&hints
);
3287 return RESULT_SUCCESS
;
3290 /*! \brief handle_show_switches: CLI support for listing registred dial plan switches */
3291 static int handle_show_switches(int fd
, int argc
, char *argv
[])
3293 struct ast_switch
*sw
;
3295 AST_LIST_LOCK(&switches
);
3297 if (AST_LIST_EMPTY(&switches
)) {
3298 AST_LIST_UNLOCK(&switches
);
3299 ast_cli(fd
, "There are no registered alternative switches\n");
3300 return RESULT_SUCCESS
;
3303 ast_cli(fd
, "\n -= Registered Asterisk Alternative Switches =-\n");
3304 AST_LIST_TRAVERSE(&switches
, sw
, list
)
3305 ast_cli(fd
, "%s: %s\n", sw
->name
, sw
->description
);
3307 AST_LIST_UNLOCK(&switches
);
3309 return RESULT_SUCCESS
;
3313 * 'show applications' CLI command implementation functions ...
3315 static int handle_show_applications_deprecated(int fd
, int argc
, char *argv
[])
3318 int like
= 0, describing
= 0;
3319 int total_match
= 0; /* Number of matches in like clause */
3320 int total_apps
= 0; /* Number of apps registered */
3322 AST_LIST_LOCK(&apps
);
3324 if (AST_LIST_EMPTY(&apps
)) {
3325 ast_cli(fd
, "There are no registered applications\n");
3326 AST_LIST_UNLOCK(&apps
);
3330 /* show applications like <keyword> */
3331 if ((argc
== 4) && (!strcmp(argv
[2], "like"))) {
3333 } else if ((argc
> 3) && (!strcmp(argv
[2], "describing"))) {
3337 /* show applications describing <keyword1> [<keyword2>] [...] */
3338 if ((!like
) && (!describing
)) {
3339 ast_cli(fd
, " -= Registered Asterisk Applications =-\n");
3341 ast_cli(fd
, " -= Matching Asterisk Applications =-\n");
3344 AST_LIST_TRAVERSE(&apps
, a
, list
) {
3348 if (strcasestr(a
->name
, argv
[3])) {
3352 } else if (describing
) {
3353 if (a
->description
) {
3354 /* Match all words on command line */
3357 for (i
= 3; i
< argc
; i
++) {
3358 if (!strcasestr(a
->description
, argv
[i
])) {
3370 ast_cli(fd
," %20s: %s\n", a
->name
, a
->synopsis
? a
->synopsis
: "<Synopsis not available>");
3373 if ((!like
) && (!describing
)) {
3374 ast_cli(fd
, " -= %d Applications Registered =-\n",total_apps
);
3376 ast_cli(fd
, " -= %d Applications Matching =-\n",total_match
);
3379 AST_LIST_UNLOCK(&apps
);
3381 return RESULT_SUCCESS
;
3383 static int handle_show_applications(int fd
, int argc
, char *argv
[])
3386 int like
= 0, describing
= 0;
3387 int total_match
= 0; /* Number of matches in like clause */
3388 int total_apps
= 0; /* Number of apps registered */
3390 AST_LIST_LOCK(&apps
);
3392 if (AST_LIST_EMPTY(&apps
)) {
3393 ast_cli(fd
, "There are no registered applications\n");
3394 AST_LIST_UNLOCK(&apps
);
3398 /* core list applications like <keyword> */
3399 if ((argc
== 5) && (!strcmp(argv
[3], "like"))) {
3401 } else if ((argc
> 4) && (!strcmp(argv
[3], "describing"))) {
3405 /* core list applications describing <keyword1> [<keyword2>] [...] */
3406 if ((!like
) && (!describing
)) {
3407 ast_cli(fd
, " -= Registered Asterisk Applications =-\n");
3409 ast_cli(fd
, " -= Matching Asterisk Applications =-\n");
3412 AST_LIST_TRAVERSE(&apps
, a
, list
) {
3416 if (strcasestr(a
->name
, argv
[4])) {
3420 } else if (describing
) {
3421 if (a
->description
) {
3422 /* Match all words on command line */
3425 for (i
= 4; i
< argc
; i
++) {
3426 if (!strcasestr(a
->description
, argv
[i
])) {
3438 ast_cli(fd
," %20s: %s\n", a
->name
, a
->synopsis
? a
->synopsis
: "<Synopsis not available>");
3441 if ((!like
) && (!describing
)) {
3442 ast_cli(fd
, " -= %d Applications Registered =-\n",total_apps
);
3444 ast_cli(fd
, " -= %d Applications Matching =-\n",total_match
);
3447 AST_LIST_UNLOCK(&apps
);
3449 return RESULT_SUCCESS
;
3452 static char *complete_show_applications_deprecated(const char *line
, const char *word
, int pos
, int state
)
3454 static char* choices
[] = { "like", "describing", NULL
};
3456 return (pos
!= 2) ? NULL
: ast_cli_complete(word
, choices
, state
);
3459 static char *complete_show_applications(const char *line
, const char *word
, int pos
, int state
)
3461 static char* choices
[] = { "like", "describing", NULL
};
3463 return (pos
!= 3) ? NULL
: ast_cli_complete(word
, choices
, state
);
3467 * 'show dialplan' CLI command implementation functions ...
3469 static char *complete_show_dialplan_context(const char *line
, const char *word
, int pos
,
3472 struct ast_context
*c
= NULL
;
3477 /* we are do completion of [exten@]context on second position only */
3481 ast_rdlock_contexts();
3483 wordlen
= strlen(word
);
3485 /* walk through all contexts and return the n-th match */
3486 while ( (c
= ast_walk_contexts(c
)) ) {
3487 if (!strncasecmp(word
, ast_get_context_name(c
), wordlen
) && ++which
> state
) {
3488 ret
= ast_strdup(ast_get_context_name(c
));
3493 ast_unlock_contexts();
3498 struct dialplan_counters
{
3502 int context_existence
;
3503 int extension_existence
;
3506 /*! \brief helper function to print an extension */
3507 static void print_ext(struct ast_exten
*e
, char * buf
, int buflen
)
3509 int prio
= ast_get_extension_priority(e
);
3510 if (prio
== PRIORITY_HINT
) {
3511 snprintf(buf
, buflen
, "hint: %s",
3512 ast_get_extension_app(e
));
3514 snprintf(buf
, buflen
, "%d. %s(%s)",
3515 prio
, ast_get_extension_app(e
),
3516 (!ast_strlen_zero(ast_get_extension_app_data(e
)) ? (char *)ast_get_extension_app_data(e
) : ""));
3520 /* XXX not verified */
3521 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
[])
3523 struct ast_context
*c
= NULL
;
3524 int res
= 0, old_total_exten
= dpc
->total_exten
;
3526 ast_rdlock_contexts();
3528 /* walk all contexts ... */
3529 while ( (c
= ast_walk_contexts(c
)) ) {
3530 struct ast_exten
*e
;
3531 struct ast_include
*i
;
3532 struct ast_ignorepat
*ip
;
3533 char buf
[256], buf2
[256];
3534 int context_info_printed
= 0;
3536 if (context
&& strcmp(ast_get_context_name(c
), context
))
3537 continue; /* skip this one, name doesn't match */
3539 dpc
->context_existence
= 1;
3541 ast_lock_context(c
);
3543 /* are we looking for exten too? if yes, we print context
3544 * only if we find our extension.
3545 * Otherwise print context even if empty ?
3546 * XXX i am not sure how the rinclude is handled.
3547 * I think it ought to go inside.
3550 dpc
->total_context
++;
3551 ast_cli(fd
, "[ Context '%s' created by '%s' ]\n",
3552 ast_get_context_name(c
), ast_get_context_registrar(c
));
3553 context_info_printed
= 1;
3556 /* walk extensions ... */
3558 while ( (e
= ast_walk_context_extensions(c
, e
)) ) {
3559 struct ast_exten
*p
;
3561 if (exten
&& !ast_extension_match(ast_get_extension_name(e
), exten
))
3562 continue; /* skip, extension match failed */
3564 dpc
->extension_existence
= 1;
3566 /* may we print context info? */
3567 if (!context_info_printed
) {
3568 dpc
->total_context
++;
3569 if (rinclude
) { /* TODO Print more info about rinclude */
3570 ast_cli(fd
, "[ Included context '%s' created by '%s' ]\n",
3571 ast_get_context_name(c
), ast_get_context_registrar(c
));
3573 ast_cli(fd
, "[ Context '%s' created by '%s' ]\n",
3574 ast_get_context_name(c
), ast_get_context_registrar(c
));
3576 context_info_printed
= 1;
3580 /* write extension name and first peer */
3581 snprintf(buf
, sizeof(buf
), "'%s' =>", ast_get_extension_name(e
));
3583 print_ext(e
, buf2
, sizeof(buf2
));
3585 ast_cli(fd
, " %-17s %-45s [%s]\n", buf
, buf2
,
3586 ast_get_extension_registrar(e
));
3589 /* walk next extension peers */
3590 p
= e
; /* skip the first one, we already got it */
3591 while ( (p
= ast_walk_extension_priorities(e
, p
)) ) {
3592 const char *el
= ast_get_extension_label(p
);
3595 snprintf(buf
, sizeof(buf
), " [%s]", el
);
3598 print_ext(p
, buf2
, sizeof(buf2
));
3600 ast_cli(fd
," %-17s %-45s [%s]\n", buf
, buf2
,
3601 ast_get_extension_registrar(p
));
3605 /* walk included and write info ... */
3607 while ( (i
= ast_walk_context_includes(c
, i
)) ) {
3608 snprintf(buf
, sizeof(buf
), "'%s'", ast_get_include_name(i
));
3610 /* Check all includes for the requested extension */
3611 if (includecount
>= AST_PBX_MAX_STACK
) {
3612 ast_log(LOG_NOTICE
, "Maximum include depth exceeded!\n");
3616 for (x
=0;x
<includecount
;x
++) {
3617 if (!strcasecmp(includes
[x
], ast_get_include_name(i
))) {
3623 includes
[includecount
] = ast_get_include_name(i
);
3624 show_dialplan_helper(fd
, ast_get_include_name(i
), exten
, dpc
, i
, includecount
+ 1, includes
);
3626 ast_log(LOG_WARNING
, "Avoiding circular include of %s within %s\n", ast_get_include_name(i
), context
);
3630 ast_cli(fd
, " Include => %-45s [%s]\n",
3631 buf
, ast_get_include_registrar(i
));
3635 /* walk ignore patterns and write info ... */
3637 while ( (ip
= ast_walk_context_ignorepats(c
, ip
)) ) {
3638 const char *ipname
= ast_get_ignorepat_name(ip
);
3639 char ignorepat
[AST_MAX_EXTENSION
];
3640 snprintf(buf
, sizeof(buf
), "'%s'", ipname
);
3641 snprintf(ignorepat
, sizeof(ignorepat
), "_%s.", ipname
);
3642 if (!exten
|| ast_extension_match(ignorepat
, exten
)) {
3643 ast_cli(fd
, " Ignore pattern => %-45s [%s]\n",
3644 buf
, ast_get_ignorepat_registrar(ip
));
3648 struct ast_sw
*sw
= NULL
;
3649 while ( (sw
= ast_walk_context_switches(c
, sw
)) ) {
3650 snprintf(buf
, sizeof(buf
), "'%s/%s'",
3651 ast_get_switch_name(sw
),
3652 ast_get_switch_data(sw
));
3653 ast_cli(fd
, " Alt. Switch => %-45s [%s]\n",
3654 buf
, ast_get_switch_registrar(sw
));
3658 ast_unlock_context(c
);
3660 /* if we print something in context, make an empty line */
3661 if (context_info_printed
)
3662 ast_cli(fd
, "\r\n");
3664 ast_unlock_contexts();
3666 return (dpc
->total_exten
== old_total_exten
) ? -1 : res
;
3669 static int handle_show_dialplan(int fd
, int argc
, char *argv
[])
3671 char *exten
= NULL
, *context
= NULL
;
3672 /* Variables used for different counters */
3673 struct dialplan_counters counters
;
3675 const char *incstack
[AST_PBX_MAX_STACK
];
3676 memset(&counters
, 0, sizeof(counters
));
3678 if (argc
!= 2 && argc
!= 3)
3679 return RESULT_SHOWUSAGE
;
3681 /* we obtain [exten@]context? if yes, split them ... */
3683 if (strchr(argv
[2], '@')) { /* split into exten & context */
3684 context
= ast_strdupa(argv
[2]);
3685 exten
= strsep(&context
, "@");
3686 /* change empty strings to NULL */
3687 if (ast_strlen_zero(exten
))
3689 } else { /* no '@' char, only context given */
3692 if (ast_strlen_zero(context
))
3695 /* else Show complete dial plan, context and exten are NULL */
3696 show_dialplan_helper(fd
, context
, exten
, &counters
, NULL
, 0, incstack
);
3698 /* check for input failure and throw some error messages */
3699 if (context
&& !counters
.context_existence
) {
3700 ast_cli(fd
, "There is no existence of '%s' context\n", context
);
3701 return RESULT_FAILURE
;
3704 if (exten
&& !counters
.extension_existence
) {
3706 ast_cli(fd
, "There is no existence of %s@%s extension\n",
3710 "There is no existence of '%s' extension in all contexts\n",
3712 return RESULT_FAILURE
;
3715 ast_cli(fd
,"-= %d %s (%d %s) in %d %s. =-\n",
3716 counters
.total_exten
, counters
.total_exten
== 1 ? "extension" : "extensions",
3717 counters
.total_prio
, counters
.total_prio
== 1 ? "priority" : "priorities",
3718 counters
.total_context
, counters
.total_context
== 1 ? "context" : "contexts");
3721 return RESULT_SUCCESS
;
3724 /*! \brief CLI support for listing global variables in a parseable way */
3725 static int handle_show_globals(int fd
, int argc
, char *argv
[])
3728 struct ast_var_t
*newvariable
;
3730 ast_mutex_lock(&globalslock
);
3731 AST_LIST_TRAVERSE (&globals
, newvariable
, entries
) {
3733 ast_cli(fd
, " %s=%s\n", ast_var_name(newvariable
), ast_var_value(newvariable
));
3735 ast_mutex_unlock(&globalslock
);
3736 ast_cli(fd
, "\n -- %d variables\n", i
);
3738 return RESULT_SUCCESS
;
3741 /*! \brief CLI support for setting global variables */
3742 static int handle_set_global_deprecated(int fd
, int argc
, char *argv
[])
3745 return RESULT_SHOWUSAGE
;
3747 pbx_builtin_setvar_helper(NULL
, argv
[2], argv
[3]);
3748 ast_cli(fd
, "\n -- Global variable %s set to %s\n", argv
[2], argv
[3]);
3750 return RESULT_SUCCESS
;
3754 static int handle_set_global(int fd
, int argc
, char *argv
[])
3757 return RESULT_SHOWUSAGE
;
3759 pbx_builtin_setvar_helper(NULL
, argv
[3], argv
[4]);
3760 ast_cli(fd
, "\n -- Global variable %s set to %s\n", argv
[3], argv
[4]);
3762 return RESULT_SUCCESS
;
3768 * CLI entries for upper commands ...
3770 static struct ast_cli_entry cli_show_applications_deprecated
= {
3771 { "show", "applications", NULL
},
3772 handle_show_applications_deprecated
, NULL
,
3773 NULL
, complete_show_applications_deprecated
};
3775 static struct ast_cli_entry cli_show_functions_deprecated
= {
3776 { "show", "functions", NULL
},
3777 handle_show_functions_deprecated
, NULL
,
3780 static struct ast_cli_entry cli_show_switches_deprecated
= {
3781 { "show", "switches", NULL
},
3782 handle_show_switches
, NULL
,
3785 static struct ast_cli_entry cli_show_hints_deprecated
= {
3786 { "show", "hints", NULL
},
3787 handle_show_hints
, NULL
,
3790 static struct ast_cli_entry cli_show_globals_deprecated
= {
3791 { "show", "globals", NULL
},
3792 handle_show_globals
, NULL
,
3795 static struct ast_cli_entry cli_show_function_deprecated
= {
3796 { "show" , "function", NULL
},
3797 handle_show_function_deprecated
, NULL
,
3798 NULL
, complete_show_function
};
3800 static struct ast_cli_entry cli_show_application_deprecated
= {
3801 { "show", "application", NULL
},
3802 handle_show_application_deprecated
, NULL
,
3803 NULL
, complete_show_application
};
3805 static struct ast_cli_entry cli_show_dialplan_deprecated
= {
3806 { "show", "dialplan", NULL
},
3807 handle_show_dialplan
, NULL
,
3808 NULL
, complete_show_dialplan_context
};
3810 static struct ast_cli_entry cli_set_global_deprecated
= {
3811 { "set", "global", NULL
},
3812 handle_set_global_deprecated
, NULL
,
3815 static struct ast_cli_entry pbx_cli
[] = {
3816 { { "core", "show", "applications", NULL
},
3817 handle_show_applications
, "Shows registered dialplan applications",
3818 show_applications_help
, complete_show_applications
, &cli_show_applications_deprecated
},
3820 { { "core", "show", "functions", NULL
},
3821 handle_show_functions
, "Shows registered dialplan functions",
3822 show_functions_help
, NULL
, &cli_show_functions_deprecated
},
3824 { { "core", "show", "switches", NULL
},
3825 handle_show_switches
, "Show alternative switches",
3826 show_switches_help
, NULL
, &cli_show_switches_deprecated
},
3828 { { "core", "show", "hints", NULL
},
3829 handle_show_hints
, "Show dialplan hints",
3830 show_hints_help
, NULL
, &cli_show_hints_deprecated
},
3832 { { "core", "show", "globals", NULL
},
3833 handle_show_globals
, "Show global dialplan variables",
3834 show_globals_help
, NULL
, &cli_show_globals_deprecated
},
3836 { { "core", "show" , "function", NULL
},
3837 handle_show_function
, "Describe a specific dialplan function",
3838 show_function_help
, complete_show_function
, &cli_show_function_deprecated
},
3840 { { "core", "show", "application", NULL
},
3841 handle_show_application
, "Describe a specific dialplan application",
3842 show_application_help
, complete_show_application
, &cli_show_application_deprecated
},
3844 { { "core", "set", "global", NULL
},
3845 handle_set_global
, "Set global dialplan variable",
3846 set_global_help
, NULL
, &cli_set_global_deprecated
},
3848 { { "dialplan", "show", NULL
},
3849 handle_show_dialplan
, "Show dialplan",
3850 show_dialplan_help
, complete_show_dialplan_context
, &cli_show_dialplan_deprecated
},
3853 int ast_unregister_application(const char *app
)
3855 struct ast_app
*tmp
;
3857 AST_LIST_LOCK(&apps
);
3858 AST_LIST_TRAVERSE_SAFE_BEGIN(&apps
, tmp
, list
) {
3859 if (!strcasecmp(app
, tmp
->name
)) {
3860 AST_LIST_REMOVE_CURRENT(&apps
, list
);
3861 if (option_verbose
> 1)
3862 ast_verbose( VERBOSE_PREFIX_2
"Unregistered application '%s'\n", tmp
->name
);
3867 AST_LIST_TRAVERSE_SAFE_END
3868 AST_LIST_UNLOCK(&apps
);
3870 return tmp
? 0 : -1;
3873 static struct ast_context
*__ast_context_create(struct ast_context
**extcontexts
, const char *name
, const char *registrar
, int existsokay
)
3875 struct ast_context
*tmp
, **local_contexts
;
3876 int length
= sizeof(struct ast_context
) + strlen(name
) + 1;
3879 ast_rdlock_contexts();
3880 local_contexts
= &contexts
;
3882 local_contexts
= extcontexts
;
3884 for (tmp
= *local_contexts
; tmp
; tmp
= tmp
->next
) {
3885 if (!strcasecmp(tmp
->name
, name
)) {
3887 ast_log(LOG_WARNING
, "Tried to register context '%s', already in use\n", name
);
3891 ast_unlock_contexts();
3897 ast_unlock_contexts();
3899 if ((tmp
= ast_calloc(1, length
))) {
3900 ast_mutex_init(&tmp
->lock
);
3901 ast_mutex_init(&tmp
->macrolock
);
3902 strcpy(tmp
->name
, name
);
3903 tmp
->registrar
= registrar
;
3905 ast_wrlock_contexts();
3906 tmp
->next
= *local_contexts
;
3907 *local_contexts
= tmp
;
3909 ast_unlock_contexts();
3911 ast_log(LOG_DEBUG
, "Registered context '%s'\n", tmp
->name
);
3912 if (option_verbose
> 2)
3913 ast_verbose( VERBOSE_PREFIX_3
"Registered extension context '%s'\n", tmp
->name
);
3919 struct ast_context
*ast_context_create(struct ast_context
**extcontexts
, const char *name
, const char *registrar
)
3921 return __ast_context_create(extcontexts
, name
, registrar
, 0);
3924 struct ast_context
*ast_context_find_or_create(struct ast_context
**extcontexts
, const char *name
, const char *registrar
)
3926 return __ast_context_create(extcontexts
, name
, registrar
, 1);
3928 void __ast_context_destroy(struct ast_context
*con
, const char *registrar
);
3933 struct ast_state_cb
*callbacks
;
3935 AST_LIST_ENTRY(store_hint
) list
;
3939 AST_LIST_HEAD(store_hints
, store_hint
);
3941 /* XXX this does not check that multiple contexts are merged */
3942 void ast_merge_contexts_and_delete(struct ast_context
**extcontexts
, const char *registrar
)
3944 struct ast_context
*tmp
, *lasttmp
= NULL
;
3945 struct store_hints store
= AST_LIST_HEAD_INIT_VALUE
;
3946 struct store_hint
*this;
3947 struct ast_hint
*hint
;
3948 struct ast_exten
*exten
;
3950 struct ast_state_cb
*thiscb
, *prevcb
;
3952 /* it is very important that this function hold the hint list lock _and_ the conlock
3953 during its operation; not only do we need to ensure that the list of contexts
3954 and extensions does not change, but also that no hint callbacks (watchers) are
3955 added or removed during the merge/delete process
3957 in addition, the locks _must_ be taken in this order, because there are already
3958 other code paths that use this order
3960 ast_wrlock_contexts();
3961 AST_LIST_LOCK(&hints
);
3963 /* preserve all watchers for hints associated with this registrar */
3964 AST_LIST_TRAVERSE(&hints
, hint
, list
) {
3965 if (hint
->callbacks
&& !strcmp(registrar
, hint
->exten
->parent
->registrar
)) {
3966 length
= strlen(hint
->exten
->exten
) + strlen(hint
->exten
->parent
->name
) + 2 + sizeof(*this);
3967 if (!(this = ast_calloc(1, length
)))
3969 this->callbacks
= hint
->callbacks
;
3970 hint
->callbacks
= NULL
;
3971 this->laststate
= hint
->laststate
;
3972 this->context
= this->data
;
3973 strcpy(this->data
, hint
->exten
->parent
->name
);
3974 this->exten
= this->data
+ strlen(this->context
) + 1;
3975 strcpy(this->exten
, hint
->exten
->exten
);
3976 AST_LIST_INSERT_HEAD(&store
, this, list
);
3982 /* XXX remove previous contexts from same registrar */
3984 ast_log(LOG_DEBUG
, "must remove any reg %s\n", registrar
);
3985 __ast_context_destroy(NULL
,registrar
);
3991 /* XXX remove contexts with the same name */
3993 ast_log(LOG_WARNING
, "must remove %s reg %s\n", tmp
->name
, tmp
->registrar
);
3994 __ast_context_destroy(tmp
,tmp
->registrar
);
4000 lasttmp
->next
= contexts
;
4001 contexts
= *extcontexts
;
4002 *extcontexts
= NULL
;
4004 ast_log(LOG_WARNING
, "Requested contexts didn't get merged\n");
4006 /* restore the watchers for hints that can be found; notify those that
4009 while ((this = AST_LIST_REMOVE_HEAD(&store
, list
))) {
4010 struct pbx_find_info q
= { .stacklen
= 0 };
4011 exten
= pbx_find_extension(NULL
, NULL
, &q
, this->context
, this->exten
, PRIORITY_HINT
, NULL
, "", E_MATCH
);
4012 /* Find the hint in the list of hints */
4013 AST_LIST_TRAVERSE(&hints
, hint
, list
) {
4014 if (hint
->exten
== exten
)
4017 if (!exten
|| !hint
) {
4018 /* this hint has been removed, notify the watchers */
4020 thiscb
= this->callbacks
;
4023 thiscb
= thiscb
->next
;
4024 prevcb
->callback(this->context
, this->exten
, AST_EXTENSION_REMOVED
, prevcb
->data
);
4028 thiscb
= this->callbacks
;
4029 while (thiscb
->next
)
4030 thiscb
= thiscb
->next
;
4031 thiscb
->next
= hint
->callbacks
;
4032 hint
->callbacks
= this->callbacks
;
4033 hint
->laststate
= this->laststate
;
4038 AST_LIST_UNLOCK(&hints
);
4039 ast_unlock_contexts();
4046 * EBUSY - can't lock
4047 * ENOENT - no existence of context
4049 int ast_context_add_include(const char *context
, const char *include
, const char *registrar
)
4052 struct ast_context
*c
= find_context_locked(context
);
4055 ret
= ast_context_add_include2(c
, include
, registrar
);
4056 ast_unlock_contexts();
4061 /*! \brief Helper for get_range.
4062 * return the index of the matching entry, starting from 1.
4063 * If names is not supplied, try numeric values.
4065 static int lookup_name(const char *s
, char *const names
[], int max
)
4070 for (i
= 0; names
[i
]; i
++) {
4071 if (!strcasecmp(s
, names
[i
]))
4074 } else if (sscanf(s
, "%d", &i
) == 1 && i
>= 1 && i
<= max
) {
4077 return 0; /* error return */
4080 /*! \brief helper function to return a range up to max (7, 12, 31 respectively).
4081 * names, if supplied, is an array of names that should be mapped to numbers.
4083 static unsigned get_range(char *src
, int max
, char *const names
[], const char *msg
)
4085 int s
, e
; /* start and ending position */
4086 unsigned int mask
= 0;
4088 /* Check for whole range */
4089 if (ast_strlen_zero(src
) || !strcmp(src
, "*")) {
4093 /* Get start and ending position */
4094 char *c
= strchr(src
, '-');
4097 /* Find the start */
4098 s
= lookup_name(src
, names
, max
);
4100 ast_log(LOG_WARNING
, "Invalid %s '%s', assuming none\n", msg
, src
);
4104 if (c
) { /* find end of range */
4105 e
= lookup_name(c
, names
, max
);
4107 ast_log(LOG_WARNING
, "Invalid end %s '%s', assuming none\n", msg
, c
);
4114 /* Fill the mask. Remember that ranges are cyclic */
4115 mask
= 1 << e
; /* initialize with last element */
4128 /*! \brief store a bitmask of valid times, one bit each 2 minute */
4129 static void get_timerange(struct ast_timing
*i
, char *times
)
4137 /* start disabling all times, fill the fields with 0's, as they may contain garbage */
4138 memset(i
->minmask
, 0, sizeof(i
->minmask
));
4140 /* 2-minutes per bit, since the mask has only 32 bits :( */
4141 /* Star is all times */
4142 if (ast_strlen_zero(times
) || !strcmp(times
, "*")) {
4143 for (x
=0; x
<24; x
++)
4144 i
->minmask
[x
] = 0x3fffffff; /* 30 bits */
4147 /* Otherwise expect a range */
4148 e
= strchr(times
, '-');
4150 ast_log(LOG_WARNING
, "Time range is not valid. Assuming no restrictions based on time.\n");
4154 /* XXX why skip non digits ? */
4155 while (*e
&& !isdigit(*e
))
4158 ast_log(LOG_WARNING
, "Invalid time range. Assuming no restrictions based on time.\n");
4161 if (sscanf(times
, "%d:%d", &s1
, &s2
) != 2) {
4162 ast_log(LOG_WARNING
, "%s isn't a time. Assuming no restrictions based on time.\n", times
);
4165 if (sscanf(e
, "%d:%d", &e1
, &e2
) != 2) {
4166 ast_log(LOG_WARNING
, "%s isn't a time. Assuming no restrictions based on time.\n", e
);
4169 /* XXX this needs to be optimized */
4171 s1
= s1
* 30 + s2
/2;
4172 if ((s1
< 0) || (s1
>= 24*30)) {
4173 ast_log(LOG_WARNING
, "%s isn't a valid start time. Assuming no time.\n", times
);
4176 e1
= e1
* 30 + e2
/2;
4177 if ((e1
< 0) || (e1
>= 24*30)) {
4178 ast_log(LOG_WARNING
, "%s isn't a valid end time. Assuming no time.\n", e
);
4181 /* Go through the time and enable each appropriate bit */
4182 for (x
=s1
;x
!= e1
;x
= (x
+ 1) % (24 * 30)) {
4183 i
->minmask
[x
/30] |= (1 << (x
% 30));
4185 /* Do the last one */
4186 i
->minmask
[x
/30] |= (1 << (x
% 30));
4188 for (cth
=0; cth
<24; cth
++) {
4189 /* Initialize masks to blank */
4190 i
->minmask
[cth
] = 0;
4191 for (ctm
=0; ctm
<30; ctm
++) {
4193 /* First hour with more than one hour */
4194 (((cth
== s1
) && (ctm
>= s2
)) &&
4197 || (((cth
== s1
) && (ctm
>= s2
)) &&
4198 ((cth
== e1
) && (ctm
<= e2
)))
4199 /* In between first and last hours (more than 2 hours) */
4202 /* Last hour with more than one hour */
4204 ((cth
== e1
) && (ctm
<= e2
)))
4206 i
->minmask
[cth
] |= (1 << (ctm
/ 2));
4214 static char *days
[] =
4226 static char *months
[] =
4243 int ast_build_timing(struct ast_timing
*i
, const char *info_in
)
4245 char info_save
[256];
4248 /* Check for empty just in case */
4249 if (ast_strlen_zero(info_in
))
4251 /* make a copy just in case we were passed a static string */
4252 ast_copy_string(info_save
, info_in
, sizeof(info_save
));
4254 /* Assume everything except time */
4255 i
->monthmask
= 0xfff; /* 12 bits */
4256 i
->daymask
= 0x7fffffffU
; /* 31 bits */
4257 i
->dowmask
= 0x7f; /* 7 bits */
4258 /* on each call, use strsep() to move info to the next argument */
4259 get_timerange(i
, strsep(&info
, "|"));
4261 i
->dowmask
= get_range(strsep(&info
, "|"), 7, days
, "day of week");
4263 i
->daymask
= get_range(strsep(&info
, "|"), 31, NULL
, "day");
4265 i
->monthmask
= get_range(strsep(&info
, "|"), 12, months
, "month");
4269 int ast_check_timing(const struct ast_timing
*i
)
4272 time_t t
= time(NULL
);
4274 ast_localtime(&t
, &tm
, NULL
);
4276 /* If it's not the right month, return */
4277 if (!(i
->monthmask
& (1 << tm
.tm_mon
)))
4280 /* If it's not that time of the month.... */
4281 /* Warning, tm_mday has range 1..31! */
4282 if (!(i
->daymask
& (1 << (tm
.tm_mday
-1))))
4285 /* If it's not the right day of the week */
4286 if (!(i
->dowmask
& (1 << tm
.tm_wday
)))
4289 /* Sanity check the hour just to be safe */
4290 if ((tm
.tm_hour
< 0) || (tm
.tm_hour
> 23)) {
4291 ast_log(LOG_WARNING
, "Insane time...\n");
4295 /* Now the tough part, we calculate if it fits
4296 in the right time based on min/hour */
4297 if (!(i
->minmask
[tm
.tm_hour
] & (1 << (tm
.tm_min
/ 2))))
4300 /* If we got this far, then we're good */
4306 * ENOMEM - out of memory
4307 * EBUSY - can't lock
4308 * EEXIST - already included
4309 * EINVAL - there is no existence of context for inclusion
4311 int ast_context_add_include2(struct ast_context
*con
, const char *value
,
4312 const char *registrar
)
4314 struct ast_include
*new_include
;
4316 struct ast_include
*i
, *il
= NULL
; /* include, include_last */
4320 length
= sizeof(struct ast_include
);
4321 length
+= 2 * (strlen(value
) + 1);
4323 /* allocate new include structure ... */
4324 if (!(new_include
= ast_calloc(1, length
)))
4326 /* Fill in this structure. Use 'p' for assignments, as the fields
4327 * in the structure are 'const char *'
4329 p
= new_include
->stuff
;
4330 new_include
->name
= p
;
4332 p
+= strlen(value
) + 1;
4333 new_include
->rname
= p
;
4335 /* Strip off timing info, and process if it is there */
4336 if ( (c
= strchr(p
, '|')) ) {
4338 new_include
->hastime
= ast_build_timing(&(new_include
->timing
), c
);
4340 new_include
->next
= NULL
;
4341 new_include
->registrar
= registrar
;
4343 ast_mutex_lock(&con
->lock
);
4345 /* ... go to last include and check if context is already included too... */
4346 for (i
= con
->includes
; i
; i
= i
->next
) {
4347 if (!strcasecmp(i
->name
, new_include
->name
)) {
4349 ast_mutex_unlock(&con
->lock
);
4356 /* ... include new context into context list, unlock, return */
4358 il
->next
= new_include
;
4360 con
->includes
= new_include
;
4361 if (option_verbose
> 2)
4362 ast_verbose(VERBOSE_PREFIX_3
"Including context '%s' in context '%s'\n", new_include
->name
, ast_get_context_name(con
));
4363 ast_mutex_unlock(&con
->lock
);
4370 * EBUSY - can't lock
4371 * ENOENT - no existence of context
4373 int ast_context_add_switch(const char *context
, const char *sw
, const char *data
, int eval
, const char *registrar
)
4376 struct ast_context
*c
= find_context_locked(context
);
4378 if (c
) { /* found, add switch to this context */
4379 ret
= ast_context_add_switch2(c
, sw
, data
, eval
, registrar
);
4380 ast_unlock_contexts();
4387 * ENOMEM - out of memory
4388 * EBUSY - can't lock
4389 * EEXIST - already included
4390 * EINVAL - there is no existence of context for inclusion
4392 int ast_context_add_switch2(struct ast_context
*con
, const char *value
,
4393 const char *data
, int eval
, const char *registrar
)
4395 struct ast_sw
*new_sw
;
4400 length
= sizeof(struct ast_sw
);
4401 length
+= strlen(value
) + 1;
4403 length
+= strlen(data
);
4406 /* allocate new sw structure ... */
4407 if (!(new_sw
= ast_calloc(1, length
)))
4409 /* ... fill in this structure ... */
4412 strcpy(new_sw
->name
, value
);
4413 p
+= strlen(value
) + 1;
4416 strcpy(new_sw
->data
, data
);
4417 p
+= strlen(data
) + 1;
4419 strcpy(new_sw
->data
, "");
4422 new_sw
->eval
= eval
;
4423 new_sw
->registrar
= registrar
;
4425 /* ... try to lock this context ... */
4426 ast_mutex_lock(&con
->lock
);
4428 /* ... go to last sw and check if context is already swd too... */
4429 AST_LIST_TRAVERSE(&con
->alts
, i
, list
) {
4430 if (!strcasecmp(i
->name
, new_sw
->name
) && !strcasecmp(i
->data
, new_sw
->data
)) {
4432 ast_mutex_unlock(&con
->lock
);
4438 /* ... sw new context into context list, unlock, return */
4439 AST_LIST_INSERT_TAIL(&con
->alts
, new_sw
, list
);
4441 if (option_verbose
> 2)
4442 ast_verbose(VERBOSE_PREFIX_3
"Including switch '%s/%s' in context '%s'\n", new_sw
->name
, new_sw
->data
, ast_get_context_name(con
));
4444 ast_mutex_unlock(&con
->lock
);
4450 * EBUSY - can't lock
4451 * ENOENT - there is not context existence
4453 int ast_context_remove_ignorepat(const char *context
, const char *ignorepat
, const char *registrar
)
4456 struct ast_context
*c
= find_context_locked(context
);
4459 ret
= ast_context_remove_ignorepat2(c
, ignorepat
, registrar
);
4460 ast_unlock_contexts();
4465 int ast_context_remove_ignorepat2(struct ast_context
*con
, const char *ignorepat
, const char *registrar
)
4467 struct ast_ignorepat
*ip
, *ipl
= NULL
;
4469 ast_mutex_lock(&con
->lock
);
4471 for (ip
= con
->ignorepats
; ip
; ip
= ip
->next
) {
4472 if (!strcmp(ip
->pattern
, ignorepat
) &&
4473 (!registrar
|| (registrar
== ip
->registrar
))) {
4475 ipl
->next
= ip
->next
;
4478 con
->ignorepats
= ip
->next
;
4481 ast_mutex_unlock(&con
->lock
);
4487 ast_mutex_unlock(&con
->lock
);
4493 * EBUSY - can't lock
4494 * ENOENT - there is no existence of context
4496 int ast_context_add_ignorepat(const char *context
, const char *value
, const char *registrar
)
4499 struct ast_context
*c
= find_context_locked(context
);
4502 ret
= ast_context_add_ignorepat2(c
, value
, registrar
);
4503 ast_unlock_contexts();
4508 int ast_context_add_ignorepat2(struct ast_context
*con
, const char *value
, const char *registrar
)
4510 struct ast_ignorepat
*ignorepat
, *ignorepatc
, *ignorepatl
= NULL
;
4512 length
= sizeof(struct ast_ignorepat
);
4513 length
+= strlen(value
) + 1;
4514 if (!(ignorepat
= ast_calloc(1, length
)))
4516 /* The cast to char * is because we need to write the initial value.
4517 * The field is not supposed to be modified otherwise
4519 strcpy((char *)ignorepat
->pattern
, value
);
4520 ignorepat
->next
= NULL
;
4521 ignorepat
->registrar
= registrar
;
4522 ast_mutex_lock(&con
->lock
);
4523 for (ignorepatc
= con
->ignorepats
; ignorepatc
; ignorepatc
= ignorepatc
->next
) {
4524 ignorepatl
= ignorepatc
;
4525 if (!strcasecmp(ignorepatc
->pattern
, value
)) {
4527 ast_mutex_unlock(&con
->lock
);
4533 ignorepatl
->next
= ignorepat
;
4535 con
->ignorepats
= ignorepat
;
4536 ast_mutex_unlock(&con
->lock
);
4541 int ast_ignore_pattern(const char *context
, const char *pattern
)
4543 struct ast_context
*con
= ast_context_find(context
);
4545 struct ast_ignorepat
*pat
;
4546 for (pat
= con
->ignorepats
; pat
; pat
= pat
->next
) {
4547 if (ast_extension_match(pat
->pattern
, pattern
))
4556 * EBUSY - can't lock
4557 * ENOENT - no existence of context
4560 int ast_add_extension(const char *context
, int replace
, const char *extension
,
4561 int priority
, const char *label
, const char *callerid
,
4562 const char *application
, void *data
, void (*datad
)(void *), const char *registrar
)
4565 struct ast_context
*c
= find_context_locked(context
);
4568 ret
= ast_add_extension2(c
, replace
, extension
, priority
, label
, callerid
,
4569 application
, data
, datad
, registrar
);
4570 ast_unlock_contexts();
4575 int ast_explicit_goto(struct ast_channel
*chan
, const char *context
, const char *exten
, int priority
)
4580 ast_channel_lock(chan
);
4582 if (!ast_strlen_zero(context
))
4583 ast_copy_string(chan
->context
, context
, sizeof(chan
->context
));
4584 if (!ast_strlen_zero(exten
))
4585 ast_copy_string(chan
->exten
, exten
, sizeof(chan
->exten
));
4586 if (priority
> -1) {
4587 chan
->priority
= priority
;
4588 /* see flag description in channel.h for explanation */
4589 if (ast_test_flag(chan
, AST_FLAG_IN_AUTOLOOP
))
4593 ast_channel_unlock(chan
);
4598 int ast_async_goto(struct ast_channel
*chan
, const char *context
, const char *exten
, int priority
)
4602 ast_channel_lock(chan
);
4604 if (chan
->pbx
) { /* This channel is currently in the PBX */
4605 ast_explicit_goto(chan
, context
, exten
, priority
);
4606 ast_softhangup_nolock(chan
, AST_SOFTHANGUP_ASYNCGOTO
);
4608 /* In order to do it when the channel doesn't really exist within
4609 the PBX, we have to make a new channel, masquerade, and start the PBX
4610 at the new location */
4611 struct ast_channel
*tmpchan
= ast_channel_alloc(0, chan
->_state
, 0, 0, chan
->accountcode
, chan
->exten
, chan
->context
, chan
->amaflags
, "AsyncGoto/%s", chan
->name
);
4613 ast_cdr_discard(tmpchan
->cdr
);
4614 tmpchan
->cdr
= ast_cdr_dup(chan
->cdr
); /* share the love */
4619 /* Make formats okay */
4620 tmpchan
->readformat
= chan
->readformat
;
4621 tmpchan
->writeformat
= chan
->writeformat
;
4622 /* Setup proper location */
4623 ast_explicit_goto(tmpchan
,
4624 S_OR(context
, chan
->context
), S_OR(exten
, chan
->exten
), priority
);
4626 /* Masquerade into temp channel */
4627 ast_channel_masquerade(tmpchan
, chan
);
4629 /* Grab the locks and get going */
4630 ast_channel_lock(tmpchan
);
4631 ast_do_masquerade(tmpchan
);
4632 ast_channel_unlock(tmpchan
);
4633 /* Start the PBX going on our stolen channel */
4634 if (ast_pbx_start(tmpchan
)) {
4635 ast_log(LOG_WARNING
, "Unable to start PBX on %s\n", tmpchan
->name
);
4636 ast_hangup(tmpchan
);
4641 ast_channel_unlock(chan
);
4645 int ast_async_goto_by_name(const char *channame
, const char *context
, const char *exten
, int priority
)
4647 struct ast_channel
*chan
;
4650 chan
= ast_get_channel_by_name_locked(channame
);
4652 res
= ast_async_goto(chan
, context
, exten
, priority
);
4653 ast_channel_unlock(chan
);
4658 /*! \brief copy a string skipping whitespace */
4659 static int ext_strncpy(char *dst
, const char *src
, int len
)
4663 while (*src
&& (count
< len
- 1)) {
4666 /* otherwise exten => [a-b],1,... doesn't work */
4682 /*! \brief add the extension in the priority chain.
4683 * returns 0 on success, -1 on failure
4685 static int add_pri(struct ast_context
*con
, struct ast_exten
*tmp
,
4686 struct ast_exten
*el
, struct ast_exten
*e
, int replace
)
4688 struct ast_exten
*ep
;
4690 for (ep
= NULL
; e
; ep
= e
, e
= e
->peer
) {
4691 if (e
->priority
>= tmp
->priority
)
4694 if (!e
) { /* go at the end, and ep is surely set because the list is not empty */
4696 return 0; /* success */
4698 if (e
->priority
== tmp
->priority
) {
4699 /* Can't have something exactly the same. Is this a
4700 replacement? If so, replace, otherwise, bonk. */
4702 ast_log(LOG_WARNING
, "Unable to register extension '%s', priority %d in '%s', already in use\n", tmp
->exten
, tmp
->priority
, con
->name
);
4704 tmp
->datad(tmp
->data
);
4708 /* we are replacing e, so copy the link fields and then update
4709 * whoever pointed to e to point to us
4711 tmp
->next
= e
->next
; /* not meaningful if we are not first in the peer list */
4712 tmp
->peer
= e
->peer
; /* always meaningful */
4713 if (ep
) /* We're in the peer list, just insert ourselves */
4715 else if (el
) /* We're the first extension. Take over e's functions */
4717 else /* We're the very first extension. */
4719 if (tmp
->priority
== PRIORITY_HINT
)
4720 ast_change_hint(e
,tmp
);
4721 /* Destroy the old one */
4725 } else { /* Slip ourselves in just before e */
4727 tmp
->next
= e
->next
; /* extension chain, or NULL if e is not the first extension */
4728 if (ep
) /* Easy enough, we're just in the peer list */
4730 else { /* we are the first in some peer list, so link in the ext list */
4732 el
->next
= tmp
; /* in the middle... */
4734 con
->root
= tmp
; /* ... or at the head */
4735 e
->next
= NULL
; /* e is no more at the head, so e->next must be reset */
4737 /* And immediately return success. */
4738 if (tmp
->priority
== PRIORITY_HINT
)
4745 * Main interface to add extensions to the list for out context.
4747 * We sort extensions in order of matching preference, so that we can
4748 * stop the search as soon as we find a suitable match.
4749 * This ordering also takes care of wildcards such as '.' (meaning
4750 * "one or more of any character") and '!' (which is 'earlymatch',
4751 * meaning "zero or more of any character" but also impacts the
4752 * return value from CANMATCH and EARLYMATCH.
4754 * The extension match rules defined in the devmeeting 2006.05.05 are
4755 * quite simple: WE SELECT THE LONGEST MATCH.
4756 * In detail, "longest" means the number of matched characters in
4757 * the extension. In case of ties (e.g. _XXX and 333) in the length
4758 * of a pattern, we give priority to entries with the smallest cardinality
4759 * (e.g, [5-9] comes before [2-8] before the former has only 5 elements,
4760 * while the latter has 7, etc.
4761 * In case of same cardinality, the first element in the range counts.
4762 * If we still have a tie, any final '!' will make this as a possibly
4763 * less specific pattern.
4765 * EBUSY - can't lock
4766 * EEXIST - extension with the same priority exist and no replace is set
4769 int ast_add_extension2(struct ast_context
*con
,
4770 int replace
, const char *extension
, int priority
, const char *label
, const char *callerid
,
4771 const char *application
, void *data
, void (*datad
)(void *),
4772 const char *registrar
)
4775 * Sort extensions (or patterns) according to the rules indicated above.
4776 * These are implemented by the function ext_cmp()).
4777 * All priorities for the same ext/pattern/cid are kept in a list,
4778 * using the 'peer' field as a link field..
4780 struct ast_exten
*tmp
, *e
, *el
= NULL
;
4784 char expand_buf
[VAR_BUF_SIZE
] = { 0, };
4786 /* if we are adding a hint, and there are global variables, and the hint
4787 contains variable references, then expand them
4789 ast_mutex_lock(&globalslock
);
4790 if (priority
== PRIORITY_HINT
&& AST_LIST_FIRST(&globals
) && strstr(application
, "${")) {
4791 pbx_substitute_variables_varshead(&globals
, application
, expand_buf
, sizeof(expand_buf
));
4792 application
= expand_buf
;
4794 ast_mutex_unlock(&globalslock
);
4796 length
= sizeof(struct ast_exten
);
4797 length
+= strlen(extension
) + 1;
4798 length
+= strlen(application
) + 1;
4800 length
+= strlen(label
) + 1;
4802 length
+= strlen(callerid
) + 1;
4804 length
++; /* just the '\0' */
4806 /* Be optimistic: Build the extension structure first */
4807 if (!(tmp
= ast_calloc(1, length
)))
4810 /* use p as dst in assignments, as the fields are const char * */
4815 p
+= strlen(label
) + 1;
4818 p
+= ext_strncpy(p
, extension
, strlen(extension
) + 1) + 1;
4819 tmp
->priority
= priority
;
4820 tmp
->cidmatch
= p
; /* but use p for assignments below */
4822 p
+= ext_strncpy(p
, callerid
, strlen(callerid
) + 1) + 1;
4829 strcpy(p
, application
);
4833 tmp
->registrar
= registrar
;
4835 ast_mutex_lock(&con
->lock
);
4836 res
= 0; /* some compilers will think it is uninitialized otherwise */
4837 for (e
= con
->root
; e
; el
= e
, e
= e
->next
) { /* scan the extension list */
4838 res
= ext_cmp(e
->exten
, extension
);
4839 if (res
== 0) { /* extension match, now look at cidmatch */
4840 if (!e
->matchcid
&& !tmp
->matchcid
)
4842 else if (tmp
->matchcid
&& !e
->matchcid
)
4844 else if (e
->matchcid
&& !tmp
->matchcid
)
4847 res
= strcasecmp(e
->cidmatch
, tmp
->cidmatch
);
4852 if (e
&& res
== 0) { /* exact match, insert in the pri chain */
4853 res
= add_pri(con
, tmp
, el
, e
, replace
);
4854 ast_mutex_unlock(&con
->lock
);
4856 errno
= EEXIST
; /* XXX do we care ? */
4857 return 0; /* XXX should we return -1 maybe ? */
4861 * not an exact match, this is the first entry with this pattern,
4862 * so insert in the main list right before 'e' (if any)
4869 ast_mutex_unlock(&con
->lock
);
4870 if (tmp
->priority
== PRIORITY_HINT
)
4874 if (tmp
->matchcid
) {
4876 ast_log(LOG_DEBUG
, "Added extension '%s' priority %d (CID match '%s') to %s\n",
4877 tmp
->exten
, tmp
->priority
, tmp
->cidmatch
, con
->name
);
4880 ast_log(LOG_DEBUG
, "Added extension '%s' priority %d to %s\n",
4881 tmp
->exten
, tmp
->priority
, con
->name
);
4884 if (option_verbose
> 2) {
4885 if (tmp
->matchcid
) {
4886 ast_verbose( VERBOSE_PREFIX_3
"Added extension '%s' priority %d (CID match '%s')to %s\n",
4887 tmp
->exten
, tmp
->priority
, tmp
->cidmatch
, con
->name
);
4889 ast_verbose( VERBOSE_PREFIX_3
"Added extension '%s' priority %d to %s\n",
4890 tmp
->exten
, tmp
->priority
, con
->name
);
4898 struct ast_channel
*chan
;
4899 char context
[AST_MAX_CONTEXT
];
4900 char exten
[AST_MAX_EXTENSION
];
4903 char app
[AST_MAX_EXTENSION
];
4907 static void *async_wait(void *data
)
4909 struct async_stat
*as
= data
;
4910 struct ast_channel
*chan
= as
->chan
;
4911 int timeout
= as
->timeout
;
4913 struct ast_frame
*f
;
4914 struct ast_app
*app
;
4916 while (timeout
&& (chan
->_state
!= AST_STATE_UP
)) {
4917 res
= ast_waitfor(chan
, timeout
);
4925 if (f
->frametype
== AST_FRAME_CONTROL
) {
4926 if ((f
->subclass
== AST_CONTROL_BUSY
) ||
4927 (f
->subclass
== AST_CONTROL_CONGESTION
) ) {
4934 if (chan
->_state
== AST_STATE_UP
) {
4935 if (!ast_strlen_zero(as
->app
)) {
4936 app
= pbx_findapp(as
->app
);
4938 if (option_verbose
> 2)
4939 ast_verbose(VERBOSE_PREFIX_3
"Launching %s(%s) on %s\n", as
->app
, as
->appdata
, chan
->name
);
4940 pbx_exec(chan
, app
, as
->appdata
);
4942 ast_log(LOG_WARNING
, "No such application '%s'\n", as
->app
);
4944 if (!ast_strlen_zero(as
->context
))
4945 ast_copy_string(chan
->context
, as
->context
, sizeof(chan
->context
));
4946 if (!ast_strlen_zero(as
->exten
))
4947 ast_copy_string(chan
->exten
, as
->exten
, sizeof(chan
->exten
));
4948 if (as
->priority
> 0)
4949 chan
->priority
= as
->priority
;
4951 if (ast_pbx_run(chan
)) {
4952 ast_log(LOG_ERROR
, "Failed to start PBX on %s\n", chan
->name
);
4954 /* PBX will have taken care of this */
4965 /*! Function to post an empty cdr after a spool call fails.
4967 * This function posts an empty cdr for a failed spool call
4970 static int ast_pbx_outgoing_cdr_failed(void)
4972 /* allocate a channel */
4973 struct ast_channel
*chan
= ast_channel_alloc(0, AST_STATE_DOWN
, 0, 0, "", "", "", 0, 0);
4976 return -1; /* failure */
4979 /* allocation of the cdr failed */
4980 ast_channel_free(chan
); /* free the channel */
4981 return -1; /* return failure */
4984 /* allocation of the cdr was successful */
4985 ast_cdr_init(chan
->cdr
, chan
); /* initilize our channel's cdr */
4986 ast_cdr_start(chan
->cdr
); /* record the start and stop time */
4987 ast_cdr_end(chan
->cdr
);
4988 ast_cdr_failed(chan
->cdr
); /* set the status to failed */
4989 ast_cdr_detach(chan
->cdr
); /* post and free the record */
4990 ast_channel_free(chan
); /* free the channel */
4992 return 0; /* success */
4995 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
)
4997 struct ast_channel
*chan
;
4998 struct async_stat
*as
;
4999 int res
= -1, cdr_res
= -1;
5000 struct outgoing_helper oh
;
5001 pthread_attr_t attr
;
5005 chan
= __ast_request_and_dial(type
, format
, data
, timeout
, reason
, cid_num
, cid_name
, &oh
);
5009 ast_channel_lock(chan
);
5012 if (chan
->_state
== AST_STATE_UP
) {
5014 if (option_verbose
> 3)
5015 ast_verbose(VERBOSE_PREFIX_4
"Channel %s was answered.\n", chan
->name
);
5019 ast_channel_unlock(chan
);
5020 if (ast_pbx_run(chan
)) {
5021 ast_log(LOG_ERROR
, "Unable to run PBX on %s\n", chan
->name
);
5029 if (ast_pbx_start(chan
)) {
5030 ast_log(LOG_ERROR
, "Unable to start PBX on %s\n", chan
->name
);
5033 ast_channel_unlock(chan
);
5041 if (option_verbose
> 3)
5042 ast_verbose(VERBOSE_PREFIX_4
"Channel %s was never answered.\n", chan
->name
);
5044 if (chan
->cdr
) { /* update the cdr */
5045 /* here we update the status of the call, which sould be busy.
5046 * if that fails then we set the status to failed */
5047 if (ast_cdr_disposition(chan
->cdr
, chan
->hangupcause
))
5048 ast_cdr_failed(chan
->cdr
);
5053 ast_channel_unlock(chan
);
5060 if (res
< 0) { /* the call failed for some reason */
5061 if (*reason
== 0) { /* if the call failed (not busy or no answer)
5062 * update the cdr with the failed message */
5063 cdr_res
= ast_pbx_outgoing_cdr_failed();
5066 goto outgoing_exten_cleanup
;
5070 /* create a fake channel and execute the "failed" extension (if it exists) within the requested context */
5071 /* check if "failed" exists */
5072 if (ast_exists_extension(chan
, context
, "failed", 1, NULL
)) {
5073 chan
= ast_channel_alloc(0, AST_STATE_DOWN
, 0, 0, "", "", "", 0, "OutgoingSpoolFailed");
5075 char failed_reason
[4] = "";
5076 if (!ast_strlen_zero(context
))
5077 ast_copy_string(chan
->context
, context
, sizeof(chan
->context
));
5078 set_ext_pri(chan
, "failed", 1);
5079 ast_set_variables(chan
, vars
);
5080 snprintf(failed_reason
, sizeof(failed_reason
), "%d", *reason
);
5081 pbx_builtin_setvar_helper(chan
, "REASON", failed_reason
);
5083 ast_cdr_setaccount(chan
, account
);
5084 if (ast_pbx_run(chan
)) {
5085 ast_log(LOG_ERROR
, "Unable to run PBX on %s\n", chan
->name
);
5093 if (!(as
= ast_calloc(1, sizeof(*as
)))) {
5095 goto outgoing_exten_cleanup
;
5097 chan
= ast_request_and_dial(type
, format
, data
, timeout
, reason
, cid_num
, cid_name
);
5101 ast_channel_lock(chan
);
5106 goto outgoing_exten_cleanup
;
5109 ast_copy_string(as
->context
, context
, sizeof(as
->context
));
5110 set_ext_pri(as
->chan
, exten
, priority
);
5111 as
->timeout
= timeout
;
5112 ast_set_variables(chan
, vars
);
5114 ast_cdr_setaccount(chan
, account
);
5115 pthread_attr_init(&attr
);
5116 pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
5117 if (ast_pthread_create(&as
->p
, &attr
, async_wait
, as
)) {
5118 ast_log(LOG_WARNING
, "Failed to start async wait\n");
5122 ast_channel_unlock(chan
);
5126 pthread_attr_destroy(&attr
);
5127 goto outgoing_exten_cleanup
;
5129 pthread_attr_destroy(&attr
);
5132 outgoing_exten_cleanup
:
5133 ast_variables_destroy(vars
);
5140 struct ast_channel
*chan
;
5144 /*! \brief run the application and free the descriptor once done */
5145 static void *ast_pbx_run_app(void *data
)
5147 struct app_tmp
*tmp
= data
;
5148 struct ast_app
*app
;
5149 app
= pbx_findapp(tmp
->app
);
5151 if (option_verbose
> 3)
5152 ast_verbose(VERBOSE_PREFIX_4
"Launching %s(%s) on %s\n", tmp
->app
, tmp
->data
, tmp
->chan
->name
);
5153 pbx_exec(tmp
->chan
, app
, tmp
->data
);
5155 ast_log(LOG_WARNING
, "No such application '%s'\n", tmp
->app
);
5156 ast_hangup(tmp
->chan
);
5161 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
)
5163 struct ast_channel
*chan
;
5164 struct app_tmp
*tmp
;
5165 int res
= -1, cdr_res
= -1;
5166 struct outgoing_helper oh
;
5167 pthread_attr_t attr
;
5169 memset(&oh
, 0, sizeof(oh
));
5171 oh
.account
= account
;
5174 *locked_channel
= NULL
;
5175 if (ast_strlen_zero(app
)) {
5177 goto outgoing_app_cleanup
;
5180 chan
= __ast_request_and_dial(type
, format
, data
, timeout
, reason
, cid_num
, cid_name
, &oh
);
5182 if (!chan
->cdr
) { /* check if the channel already has a cdr record, if not give it one */
5183 chan
->cdr
= ast_cdr_alloc(); /* allocate a cdr for the channel */
5185 /* allocation of the cdr failed */
5188 goto outgoing_app_cleanup
;
5190 /* allocation of the cdr was successful */
5191 ast_cdr_init(chan
->cdr
, chan
); /* initilize our channel's cdr */
5192 ast_cdr_start(chan
->cdr
);
5194 ast_set_variables(chan
, vars
);
5196 ast_cdr_setaccount(chan
, account
);
5197 if (chan
->_state
== AST_STATE_UP
) {
5199 if (option_verbose
> 3)
5200 ast_verbose(VERBOSE_PREFIX_4
"Channel %s was answered.\n", chan
->name
);
5201 tmp
= ast_calloc(1, sizeof(*tmp
));
5205 ast_copy_string(tmp
->app
, app
, sizeof(tmp
->app
));
5207 ast_copy_string(tmp
->data
, appdata
, sizeof(tmp
->data
));
5211 ast_channel_unlock(chan
);
5212 ast_pbx_run_app(tmp
);
5214 pthread_attr_init(&attr
);
5215 pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
5217 ast_channel_lock(chan
);
5218 if (ast_pthread_create(&tmp
->t
, &attr
, ast_pbx_run_app
, tmp
)) {
5219 ast_log(LOG_WARNING
, "Unable to spawn execute thread on %s: %s\n", chan
->name
, strerror(errno
));
5222 ast_channel_unlock(chan
);
5227 *locked_channel
= chan
;
5229 pthread_attr_destroy(&attr
);
5233 if (option_verbose
> 3)
5234 ast_verbose(VERBOSE_PREFIX_4
"Channel %s was never answered.\n", chan
->name
);
5235 if (chan
->cdr
) { /* update the cdr */
5236 /* here we update the status of the call, which sould be busy.
5237 * if that fails then we set the status to failed */
5238 if (ast_cdr_disposition(chan
->cdr
, chan
->hangupcause
))
5239 ast_cdr_failed(chan
->cdr
);
5245 if (res
< 0) { /* the call failed for some reason */
5246 if (*reason
== 0) { /* if the call failed (not busy or no answer)
5247 * update the cdr with the failed message */
5248 cdr_res
= ast_pbx_outgoing_cdr_failed();
5251 goto outgoing_app_cleanup
;
5257 struct async_stat
*as
;
5258 if (!(as
= ast_calloc(1, sizeof(*as
)))) {
5260 goto outgoing_app_cleanup
;
5262 chan
= __ast_request_and_dial(type
, format
, data
, timeout
, reason
, cid_num
, cid_name
, &oh
);
5266 goto outgoing_app_cleanup
;
5269 ast_copy_string(as
->app
, app
, sizeof(as
->app
));
5271 ast_copy_string(as
->appdata
, appdata
, sizeof(as
->appdata
));
5272 as
->timeout
= timeout
;
5273 ast_set_variables(chan
, vars
);
5275 ast_cdr_setaccount(chan
, account
);
5276 /* Start a new thread, and get something handling this channel. */
5277 pthread_attr_init(&attr
);
5278 pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
5280 ast_channel_lock(chan
);
5281 if (ast_pthread_create(&as
->p
, &attr
, async_wait
, as
)) {
5282 ast_log(LOG_WARNING
, "Failed to start async wait\n");
5285 ast_channel_unlock(chan
);
5288 pthread_attr_destroy(&attr
);
5289 goto outgoing_app_cleanup
;
5292 *locked_channel
= chan
;
5294 pthread_attr_destroy(&attr
);
5297 outgoing_app_cleanup
:
5298 ast_variables_destroy(vars
);
5302 void __ast_context_destroy(struct ast_context
*con
, const char *registrar
)
5304 struct ast_context
*tmp
, *tmpl
=NULL
;
5305 struct ast_include
*tmpi
;
5307 struct ast_exten
*e
, *el
, *en
;
5308 struct ast_ignorepat
*ipi
;
5310 for (tmp
= contexts
; tmp
; ) {
5311 struct ast_context
*next
; /* next starting point */
5312 for (; tmp
; tmpl
= tmp
, tmp
= tmp
->next
) {
5314 ast_log(LOG_DEBUG
, "check ctx %s %s\n", tmp
->name
, tmp
->registrar
);
5315 if ( (!registrar
|| !strcasecmp(registrar
, tmp
->registrar
)) &&
5316 (!con
|| !strcasecmp(tmp
->name
, con
->name
)) )
5317 break; /* found it */
5319 if (!tmp
) /* not found, we are done */
5321 ast_mutex_lock(&tmp
->lock
);
5323 ast_log(LOG_DEBUG
, "delete ctx %s %s\n", tmp
->name
, tmp
->registrar
);
5329 /* Okay, now we're safe to let it go -- in a sense, we were
5330 ready to let it go as soon as we locked it. */
5331 ast_mutex_unlock(&tmp
->lock
);
5332 for (tmpi
= tmp
->includes
; tmpi
; ) { /* Free includes */
5333 struct ast_include
*tmpil
= tmpi
;
5337 for (ipi
= tmp
->ignorepats
; ipi
; ) { /* Free ignorepats */
5338 struct ast_ignorepat
*ipl
= ipi
;
5342 while ((sw
= AST_LIST_REMOVE_HEAD(&tmp
->alts
, list
)))
5344 for (e
= tmp
->root
; e
;) {
5345 for (en
= e
->peer
; en
;) {
5354 ast_mutex_destroy(&tmp
->lock
);
5356 /* if we have a specific match, we are done, otherwise continue */
5357 tmp
= con
? NULL
: next
;
5361 void ast_context_destroy(struct ast_context
*con
, const char *registrar
)
5363 ast_wrlock_contexts();
5364 __ast_context_destroy(con
,registrar
);
5365 ast_unlock_contexts();
5368 static void wait_for_hangup(struct ast_channel
*chan
, void *data
)
5371 struct ast_frame
*f
;
5374 if (ast_strlen_zero(data
) || (sscanf(data
, "%d", &waittime
) != 1) || (waittime
< 0))
5376 if (waittime
> -1) {
5377 ast_safe_sleep(chan
, waittime
* 1000);
5379 res
= ast_waitfor(chan
, -1);
5389 * \ingroup applications
5391 static int pbx_builtin_progress(struct ast_channel
*chan
, void *data
)
5393 ast_indicate(chan
, AST_CONTROL_PROGRESS
);
5398 * \ingroup applications
5400 static int pbx_builtin_ringing(struct ast_channel
*chan
, void *data
)
5402 ast_indicate(chan
, AST_CONTROL_RINGING
);
5407 * \ingroup applications
5409 static int pbx_builtin_busy(struct ast_channel
*chan
, void *data
)
5411 ast_indicate(chan
, AST_CONTROL_BUSY
);
5412 /* Don't change state of an UP channel, just indicate
5414 if (chan
->_state
!= AST_STATE_UP
)
5415 ast_setstate(chan
, AST_STATE_BUSY
);
5416 wait_for_hangup(chan
, data
);
5421 * \ingroup applications
5423 static int pbx_builtin_congestion(struct ast_channel
*chan
, void *data
)
5425 ast_indicate(chan
, AST_CONTROL_CONGESTION
);
5426 /* Don't change state of an UP channel, just indicate
5427 congestion in audio */
5428 if (chan
->_state
!= AST_STATE_UP
)
5429 ast_setstate(chan
, AST_STATE_BUSY
);
5430 wait_for_hangup(chan
, data
);
5435 * \ingroup applications
5437 static int pbx_builtin_answer(struct ast_channel
*chan
, void *data
)
5442 if (chan
->_state
== AST_STATE_UP
)
5444 else if (!ast_strlen_zero(data
))
5447 res
= ast_answer(chan
);
5452 res
= ast_safe_sleep(chan
, delay
);
5457 AST_APP_OPTIONS(resetcdr_opts
, {
5458 AST_APP_OPTION('w', AST_CDR_FLAG_POSTED
),
5459 AST_APP_OPTION('a', AST_CDR_FLAG_LOCKED
),
5460 AST_APP_OPTION('v', AST_CDR_FLAG_KEEP_VARS
),
5464 * \ingroup applications
5466 static int pbx_builtin_resetcdr(struct ast_channel
*chan
, void *data
)
5469 struct ast_flags flags
= { 0 };
5471 if (!ast_strlen_zero(data
)) {
5472 args
= ast_strdupa(data
);
5473 ast_app_parse_options(resetcdr_opts
, &flags
, NULL
, args
);
5476 ast_cdr_reset(chan
->cdr
, &flags
);
5482 * \ingroup applications
5484 static int pbx_builtin_setamaflags(struct ast_channel
*chan
, void *data
)
5486 /* Copy the AMA Flags as specified */
5487 ast_cdr_setamaflags(chan
, data
? data
: "");
5492 * \ingroup applications
5494 static int pbx_builtin_hangup(struct ast_channel
*chan
, void *data
)
5496 if (!ast_strlen_zero(data
)) {
5500 if ((cause
= ast_str2cause(data
)) > -1) {
5501 chan
->hangupcause
= cause
;
5505 cause
= strtol((const char *) data
, &endptr
, 10);
5506 if (cause
!= 0 || (data
!= endptr
)) {
5507 chan
->hangupcause
= cause
;
5511 ast_log(LOG_NOTICE
, "Invalid cause given to Hangup(): \"%s\"\n", (char *) data
);
5514 if (!chan
->hangupcause
) {
5515 chan
->hangupcause
= AST_CAUSE_NORMAL_CLEARING
;
5522 * \ingroup applications
5524 static int pbx_builtin_gotoiftime(struct ast_channel
*chan
, void *data
)
5528 struct ast_timing timing
;
5530 if (ast_strlen_zero(data
)) {
5531 ast_log(LOG_WARNING
, "GotoIfTime requires an argument:\n <time range>|<days of week>|<days of month>|<months>?[[context|]extension|]priority\n");
5535 ts
= s
= ast_strdupa(data
);
5537 /* Separate the Goto path */
5540 /* struct ast_include include contained garbage here, fixed by zeroing it on get_timerange */
5541 if (ast_build_timing(&timing
, s
) && ast_check_timing(&timing
))
5542 res
= pbx_builtin_goto(chan
, ts
);
5548 * \ingroup applications
5550 static int pbx_builtin_execiftime(struct ast_channel
*chan
, void *data
)
5553 struct ast_timing timing
;
5554 struct ast_app
*app
;
5555 static const char *usage
= "ExecIfTime requires an argument:\n <time range>|<days of week>|<days of month>|<months>?<appname>[|<appargs>]";
5557 if (ast_strlen_zero(data
)) {
5558 ast_log(LOG_WARNING
, "%s\n", usage
);
5562 appname
= ast_strdupa(data
);
5564 s
= strsep(&appname
,"?"); /* Separate the timerange and application name/data */
5565 if (!appname
) { /* missing application */
5566 ast_log(LOG_WARNING
, "%s\n", usage
);
5570 if (!ast_build_timing(&timing
, s
)) {
5571 ast_log(LOG_WARNING
, "Invalid Time Spec: %s\nCorrect usage: %s\n", s
, usage
);
5575 if (!ast_check_timing(&timing
)) /* outside the valid time window, just return */
5578 /* now split appname|appargs */
5579 if ((s
= strchr(appname
, '|')))
5582 if ((app
= pbx_findapp(appname
))) {
5583 return pbx_exec(chan
, app
, S_OR(s
, ""));
5585 ast_log(LOG_WARNING
, "Cannot locate application %s\n", appname
);
5591 * \ingroup applications
5593 static int pbx_builtin_wait(struct ast_channel
*chan
, void *data
)
5598 /* Wait for "n" seconds */
5599 if (data
&& (s
= atof(data
)) > 0) {
5601 return ast_safe_sleep(chan
, ms
);
5607 * \ingroup applications
5609 static int pbx_builtin_waitexten(struct ast_channel
*chan
, void *data
)
5613 struct ast_flags flags
= {0};
5614 char *opts
[1] = { NULL
};
5616 AST_DECLARE_APP_ARGS(args
,
5617 AST_APP_ARG(timeout
);
5618 AST_APP_ARG(options
);
5621 if (!ast_strlen_zero(data
)) {
5622 parse
= ast_strdupa(data
);
5623 AST_STANDARD_APP_ARGS(args
, parse
);
5625 memset(&args
, 0, sizeof(args
));
5628 ast_app_parse_options(waitexten_opts
, &flags
, opts
, args
.options
);
5630 if (ast_test_flag(&flags
, WAITEXTEN_MOH
) && !opts
[0] ) {
5631 ast_log(LOG_WARNING
, "The 'm' option has been specified for WaitExten without a class.\n");
5632 } else if (ast_test_flag(&flags
, WAITEXTEN_MOH
))
5633 ast_indicate_data(chan
, AST_CONTROL_HOLD
, opts
[0], strlen(opts
[0]));
5635 /* Wait for "n" seconds */
5636 if (args
.timeout
&& (sec
= atof(args
.timeout
)) > 0.0)
5639 ms
= chan
->pbx
->rtimeout
* 1000;
5642 res
= ast_waitfordigit(chan
, ms
);
5644 if (ast_exists_extension(chan
, chan
->context
, chan
->exten
, chan
->priority
+ 1, chan
->cid
.cid_num
)) {
5645 if (option_verbose
> 2)
5646 ast_verbose(VERBOSE_PREFIX_3
"Timeout on %s, continuing...\n", chan
->name
);
5647 } else if (chan
->_softhangup
== AST_SOFTHANGUP_TIMEOUT
) {
5648 if (option_verbose
> 2)
5649 ast_verbose(VERBOSE_PREFIX_3
"Call timeout on %s, checking for 'T'\n", chan
->name
);
5651 } else if (ast_exists_extension(chan
, chan
->context
, "t", 1, chan
->cid
.cid_num
)) {
5652 if (option_verbose
> 2)
5653 ast_verbose(VERBOSE_PREFIX_3
"Timeout on %s, going to 't'\n", chan
->name
);
5654 set_ext_pri(chan
, "t", 0); /* 0 will become 1, next time through the loop */
5656 ast_log(LOG_WARNING
, "Timeout but no rule 't' in context '%s'\n", chan
->context
);
5661 if (ast_test_flag(&flags
, WAITEXTEN_MOH
))
5662 ast_indicate(chan
, AST_CONTROL_UNHOLD
);
5668 * \ingroup applications
5670 static int pbx_builtin_background(struct ast_channel
*chan
, void *data
)
5673 struct ast_flags flags
= {0};
5675 AST_DECLARE_APP_ARGS(args
,
5676 AST_APP_ARG(filename
);
5677 AST_APP_ARG(options
);
5679 AST_APP_ARG(context
);
5682 if (ast_strlen_zero(data
)) {
5683 ast_log(LOG_WARNING
, "Background requires an argument (filename)\n");
5687 parse
= ast_strdupa(data
);
5689 AST_STANDARD_APP_ARGS(args
, parse
);
5691 if (ast_strlen_zero(args
.lang
))
5692 args
.lang
= (char *)chan
->language
; /* XXX this is const */
5694 if (ast_strlen_zero(args
.context
))
5695 args
.context
= chan
->context
;
5698 if (!strcasecmp(args
.options
, "skip"))
5699 flags
.flags
= BACKGROUND_SKIP
;
5700 else if (!strcasecmp(args
.options
, "noanswer"))
5701 flags
.flags
= BACKGROUND_NOANSWER
;
5703 ast_app_parse_options(background_opts
, &flags
, NULL
, args
.options
);
5706 /* Answer if need be */
5707 if (chan
->_state
!= AST_STATE_UP
) {
5708 if (ast_test_flag(&flags
, BACKGROUND_SKIP
)) {
5710 } else if (!ast_test_flag(&flags
, BACKGROUND_NOANSWER
)) {
5711 res
= ast_answer(chan
);
5716 char *back
= args
.filename
;
5718 ast_stopstream(chan
); /* Stop anything playing */
5719 /* Stream the list of files */
5720 while (!res
&& (front
= strsep(&back
, "&")) ) {
5721 if ( (res
= ast_streamfile(chan
, front
, args
.lang
)) ) {
5722 ast_log(LOG_WARNING
, "ast_streamfile failed on %s for %s\n", chan
->name
, (char*)data
);
5726 if (ast_test_flag(&flags
, BACKGROUND_PLAYBACK
)) {
5727 res
= ast_waitstream(chan
, "");
5728 } else if (ast_test_flag(&flags
, BACKGROUND_MATCHEXTEN
)) {
5729 res
= ast_waitstream_exten(chan
, args
.context
);
5731 res
= ast_waitstream(chan
, AST_DIGIT_ANY
);
5733 ast_stopstream(chan
);
5736 if (args
.context
!= chan
->context
&& res
) {
5737 snprintf(chan
->exten
, sizeof(chan
->exten
), "%c", res
);
5738 ast_copy_string(chan
->context
, args
.context
, sizeof(chan
->context
));
5746 * \ingroup applications
5748 static int pbx_builtin_goto(struct ast_channel
*chan
, void *data
)
5750 int res
= ast_parseable_goto(chan
, data
);
5751 if (!res
&& (option_verbose
> 2))
5752 ast_verbose( VERBOSE_PREFIX_3
"Goto (%s,%s,%d)\n", chan
->context
,chan
->exten
, chan
->priority
+1);
5757 int pbx_builtin_serialize_variables(struct ast_channel
*chan
, char *buf
, size_t size
)
5759 struct ast_var_t
*variables
;
5760 const char *var
, *val
;
5766 memset(buf
, 0, size
);
5768 ast_channel_lock(chan
);
5770 AST_LIST_TRAVERSE(&chan
->varshead
, variables
, entries
) {
5771 if ((var
=ast_var_name(variables
)) && (val
=ast_var_value(variables
))
5772 /* && !ast_strlen_zero(var) && !ast_strlen_zero(val) */
5774 if (ast_build_string(&buf
, &size
, "%s=%s\n", var
, val
)) {
5775 ast_log(LOG_ERROR
, "Data Buffer Size Exceeded!\n");
5783 ast_channel_unlock(chan
);
5788 const char *pbx_builtin_getvar_helper(struct ast_channel
*chan
, const char *name
)
5790 struct ast_var_t
*variables
;
5791 const char *ret
= NULL
;
5793 struct varshead
*places
[2] = { NULL
, &globals
};
5799 ast_channel_lock(chan
);
5800 places
[0] = &chan
->varshead
;
5803 for (i
= 0; i
< 2; i
++) {
5806 if (places
[i
] == &globals
)
5807 ast_mutex_lock(&globalslock
);
5808 AST_LIST_TRAVERSE(places
[i
], variables
, entries
) {
5809 if (!strcmp(name
, ast_var_name(variables
))) {
5810 ret
= ast_var_value(variables
);
5814 if (places
[i
] == &globals
)
5815 ast_mutex_unlock(&globalslock
);
5821 ast_channel_unlock(chan
);
5826 void pbx_builtin_pushvar_helper(struct ast_channel
*chan
, const char *name
, const char *value
)
5828 struct ast_var_t
*newvariable
;
5829 struct varshead
*headp
;
5831 if (name
[strlen(name
)-1] == ')') {
5832 char *function
= ast_strdupa(name
);
5834 ast_log(LOG_WARNING
, "Cannot push a value onto a function\n");
5835 ast_func_write(chan
, function
, value
);
5840 ast_channel_lock(chan
);
5841 headp
= &chan
->varshead
;
5843 ast_mutex_lock(&globalslock
);
5848 if ((option_verbose
> 1) && (headp
== &globals
))
5849 ast_verbose(VERBOSE_PREFIX_2
"Setting global variable '%s' to '%s'\n", name
, value
);
5850 newvariable
= ast_var_assign(name
, value
);
5851 AST_LIST_INSERT_HEAD(headp
, newvariable
, entries
);
5855 ast_channel_unlock(chan
);
5857 ast_mutex_unlock(&globalslock
);
5860 void pbx_builtin_setvar_helper(struct ast_channel
*chan
, const char *name
, const char *value
)
5862 struct ast_var_t
*newvariable
;
5863 struct varshead
*headp
;
5864 const char *nametail
= name
;
5866 if (name
[strlen(name
)-1] == ')') {
5867 char *function
= ast_strdupa(name
);
5869 ast_func_write(chan
, function
, value
);
5874 ast_channel_lock(chan
);
5875 headp
= &chan
->varshead
;
5877 ast_mutex_lock(&globalslock
);
5881 /* For comparison purposes, we have to strip leading underscores */
5882 if (*nametail
== '_') {
5884 if (*nametail
== '_')
5888 AST_LIST_TRAVERSE (headp
, newvariable
, entries
) {
5889 if (strcasecmp(ast_var_name(newvariable
), nametail
) == 0) {
5890 /* there is already such a variable, delete it */
5891 AST_LIST_REMOVE(headp
, newvariable
, entries
);
5892 ast_var_delete(newvariable
);
5898 if ((option_verbose
> 1) && (headp
== &globals
))
5899 ast_verbose(VERBOSE_PREFIX_2
"Setting global variable '%s' to '%s'\n", name
, value
);
5900 newvariable
= ast_var_assign(name
, value
);
5901 AST_LIST_INSERT_HEAD(headp
, newvariable
, entries
);
5905 ast_channel_unlock(chan
);
5907 ast_mutex_unlock(&globalslock
);
5910 int pbx_builtin_setvar(struct ast_channel
*chan
, void *data
)
5912 char *name
, *value
, *mydata
;
5914 char *argv
[24]; /* this will only support a maximum of 24 variables being set in a single operation */
5918 if (ast_strlen_zero(data
)) {
5919 ast_log(LOG_WARNING
, "Set requires at least one variable name/value pair.\n");
5923 mydata
= ast_strdupa(data
);
5924 argc
= ast_app_separate_args(mydata
, '|', argv
, sizeof(argv
) / sizeof(argv
[0]));
5926 /* check for a trailing flags argument */
5927 if ((argc
> 1) && !strchr(argv
[argc
-1], '=')) {
5929 if (strchr(argv
[argc
], 'g')) {
5930 ast_log(LOG_WARNING
, "The use of the 'g' flag is deprecated. Please use Set(GLOBAL(foo)=bar) instead\n");
5936 ast_log(LOG_WARNING
, "Setting multiple variables at once within Set is deprecated. Please separate each name/value pair into its own line.\n");
5938 for (x
= 0; x
< argc
; x
++) {
5940 if ((value
= strchr(name
, '='))) {
5942 pbx_builtin_setvar_helper((global
) ? NULL
: chan
, name
, value
);
5944 ast_log(LOG_WARNING
, "Ignoring entry '%s' with no = (and not last 'options' entry)\n", name
);
5950 int pbx_builtin_importvar(struct ast_channel
*chan
, void *data
)
5955 char tmp
[VAR_BUF_SIZE
]="";
5957 if (ast_strlen_zero(data
)) {
5958 ast_log(LOG_WARNING
, "Ignoring, since there is no variable to set\n");
5962 value
= ast_strdupa(data
);
5963 name
= strsep(&value
,"=");
5964 channel
= strsep(&value
,"|");
5965 if (channel
&& value
&& name
) { /*! \todo XXX should do !ast_strlen_zero(..) of the args ? */
5966 struct ast_channel
*chan2
= ast_get_channel_by_name_locked(channel
);
5968 char *s
= alloca(strlen(value
) + 4);
5970 sprintf(s
, "${%s}", value
);
5971 pbx_substitute_variables_helper(chan2
, s
, tmp
, sizeof(tmp
) - 1);
5973 ast_channel_unlock(chan2
);
5975 pbx_builtin_setvar_helper(chan
, name
, tmp
);
5981 /*! \todo XXX overwrites data ? */
5982 static int pbx_builtin_setglobalvar(struct ast_channel
*chan
, void *data
)
5985 char *stringp
= data
;
5986 static int dep_warning
= 0;
5988 if (ast_strlen_zero(data
)) {
5989 ast_log(LOG_WARNING
, "Ignoring, since there is no variable to set\n");
5993 name
= strsep(&stringp
, "=");
5997 ast_log(LOG_WARNING
, "SetGlobalVar is deprecated. Please use Set(GLOBAL(%s)=%s) instead.\n", name
, stringp
);
6000 /*! \todo XXX watch out, leading whitespace ? */
6001 pbx_builtin_setvar_helper(NULL
, name
, stringp
);
6006 static int pbx_builtin_noop(struct ast_channel
*chan
, void *data
)
6011 void pbx_builtin_clear_globals(void)
6013 struct ast_var_t
*vardata
;
6015 ast_mutex_lock(&globalslock
);
6016 while ((vardata
= AST_LIST_REMOVE_HEAD(&globals
, entries
)))
6017 ast_var_delete(vardata
);
6018 ast_mutex_unlock(&globalslock
);
6021 int pbx_checkcondition(const char *condition
)
6023 if (ast_strlen_zero(condition
)) /* NULL or empty strings are false */
6025 else if (*condition
>= '0' && *condition
<= '9') /* Numbers are evaluated for truth */
6026 return atoi(condition
);
6027 else /* Strings are true */
6031 static int pbx_builtin_gotoif(struct ast_channel
*chan
, void *data
)
6033 char *condition
, *branch1
, *branch2
, *branch
;
6037 if (ast_strlen_zero(data
)) {
6038 ast_log(LOG_WARNING
, "Ignoring, since there is no variable to check\n");
6042 stringp
= ast_strdupa(data
);
6043 condition
= strsep(&stringp
,"?");
6044 branch1
= strsep(&stringp
,":");
6045 branch2
= strsep(&stringp
,"");
6046 branch
= pbx_checkcondition(condition
) ? branch1
: branch2
;
6048 if (ast_strlen_zero(branch
)) {
6050 ast_log(LOG_DEBUG
, "Not taking any branch\n");
6054 rc
= pbx_builtin_goto(chan
, branch
);
6059 static int pbx_builtin_saynumber(struct ast_channel
*chan
, void *data
)
6065 if (ast_strlen_zero(data
)) {
6066 ast_log(LOG_WARNING
, "SayNumber requires an argument (number)\n");
6069 ast_copy_string(tmp
, data
, sizeof(tmp
));
6070 strsep(&number
, "|");
6071 options
= strsep(&number
, "|");
6073 if ( strcasecmp(options
, "f") && strcasecmp(options
,"m") &&
6074 strcasecmp(options
, "c") && strcasecmp(options
, "n") ) {
6075 ast_log(LOG_WARNING
, "SayNumber gender option is either 'f', 'm', 'c' or 'n'\n");
6080 if (ast_say_number(chan
, atoi(tmp
), "", chan
->language
, options
)) {
6081 ast_log(LOG_WARNING
, "We were unable to say the number %s, is it too large?\n", tmp
);
6087 static int pbx_builtin_saydigits(struct ast_channel
*chan
, void *data
)
6092 res
= ast_say_digit_str(chan
, data
, "", chan
->language
);
6096 static int pbx_builtin_saycharacters(struct ast_channel
*chan
, void *data
)
6101 res
= ast_say_character_str(chan
, data
, "", chan
->language
);
6105 static int pbx_builtin_sayphonetic(struct ast_channel
*chan
, void *data
)
6110 res
= ast_say_phonetic_str(chan
, data
, "", chan
->language
);
6118 /* Initialize the PBX */
6119 if (option_verbose
) {
6120 ast_verbose( "Asterisk PBX Core Initializing\n");
6121 ast_verbose( "Registering builtin applications:\n");
6123 ast_cli_register_multiple(pbx_cli
, sizeof(pbx_cli
) / sizeof(struct ast_cli_entry
));
6125 /* Register builtin applications */
6126 for (x
=0; x
<sizeof(builtins
) / sizeof(struct pbx_builtin
); x
++) {
6128 ast_verbose( VERBOSE_PREFIX_1
"[%s]\n", builtins
[x
].name
);
6129 if (ast_register_application(builtins
[x
].name
, builtins
[x
].execute
, builtins
[x
].synopsis
, builtins
[x
].description
)) {
6130 ast_log(LOG_ERROR
, "Unable to register builtin application '%s'\n", builtins
[x
].name
);
6138 * Lock context list functions ...
6140 int ast_lock_contexts()
6142 return ast_rwlock_wrlock(&conlock
);
6145 int ast_rdlock_contexts(void)
6147 return ast_rwlock_rdlock(&conlock
);
6150 int ast_wrlock_contexts(void)
6152 return ast_rwlock_wrlock(&conlock
);
6155 int ast_unlock_contexts()
6157 return ast_rwlock_unlock(&conlock
);
6163 int ast_lock_context(struct ast_context
*con
)
6165 return ast_mutex_lock(&con
->lock
);
6168 int ast_unlock_context(struct ast_context
*con
)
6170 return ast_mutex_unlock(&con
->lock
);
6174 * Name functions ...
6176 const char *ast_get_context_name(struct ast_context
*con
)
6178 return con
? con
->name
: NULL
;
6181 struct ast_context
*ast_get_extension_context(struct ast_exten
*exten
)
6183 return exten
? exten
->parent
: NULL
;
6186 const char *ast_get_extension_name(struct ast_exten
*exten
)
6188 return exten
? exten
->exten
: NULL
;
6191 const char *ast_get_extension_label(struct ast_exten
*exten
)
6193 return exten
? exten
->label
: NULL
;
6196 const char *ast_get_include_name(struct ast_include
*inc
)
6198 return inc
? inc
->name
: NULL
;
6201 const char *ast_get_ignorepat_name(struct ast_ignorepat
*ip
)
6203 return ip
? ip
->pattern
: NULL
;
6206 int ast_get_extension_priority(struct ast_exten
*exten
)
6208 return exten
? exten
->priority
: -1;
6212 * Registrar info functions ...
6214 const char *ast_get_context_registrar(struct ast_context
*c
)
6216 return c
? c
->registrar
: NULL
;
6219 const char *ast_get_extension_registrar(struct ast_exten
*e
)
6221 return e
? e
->registrar
: NULL
;
6224 const char *ast_get_include_registrar(struct ast_include
*i
)
6226 return i
? i
->registrar
: NULL
;
6229 const char *ast_get_ignorepat_registrar(struct ast_ignorepat
*ip
)
6231 return ip
? ip
->registrar
: NULL
;
6234 int ast_get_extension_matchcid(struct ast_exten
*e
)
6236 return e
? e
->matchcid
: 0;
6239 const char *ast_get_extension_cidmatch(struct ast_exten
*e
)
6241 return e
? e
->cidmatch
: NULL
;
6244 const char *ast_get_extension_app(struct ast_exten
*e
)
6246 return e
? e
->app
: NULL
;
6249 void *ast_get_extension_app_data(struct ast_exten
*e
)
6251 return e
? e
->data
: NULL
;
6254 const char *ast_get_switch_name(struct ast_sw
*sw
)
6256 return sw
? sw
->name
: NULL
;
6259 const char *ast_get_switch_data(struct ast_sw
*sw
)
6261 return sw
? sw
->data
: NULL
;
6264 const char *ast_get_switch_registrar(struct ast_sw
*sw
)
6266 return sw
? sw
->registrar
: NULL
;
6270 * Walking functions ...
6272 struct ast_context
*ast_walk_contexts(struct ast_context
*con
)
6274 return con
? con
->next
: contexts
;
6277 struct ast_exten
*ast_walk_context_extensions(struct ast_context
*con
,
6278 struct ast_exten
*exten
)
6281 return con
? con
->root
: NULL
;
6286 struct ast_sw
*ast_walk_context_switches(struct ast_context
*con
,
6290 return con
? AST_LIST_FIRST(&con
->alts
) : NULL
;
6292 return AST_LIST_NEXT(sw
, list
);
6295 struct ast_exten
*ast_walk_extension_priorities(struct ast_exten
*exten
,
6296 struct ast_exten
*priority
)
6298 return priority
? priority
->peer
: exten
;
6301 struct ast_include
*ast_walk_context_includes(struct ast_context
*con
,
6302 struct ast_include
*inc
)
6305 return con
? con
->includes
: NULL
;
6310 struct ast_ignorepat
*ast_walk_context_ignorepats(struct ast_context
*con
,
6311 struct ast_ignorepat
*ip
)
6314 return con
? con
->ignorepats
: NULL
;
6319 int ast_context_verify_includes(struct ast_context
*con
)
6321 struct ast_include
*inc
= NULL
;
6324 while ( (inc
= ast_walk_context_includes(con
, inc
)) ) {
6325 if (ast_context_find(inc
->rname
))
6329 ast_log(LOG_WARNING
, "Context '%s' tries includes nonexistent context '%s'\n",
6330 ast_get_context_name(con
), inc
->rname
);
6338 static int __ast_goto_if_exists(struct ast_channel
*chan
, const char *context
, const char *exten
, int priority
, int async
)
6340 int (*goto_func
)(struct ast_channel
*chan
, const char *context
, const char *exten
, int priority
);
6345 if (context
== NULL
)
6346 context
= chan
->context
;
6348 exten
= chan
->exten
;
6350 goto_func
= (async
) ? ast_async_goto
: ast_explicit_goto
;
6351 if (ast_exists_extension(chan
, context
, exten
, priority
, chan
->cid
.cid_num
))
6352 return goto_func(chan
, context
, exten
, priority
);
6357 int ast_goto_if_exists(struct ast_channel
*chan
, const char* context
, const char *exten
, int priority
)
6359 return __ast_goto_if_exists(chan
, context
, exten
, priority
, 0);
6362 int ast_async_goto_if_exists(struct ast_channel
*chan
, const char * context
, const char *exten
, int priority
)
6364 return __ast_goto_if_exists(chan
, context
, exten
, priority
, 1);
6367 int ast_parseable_goto(struct ast_channel
*chan
, const char *goto_string
)
6369 char *exten
, *pri
, *context
;
6374 if (ast_strlen_zero(goto_string
)) {
6375 ast_log(LOG_WARNING
, "Goto requires an argument (optional context|optional extension|priority)\n");
6378 stringp
= ast_strdupa(goto_string
);
6379 context
= strsep(&stringp
, "|"); /* guaranteed non-null */
6380 exten
= strsep(&stringp
, "|");
6381 pri
= strsep(&stringp
, "|");
6382 if (!exten
) { /* Only a priority in this one */
6386 } else if (!pri
) { /* Only an extension and priority in this one */
6394 } else if (*pri
== '-') {
6398 if (sscanf(pri
, "%d", &ipri
) != 1) {
6399 if ((ipri
= ast_findlabel_extension(chan
, context
? context
: chan
->context
, exten
? exten
: chan
->exten
,
6400 pri
, chan
->cid
.cid_num
)) < 1) {
6401 ast_log(LOG_WARNING
, "Priority '%s' must be a number > 0, or valid label\n", pri
);
6406 /* At this point we have a priority and maybe an extension and a context */
6409 ipri
= chan
->priority
+ (ipri
* mode
);
6411 ast_explicit_goto(chan
, context
, exten
, ipri
);
6412 ast_cdr_update(chan
);