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"
293 { "Busy", pbx_builtin_busy
,
294 "Indicate the Busy condition",
295 " Busy([timeout]): This application will indicate the busy condition to\n"
296 "the calling channel. If the optional timeout is specified, the calling channel\n"
297 "will be hung up after the specified number of seconds. Otherwise, this\n"
298 "application will wait until the calling channel hangs up.\n"
301 { "Congestion", pbx_builtin_congestion
,
302 "Indicate the Congestion condition",
303 " Congestion([timeout]): This application will indicate the congestion\n"
304 "condition to the calling channel. If the optional timeout is specified, the\n"
305 "calling channel will be hung up after the specified number of seconds.\n"
306 "Otherwise, this application will wait until the calling channel hangs up.\n"
309 { "Goto", pbx_builtin_goto
,
310 "Jump to a particular priority, extension, or context",
311 " Goto([[context|]extension|]priority): This application will set the current\n"
312 "context, extension, and priority in the channel structure. After it completes, the\n"
313 "pbx engine will continue dialplan execution at the specified location.\n"
314 "If no specific extension, or extension and context, are specified, then this\n"
315 "application will just set the specified priority of the current extension.\n"
316 " At least a priority is required as an argument, or the goto will return a -1,\n"
317 "and the channel and call will be terminated.\n"
318 " If the location that is put into the channel information is bogus, and asterisk cannot\n"
319 "find that location in the dialplan,\n"
320 "then the execution engine will try to find and execute the code in the 'i' (invalid)\n"
321 "extension in the current context. If that does not exist, it will try to execute the\n"
322 "'h' extension. If either or neither the 'h' or 'i' extensions have been defined, the\n"
323 "channel is hung up, and the execution of instructions on the channel is terminated.\n"
324 "What this means is that, for example, you specify a context that does not exist, then\n"
325 "it will not be possible to find the 'h' or 'i' extensions, and the call will terminate!\n"
328 { "GotoIf", pbx_builtin_gotoif
,
330 " GotoIf(condition?[labeliftrue]:[labeliffalse]): This application will set the current\n"
331 "context, extension, and priority in the channel structure based on the evaluation of\n"
332 "the given condition. After this application completes, the\n"
333 "pbx engine will continue dialplan execution at the specified location in the dialplan.\n"
334 "The channel will continue at\n"
335 "'labeliftrue' if the condition is true, or 'labeliffalse' if the condition is\n"
336 "false. The labels are specified with the same syntax as used within the Goto\n"
337 "application. If the label chosen by the condition is omitted, no jump is\n"
338 "performed, and the execution passes to the next instruction.\n"
339 "If the target location is bogus, and does not exist, the execution engine will try \n"
340 "to find and execute the code in the 'i' (invalid)\n"
341 "extension in the current context. If that does not exist, it will try to execute the\n"
342 "'h' extension. If either or neither the 'h' or 'i' extensions have been defined, the\n"
343 "channel is hung up, and the execution of instructions on the channel is terminated.\n"
344 "Remember that this command can set the current context, and if the context specified\n"
345 "does not exist, then it will not be able to find any 'h' or 'i' extensions there, and\n"
346 "the channel and call will both be terminated!\n"
349 { "GotoIfTime", pbx_builtin_gotoiftime
,
350 "Conditional Goto based on the current time",
351 " GotoIfTime(<times>|<weekdays>|<mdays>|<months>?[[context|]exten|]priority):\n"
352 "This application will set the context, extension, and priority in the channel structure\n"
353 "if the current time matches the given time specification. Otherwise, nothing is done.\n"
354 "Further information on the time specification can be found in examples\n"
355 "illustrating how to do time-based context includes in the dialplan.\n"
356 "If the target jump location is bogus, the same actions would be taken as for Goto.\n"
359 { "ExecIfTime", pbx_builtin_execiftime
,
360 "Conditional application execution based on the current time",
361 " ExecIfTime(<times>|<weekdays>|<mdays>|<months>?appname[|appargs]):\n"
362 "This application will execute the specified dialplan application, with optional\n"
363 "arguments, if the current time matches the given time specification.\n"
366 { "Hangup", pbx_builtin_hangup
,
367 "Hang up the calling channel",
368 " Hangup([causecode]): This application will hang up the calling channel.\n"
369 "If a causecode is given the channel's hangup cause will be set to the given\n"
373 { "NoOp", pbx_builtin_noop
,
375 " NoOp(): This applicatiion does nothing. However, it is useful for debugging\n"
376 "purposes. Any text that is provided as arguments to this application can be\n"
377 "viewed at the Asterisk CLI. This method can be used to see the evaluations of\n"
378 "variables or functions without having any effect."
381 { "Progress", pbx_builtin_progress
,
383 " Progress(): This application will request that in-band progress information\n"
384 "be provided to the calling channel.\n"
387 { "ResetCDR", pbx_builtin_resetcdr
,
388 "Resets the Call Data Record",
389 " ResetCDR([options]): This application causes the Call Data Record to be\n"
392 " w -- Store the current CDR record before resetting it.\n"
393 " a -- Store any stacked records.\n"
394 " v -- Save CDR variables.\n"
397 { "Ringing", pbx_builtin_ringing
,
398 "Indicate ringing tone",
399 " Ringing(): This application will request that the channel indicate a ringing\n"
400 "tone to the user.\n"
403 { "SayNumber", pbx_builtin_saynumber
,
405 " SayNumber(digits[,gender]): This application will play the sounds that\n"
406 "correspond to the given number. Optionally, a gender may be specified.\n"
407 "This will use the language that is currently set for the channel. See the\n"
408 "LANGUAGE function for more information on setting the language for the channel.\n"
411 { "SayDigits", pbx_builtin_saydigits
,
413 " SayDigits(digits): This application will play the sounds that correspond\n"
414 "to the digits of the given number. This will use the language that is currently\n"
415 "set for the channel. See the LANGUAGE function for more information on setting\n"
416 "the language for the channel.\n"
419 { "SayAlpha", pbx_builtin_saycharacters
,
421 " SayAlpha(string): This application will play the sounds that correspond to\n"
422 "the letters of the given string.\n"
425 { "SayPhonetic", pbx_builtin_sayphonetic
,
427 " SayPhonetic(string): This application will play the sounds from the phonetic\n"
428 "alphabet that correspond to the letters in the given string.\n"
431 { "SetAMAFlags", pbx_builtin_setamaflags
,
433 " SetAMAFlags([flag]): This application will set the channel's AMA Flags for\n"
434 " billing purposes.\n"
437 { "SetGlobalVar", pbx_builtin_setglobalvar
,
438 "Set a global variable to a given value",
439 " SetGlobalVar(variable=value): This application sets a given global variable to\n"
440 "the specified value.\n"
441 "\n\nThis application is deprecated in favor of Set(GLOBAL(var)=value)\n"
444 { "Set", pbx_builtin_setvar
,
445 "Set channel variable(s) or function value(s)",
446 " Set(name1=value1|name2=value2|..[|options])\n"
447 "This function can be used to set the value of channel variables or dialplan\n"
448 "functions. It will accept up to 24 name/value pairs. When setting variables,\n"
449 "if the variable name is prefixed with _, the variable will be inherited into\n"
450 "channels created from the current channel. If the variable name is prefixed\n"
451 "with __, the variable will be inherited into channels created from the current\n"
452 "channel and all children channels.\n"
454 " g - Set variable globally instead of on the channel\n"
455 " (applies only to variables, not functions)\n"
456 "\n\nThe use of Set to set multiple variables at once and the g flag have both\n"
457 "been deprecated. Please use multiple Set calls and the GLOBAL() dialplan\n"
458 "function instead.\n"
461 { "ImportVar", pbx_builtin_importvar
,
462 "Import a variable from a channel into a new variable",
463 " ImportVar(newvar=channelname|variable): This application imports a variable\n"
464 "from the specified channel (as opposed to the current one) and stores it as\n"
465 "a variable in the current channel (the channel that is calling this\n"
466 "application). Variables created by this application have the same inheritance\n"
467 "properties as those created with the Set application. See the documentation for\n"
468 "Set for more information.\n"
471 { "Wait", pbx_builtin_wait
,
472 "Waits for some time",
473 " Wait(seconds): This application waits for a specified number of seconds.\n"
474 "Then, dialplan execution will continue at the next priority.\n"
475 " Note that the seconds can be passed with fractions of a second. For example,\n"
476 "'1.5' will ask the application to wait for 1.5 seconds.\n"
479 { "WaitExten", pbx_builtin_waitexten
,
480 "Waits for an extension to be entered",
481 " WaitExten([seconds][|options]): This application waits for the user to enter\n"
482 "a new extension for a specified number of seconds.\n"
483 " Note that the seconds can be passed with fractions of a second. For example,\n"
484 "'1.5' will ask the application to wait for 1.5 seconds.\n"
486 " m[(x)] - Provide music on hold to the caller while waiting for an extension.\n"
487 " Optionally, specify the class for music on hold within parenthesis.\n"
492 static struct ast_context
*contexts
;
493 AST_RWLOCK_DEFINE_STATIC(conlock
); /*!< Lock for the ast_context list */
495 static AST_LIST_HEAD_STATIC(apps
, ast_app
);
497 static AST_LIST_HEAD_STATIC(switches
, ast_switch
);
499 static int stateid
= 1;
501 When holding this list's lock, do _not_ do anything that will cause conlock
502 to be taken, unless you _already_ hold it. The ast_merge_contexts_and_delete
503 function will take the locks in conlock/hints order, so any other
504 paths that require both locks must also take them in that order.
506 static AST_LIST_HEAD_STATIC(hints
, ast_hint
);
507 struct ast_state_cb
*statecbs
;
510 \note This function is special. It saves the stack so that no matter
511 how many times it is called, it returns to the same place */
512 int pbx_exec(struct ast_channel
*c
, /*!< Channel */
513 struct ast_app
*app
, /*!< Application */
514 void *data
) /*!< Data for execution */
518 const char *saved_c_appl
;
519 const char *saved_c_data
;
521 if (c
->cdr
&& !ast_check_hangup(c
))
522 ast_cdr_setapp(c
->cdr
, app
->name
, data
);
524 /* save channel values */
525 saved_c_appl
= c
->appl
;
526 saved_c_data
= c
->data
;
530 /* XXX remember what to to when we have linked apps to modules */
532 /* XXX LOCAL_USER_ADD(app->module) */
534 res
= app
->execute(c
, S_OR(data
, ""));
536 /* XXX LOCAL_USER_REMOVE(app->module) */
538 /* restore channel values */
539 c
->appl
= saved_c_appl
;
540 c
->data
= saved_c_data
;
545 /*! Go no deeper than this through includes (not counting loops) */
546 #define AST_PBX_MAX_STACK 128
548 /*! \brief Find application handle in linked list
550 struct ast_app
*pbx_findapp(const char *app
)
554 AST_LIST_LOCK(&apps
);
555 AST_LIST_TRAVERSE(&apps
, tmp
, list
) {
556 if (!strcasecmp(tmp
->name
, app
))
559 AST_LIST_UNLOCK(&apps
);
564 static struct ast_switch
*pbx_findswitch(const char *sw
)
566 struct ast_switch
*asw
;
568 AST_LIST_LOCK(&switches
);
569 AST_LIST_TRAVERSE(&switches
, asw
, list
) {
570 if (!strcasecmp(asw
->name
, sw
))
573 AST_LIST_UNLOCK(&switches
);
578 static inline int include_valid(struct ast_include
*i
)
583 return ast_check_timing(&(i
->timing
));
586 static void pbx_destroy(struct ast_pbx
*p
)
592 * Special characters used in patterns:
593 * '_' underscore is the leading character of a pattern.
594 * In other position it is treated as a regular char.
595 * ' ' '-' space and '-' are separator and ignored.
596 * . one or more of any character. Only allowed at the end of
598 * ! zero or more of anything. Also impacts the result of CANMATCH
599 * and MATCHMORE. Only allowed at the end of a pattern.
600 * In the core routine, ! causes a match with a return code of 2.
601 * In turn, depending on the search mode: (XXX check if it is implemented)
602 * - E_MATCH retuns 1 (does match)
603 * - E_MATCHMORE returns 0 (no match)
604 * - E_CANMATCH returns 1 (does match)
606 * / should not appear as it is considered the separator of the CID info.
607 * XXX at the moment we may stop on this char.
609 * X Z N match ranges 0-9, 1-9, 2-9 respectively.
610 * [ denotes the start of a set of character. Everything inside
611 * is considered literally. We can have ranges a-d and individual
612 * characters. A '[' and '-' can be considered literally if they
613 * are just before ']'.
614 * XXX currently there is no way to specify ']' in a range, nor \ is
615 * considered specially.
617 * When we compare a pattern with a specific extension, all characters in the extension
618 * itself are considered literally with the only exception of '-' which is considered
619 * as a separator and thus ignored.
620 * XXX do we want to consider space as a separator as well ?
621 * XXX do we want to consider the separators in non-patterns as well ?
625 * \brief helper functions to sort extensions and patterns in the desired way,
626 * so that more specific patterns appear first.
628 * ext_cmp1 compares individual characters (or sets of), returning
629 * an int where bits 0-7 are the ASCII code of the first char in the set,
630 * while bit 8-15 are the cardinality of the set minus 1.
631 * This way more specific patterns (smaller cardinality) appear first.
632 * Wildcards have a special value, so that we can directly compare them to
633 * sets by subtracting the two values. In particular:
634 * 0x000xx one character, xx
635 * 0x0yyxx yy character set starting with xx
636 * 0x10000 '.' (one or more of anything)
637 * 0x20000 '!' (zero or more of anything)
638 * 0x30000 NUL (end of string)
639 * 0x40000 error in set.
640 * The pointer to the string is advanced according to needs.
642 * 1. the empty set is equivalent to NUL.
643 * 2. given that a full set has always 0 as the first element,
644 * we could encode the special cases as 0xffXX where XX
645 * is 1, 2, 3, 4 as used above.
647 static int ext_cmp1(const char **p
)
650 int c
, cmin
= 0xff, count
= 0;
653 /* load, sign extend and advance pointer until we find
656 while ( (c
= *(*p
)++) && (c
== ' ' || c
== '-') )
657 ; /* ignore some characters */
659 /* always return unless we have a set of chars */
661 default: /* ordinary character */
662 return 0x0000 | (c
& 0xff);
665 return 0x0700 | '2' ;
673 case '.': /* wildcard */
676 case '!': /* earlymatch */
677 return 0x20000; /* less specific than NULL */
679 case '\0': /* empty string */
683 case '[': /* pattern */
686 /* locate end of set */
687 end
= strchr(*p
, ']');
690 ast_log(LOG_WARNING
, "Wrong usage of [] in the extension\n");
691 return 0x40000; /* XXX make this entry go last... */
694 bzero(chars
, sizeof(chars
)); /* clear all chars in the set */
695 for (; *p
< end
; (*p
)++) {
696 unsigned char c1
, c2
; /* first-last char in range */
697 c1
= (unsigned char)((*p
)[0]);
698 if (*p
+ 2 < end
&& (*p
)[1] == '-') { /* this is a range */
699 c2
= (unsigned char)((*p
)[2]);
700 *p
+= 2; /* skip a total of 3 chars */
701 } else /* individual character */
705 for (; c1
<= c2
; c1
++) {
706 uint32_t mask
= 1 << (c1
% 32);
707 if ( (chars
[ c1
/ 32 ] & mask
) == 0)
709 chars
[ c1
/ 32 ] |= mask
;
713 return count
== 0 ? 0x30000 : (count
| cmin
);
717 * \brief the full routine to compare extensions in rules.
719 static int ext_cmp(const char *a
, const char *b
)
721 /* make sure non-patterns come first.
722 * If a is not a pattern, it either comes first or
723 * we use strcmp to compare the strings.
728 return (b
[0] == '_') ? -1 : strcmp(a
, b
);
730 /* Now we know a is a pattern; if b is not, a comes first */
733 #if 0 /* old mode for ext matching */
736 /* ok we need full pattern sorting routine */
737 while (!ret
&& a
&& b
)
738 ret
= ext_cmp1(&a
) - ext_cmp1(&b
);
742 return (ret
> 0) ? 1 : -1;
746 * When looking up extensions, we can have different requests
747 * identified by the 'action' argument, as follows.
748 * Note that the coding is such that the low 4 bits are the
749 * third argument to extension_match_core.
752 E_MATCHMORE
= 0x00, /* extension can match but only with more 'digits' */
753 E_CANMATCH
= 0x01, /* extension can match with or without more 'digits' */
754 E_MATCH
= 0x02, /* extension is an exact match */
755 E_MATCH_MASK
= 0x03, /* mask for the argument to extension_match_core() */
756 E_SPAWN
= 0x12, /* want to spawn an extension. Requires exact match */
757 E_FINDLABEL
= 0x22 /* returns the priority for a given label. Requires exact match */
761 * Internal function for ast_extension_{match|close}
762 * return 0 on no-match, 1 on match, 2 on early match.
763 * mode is as follows:
764 * E_MATCH success only on exact match
765 * E_MATCHMORE success only on partial match (i.e. leftover digits in pattern)
766 * E_CANMATCH either of the above.
769 static int _extension_match_core(const char *pattern
, const char *data
, enum ext_match_t mode
)
771 mode
&= E_MATCH_MASK
; /* only consider the relevant bits */
773 if ( (mode
== E_MATCH
) && (pattern
[0] == '_') && (strcasecmp(pattern
,data
)==0) ) /* note: if this test is left out, then _x. will not match _x. !!! */
776 if (pattern
[0] != '_') { /* not a pattern, try exact or partial match */
777 int ld
= strlen(data
), lp
= strlen(pattern
);
779 if (lp
< ld
) /* pattern too short, cannot match */
781 /* depending on the mode, accept full or partial match or both */
783 return !strcmp(pattern
, data
); /* 1 on match, 0 on fail */
784 if (ld
== 0 || !strncasecmp(pattern
, data
, ld
)) /* partial or full match */
785 return (mode
== E_MATCHMORE
) ? lp
> ld
: 1; /* XXX should consider '!' and '/' ? */
789 pattern
++; /* skip leading _ */
791 * XXX below we stop at '/' which is a separator for the CID info. However we should
792 * not store '/' in the pattern at all. When we insure it, we can remove the checks.
794 while (*data
&& *pattern
&& *pattern
!= '/') {
797 if (*data
== '-') { /* skip '-' in data (just a separator) */
801 switch (toupper(*pattern
)) {
802 case '[': /* a range */
803 end
= strchr(pattern
+1, ']'); /* XXX should deal with escapes ? */
805 ast_log(LOG_WARNING
, "Wrong usage of [] in the extension\n");
806 return 0; /* unconditional failure */
808 for (pattern
++; pattern
!= end
; pattern
++) {
809 if (pattern
+2 < end
&& pattern
[1] == '-') { /* this is a range */
810 if (*data
>= pattern
[0] && *data
<= pattern
[2])
811 break; /* match found */
813 pattern
+= 2; /* skip a total of 3 chars */
816 } else if (*data
== pattern
[0])
817 break; /* match found */
821 pattern
= end
; /* skip and continue */
824 if (*data
< '2' || *data
> '9')
828 if (*data
< '0' || *data
> '9')
832 if (*data
< '1' || *data
> '9')
835 case '.': /* Must match, even with more digits */
837 case '!': /* Early match */
840 case '-': /* Ignore these in patterns */
841 data
--; /* compensate the final data++ */
844 if (*data
!= *pattern
)
850 if (*data
) /* data longer than pattern, no match */
853 * match so far, but ran off the end of the data.
854 * Depending on what is next, determine match or not.
856 if (*pattern
== '\0' || *pattern
== '/') /* exact match */
857 return (mode
== E_MATCHMORE
) ? 0 : 1; /* this is a failure for E_MATCHMORE */
858 else if (*pattern
== '!') /* early match */
860 else /* partial match */
861 return (mode
== E_MATCH
) ? 0 : 1; /* this is a failure for E_MATCH */
865 * Wrapper around _extension_match_core() to do performance measurement
866 * using the profiling code.
868 static int extension_match_core(const char *pattern
, const char *data
, enum ext_match_t mode
)
871 static int prof_id
= -2; /* marker for 'unallocated' id */
873 prof_id
= ast_add_profile("ext_match", 0);
874 ast_mark(prof_id
, 1);
875 i
= _extension_match_core(pattern
, data
, mode
);
876 ast_mark(prof_id
, 0);
880 int ast_extension_match(const char *pattern
, const char *data
)
882 return extension_match_core(pattern
, data
, E_MATCH
);
885 int ast_extension_close(const char *pattern
, const char *data
, int needmore
)
887 if (needmore
!= E_MATCHMORE
&& needmore
!= E_CANMATCH
)
888 ast_log(LOG_WARNING
, "invalid argument %d\n", needmore
);
889 return extension_match_core(pattern
, data
, needmore
);
892 struct ast_context
*ast_context_find(const char *name
)
894 struct ast_context
*tmp
= NULL
;
896 ast_rdlock_contexts();
898 while ( (tmp
= ast_walk_contexts(tmp
)) ) {
899 if (!name
|| !strcasecmp(name
, tmp
->name
))
903 ast_unlock_contexts();
908 #define STATUS_NO_CONTEXT 1
909 #define STATUS_NO_EXTENSION 2
910 #define STATUS_NO_PRIORITY 3
911 #define STATUS_NO_LABEL 4
912 #define STATUS_SUCCESS 5
914 static int matchcid(const char *cidpattern
, const char *callerid
)
916 /* If the Caller*ID pattern is empty, then we're matching NO Caller*ID, so
917 failing to get a number should count as a match, otherwise not */
919 if (ast_strlen_zero(callerid
))
920 return ast_strlen_zero(cidpattern
) ? 1 : 0;
922 return ast_extension_match(cidpattern
, callerid
);
925 /* request and result for pbx_find_extension */
926 struct pbx_find_info
{
933 char *incstack
[AST_PBX_MAX_STACK
]; /* filled during the search */
934 int stacklen
; /* modified during the search */
935 int status
; /* set on return */
936 struct ast_switch
*swo
; /* set on return */
937 const char *data
; /* set on return */
938 const char *foundcontext
; /* set on return */
941 static struct ast_exten
*pbx_find_extension(struct ast_channel
*chan
,
942 struct ast_context
*bypass
, struct pbx_find_info
*q
,
943 const char *context
, const char *exten
, int priority
,
944 const char *label
, const char *callerid
, enum ext_match_t action
)
947 struct ast_context
*tmp
;
948 struct ast_exten
*e
, *eroot
;
949 struct ast_include
*i
;
951 char *tmpdata
= NULL
;
953 /* Initialize status if appropriate */
954 if (q
->stacklen
== 0) {
955 q
->status
= STATUS_NO_CONTEXT
;
958 q
->foundcontext
= NULL
;
960 /* Check for stack overflow */
961 if (q
->stacklen
>= AST_PBX_MAX_STACK
) {
962 ast_log(LOG_WARNING
, "Maximum PBX stack exceeded\n");
965 /* Check first to see if we've already been checked */
966 for (x
= 0; x
< q
->stacklen
; x
++) {
967 if (!strcasecmp(q
->incstack
[x
], context
))
970 if (bypass
) /* bypass means we only look there */
972 else { /* look in contexts */
974 while ((tmp
= ast_walk_contexts(tmp
)) ) {
975 if (!strcmp(tmp
->name
, context
))
981 if (q
->status
< STATUS_NO_EXTENSION
)
982 q
->status
= STATUS_NO_EXTENSION
;
984 /* scan the list trying to match extension and CID */
986 while ( (eroot
= ast_walk_context_extensions(tmp
, eroot
)) ) {
987 int match
= extension_match_core(eroot
->exten
, exten
, action
);
988 /* 0 on fail, 1 on match, 2 on earlymatch */
990 if (!match
|| (eroot
->matchcid
&& !matchcid(eroot
->cidmatch
, callerid
)))
991 continue; /* keep trying */
992 if (match
== 2 && action
== E_MATCHMORE
) {
993 /* We match an extension ending in '!'.
994 * The decision in this case is final and is NULL (no match).
998 /* found entry, now look for the right priority */
999 if (q
->status
< STATUS_NO_PRIORITY
)
1000 q
->status
= STATUS_NO_PRIORITY
;
1002 while ( (e
= ast_walk_extension_priorities(eroot
, e
)) ) {
1003 /* Match label or priority */
1004 if (action
== E_FINDLABEL
) {
1005 if (q
->status
< STATUS_NO_LABEL
)
1006 q
->status
= STATUS_NO_LABEL
;
1007 if (label
&& e
->label
&& !strcmp(label
, e
->label
))
1008 break; /* found it */
1009 } else if (e
->priority
== priority
) {
1010 break; /* found it */
1011 } /* else keep searching */
1013 if (e
) { /* found a valid match */
1014 q
->status
= STATUS_SUCCESS
;
1015 q
->foundcontext
= context
;
1019 /* Check alternative switches */
1020 AST_LIST_TRAVERSE(&tmp
->alts
, sw
, list
) {
1021 struct ast_switch
*asw
= pbx_findswitch(sw
->name
);
1022 ast_switch_f
*aswf
= NULL
;
1026 ast_log(LOG_WARNING
, "No such switch '%s'\n", sw
->name
);
1029 /* Substitute variables now */
1031 if (!(tmpdata
= ast_threadstorage_get(&switch_data
, 512))) {
1032 ast_log(LOG_WARNING
, "Can't evaluate switch?!");
1035 pbx_substitute_variables_helper(chan
, sw
->data
, tmpdata
, 512);
1038 /* equivalent of extension_match_core() at the switch level */
1039 if (action
== E_CANMATCH
)
1040 aswf
= asw
->canmatch
;
1041 else if (action
== E_MATCHMORE
)
1042 aswf
= asw
->matchmore
;
1043 else /* action == E_MATCH */
1045 datap
= sw
->eval
? tmpdata
: sw
->data
;
1050 ast_autoservice_start(chan
);
1051 res
= aswf(chan
, context
, exten
, priority
, callerid
, datap
);
1053 ast_autoservice_stop(chan
);
1055 if (res
) { /* Got a match */
1058 q
->foundcontext
= context
;
1059 /* XXX keep status = STATUS_NO_CONTEXT ? */
1063 q
->incstack
[q
->stacklen
++] = tmp
->name
; /* Setup the stack */
1064 /* Now try any includes we have in this context */
1065 for (i
= tmp
->includes
; i
; i
= i
->next
) {
1066 if (include_valid(i
)) {
1067 if ((e
= pbx_find_extension(chan
, bypass
, q
, i
->rname
, exten
, priority
, label
, callerid
, action
)))
1076 /*! \brief extract offset:length from variable name.
1077 * Returns 1 if there is a offset:length part, which is
1078 * trimmed off (values go into variables)
1080 static int parse_variable_name(char *var
, int *offset
, int *length
, int *isfunc
)
1087 for (; *var
; var
++) {
1091 } else if (*var
== ')') {
1093 } else if (*var
== ':' && parens
== 0) {
1095 sscanf(var
, "%d:%d", offset
, length
);
1096 return 1; /* offset:length valid */
1102 /*! \brief takes a substring. It is ok to call with value == workspace.
1104 * offset < 0 means start from the end of the string and set the beginning
1105 * to be that many characters back.
1106 * length is the length of the substring. A value less than 0 means to leave
1107 * that many off the end.
1108 * Always return a copy in workspace.
1110 static char *substring(const char *value
, int offset
, int length
, char *workspace
, size_t workspace_len
)
1112 char *ret
= workspace
;
1113 int lr
; /* length of the input string after the copy */
1115 ast_copy_string(workspace
, value
, workspace_len
); /* always make a copy */
1117 lr
= strlen(ret
); /* compute length after copy, so we never go out of the workspace */
1119 /* Quick check if no need to do anything */
1120 if (offset
== 0 && length
>= lr
) /* take the whole string */
1123 if (offset
< 0) { /* translate negative offset into positive ones */
1124 offset
= lr
+ offset
;
1125 if (offset
< 0) /* If the negative offset was greater than the length of the string, just start at the beginning */
1129 /* too large offset result in empty string so we know what to return */
1131 return ret
+ lr
; /* the final '\0' */
1133 ret
+= offset
; /* move to the start position */
1134 if (length
>= 0 && length
< lr
- offset
) /* truncate if necessary */
1136 else if (length
< 0) {
1137 if (lr
> offset
- length
) /* After we remove from the front and from the rear, is there anything left? */
1138 ret
[lr
+ length
- offset
] = '\0';
1146 /*! \brief pbx_retrieve_variable: Support for Asterisk built-in variables
1148 void pbx_retrieve_variable(struct ast_channel
*c
, const char *var
, char **ret
, char *workspace
, int workspacelen
, struct varshead
*headp
)
1150 const char not_found
= '\0';
1152 const char *s
; /* the result */
1154 int i
, need_substring
;
1155 struct varshead
*places
[2] = { headp
, &globals
}; /* list of places where we may look */
1158 ast_channel_lock(c
);
1159 places
[0] = &c
->varshead
;
1162 * Make a copy of var because parse_variable_name() modifies the string.
1163 * Then if called directly, we might need to run substring() on the result;
1164 * remember this for later in 'need_substring', 'offset' and 'length'
1166 tmpvar
= ast_strdupa(var
); /* parse_variable_name modifies the string */
1167 need_substring
= parse_variable_name(tmpvar
, &offset
, &length
, &i
/* ignored */);
1170 * Look first into predefined variables, then into variable lists.
1171 * Variable 's' points to the result, according to the following rules:
1172 * s == ¬_found (set at the beginning) means that we did not find a
1173 * matching variable and need to look into more places.
1174 * If s != ¬_found, s is a valid result string as follows:
1175 * s = NULL if the variable does not have a value;
1176 * you typically do this when looking for an unset predefined variable.
1177 * s = workspace if the result has been assembled there;
1178 * typically done when the result is built e.g. with an snprintf(),
1179 * so we don't need to do an additional copy.
1180 * s != workspace in case we have a string, that needs to be copied
1181 * (the ast_copy_string is done once for all at the end).
1182 * Typically done when the result is already available in some string.
1184 s
= ¬_found
; /* default value */
1185 if (c
) { /* This group requires a valid channel */
1186 /* Names with common parts are looked up a piece at a time using strncmp. */
1187 if (!strncmp(var
, "CALL", 4)) {
1188 if (!strncmp(var
+ 4, "ING", 3)) {
1189 if (!strcmp(var
+ 7, "PRES")) { /* CALLINGPRES */
1190 snprintf(workspace
, workspacelen
, "%d", c
->cid
.cid_pres
);
1192 } else if (!strcmp(var
+ 7, "ANI2")) { /* CALLINGANI2 */
1193 snprintf(workspace
, workspacelen
, "%d", c
->cid
.cid_ani2
);
1195 } else if (!strcmp(var
+ 7, "TON")) { /* CALLINGTON */
1196 snprintf(workspace
, workspacelen
, "%d", c
->cid
.cid_ton
);
1198 } else if (!strcmp(var
+ 7, "TNS")) { /* CALLINGTNS */
1199 snprintf(workspace
, workspacelen
, "%d", c
->cid
.cid_tns
);
1203 } else if (!strcmp(var
, "HINT")) {
1204 s
= ast_get_hint(workspace
, workspacelen
, NULL
, 0, c
, c
->context
, c
->exten
) ? workspace
: NULL
;
1205 } else if (!strcmp(var
, "HINTNAME")) {
1206 s
= ast_get_hint(NULL
, 0, workspace
, workspacelen
, c
, c
->context
, c
->exten
) ? workspace
: NULL
;
1207 } else if (!strcmp(var
, "EXTEN")) {
1209 } else if (!strcmp(var
, "CONTEXT")) {
1211 } else if (!strcmp(var
, "PRIORITY")) {
1212 snprintf(workspace
, workspacelen
, "%d", c
->priority
);
1214 } else if (!strcmp(var
, "CHANNEL")) {
1216 } else if (!strcmp(var
, "UNIQUEID")) {
1218 } else if (!strcmp(var
, "HANGUPCAUSE")) {
1219 snprintf(workspace
, workspacelen
, "%d", c
->hangupcause
);
1223 if (s
== ¬_found
) { /* look for more */
1224 if (!strcmp(var
, "EPOCH")) {
1225 snprintf(workspace
, workspacelen
, "%u",(int)time(NULL
));
1227 } else if (!strcmp(var
, "SYSTEMNAME")) {
1228 s
= ast_config_AST_SYSTEM_NAME
;
1231 /* if not found, look into chanvars or global vars */
1232 for (i
= 0; s
== ¬_found
&& i
< (sizeof(places
) / sizeof(places
[0])); i
++) {
1233 struct ast_var_t
*variables
;
1236 if (places
[i
] == &globals
)
1237 ast_mutex_lock(&globalslock
);
1238 AST_LIST_TRAVERSE(places
[i
], variables
, entries
) {
1239 if (strcasecmp(ast_var_name(variables
), var
)==0) {
1240 s
= ast_var_value(variables
);
1244 if (places
[i
] == &globals
)
1245 ast_mutex_unlock(&globalslock
);
1247 if (s
== ¬_found
|| s
== NULL
)
1251 ast_copy_string(workspace
, s
, workspacelen
);
1254 *ret
= substring(*ret
, offset
, length
, workspace
, workspacelen
);
1258 ast_channel_unlock(c
);
1261 /*! \brief CLI function to show installed custom functions
1262 \addtogroup CLI_functions
1264 static int handle_show_functions_deprecated(int fd
, int argc
, char *argv
[])
1266 struct ast_custom_function
*acf
;
1270 if (argc
== 4 && (!strcmp(argv
[2], "like")) ) {
1272 } else if (argc
!= 2) {
1273 return RESULT_SHOWUSAGE
;
1276 ast_cli(fd
, "%s Custom Functions:\n--------------------------------------------------------------------------------\n", like
? "Matching" : "Installed");
1278 AST_LIST_LOCK(&acf_root
);
1279 AST_LIST_TRAVERSE(&acf_root
, acf
, acflist
) {
1280 if (!like
|| strstr(acf
->name
, argv
[3])) {
1282 ast_cli(fd
, "%-20.20s %-35.35s %s\n", acf
->name
, acf
->syntax
, acf
->synopsis
);
1285 AST_LIST_UNLOCK(&acf_root
);
1287 ast_cli(fd
, "%d %scustom functions installed.\n", count_acf
, like
? "matching " : "");
1289 return RESULT_SUCCESS
;
1291 static int handle_show_functions(int fd
, int argc
, char *argv
[])
1293 struct ast_custom_function
*acf
;
1297 if (argc
== 5 && (!strcmp(argv
[3], "like")) ) {
1299 } else if (argc
!= 3) {
1300 return RESULT_SHOWUSAGE
;
1303 ast_cli(fd
, "%s Custom Functions:\n--------------------------------------------------------------------------------\n", like
? "Matching" : "Installed");
1305 AST_LIST_LOCK(&acf_root
);
1306 AST_LIST_TRAVERSE(&acf_root
, acf
, acflist
) {
1307 if (!like
|| strstr(acf
->name
, argv
[4])) {
1309 ast_cli(fd
, "%-20.20s %-35.35s %s\n", acf
->name
, acf
->syntax
, acf
->synopsis
);
1312 AST_LIST_UNLOCK(&acf_root
);
1314 ast_cli(fd
, "%d %scustom functions installed.\n", count_acf
, like
? "matching " : "");
1316 return RESULT_SUCCESS
;
1319 static int handle_show_function_deprecated(int fd
, int argc
, char *argv
[])
1321 struct ast_custom_function
*acf
;
1322 /* Maximum number of characters added by terminal coloring is 22 */
1323 char infotitle
[64 + AST_MAX_APP
+ 22], syntitle
[40], destitle
[40];
1324 char info
[64 + AST_MAX_APP
], *synopsis
= NULL
, *description
= NULL
;
1325 char stxtitle
[40], *syntax
= NULL
;
1326 int synopsis_size
, description_size
, syntax_size
;
1329 return RESULT_SHOWUSAGE
;
1331 if (!(acf
= ast_custom_function_find(argv
[2]))) {
1332 ast_cli(fd
, "No function by that name registered.\n");
1333 return RESULT_FAILURE
;
1338 synopsis_size
= strlen(acf
->synopsis
) + 23;
1340 synopsis_size
= strlen("Not available") + 23;
1341 synopsis
= alloca(synopsis_size
);
1344 description_size
= strlen(acf
->desc
) + 23;
1346 description_size
= strlen("Not available") + 23;
1347 description
= alloca(description_size
);
1350 syntax_size
= strlen(acf
->syntax
) + 23;
1352 syntax_size
= strlen("Not available") + 23;
1353 syntax
= alloca(syntax_size
);
1355 snprintf(info
, 64 + AST_MAX_APP
, "\n -= Info about function '%s' =- \n\n", acf
->name
);
1356 term_color(infotitle
, info
, COLOR_MAGENTA
, 0, 64 + AST_MAX_APP
+ 22);
1357 term_color(stxtitle
, "[Syntax]\n", COLOR_MAGENTA
, 0, 40);
1358 term_color(syntitle
, "[Synopsis]\n", COLOR_MAGENTA
, 0, 40);
1359 term_color(destitle
, "[Description]\n", COLOR_MAGENTA
, 0, 40);
1361 acf
->syntax
? acf
->syntax
: "Not available",
1362 COLOR_CYAN
, 0, syntax_size
);
1363 term_color(synopsis
,
1364 acf
->synopsis
? acf
->synopsis
: "Not available",
1365 COLOR_CYAN
, 0, synopsis_size
);
1366 term_color(description
,
1367 acf
->desc
? acf
->desc
: "Not available",
1368 COLOR_CYAN
, 0, description_size
);
1370 ast_cli(fd
,"%s%s%s\n\n%s%s\n\n%s%s\n", infotitle
, stxtitle
, syntax
, syntitle
, synopsis
, destitle
, description
);
1372 return RESULT_SUCCESS
;
1375 static int handle_show_function(int fd
, int argc
, char *argv
[])
1377 struct ast_custom_function
*acf
;
1378 /* Maximum number of characters added by terminal coloring is 22 */
1379 char infotitle
[64 + AST_MAX_APP
+ 22], syntitle
[40], destitle
[40];
1380 char info
[64 + AST_MAX_APP
], *synopsis
= NULL
, *description
= NULL
;
1381 char stxtitle
[40], *syntax
= NULL
;
1382 int synopsis_size
, description_size
, syntax_size
;
1385 return RESULT_SHOWUSAGE
;
1387 if (!(acf
= ast_custom_function_find(argv
[3]))) {
1388 ast_cli(fd
, "No function by that name registered.\n");
1389 return RESULT_FAILURE
;
1394 synopsis_size
= strlen(acf
->synopsis
) + 23;
1396 synopsis_size
= strlen("Not available") + 23;
1397 synopsis
= alloca(synopsis_size
);
1400 description_size
= strlen(acf
->desc
) + 23;
1402 description_size
= strlen("Not available") + 23;
1403 description
= alloca(description_size
);
1406 syntax_size
= strlen(acf
->syntax
) + 23;
1408 syntax_size
= strlen("Not available") + 23;
1409 syntax
= alloca(syntax_size
);
1411 snprintf(info
, 64 + AST_MAX_APP
, "\n -= Info about function '%s' =- \n\n", acf
->name
);
1412 term_color(infotitle
, info
, COLOR_MAGENTA
, 0, 64 + AST_MAX_APP
+ 22);
1413 term_color(stxtitle
, "[Syntax]\n", COLOR_MAGENTA
, 0, 40);
1414 term_color(syntitle
, "[Synopsis]\n", COLOR_MAGENTA
, 0, 40);
1415 term_color(destitle
, "[Description]\n", COLOR_MAGENTA
, 0, 40);
1417 acf
->syntax
? acf
->syntax
: "Not available",
1418 COLOR_CYAN
, 0, syntax_size
);
1419 term_color(synopsis
,
1420 acf
->synopsis
? acf
->synopsis
: "Not available",
1421 COLOR_CYAN
, 0, synopsis_size
);
1422 term_color(description
,
1423 acf
->desc
? acf
->desc
: "Not available",
1424 COLOR_CYAN
, 0, description_size
);
1426 ast_cli(fd
,"%s%s%s\n\n%s%s\n\n%s%s\n", infotitle
, stxtitle
, syntax
, syntitle
, synopsis
, destitle
, description
);
1428 return RESULT_SUCCESS
;
1431 static char *complete_show_function(const char *line
, const char *word
, int pos
, int state
)
1433 struct ast_custom_function
*acf
;
1436 int wordlen
= strlen(word
);
1438 /* case-insensitive for convenience in this 'complete' function */
1439 AST_LIST_LOCK(&acf_root
);
1440 AST_LIST_TRAVERSE(&acf_root
, acf
, acflist
) {
1441 if (!strncasecmp(word
, acf
->name
, wordlen
) && ++which
> state
) {
1442 ret
= strdup(acf
->name
);
1446 AST_LIST_UNLOCK(&acf_root
);
1451 struct ast_custom_function
*ast_custom_function_find(const char *name
)
1453 struct ast_custom_function
*acf
= NULL
;
1455 AST_LIST_LOCK(&acf_root
);
1456 AST_LIST_TRAVERSE(&acf_root
, acf
, acflist
) {
1457 if (!strcmp(name
, acf
->name
))
1460 AST_LIST_UNLOCK(&acf_root
);
1465 int ast_custom_function_unregister(struct ast_custom_function
*acf
)
1467 struct ast_custom_function
*cur
;
1472 AST_LIST_LOCK(&acf_root
);
1473 AST_LIST_TRAVERSE_SAFE_BEGIN(&acf_root
, cur
, acflist
) {
1475 AST_LIST_REMOVE_CURRENT(&acf_root
, acflist
);
1476 if (option_verbose
> 1)
1477 ast_verbose(VERBOSE_PREFIX_2
"Unregistered custom function %s\n", acf
->name
);
1481 AST_LIST_TRAVERSE_SAFE_END
1482 AST_LIST_UNLOCK(&acf_root
);
1484 return acf
? 0 : -1;
1487 int ast_custom_function_register(struct ast_custom_function
*acf
)
1489 struct ast_custom_function
*cur
;
1494 AST_LIST_LOCK(&acf_root
);
1496 if (ast_custom_function_find(acf
->name
)) {
1497 ast_log(LOG_ERROR
, "Function %s already registered.\n", acf
->name
);
1498 AST_LIST_UNLOCK(&acf_root
);
1502 /* Store in alphabetical order */
1503 AST_LIST_TRAVERSE_SAFE_BEGIN(&acf_root
, cur
, acflist
) {
1504 if (strcasecmp(acf
->name
, cur
->name
) < 0) {
1505 AST_LIST_INSERT_BEFORE_CURRENT(&acf_root
, acf
, acflist
);
1509 AST_LIST_TRAVERSE_SAFE_END
1511 AST_LIST_INSERT_TAIL(&acf_root
, acf
, acflist
);
1513 AST_LIST_UNLOCK(&acf_root
);
1515 if (option_verbose
> 1)
1516 ast_verbose(VERBOSE_PREFIX_2
"Registered custom function %s\n", acf
->name
);
1521 /*! \brief return a pointer to the arguments of the function,
1522 * and terminates the function name with '\\0'
1524 static char *func_args(char *function
)
1526 char *args
= strchr(function
, '(');
1529 ast_log(LOG_WARNING
, "Function doesn't contain parentheses. Assuming null argument.\n");
1533 if ((p
= strrchr(args
, ')')) )
1536 ast_log(LOG_WARNING
, "Can't find trailing parenthesis?\n");
1541 int ast_func_read(struct ast_channel
*chan
, char *function
, char *workspace
, size_t len
)
1543 char *args
= func_args(function
);
1544 struct ast_custom_function
*acfptr
= ast_custom_function_find(function
);
1547 ast_log(LOG_ERROR
, "Function %s not registered\n", function
);
1548 else if (!acfptr
->read
)
1549 ast_log(LOG_ERROR
, "Function %s cannot be read\n", function
);
1551 return acfptr
->read(chan
, function
, args
, workspace
, len
);
1555 int ast_func_write(struct ast_channel
*chan
, char *function
, const char *value
)
1557 char *args
= func_args(function
);
1558 struct ast_custom_function
*acfptr
= ast_custom_function_find(function
);
1561 ast_log(LOG_ERROR
, "Function %s not registered\n", function
);
1562 else if (!acfptr
->write
)
1563 ast_log(LOG_ERROR
, "Function %s cannot be written to\n", function
);
1565 return acfptr
->write(chan
, function
, args
, value
);
1570 static void pbx_substitute_variables_helper_full(struct ast_channel
*c
, struct varshead
*headp
, const char *cp1
, char *cp2
, int count
)
1572 /* Substitutes variables into cp2, based on string cp1, and assuming cp2 to be
1575 const char *tmp
, *whereweare
;
1576 int length
, offset
, offset2
, isfunction
;
1577 char *workspace
= NULL
;
1578 char *ltmp
= NULL
, *var
= NULL
;
1579 char *nextvar
, *nextexp
, *nextthing
;
1581 int pos
, brackets
, needsub
, len
;
1584 while (!ast_strlen_zero(whereweare
) && count
) {
1585 /* Assume we're copying the whole remaining string */
1586 pos
= strlen(whereweare
);
1589 nextthing
= strchr(whereweare
, '$');
1591 switch(nextthing
[1]) {
1593 nextvar
= nextthing
;
1594 pos
= nextvar
- whereweare
;
1597 nextexp
= nextthing
;
1598 pos
= nextexp
- whereweare
;
1606 /* Can't copy more than 'count' bytes */
1610 /* Copy that many bytes */
1611 memcpy(cp2
, whereweare
, pos
);
1619 /* We have a variable. Find the start and end, and determine
1620 if we are going to have to recursively call ourselves on the
1622 vars
= vare
= nextvar
+ 2;
1626 /* Find the end of it */
1627 while (brackets
&& *vare
) {
1628 if ((vare
[0] == '$') && (vare
[1] == '{')) {
1630 } else if (vare
[0] == '{') {
1632 } else if (vare
[0] == '}') {
1634 } else if ((vare
[0] == '$') && (vare
[1] == '['))
1639 ast_log(LOG_NOTICE
, "Error in extension logic (missing '}')\n");
1640 len
= vare
- vars
- 1;
1642 /* Skip totally over variable string */
1643 whereweare
+= (len
+ 3);
1646 var
= alloca(VAR_BUF_SIZE
);
1648 /* Store variable name (and truncate) */
1649 ast_copy_string(var
, vars
, len
+ 1);
1651 /* Substitute if necessary */
1654 ltmp
= alloca(VAR_BUF_SIZE
);
1656 memset(ltmp
, 0, VAR_BUF_SIZE
);
1657 pbx_substitute_variables_helper_full(c
, headp
, var
, ltmp
, VAR_BUF_SIZE
- 1);
1664 workspace
= alloca(VAR_BUF_SIZE
);
1666 workspace
[0] = '\0';
1668 parse_variable_name(vars
, &offset
, &offset2
, &isfunction
);
1670 /* Evaluate function */
1672 cp4
= ast_func_read(c
, vars
, workspace
, VAR_BUF_SIZE
) ? NULL
: workspace
;
1674 struct varshead old
;
1675 struct ast_channel
*c
= ast_channel_alloc(0, 0, "", "", "", "", "", 0, "Bogus/%p", vars
);
1677 memcpy(&old
, &c
->varshead
, sizeof(old
));
1678 memcpy(&c
->varshead
, headp
, sizeof(c
->varshead
));
1679 cp4
= ast_func_read(c
, vars
, workspace
, VAR_BUF_SIZE
) ? NULL
: workspace
;
1680 /* Don't deallocate the varshead that was passed in */
1681 memcpy(&c
->varshead
, &old
, sizeof(c
->varshead
));
1682 ast_channel_free(c
);
1684 ast_log(LOG_ERROR
, "Unable to allocate bogus channel for variable substitution. Function results may be blank.\n");
1688 ast_log(LOG_DEBUG
, "Function result is '%s'\n", cp4
? cp4
: "(null)");
1690 /* Retrieve variable value */
1691 pbx_retrieve_variable(c
, vars
, &cp4
, workspace
, VAR_BUF_SIZE
, headp
);
1694 cp4
= substring(cp4
, offset
, offset2
, workspace
, VAR_BUF_SIZE
);
1696 length
= strlen(cp4
);
1699 memcpy(cp2
, cp4
, length
);
1703 } else if (nextexp
) {
1704 /* We have an expression. Find the start and end, and determine
1705 if we are going to have to recursively call ourselves on the
1707 vars
= vare
= nextexp
+ 2;
1711 /* Find the end of it */
1712 while(brackets
&& *vare
) {
1713 if ((vare
[0] == '$') && (vare
[1] == '[')) {
1717 } else if (vare
[0] == '[') {
1719 } else if (vare
[0] == ']') {
1721 } else if ((vare
[0] == '$') && (vare
[1] == '{')) {
1728 ast_log(LOG_NOTICE
, "Error in extension logic (missing ']')\n");
1729 len
= vare
- vars
- 1;
1731 /* Skip totally over expression */
1732 whereweare
+= (len
+ 3);
1735 var
= alloca(VAR_BUF_SIZE
);
1737 /* Store variable name (and truncate) */
1738 ast_copy_string(var
, vars
, len
+ 1);
1740 /* Substitute if necessary */
1743 ltmp
= alloca(VAR_BUF_SIZE
);
1745 memset(ltmp
, 0, VAR_BUF_SIZE
);
1746 pbx_substitute_variables_helper_full(c
, headp
, var
, ltmp
, VAR_BUF_SIZE
- 1);
1752 length
= ast_expr(vars
, cp2
, count
);
1756 ast_log(LOG_DEBUG
, "Expression result is '%s'\n", cp2
);
1764 void pbx_substitute_variables_helper(struct ast_channel
*c
, const char *cp1
, char *cp2
, int count
)
1766 pbx_substitute_variables_helper_full(c
, (c
) ? &c
->varshead
: NULL
, cp1
, cp2
, count
);
1769 void pbx_substitute_variables_varshead(struct varshead
*headp
, const char *cp1
, char *cp2
, int count
)
1771 pbx_substitute_variables_helper_full(NULL
, headp
, cp1
, cp2
, count
);
1774 static void pbx_substitute_variables(char *passdata
, int datalen
, struct ast_channel
*c
, struct ast_exten
*e
)
1776 memset(passdata
, 0, datalen
);
1778 /* No variables or expressions in e->data, so why scan it? */
1779 if (e
->data
&& !strchr(e
->data
, '$') && !strstr(e
->data
,"${") && !strstr(e
->data
,"$[") && !strstr(e
->data
,"$(")) {
1780 ast_copy_string(passdata
, e
->data
, datalen
);
1784 pbx_substitute_variables_helper(c
, e
->data
, passdata
, datalen
- 1);
1788 * \brief The return value depends on the action:
1790 * E_MATCH, E_CANMATCH, E_MATCHMORE require a real match,
1791 * and return 0 on failure, -1 on match;
1792 * E_FINDLABEL maps the label to a priority, and returns
1793 * the priority on success, ... XXX
1794 * E_SPAWN, spawn an application,
1795 * and return 0 on success, -1 on failure.
1797 * \note The channel is auto-serviced in this function, because doing an extension
1798 * match may block for a long time. For example, if the lookup has to use a network
1799 * dialplan switch, such as DUNDi or IAX2, it may take a while. However, the channel
1800 * auto-service code will queue up any important signalling frames to be processed
1801 * after this is done.
1803 static int pbx_extension_helper(struct ast_channel
*c
, struct ast_context
*con
,
1804 const char *context
, const char *exten
, int priority
,
1805 const char *label
, const char *callerid
, enum ext_match_t action
)
1807 struct ast_exten
*e
;
1808 struct ast_app
*app
;
1810 struct pbx_find_info q
= { .stacklen
= 0 }; /* the rest is reset in pbx_find_extension */
1811 char passdata
[EXT_DATA_SIZE
];
1813 int matching_action
= (action
== E_MATCH
|| action
== E_CANMATCH
|| action
== E_MATCHMORE
);
1815 ast_rdlock_contexts();
1816 e
= pbx_find_extension(c
, con
, &q
, context
, exten
, priority
, label
, callerid
, action
);
1818 if (matching_action
) {
1819 ast_unlock_contexts();
1820 return -1; /* success, we found it */
1821 } else if (action
== E_FINDLABEL
) { /* map the label to a priority */
1823 ast_unlock_contexts();
1824 return res
; /* the priority we were looking for */
1825 } else { /* spawn */
1826 app
= pbx_findapp(e
->app
);
1827 ast_unlock_contexts();
1829 ast_log(LOG_WARNING
, "No application '%s' for extension (%s, %s, %d)\n", e
->app
, context
, exten
, priority
);
1832 if (c
->context
!= context
)
1833 ast_copy_string(c
->context
, context
, sizeof(c
->context
));
1834 if (c
->exten
!= exten
)
1835 ast_copy_string(c
->exten
, exten
, sizeof(c
->exten
));
1836 c
->priority
= priority
;
1837 pbx_substitute_variables(passdata
, sizeof(passdata
), c
, e
);
1839 ast_log(LOG_DEBUG
, "Launching '%s'\n", app
->name
);
1841 if (option_verbose
> 2) {
1842 char tmp
[80], tmp2
[80], tmp3
[EXT_DATA_SIZE
];
1843 ast_verbose( VERBOSE_PREFIX_3
"Executing [%s@%s:%d] %s(\"%s\", \"%s\") %s\n",
1844 exten
, context
, priority
,
1845 term_color(tmp
, app
->name
, COLOR_BRCYAN
, 0, sizeof(tmp
)),
1846 term_color(tmp2
, c
->name
, COLOR_BRMAGENTA
, 0, sizeof(tmp2
)),
1847 term_color(tmp3
, passdata
, COLOR_BRMAGENTA
, 0, sizeof(tmp3
)),
1850 manager_event(EVENT_FLAG_CALL
, "Newexten",
1855 "Application: %s\r\n"
1858 c
->name
, c
->context
, c
->exten
, c
->priority
, app
->name
, passdata
, c
->uniqueid
);
1859 return pbx_exec(c
, app
, passdata
); /* 0 on success, -1 on failure */
1861 } else if (q
.swo
) { /* not found here, but in another switch */
1862 ast_unlock_contexts();
1863 if (matching_action
) {
1867 ast_log(LOG_WARNING
, "No execution engine for switch %s\n", q
.swo
->name
);
1870 return q
.swo
->exec(c
, q
.foundcontext
? q
.foundcontext
: context
, exten
, priority
, callerid
, q
.data
);
1872 } else { /* not found anywhere, see what happened */
1873 ast_unlock_contexts();
1875 case STATUS_NO_CONTEXT
:
1876 if (!matching_action
)
1877 ast_log(LOG_NOTICE
, "Cannot find extension context '%s'\n", context
);
1879 case STATUS_NO_EXTENSION
:
1880 if (!matching_action
)
1881 ast_log(LOG_NOTICE
, "Cannot find extension '%s' in context '%s'\n", exten
, context
);
1883 case STATUS_NO_PRIORITY
:
1884 if (!matching_action
)
1885 ast_log(LOG_NOTICE
, "No such priority %d in extension '%s' in context '%s'\n", priority
, exten
, context
);
1887 case STATUS_NO_LABEL
:
1889 ast_log(LOG_NOTICE
, "No such label '%s' in extension '%s' in context '%s'\n", label
, exten
, context
);
1893 ast_log(LOG_DEBUG
, "Shouldn't happen!\n");
1896 return (matching_action
) ? 0 : -1;
1900 /*! \brief ast_hint_extension: Find hint for given extension in context */
1901 static struct ast_exten
*ast_hint_extension(struct ast_channel
*c
, const char *context
, const char *exten
)
1903 struct ast_exten
*e
;
1904 struct pbx_find_info q
= { .stacklen
= 0 }; /* the rest is set in pbx_find_context */
1906 ast_rdlock_contexts();
1907 e
= pbx_find_extension(c
, NULL
, &q
, context
, exten
, PRIORITY_HINT
, NULL
, "", E_MATCH
);
1908 ast_unlock_contexts();
1913 /*! \brief ast_extensions_state2: Check state of extension by using hints */
1914 static int ast_extension_state2(struct ast_exten
*e
)
1916 char hint
[AST_MAX_EXTENSION
];
1918 int allunavailable
= 1, allbusy
= 1, allfree
= 1, allonhold
= 1;
1919 int busy
= 0, inuse
= 0, ring
= 0;
1924 ast_copy_string(hint
, ast_get_extension_app(e
), sizeof(hint
));
1926 rest
= hint
; /* One or more devices separated with a & character */
1927 while ( (cur
= strsep(&rest
, "&")) ) {
1928 int res
= ast_device_state(cur
);
1930 case AST_DEVICE_NOT_INUSE
:
1935 case AST_DEVICE_INUSE
:
1941 case AST_DEVICE_RINGING
:
1947 case AST_DEVICE_RINGINUSE
:
1954 case AST_DEVICE_ONHOLD
:
1958 case AST_DEVICE_BUSY
:
1964 case AST_DEVICE_UNAVAILABLE
:
1965 case AST_DEVICE_INVALID
:
1979 return AST_EXTENSION_RINGING
;
1981 return (AST_EXTENSION_INUSE
| AST_EXTENSION_RINGING
);
1983 return AST_EXTENSION_INUSE
;
1985 return AST_EXTENSION_NOT_INUSE
;
1987 return AST_EXTENSION_ONHOLD
;
1989 return AST_EXTENSION_BUSY
;
1991 return AST_EXTENSION_UNAVAILABLE
;
1993 return AST_EXTENSION_INUSE
;
1995 return AST_EXTENSION_NOT_INUSE
;
1998 /*! \brief ast_extension_state2str: Return extension_state as string */
1999 const char *ast_extension_state2str(int extension_state
)
2003 for (i
= 0; (i
< (sizeof(extension_states
) / sizeof(extension_states
[0]))); i
++) {
2004 if (extension_states
[i
].extension_state
== extension_state
)
2005 return extension_states
[i
].text
;
2010 /*! \brief ast_extension_state: Check extension state for an extension by using hint */
2011 int ast_extension_state(struct ast_channel
*c
, const char *context
, const char *exten
)
2013 struct ast_exten
*e
;
2015 e
= ast_hint_extension(c
, context
, exten
); /* Do we have a hint for this extension ? */
2017 return -1; /* No hint, return -1 */
2019 return ast_extension_state2(e
); /* Check all devices in the hint */
2022 void ast_hint_state_changed(const char *device
)
2024 struct ast_hint
*hint
;
2026 AST_LIST_LOCK(&hints
);
2028 AST_LIST_TRAVERSE(&hints
, hint
, list
) {
2029 struct ast_state_cb
*cblist
;
2030 char buf
[AST_MAX_EXTENSION
];
2035 ast_copy_string(buf
, ast_get_extension_app(hint
->exten
), sizeof(buf
));
2036 while ( (cur
= strsep(&parse
, "&")) ) {
2037 if (!strcasecmp(cur
, device
))
2043 /* Get device state for this hint */
2044 state
= ast_extension_state2(hint
->exten
);
2046 if ((state
== -1) || (state
== hint
->laststate
))
2049 /* Device state changed since last check - notify the watchers */
2051 /* For general callbacks */
2052 for (cblist
= statecbs
; cblist
; cblist
= cblist
->next
)
2053 cblist
->callback(hint
->exten
->parent
->name
, hint
->exten
->exten
, state
, cblist
->data
);
2055 /* For extension callbacks */
2056 for (cblist
= hint
->callbacks
; cblist
; cblist
= cblist
->next
)
2057 cblist
->callback(hint
->exten
->parent
->name
, hint
->exten
->exten
, state
, cblist
->data
);
2059 hint
->laststate
= state
; /* record we saw the change */
2062 AST_LIST_UNLOCK(&hints
);
2065 /*! \brief ast_extension_state_add: Add watcher for extension states */
2066 int ast_extension_state_add(const char *context
, const char *exten
,
2067 ast_state_cb_type callback
, void *data
)
2069 struct ast_hint
*hint
;
2070 struct ast_state_cb
*cblist
;
2071 struct ast_exten
*e
;
2073 /* If there's no context and extension: add callback to statecbs list */
2074 if (!context
&& !exten
) {
2075 AST_LIST_LOCK(&hints
);
2077 for (cblist
= statecbs
; cblist
; cblist
= cblist
->next
) {
2078 if (cblist
->callback
== callback
) {
2079 cblist
->data
= data
;
2080 AST_LIST_UNLOCK(&hints
);
2085 /* Now insert the callback */
2086 if (!(cblist
= ast_calloc(1, sizeof(*cblist
)))) {
2087 AST_LIST_UNLOCK(&hints
);
2091 cblist
->callback
= callback
;
2092 cblist
->data
= data
;
2094 cblist
->next
= statecbs
;
2097 AST_LIST_UNLOCK(&hints
);
2101 if (!context
|| !exten
)
2104 /* This callback type is for only one hint, so get the hint */
2105 e
= ast_hint_extension(NULL
, context
, exten
);
2110 /* Find the hint in the list of hints */
2111 AST_LIST_LOCK(&hints
);
2113 AST_LIST_TRAVERSE(&hints
, hint
, list
) {
2114 if (hint
->exten
== e
)
2119 /* We have no hint, sorry */
2120 AST_LIST_UNLOCK(&hints
);
2124 /* Now insert the callback in the callback list */
2125 if (!(cblist
= ast_calloc(1, sizeof(*cblist
)))) {
2126 AST_LIST_UNLOCK(&hints
);
2129 cblist
->id
= stateid
++; /* Unique ID for this callback */
2130 cblist
->callback
= callback
; /* Pointer to callback routine */
2131 cblist
->data
= data
; /* Data for the callback */
2133 cblist
->next
= hint
->callbacks
;
2134 hint
->callbacks
= cblist
;
2136 AST_LIST_UNLOCK(&hints
);
2140 /*! \brief ast_extension_state_del: Remove a watcher from the callback list */
2141 int ast_extension_state_del(int id
, ast_state_cb_type callback
)
2143 struct ast_state_cb
**p_cur
= NULL
; /* address of pointer to us */
2146 if (!id
&& !callback
)
2149 AST_LIST_LOCK(&hints
);
2151 if (!id
) { /* id == 0 is a callback without extension */
2152 for (p_cur
= &statecbs
; *p_cur
; p_cur
= &(*p_cur
)->next
) {
2153 if ((*p_cur
)->callback
== callback
)
2156 } else { /* callback with extension, find the callback based on ID */
2157 struct ast_hint
*hint
;
2158 AST_LIST_TRAVERSE(&hints
, hint
, list
) {
2159 for (p_cur
= &hint
->callbacks
; *p_cur
; p_cur
= &(*p_cur
)->next
) {
2160 if ((*p_cur
)->id
== id
)
2163 if (*p_cur
) /* found in the inner loop */
2167 if (p_cur
&& *p_cur
) {
2168 struct ast_state_cb
*cur
= *p_cur
;
2173 AST_LIST_UNLOCK(&hints
);
2177 /*! \brief ast_add_hint: Add hint to hint list, check initial extension state */
2178 static int ast_add_hint(struct ast_exten
*e
)
2180 struct ast_hint
*hint
;
2185 AST_LIST_LOCK(&hints
);
2187 /* Search if hint exists, do nothing */
2188 AST_LIST_TRAVERSE(&hints
, hint
, list
) {
2189 if (hint
->exten
== e
) {
2190 AST_LIST_UNLOCK(&hints
);
2191 if (option_debug
> 1)
2192 ast_log(LOG_DEBUG
, "HINTS: Not re-adding existing hint %s: %s\n", ast_get_extension_name(e
), ast_get_extension_app(e
));
2197 if (option_debug
> 1)
2198 ast_log(LOG_DEBUG
, "HINTS: Adding hint %s: %s\n", ast_get_extension_name(e
), ast_get_extension_app(e
));
2200 if (!(hint
= ast_calloc(1, sizeof(*hint
)))) {
2201 AST_LIST_UNLOCK(&hints
);
2204 /* Initialize and insert new item at the top */
2206 hint
->laststate
= ast_extension_state2(e
);
2207 AST_LIST_INSERT_HEAD(&hints
, hint
, list
);
2209 AST_LIST_UNLOCK(&hints
);
2213 /*! \brief ast_change_hint: Change hint for an extension */
2214 static int ast_change_hint(struct ast_exten
*oe
, struct ast_exten
*ne
)
2216 struct ast_hint
*hint
;
2219 AST_LIST_LOCK(&hints
);
2220 AST_LIST_TRAVERSE(&hints
, hint
, list
) {
2221 if (hint
->exten
== oe
) {
2227 AST_LIST_UNLOCK(&hints
);
2232 /*! \brief ast_remove_hint: Remove hint from extension */
2233 static int ast_remove_hint(struct ast_exten
*e
)
2235 /* Cleanup the Notifys if hint is removed */
2236 struct ast_hint
*hint
;
2237 struct ast_state_cb
*cblist
, *cbprev
;
2243 AST_LIST_LOCK(&hints
);
2244 AST_LIST_TRAVERSE_SAFE_BEGIN(&hints
, hint
, list
) {
2245 if (hint
->exten
== e
) {
2247 cblist
= hint
->callbacks
;
2249 /* Notify with -1 and remove all callbacks */
2251 cblist
= cblist
->next
;
2252 cbprev
->callback(hint
->exten
->parent
->name
, hint
->exten
->exten
, AST_EXTENSION_DEACTIVATED
, cbprev
->data
);
2255 hint
->callbacks
= NULL
;
2256 AST_LIST_REMOVE_CURRENT(&hints
, list
);
2262 AST_LIST_TRAVERSE_SAFE_END
2263 AST_LIST_UNLOCK(&hints
);
2269 /*! \brief ast_get_hint: Get hint for channel */
2270 int ast_get_hint(char *hint
, int hintsize
, char *name
, int namesize
, struct ast_channel
*c
, const char *context
, const char *exten
)
2272 struct ast_exten
*e
= ast_hint_extension(c
, context
, exten
);
2276 ast_copy_string(hint
, ast_get_extension_app(e
), hintsize
);
2278 const char *tmp
= ast_get_extension_app_data(e
);
2280 ast_copy_string(name
, tmp
, namesize
);
2287 int ast_exists_extension(struct ast_channel
*c
, const char *context
, const char *exten
, int priority
, const char *callerid
)
2289 return pbx_extension_helper(c
, NULL
, context
, exten
, priority
, NULL
, callerid
, E_MATCH
);
2292 int ast_findlabel_extension(struct ast_channel
*c
, const char *context
, const char *exten
, const char *label
, const char *callerid
)
2294 return pbx_extension_helper(c
, NULL
, context
, exten
, 0, label
, callerid
, E_FINDLABEL
);
2297 int ast_findlabel_extension2(struct ast_channel
*c
, struct ast_context
*con
, const char *exten
, const char *label
, const char *callerid
)
2299 return pbx_extension_helper(c
, con
, NULL
, exten
, 0, label
, callerid
, E_FINDLABEL
);
2302 int ast_canmatch_extension(struct ast_channel
*c
, const char *context
, const char *exten
, int priority
, const char *callerid
)
2304 return pbx_extension_helper(c
, NULL
, context
, exten
, priority
, NULL
, callerid
, E_CANMATCH
);
2307 int ast_matchmore_extension(struct ast_channel
*c
, const char *context
, const char *exten
, int priority
, const char *callerid
)
2309 return pbx_extension_helper(c
, NULL
, context
, exten
, priority
, NULL
, callerid
, E_MATCHMORE
);
2312 int ast_spawn_extension(struct ast_channel
*c
, const char *context
, const char *exten
, int priority
, const char *callerid
)
2314 return pbx_extension_helper(c
, NULL
, context
, exten
, priority
, NULL
, callerid
, E_SPAWN
);
2317 /* helper function to set extension and priority */
2318 static void set_ext_pri(struct ast_channel
*c
, const char *exten
, int pri
)
2320 ast_channel_lock(c
);
2321 ast_copy_string(c
->exten
, exten
, sizeof(c
->exten
));
2323 ast_channel_unlock(c
);
2327 * \brief collect digits from the channel into the buffer,
2328 * return -1 on error, 0 on timeout or done.
2330 static int collect_digits(struct ast_channel
*c
, int waittime
, char *buf
, int buflen
, int pos
)
2334 buf
[pos
] = '\0'; /* make sure it is properly terminated */
2335 while (ast_matchmore_extension(c
, c
->context
, buf
, 1, c
->cid
.cid_num
)) {
2336 /* As long as we're willing to wait, and as long as it's not defined,
2337 keep reading digits until we can't possibly get a right answer anymore. */
2338 digit
= ast_waitfordigit(c
, waittime
* 1000);
2339 if (c
->_softhangup
== AST_SOFTHANGUP_ASYNCGOTO
) {
2342 if (!digit
) /* No entry */
2344 if (digit
< 0) /* Error, maybe a hangup */
2346 if (pos
< buflen
- 1) { /* XXX maybe error otherwise ? */
2350 waittime
= c
->pbx
->dtimeout
;
2356 static int __ast_pbx_run(struct ast_channel
*c
)
2358 int found
= 0; /* set if we find at least one match */
2361 int error
= 0; /* set an error conditions */
2363 /* A little initial setup here */
2365 ast_log(LOG_WARNING
, "%s already has PBX structure??\n", c
->name
);
2366 /* XXX and now what ? */
2369 if (!(c
->pbx
= ast_calloc(1, sizeof(*c
->pbx
))))
2373 c
->cdr
= ast_cdr_alloc();
2375 ast_log(LOG_WARNING
, "Unable to create Call Detail Record\n");
2379 ast_cdr_init(c
->cdr
, c
);
2382 /* Set reasonable defaults */
2383 c
->pbx
->rtimeout
= 10;
2384 c
->pbx
->dtimeout
= 5;
2386 autoloopflag
= ast_test_flag(c
, AST_FLAG_IN_AUTOLOOP
); /* save value to restore at the end */
2387 ast_set_flag(c
, AST_FLAG_IN_AUTOLOOP
);
2389 /* Start by trying whatever the channel is set to */
2390 if (!ast_exists_extension(c
, c
->context
, c
->exten
, c
->priority
, c
->cid
.cid_num
)) {
2391 /* If not successful fall back to 's' */
2392 if (option_verbose
> 1)
2393 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
);
2394 /* XXX the original code used the existing priority in the call to
2395 * ast_exists_extension(), and reset it to 1 afterwards.
2396 * I believe the correct thing is to set it to 1 immediately.
2398 set_ext_pri(c
, "s", 1);
2399 if (!ast_exists_extension(c
, c
->context
, c
->exten
, c
->priority
, c
->cid
.cid_num
)) {
2400 /* JK02: And finally back to default if everything else failed */
2401 if (option_verbose
> 1)
2402 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
);
2403 ast_copy_string(c
->context
, "default", sizeof(c
->context
));
2406 if (c
->cdr
&& ast_tvzero(c
->cdr
->start
))
2407 ast_cdr_start(c
->cdr
);
2409 char dst_exten
[256]; /* buffer to accumulate digits */
2410 int pos
= 0; /* XXX should check bounds */
2413 /* loop on priorities in this context/exten */
2414 while (ast_exists_extension(c
, c
->context
, c
->exten
, c
->priority
, c
->cid
.cid_num
)) {
2416 if ((res
= ast_spawn_extension(c
, c
->context
, c
->exten
, c
->priority
, c
->cid
.cid_num
))) {
2417 /* Something bad happened, or a hangup has been requested. */
2418 if (strchr("0123456789ABCDEF*#", res
)) {
2420 ast_log(LOG_DEBUG
, "Oooh, got something to jump out with ('%c')!\n", res
);
2422 dst_exten
[pos
++] = digit
= res
;
2423 dst_exten
[pos
] = '\0';
2426 if (res
== AST_PBX_KEEPALIVE
) {
2428 ast_log(LOG_DEBUG
, "Spawn extension (%s,%s,%d) exited KEEPALIVE on '%s'\n", c
->context
, c
->exten
, c
->priority
, c
->name
);
2429 if (option_verbose
> 1)
2430 ast_verbose( VERBOSE_PREFIX_2
"Spawn extension (%s, %s, %d) exited KEEPALIVE on '%s'\n", c
->context
, c
->exten
, c
->priority
, c
->name
);
2435 ast_log(LOG_DEBUG
, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c
->context
, c
->exten
, c
->priority
, c
->name
);
2436 if (option_verbose
> 1)
2437 ast_verbose( VERBOSE_PREFIX_2
"Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c
->context
, c
->exten
, c
->priority
, c
->name
);
2438 if (c
->_softhangup
== AST_SOFTHANGUP_ASYNCGOTO
) {
2440 } else if (c
->_softhangup
== AST_SOFTHANGUP_TIMEOUT
) {
2441 /* atimeout, nothing bad */
2449 if (c
->_softhangup
== AST_SOFTHANGUP_TIMEOUT
&& ast_exists_extension(c
,c
->context
,"T",1,c
->cid
.cid_num
)) {
2450 set_ext_pri(c
, "T", 0); /* 0 will become 1 with the c->priority++; at the end */
2451 /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
2452 c
->whentohangup
= 0;
2453 c
->_softhangup
&= ~AST_SOFTHANGUP_TIMEOUT
;
2454 } else if (c
->_softhangup
) {
2456 ast_log(LOG_DEBUG
, "Extension %s, priority %d returned normally even though call was hung up\n",
2457 c
->exten
, c
->priority
);
2462 } /* end while - from here on we can use 'break' to go out */
2466 /* XXX we get here on non-existing extension or a keypress or hangup ? */
2468 if (!ast_exists_extension(c
, c
->context
, c
->exten
, 1, c
->cid
.cid_num
)) {
2469 /* If there is no match at priority 1, it is not a valid extension anymore.
2470 * Try to continue at "i", 1 or exit if the latter does not exist.
2472 if (ast_exists_extension(c
, c
->context
, "i", 1, c
->cid
.cid_num
)) {
2473 if (option_verbose
> 2)
2474 ast_verbose(VERBOSE_PREFIX_3
"Sent into invalid extension '%s' in context '%s' on %s\n", c
->exten
, c
->context
, c
->name
);
2475 pbx_builtin_setvar_helper(c
, "INVALID_EXTEN", c
->exten
);
2476 set_ext_pri(c
, "i", 1);
2478 ast_log(LOG_WARNING
, "Channel '%s' sent into invalid extension '%s' in context '%s', but no invalid handler\n",
2479 c
->name
, c
->exten
, c
->context
);
2480 error
= 1; /* we know what to do with it */
2483 } else if (c
->_softhangup
== AST_SOFTHANGUP_TIMEOUT
) {
2484 /* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */
2486 } else { /* keypress received, get more digits for a full extension */
2489 waittime
= c
->pbx
->dtimeout
;
2490 else if (!autofallthrough
)
2491 waittime
= c
->pbx
->rtimeout
;
2493 const char *status
= pbx_builtin_getvar_helper(c
, "DIALSTATUS");
2496 if (option_verbose
> 2)
2497 ast_verbose(VERBOSE_PREFIX_2
"Auto fallthrough, channel '%s' status is '%s'\n", c
->name
, status
);
2498 if (!strcasecmp(status
, "CONGESTION"))
2499 res
= pbx_builtin_congestion(c
, "10");
2500 else if (!strcasecmp(status
, "CHANUNAVAIL"))
2501 res
= pbx_builtin_congestion(c
, "10");
2502 else if (!strcasecmp(status
, "BUSY"))
2503 res
= pbx_builtin_busy(c
, "10");
2504 error
= 1; /* XXX disable message */
2505 break; /* exit from the 'for' loop */
2508 if (collect_digits(c
, waittime
, dst_exten
, sizeof(dst_exten
), pos
))
2510 if (ast_exists_extension(c
, c
->context
, dst_exten
, 1, c
->cid
.cid_num
)) /* Prepare the next cycle */
2511 set_ext_pri(c
, dst_exten
, 1);
2513 /* No such extension */
2514 if (!ast_strlen_zero(dst_exten
)) {
2515 /* An invalid extension */
2516 if (ast_exists_extension(c
, c
->context
, "i", 1, c
->cid
.cid_num
)) {
2517 if (option_verbose
> 2)
2518 ast_verbose( VERBOSE_PREFIX_3
"Invalid extension '%s' in context '%s' on %s\n", dst_exten
, c
->context
, c
->name
);
2519 pbx_builtin_setvar_helper(c
, "INVALID_EXTEN", dst_exten
);
2520 set_ext_pri(c
, "i", 1);
2522 ast_log(LOG_WARNING
, "Invalid extension '%s', but no rule 'i' in context '%s'\n", dst_exten
, c
->context
);
2523 found
= 1; /* XXX disable message */
2527 /* A simple timeout */
2528 if (ast_exists_extension(c
, c
->context
, "t", 1, c
->cid
.cid_num
)) {
2529 if (option_verbose
> 2)
2530 ast_verbose( VERBOSE_PREFIX_3
"Timeout on %s\n", c
->name
);
2531 set_ext_pri(c
, "t", 1);
2533 ast_log(LOG_WARNING
, "Timeout, but no rule 't' in context '%s'\n", c
->context
);
2534 found
= 1; /* XXX disable message */
2540 if (option_verbose
> 2)
2541 ast_verbose(VERBOSE_PREFIX_2
"CDR updated on %s\n",c
->name
);
2546 if (!found
&& !error
)
2547 ast_log(LOG_WARNING
, "Don't know what to do with '%s'\n", c
->name
);
2548 if (res
!= AST_PBX_KEEPALIVE
)
2549 ast_softhangup(c
, c
->hangupcause
? c
->hangupcause
: AST_CAUSE_NORMAL_CLEARING
);
2550 if ((res
!= AST_PBX_KEEPALIVE
) && ast_exists_extension(c
, c
->context
, "h", 1, c
->cid
.cid_num
)) {
2551 if (c
->cdr
&& ast_opt_end_cdr_before_h_exten
)
2552 ast_cdr_end(c
->cdr
);
2553 set_ext_pri(c
, "h", 1);
2554 while(ast_exists_extension(c
, c
->context
, c
->exten
, c
->priority
, c
->cid
.cid_num
)) {
2555 if ((res
= ast_spawn_extension(c
, c
->context
, c
->exten
, c
->priority
, c
->cid
.cid_num
))) {
2556 /* Something bad happened, or a hangup has been requested. */
2558 ast_log(LOG_DEBUG
, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c
->context
, c
->exten
, c
->priority
, c
->name
);
2559 if (option_verbose
> 1)
2560 ast_verbose( VERBOSE_PREFIX_2
"Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c
->context
, c
->exten
, c
->priority
, c
->name
);
2566 ast_set2_flag(c
, autoloopflag
, AST_FLAG_IN_AUTOLOOP
);
2568 pbx_destroy(c
->pbx
);
2570 if (res
!= AST_PBX_KEEPALIVE
)
2575 /* Returns 0 on success, non-zero if call limit was reached */
2576 static int increase_call_count(const struct ast_channel
*c
)
2580 ast_mutex_lock(&maxcalllock
);
2581 if (option_maxcalls
) {
2582 if (countcalls
>= option_maxcalls
) {
2583 ast_log(LOG_NOTICE
, "Maximum call limit of %d calls exceeded by '%s'!\n", option_maxcalls
, c
->name
);
2587 if (option_maxload
) {
2588 getloadavg(&curloadavg
, 1);
2589 if (curloadavg
>= option_maxload
) {
2590 ast_log(LOG_NOTICE
, "Maximum loadavg limit of %f load exceeded by '%s' (currently %f)!\n", option_maxload
, c
->name
, curloadavg
);
2596 ast_mutex_unlock(&maxcalllock
);
2601 static void decrease_call_count(void)
2603 ast_mutex_lock(&maxcalllock
);
2606 ast_mutex_unlock(&maxcalllock
);
2609 static void destroy_exten(struct ast_exten
*e
)
2611 if (e
->priority
== PRIORITY_HINT
)
2619 static void *pbx_thread(void *data
)
2621 /* Oh joyeous kernel, we're a new thread, with nothing to do but
2622 answer this channel and get it going.
2625 The launcher of this function _MUST_ increment 'countcalls'
2626 before invoking the function; it will be decremented when the
2627 PBX has finished running on the channel
2629 struct ast_channel
*c
= data
;
2632 decrease_call_count();
2639 enum ast_pbx_result
ast_pbx_start(struct ast_channel
*c
)
2642 pthread_attr_t attr
;
2645 ast_log(LOG_WARNING
, "Asked to start thread on NULL channel?\n");
2646 return AST_PBX_FAILED
;
2649 if (increase_call_count(c
))
2650 return AST_PBX_CALL_LIMIT
;
2652 /* Start a new thread, and get something handling this channel. */
2653 pthread_attr_init(&attr
);
2654 pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
2655 if (ast_pthread_create(&t
, &attr
, pbx_thread
, c
)) {
2656 ast_log(LOG_WARNING
, "Failed to create new channel thread\n");
2657 pthread_attr_destroy(&attr
);
2658 return AST_PBX_FAILED
;
2660 pthread_attr_destroy(&attr
);
2662 return AST_PBX_SUCCESS
;
2665 enum ast_pbx_result
ast_pbx_run(struct ast_channel
*c
)
2667 enum ast_pbx_result res
= AST_PBX_SUCCESS
;
2669 if (increase_call_count(c
))
2670 return AST_PBX_CALL_LIMIT
;
2672 res
= __ast_pbx_run(c
);
2673 decrease_call_count();
2678 int ast_active_calls(void)
2683 int pbx_set_autofallthrough(int newval
)
2685 int oldval
= autofallthrough
;
2686 autofallthrough
= newval
;
2690 /* lookup for a context with a given name,
2691 * return with conlock held if found, NULL if not found
2693 static struct ast_context
*find_context_locked(const char *context
)
2695 struct ast_context
*c
= NULL
;
2697 ast_rdlock_contexts();
2698 while ( (c
= ast_walk_contexts(c
)) ) {
2699 if (!strcmp(ast_get_context_name(c
), context
))
2702 ast_unlock_contexts();
2708 * This function locks contexts list by &conlist, search for the right context
2709 * structure, leave context list locked and call ast_context_remove_include2
2710 * which removes include, unlock contexts list and return ...
2712 int ast_context_remove_include(const char *context
, const char *include
, const char *registrar
)
2715 struct ast_context
*c
= find_context_locked(context
);
2718 /* found, remove include from this context ... */
2719 ret
= ast_context_remove_include2(c
, include
, registrar
);
2720 ast_unlock_contexts();
2726 * When we call this function, &conlock lock must be locked, because when
2727 * we giving *con argument, some process can remove/change this context
2728 * and after that there can be segfault.
2730 * This function locks given context, removes include, unlock context and
2733 int ast_context_remove_include2(struct ast_context
*con
, const char *include
, const char *registrar
)
2735 struct ast_include
*i
, *pi
= NULL
;
2738 ast_mutex_lock(&con
->lock
);
2740 /* find our include */
2741 for (i
= con
->includes
; i
; pi
= i
, i
= i
->next
) {
2742 if (!strcmp(i
->name
, include
) &&
2743 (!registrar
|| !strcmp(i
->registrar
, registrar
))) {
2744 /* remove from list */
2748 con
->includes
= i
->next
;
2749 /* free include and return */
2756 ast_mutex_unlock(&con
->lock
);
2761 * \note This function locks contexts list by &conlist, search for the rigt context
2762 * structure, leave context list locked and call ast_context_remove_switch2
2763 * which removes switch, unlock contexts list and return ...
2765 int ast_context_remove_switch(const char *context
, const char *sw
, const char *data
, const char *registrar
)
2767 int ret
= -1; /* default error return */
2768 struct ast_context
*c
= find_context_locked(context
);
2771 /* remove switch from this context ... */
2772 ret
= ast_context_remove_switch2(c
, sw
, data
, registrar
);
2773 ast_unlock_contexts();
2779 * \brief This function locks given context, removes switch, unlock context and
2781 * \note When we call this function, &conlock lock must be locked, because when
2782 * we giving *con argument, some process can remove/change this context
2783 * and after that there can be segfault.
2786 int ast_context_remove_switch2(struct ast_context
*con
, const char *sw
, const char *data
, const char *registrar
)
2791 ast_mutex_lock(&con
->lock
);
2794 AST_LIST_TRAVERSE_SAFE_BEGIN(&con
->alts
, i
, list
) {
2795 if (!strcmp(i
->name
, sw
) && !strcmp(i
->data
, data
) &&
2796 (!registrar
|| !strcmp(i
->registrar
, registrar
))) {
2797 /* found, remove from list */
2798 AST_LIST_REMOVE_CURRENT(&con
->alts
, list
);
2799 free(i
); /* free switch and return */
2804 AST_LIST_TRAVERSE_SAFE_END
2806 ast_mutex_unlock(&con
->lock
);
2812 * \note This functions lock contexts list, search for the right context,
2813 * call ast_context_remove_extension2, unlock contexts list and return.
2814 * In this function we are using
2816 int ast_context_remove_extension(const char *context
, const char *extension
, int priority
, const char *registrar
)
2818 int ret
= -1; /* default error return */
2819 struct ast_context
*c
= find_context_locked(context
);
2821 if (c
) { /* ... remove extension ... */
2822 ret
= ast_context_remove_extension2(c
, extension
, priority
, registrar
);
2823 ast_unlock_contexts();
2829 * \brief This functionc locks given context, search for the right extension and
2830 * fires out all peer in this extensions with given priority. If priority
2831 * is set to 0, all peers are removed. After that, unlock context and
2833 * \note When do you want to call this function, make sure that &conlock is locked,
2834 * because some process can handle with your *con context before you lock
2838 int ast_context_remove_extension2(struct ast_context
*con
, const char *extension
, int priority
, const char *registrar
)
2840 struct ast_exten
*exten
, *prev_exten
= NULL
;
2841 struct ast_exten
*peer
;
2843 ast_mutex_lock(&con
->lock
);
2845 /* scan the extension list to find matching extension-registrar */
2846 for (exten
= con
->root
; exten
; prev_exten
= exten
, exten
= exten
->next
) {
2847 if (!strcmp(exten
->exten
, extension
) &&
2848 (!registrar
|| !strcmp(exten
->registrar
, registrar
)))
2852 /* we can't find right extension */
2853 ast_mutex_unlock(&con
->lock
);
2857 /* should we free all peers in this extension? (priority == 0)? */
2858 if (priority
== 0) {
2859 /* remove this extension from context list */
2861 prev_exten
->next
= exten
->next
;
2863 con
->root
= exten
->next
;
2865 /* fire out all peers */
2866 while ( (peer
= exten
) ) {
2867 exten
= peer
->peer
; /* prepare for next entry */
2868 destroy_exten(peer
);
2871 /* scan the priority list to remove extension with exten->priority == priority */
2872 struct ast_exten
*previous_peer
= NULL
;
2874 for (peer
= exten
; peer
; previous_peer
= peer
, peer
= peer
->peer
) {
2875 if (peer
->priority
== priority
&&
2876 (!registrar
|| !strcmp(peer
->registrar
, registrar
) ))
2877 break; /* found our priority */
2879 if (!peer
) { /* not found */
2880 ast_mutex_unlock(&con
->lock
);
2883 /* we are first priority extension? */
2884 if (!previous_peer
) {
2886 * We are first in the priority chain, so must update the extension chain.
2887 * The next node is either the next priority or the next extension
2889 struct ast_exten
*next_node
= peer
->peer
? peer
->peer
: peer
->next
;
2891 if (!prev_exten
) /* change the root... */
2892 con
->root
= next_node
;
2894 prev_exten
->next
= next_node
; /* unlink */
2895 if (peer
->peer
) /* XXX update the new head of the pri list */
2896 peer
->peer
->next
= peer
->next
;
2897 } else { /* easy, we are not first priority in extension */
2898 previous_peer
->peer
= peer
->peer
;
2901 /* now, free whole priority extension */
2902 destroy_exten(peer
);
2903 /* XXX should we return -1 ? */
2905 ast_mutex_unlock(&con
->lock
);
2911 * \note This function locks contexts list by &conlist, searches for the right context
2912 * structure, and locks the macrolock mutex in that context.
2913 * macrolock is used to limit a macro to be executed by one call at a time.
2915 int ast_context_lockmacro(const char *context
)
2917 struct ast_context
*c
= NULL
;
2920 ast_rdlock_contexts();
2922 while ((c
= ast_walk_contexts(c
))) {
2923 if (!strcmp(ast_get_context_name(c
), context
)) {
2929 ast_unlock_contexts();
2931 /* if we found context, lock macrolock */
2933 ret
= ast_mutex_lock(&c
->macrolock
);
2939 * \note This function locks contexts list by &conlist, searches for the right context
2940 * structure, and unlocks the macrolock mutex in that context.
2941 * macrolock is used to limit a macro to be executed by one call at a time.
2943 int ast_context_unlockmacro(const char *context
)
2945 struct ast_context
*c
= NULL
;
2948 ast_rdlock_contexts();
2950 while ((c
= ast_walk_contexts(c
))) {
2951 if (!strcmp(ast_get_context_name(c
), context
)) {
2957 ast_unlock_contexts();
2959 /* if we found context, unlock macrolock */
2961 ret
= ast_mutex_unlock(&c
->macrolock
);
2966 /*! \brief Dynamically register a new dial plan application */
2967 int ast_register_application(const char *app
, int (*execute
)(struct ast_channel
*, void *), const char *synopsis
, const char *description
)
2969 struct ast_app
*tmp
, *cur
= NULL
;
2973 AST_LIST_LOCK(&apps
);
2974 AST_LIST_TRAVERSE(&apps
, tmp
, list
) {
2975 if (!strcasecmp(app
, tmp
->name
)) {
2976 ast_log(LOG_WARNING
, "Already have an application '%s'\n", app
);
2977 AST_LIST_UNLOCK(&apps
);
2982 length
= sizeof(*tmp
) + strlen(app
) + 1;
2984 if (!(tmp
= ast_calloc(1, length
))) {
2985 AST_LIST_UNLOCK(&apps
);
2989 strcpy(tmp
->name
, app
);
2990 tmp
->execute
= execute
;
2991 tmp
->synopsis
= synopsis
;
2992 tmp
->description
= description
;
2994 /* Store in alphabetical order */
2995 AST_LIST_TRAVERSE_SAFE_BEGIN(&apps
, cur
, list
) {
2996 if (strcasecmp(tmp
->name
, cur
->name
) < 0) {
2997 AST_LIST_INSERT_BEFORE_CURRENT(&apps
, tmp
, list
);
3001 AST_LIST_TRAVERSE_SAFE_END
3003 AST_LIST_INSERT_TAIL(&apps
, tmp
, list
);
3005 if (option_verbose
> 1)
3006 ast_verbose( VERBOSE_PREFIX_2
"Registered application '%s'\n", term_color(tmps
, tmp
->name
, COLOR_BRCYAN
, 0, sizeof(tmps
)));
3008 AST_LIST_UNLOCK(&apps
);
3014 * Append to the list. We don't have a tail pointer because we need
3015 * to scan the list anyways to check for duplicates during insertion.
3017 int ast_register_switch(struct ast_switch
*sw
)
3019 struct ast_switch
*tmp
;
3021 AST_LIST_LOCK(&switches
);
3022 AST_LIST_TRAVERSE(&switches
, tmp
, list
) {
3023 if (!strcasecmp(tmp
->name
, sw
->name
)) {
3024 AST_LIST_UNLOCK(&switches
);
3025 ast_log(LOG_WARNING
, "Switch '%s' already found\n", sw
->name
);
3029 AST_LIST_INSERT_TAIL(&switches
, sw
, list
);
3030 AST_LIST_UNLOCK(&switches
);
3035 void ast_unregister_switch(struct ast_switch
*sw
)
3037 AST_LIST_LOCK(&switches
);
3038 AST_LIST_REMOVE(&switches
, sw
, list
);
3039 AST_LIST_UNLOCK(&switches
);
3043 * Help for CLI commands ...
3045 static char show_applications_help
[] =
3046 "Usage: core show applications [{like|describing} <text>]\n"
3047 " List applications which are currently available.\n"
3048 " If 'like', <text> will be a substring of the app name\n"
3049 " If 'describing', <text> will be a substring of the description\n";
3051 static char show_functions_help
[] =
3052 "Usage: core show functions [like <text>]\n"
3053 " List builtin functions, optionally only those matching a given string\n";
3055 static char show_switches_help
[] =
3056 "Usage: core show switches\n"
3057 " List registered switches\n";
3059 static char show_hints_help
[] =
3060 "Usage: core show hints\n"
3061 " List registered hints\n";
3063 static char show_globals_help
[] =
3064 "Usage: core show globals\n"
3065 " List current global dialplan variables and their values\n";
3067 static char show_application_help
[] =
3068 "Usage: core show application <application> [<application> [<application> [...]]]\n"
3069 " Describes a particular application.\n";
3071 static char show_function_help
[] =
3072 "Usage: core show function <function>\n"
3073 " Describe a particular dialplan function.\n";
3075 static char show_dialplan_help
[] =
3076 "Usage: dialplan show [exten@][context]\n"
3079 static char set_global_help
[] =
3080 "Usage: core set global <name> <value>\n"
3081 " Set global dialplan variable <name> to <value>\n";
3085 * \brief 'show application' CLI command implementation functions ...
3089 * There is a possibility to show informations about more than one
3090 * application at one time. You can type 'show application Dial Echo' and
3091 * you will see informations about these two applications ...
3093 static char *complete_show_application(const char *line
, const char *word
, int pos
, int state
)
3098 int wordlen
= strlen(word
);
3100 /* return the n-th [partial] matching entry */
3101 AST_LIST_LOCK(&apps
);
3102 AST_LIST_TRAVERSE(&apps
, a
, list
) {
3103 if (!strncasecmp(word
, a
->name
, wordlen
) && ++which
> state
) {
3104 ret
= strdup(a
->name
);
3108 AST_LIST_UNLOCK(&apps
);
3113 static int handle_show_application_deprecated(int fd
, int argc
, char *argv
[])
3116 int app
, no_registered_app
= 1;
3119 return RESULT_SHOWUSAGE
;
3121 /* ... go through all applications ... */
3122 AST_LIST_LOCK(&apps
);
3123 AST_LIST_TRAVERSE(&apps
, a
, list
) {
3124 /* ... compare this application name with all arguments given
3125 * to 'show application' command ... */
3126 for (app
= 2; app
< argc
; app
++) {
3127 if (!strcasecmp(a
->name
, argv
[app
])) {
3128 /* Maximum number of characters added by terminal coloring is 22 */
3129 char infotitle
[64 + AST_MAX_APP
+ 22], syntitle
[40], destitle
[40];
3130 char info
[64 + AST_MAX_APP
], *synopsis
= NULL
, *description
= NULL
;
3131 int synopsis_size
, description_size
;
3133 no_registered_app
= 0;
3136 synopsis_size
= strlen(a
->synopsis
) + 23;
3138 synopsis_size
= strlen("Not available") + 23;
3139 synopsis
= alloca(synopsis_size
);
3142 description_size
= strlen(a
->description
) + 23;
3144 description_size
= strlen("Not available") + 23;
3145 description
= alloca(description_size
);
3147 if (synopsis
&& description
) {
3148 snprintf(info
, 64 + AST_MAX_APP
, "\n -= Info about application '%s' =- \n\n", a
->name
);
3149 term_color(infotitle
, info
, COLOR_MAGENTA
, 0, 64 + AST_MAX_APP
+ 22);
3150 term_color(syntitle
, "[Synopsis]\n", COLOR_MAGENTA
, 0, 40);
3151 term_color(destitle
, "[Description]\n", COLOR_MAGENTA
, 0, 40);
3152 term_color(synopsis
,
3153 a
->synopsis
? a
->synopsis
: "Not available",
3154 COLOR_CYAN
, 0, synopsis_size
);
3155 term_color(description
,
3156 a
->description
? a
->description
: "Not available",
3157 COLOR_CYAN
, 0, description_size
);
3159 ast_cli(fd
,"%s%s%s\n\n%s%s\n", infotitle
, syntitle
, synopsis
, destitle
, description
);
3161 /* ... one of our applications, show info ...*/
3162 ast_cli(fd
,"\n -= Info about application '%s' =- \n\n"
3163 "[Synopsis]\n %s\n\n"
3164 "[Description]\n%s\n",
3166 a
->synopsis
? a
->synopsis
: "Not available",
3167 a
->description
? a
->description
: "Not available");
3172 AST_LIST_UNLOCK(&apps
);
3174 /* we found at least one app? no? */
3175 if (no_registered_app
) {
3176 ast_cli(fd
, "Your application(s) is (are) not registered\n");
3177 return RESULT_FAILURE
;
3180 return RESULT_SUCCESS
;
3183 static int handle_show_application(int fd
, int argc
, char *argv
[])
3186 int app
, no_registered_app
= 1;
3189 return RESULT_SHOWUSAGE
;
3191 /* ... go through all applications ... */
3192 AST_LIST_LOCK(&apps
);
3193 AST_LIST_TRAVERSE(&apps
, a
, list
) {
3194 /* ... compare this application name with all arguments given
3195 * to 'show application' command ... */
3196 for (app
= 3; app
< argc
; app
++) {
3197 if (!strcasecmp(a
->name
, argv
[app
])) {
3198 /* Maximum number of characters added by terminal coloring is 22 */
3199 char infotitle
[64 + AST_MAX_APP
+ 22], syntitle
[40], destitle
[40];
3200 char info
[64 + AST_MAX_APP
], *synopsis
= NULL
, *description
= NULL
;
3201 int synopsis_size
, description_size
;
3203 no_registered_app
= 0;
3206 synopsis_size
= strlen(a
->synopsis
) + 23;
3208 synopsis_size
= strlen("Not available") + 23;
3209 synopsis
= alloca(synopsis_size
);
3212 description_size
= strlen(a
->description
) + 23;
3214 description_size
= strlen("Not available") + 23;
3215 description
= alloca(description_size
);
3217 if (synopsis
&& description
) {
3218 snprintf(info
, 64 + AST_MAX_APP
, "\n -= Info about application '%s' =- \n\n", a
->name
);
3219 term_color(infotitle
, info
, COLOR_MAGENTA
, 0, 64 + AST_MAX_APP
+ 22);
3220 term_color(syntitle
, "[Synopsis]\n", COLOR_MAGENTA
, 0, 40);
3221 term_color(destitle
, "[Description]\n", COLOR_MAGENTA
, 0, 40);
3222 term_color(synopsis
,
3223 a
->synopsis
? a
->synopsis
: "Not available",
3224 COLOR_CYAN
, 0, synopsis_size
);
3225 term_color(description
,
3226 a
->description
? a
->description
: "Not available",
3227 COLOR_CYAN
, 0, description_size
);
3229 ast_cli(fd
,"%s%s%s\n\n%s%s\n", infotitle
, syntitle
, synopsis
, destitle
, description
);
3231 /* ... one of our applications, show info ...*/
3232 ast_cli(fd
,"\n -= Info about application '%s' =- \n\n"
3233 "[Synopsis]\n %s\n\n"
3234 "[Description]\n%s\n",
3236 a
->synopsis
? a
->synopsis
: "Not available",
3237 a
->description
? a
->description
: "Not available");
3242 AST_LIST_UNLOCK(&apps
);
3244 /* we found at least one app? no? */
3245 if (no_registered_app
) {
3246 ast_cli(fd
, "Your application(s) is (are) not registered\n");
3247 return RESULT_FAILURE
;
3250 return RESULT_SUCCESS
;
3253 /*! \brief handle_show_hints: CLI support for listing registred dial plan hints */
3254 static int handle_show_hints(int fd
, int argc
, char *argv
[])
3256 struct ast_hint
*hint
;
3259 struct ast_state_cb
*watcher
;
3261 if (AST_LIST_EMPTY(&hints
)) {
3262 ast_cli(fd
, "There are no registered dialplan hints\n");
3263 return RESULT_SUCCESS
;
3265 /* ... we have hints ... */
3266 ast_cli(fd
, "\n -= Registered Asterisk Dial Plan Hints =-\n");
3267 AST_LIST_LOCK(&hints
);
3268 AST_LIST_TRAVERSE(&hints
, hint
, list
) {
3270 for (watcher
= hint
->callbacks
; watcher
; watcher
= watcher
->next
)
3272 ast_cli(fd
, " %20s@%-20.20s: %-20.20s State:%-15.15s Watchers %2d\n",
3273 ast_get_extension_name(hint
->exten
),
3274 ast_get_context_name(ast_get_extension_context(hint
->exten
)),
3275 ast_get_extension_app(hint
->exten
),
3276 ast_extension_state2str(hint
->laststate
), watchers
);
3279 ast_cli(fd
, "----------------\n");
3280 ast_cli(fd
, "- %d hints registered\n", num
);
3281 AST_LIST_UNLOCK(&hints
);
3282 return RESULT_SUCCESS
;
3285 /*! \brief handle_show_switches: CLI support for listing registred dial plan switches */
3286 static int handle_show_switches(int fd
, int argc
, char *argv
[])
3288 struct ast_switch
*sw
;
3290 AST_LIST_LOCK(&switches
);
3292 if (AST_LIST_EMPTY(&switches
)) {
3293 AST_LIST_UNLOCK(&switches
);
3294 ast_cli(fd
, "There are no registered alternative switches\n");
3295 return RESULT_SUCCESS
;
3298 ast_cli(fd
, "\n -= Registered Asterisk Alternative Switches =-\n");
3299 AST_LIST_TRAVERSE(&switches
, sw
, list
)
3300 ast_cli(fd
, "%s: %s\n", sw
->name
, sw
->description
);
3302 AST_LIST_UNLOCK(&switches
);
3304 return RESULT_SUCCESS
;
3308 * 'show applications' CLI command implementation functions ...
3310 static int handle_show_applications_deprecated(int fd
, int argc
, char *argv
[])
3313 int like
= 0, describing
= 0;
3314 int total_match
= 0; /* Number of matches in like clause */
3315 int total_apps
= 0; /* Number of apps registered */
3317 AST_LIST_LOCK(&apps
);
3319 if (AST_LIST_EMPTY(&apps
)) {
3320 ast_cli(fd
, "There are no registered applications\n");
3321 AST_LIST_UNLOCK(&apps
);
3325 /* show applications like <keyword> */
3326 if ((argc
== 4) && (!strcmp(argv
[2], "like"))) {
3328 } else if ((argc
> 3) && (!strcmp(argv
[2], "describing"))) {
3332 /* show applications describing <keyword1> [<keyword2>] [...] */
3333 if ((!like
) && (!describing
)) {
3334 ast_cli(fd
, " -= Registered Asterisk Applications =-\n");
3336 ast_cli(fd
, " -= Matching Asterisk Applications =-\n");
3339 AST_LIST_TRAVERSE(&apps
, a
, list
) {
3343 if (strcasestr(a
->name
, argv
[3])) {
3347 } else if (describing
) {
3348 if (a
->description
) {
3349 /* Match all words on command line */
3352 for (i
= 3; i
< argc
; i
++) {
3353 if (!strcasestr(a
->description
, argv
[i
])) {
3365 ast_cli(fd
," %20s: %s\n", a
->name
, a
->synopsis
? a
->synopsis
: "<Synopsis not available>");
3368 if ((!like
) && (!describing
)) {
3369 ast_cli(fd
, " -= %d Applications Registered =-\n",total_apps
);
3371 ast_cli(fd
, " -= %d Applications Matching =-\n",total_match
);
3374 AST_LIST_UNLOCK(&apps
);
3376 return RESULT_SUCCESS
;
3378 static int handle_show_applications(int fd
, int argc
, char *argv
[])
3381 int like
= 0, describing
= 0;
3382 int total_match
= 0; /* Number of matches in like clause */
3383 int total_apps
= 0; /* Number of apps registered */
3385 AST_LIST_LOCK(&apps
);
3387 if (AST_LIST_EMPTY(&apps
)) {
3388 ast_cli(fd
, "There are no registered applications\n");
3389 AST_LIST_UNLOCK(&apps
);
3393 /* core list applications like <keyword> */
3394 if ((argc
== 5) && (!strcmp(argv
[3], "like"))) {
3396 } else if ((argc
> 4) && (!strcmp(argv
[3], "describing"))) {
3400 /* core list applications describing <keyword1> [<keyword2>] [...] */
3401 if ((!like
) && (!describing
)) {
3402 ast_cli(fd
, " -= Registered Asterisk Applications =-\n");
3404 ast_cli(fd
, " -= Matching Asterisk Applications =-\n");
3407 AST_LIST_TRAVERSE(&apps
, a
, list
) {
3411 if (strcasestr(a
->name
, argv
[4])) {
3415 } else if (describing
) {
3416 if (a
->description
) {
3417 /* Match all words on command line */
3420 for (i
= 4; i
< argc
; i
++) {
3421 if (!strcasestr(a
->description
, argv
[i
])) {
3433 ast_cli(fd
," %20s: %s\n", a
->name
, a
->synopsis
? a
->synopsis
: "<Synopsis not available>");
3436 if ((!like
) && (!describing
)) {
3437 ast_cli(fd
, " -= %d Applications Registered =-\n",total_apps
);
3439 ast_cli(fd
, " -= %d Applications Matching =-\n",total_match
);
3442 AST_LIST_UNLOCK(&apps
);
3444 return RESULT_SUCCESS
;
3447 static char *complete_show_applications_deprecated(const char *line
, const char *word
, int pos
, int state
)
3449 static char* choices
[] = { "like", "describing", NULL
};
3451 return (pos
!= 2) ? NULL
: ast_cli_complete(word
, choices
, state
);
3454 static char *complete_show_applications(const char *line
, const char *word
, int pos
, int state
)
3456 static char* choices
[] = { "like", "describing", NULL
};
3458 return (pos
!= 3) ? NULL
: ast_cli_complete(word
, choices
, state
);
3462 * 'show dialplan' CLI command implementation functions ...
3464 static char *complete_show_dialplan_context(const char *line
, const char *word
, int pos
,
3467 struct ast_context
*c
= NULL
;
3472 /* we are do completion of [exten@]context on second position only */
3476 ast_rdlock_contexts();
3478 wordlen
= strlen(word
);
3480 /* walk through all contexts and return the n-th match */
3481 while ( (c
= ast_walk_contexts(c
)) ) {
3482 if (!strncasecmp(word
, ast_get_context_name(c
), wordlen
) && ++which
> state
) {
3483 ret
= ast_strdup(ast_get_context_name(c
));
3488 ast_unlock_contexts();
3493 struct dialplan_counters
{
3497 int context_existence
;
3498 int extension_existence
;
3501 /*! \brief helper function to print an extension */
3502 static void print_ext(struct ast_exten
*e
, char * buf
, int buflen
)
3504 int prio
= ast_get_extension_priority(e
);
3505 if (prio
== PRIORITY_HINT
) {
3506 snprintf(buf
, buflen
, "hint: %s",
3507 ast_get_extension_app(e
));
3509 snprintf(buf
, buflen
, "%d. %s(%s)",
3510 prio
, ast_get_extension_app(e
),
3511 (!ast_strlen_zero(ast_get_extension_app_data(e
)) ? (char *)ast_get_extension_app_data(e
) : ""));
3515 /* XXX not verified */
3516 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
[])
3518 struct ast_context
*c
= NULL
;
3519 int res
= 0, old_total_exten
= dpc
->total_exten
;
3521 ast_rdlock_contexts();
3523 /* walk all contexts ... */
3524 while ( (c
= ast_walk_contexts(c
)) ) {
3525 struct ast_exten
*e
;
3526 struct ast_include
*i
;
3527 struct ast_ignorepat
*ip
;
3528 char buf
[256], buf2
[256];
3529 int context_info_printed
= 0;
3531 if (context
&& strcmp(ast_get_context_name(c
), context
))
3532 continue; /* skip this one, name doesn't match */
3534 dpc
->context_existence
= 1;
3536 ast_lock_context(c
);
3538 /* are we looking for exten too? if yes, we print context
3539 * only if we find our extension.
3540 * Otherwise print context even if empty ?
3541 * XXX i am not sure how the rinclude is handled.
3542 * I think it ought to go inside.
3545 dpc
->total_context
++;
3546 ast_cli(fd
, "[ Context '%s' created by '%s' ]\n",
3547 ast_get_context_name(c
), ast_get_context_registrar(c
));
3548 context_info_printed
= 1;
3551 /* walk extensions ... */
3553 while ( (e
= ast_walk_context_extensions(c
, e
)) ) {
3554 struct ast_exten
*p
;
3556 if (exten
&& !ast_extension_match(ast_get_extension_name(e
), exten
))
3557 continue; /* skip, extension match failed */
3559 dpc
->extension_existence
= 1;
3561 /* may we print context info? */
3562 if (!context_info_printed
) {
3563 dpc
->total_context
++;
3564 if (rinclude
) { /* TODO Print more info about rinclude */
3565 ast_cli(fd
, "[ Included context '%s' created by '%s' ]\n",
3566 ast_get_context_name(c
), ast_get_context_registrar(c
));
3568 ast_cli(fd
, "[ Context '%s' created by '%s' ]\n",
3569 ast_get_context_name(c
), ast_get_context_registrar(c
));
3571 context_info_printed
= 1;
3575 /* write extension name and first peer */
3576 snprintf(buf
, sizeof(buf
), "'%s' =>", ast_get_extension_name(e
));
3578 print_ext(e
, buf2
, sizeof(buf2
));
3580 ast_cli(fd
, " %-17s %-45s [%s]\n", buf
, buf2
,
3581 ast_get_extension_registrar(e
));
3584 /* walk next extension peers */
3585 p
= e
; /* skip the first one, we already got it */
3586 while ( (p
= ast_walk_extension_priorities(e
, p
)) ) {
3587 const char *el
= ast_get_extension_label(p
);
3590 snprintf(buf
, sizeof(buf
), " [%s]", el
);
3593 print_ext(p
, buf2
, sizeof(buf2
));
3595 ast_cli(fd
," %-17s %-45s [%s]\n", buf
, buf2
,
3596 ast_get_extension_registrar(p
));
3600 /* walk included and write info ... */
3602 while ( (i
= ast_walk_context_includes(c
, i
)) ) {
3603 snprintf(buf
, sizeof(buf
), "'%s'", ast_get_include_name(i
));
3605 /* Check all includes for the requested extension */
3606 if (includecount
>= AST_PBX_MAX_STACK
) {
3607 ast_log(LOG_NOTICE
, "Maximum include depth exceeded!\n");
3611 for (x
=0;x
<includecount
;x
++) {
3612 if (!strcasecmp(includes
[x
], ast_get_include_name(i
))) {
3618 includes
[includecount
] = ast_get_include_name(i
);
3619 show_dialplan_helper(fd
, ast_get_include_name(i
), exten
, dpc
, i
, includecount
+ 1, includes
);
3621 ast_log(LOG_WARNING
, "Avoiding circular include of %s within %s\n", ast_get_include_name(i
), context
);
3625 ast_cli(fd
, " Include => %-45s [%s]\n",
3626 buf
, ast_get_include_registrar(i
));
3630 /* walk ignore patterns and write info ... */
3632 while ( (ip
= ast_walk_context_ignorepats(c
, ip
)) ) {
3633 const char *ipname
= ast_get_ignorepat_name(ip
);
3634 char ignorepat
[AST_MAX_EXTENSION
];
3635 snprintf(buf
, sizeof(buf
), "'%s'", ipname
);
3636 snprintf(ignorepat
, sizeof(ignorepat
), "_%s.", ipname
);
3637 if (!exten
|| ast_extension_match(ignorepat
, exten
)) {
3638 ast_cli(fd
, " Ignore pattern => %-45s [%s]\n",
3639 buf
, ast_get_ignorepat_registrar(ip
));
3643 struct ast_sw
*sw
= NULL
;
3644 while ( (sw
= ast_walk_context_switches(c
, sw
)) ) {
3645 snprintf(buf
, sizeof(buf
), "'%s/%s'",
3646 ast_get_switch_name(sw
),
3647 ast_get_switch_data(sw
));
3648 ast_cli(fd
, " Alt. Switch => %-45s [%s]\n",
3649 buf
, ast_get_switch_registrar(sw
));
3653 ast_unlock_context(c
);
3655 /* if we print something in context, make an empty line */
3656 if (context_info_printed
)
3657 ast_cli(fd
, "\r\n");
3659 ast_unlock_contexts();
3661 return (dpc
->total_exten
== old_total_exten
) ? -1 : res
;
3664 static int handle_show_dialplan(int fd
, int argc
, char *argv
[])
3666 char *exten
= NULL
, *context
= NULL
;
3667 /* Variables used for different counters */
3668 struct dialplan_counters counters
;
3670 const char *incstack
[AST_PBX_MAX_STACK
];
3671 memset(&counters
, 0, sizeof(counters
));
3673 if (argc
!= 2 && argc
!= 3)
3674 return RESULT_SHOWUSAGE
;
3676 /* we obtain [exten@]context? if yes, split them ... */
3678 if (strchr(argv
[2], '@')) { /* split into exten & context */
3679 context
= ast_strdupa(argv
[2]);
3680 exten
= strsep(&context
, "@");
3681 /* change empty strings to NULL */
3682 if (ast_strlen_zero(exten
))
3684 } else { /* no '@' char, only context given */
3687 if (ast_strlen_zero(context
))
3690 /* else Show complete dial plan, context and exten are NULL */
3691 show_dialplan_helper(fd
, context
, exten
, &counters
, NULL
, 0, incstack
);
3693 /* check for input failure and throw some error messages */
3694 if (context
&& !counters
.context_existence
) {
3695 ast_cli(fd
, "There is no existence of '%s' context\n", context
);
3696 return RESULT_FAILURE
;
3699 if (exten
&& !counters
.extension_existence
) {
3701 ast_cli(fd
, "There is no existence of %s@%s extension\n",
3705 "There is no existence of '%s' extension in all contexts\n",
3707 return RESULT_FAILURE
;
3710 ast_cli(fd
,"-= %d %s (%d %s) in %d %s. =-\n",
3711 counters
.total_exten
, counters
.total_exten
== 1 ? "extension" : "extensions",
3712 counters
.total_prio
, counters
.total_prio
== 1 ? "priority" : "priorities",
3713 counters
.total_context
, counters
.total_context
== 1 ? "context" : "contexts");
3716 return RESULT_SUCCESS
;
3719 /*! \brief CLI support for listing global variables in a parseable way */
3720 static int handle_show_globals(int fd
, int argc
, char *argv
[])
3723 struct ast_var_t
*newvariable
;
3725 ast_mutex_lock(&globalslock
);
3726 AST_LIST_TRAVERSE (&globals
, newvariable
, entries
) {
3728 ast_cli(fd
, " %s=%s\n", ast_var_name(newvariable
), ast_var_value(newvariable
));
3730 ast_mutex_unlock(&globalslock
);
3731 ast_cli(fd
, "\n -- %d variables\n", i
);
3733 return RESULT_SUCCESS
;
3736 /*! \brief CLI support for setting global variables */
3737 static int handle_set_global_deprecated(int fd
, int argc
, char *argv
[])
3740 return RESULT_SHOWUSAGE
;
3742 pbx_builtin_setvar_helper(NULL
, argv
[2], argv
[3]);
3743 ast_cli(fd
, "\n -- Global variable %s set to %s\n", argv
[2], argv
[3]);
3745 return RESULT_SUCCESS
;
3749 static int handle_set_global(int fd
, int argc
, char *argv
[])
3752 return RESULT_SHOWUSAGE
;
3754 pbx_builtin_setvar_helper(NULL
, argv
[3], argv
[4]);
3755 ast_cli(fd
, "\n -- Global variable %s set to %s\n", argv
[3], argv
[4]);
3757 return RESULT_SUCCESS
;
3763 * CLI entries for upper commands ...
3765 static struct ast_cli_entry cli_show_applications_deprecated
= {
3766 { "show", "applications", NULL
},
3767 handle_show_applications_deprecated
, NULL
,
3768 NULL
, complete_show_applications_deprecated
};
3770 static struct ast_cli_entry cli_show_functions_deprecated
= {
3771 { "show", "functions", NULL
},
3772 handle_show_functions_deprecated
, NULL
,
3775 static struct ast_cli_entry cli_show_switches_deprecated
= {
3776 { "show", "switches", NULL
},
3777 handle_show_switches
, NULL
,
3780 static struct ast_cli_entry cli_show_hints_deprecated
= {
3781 { "show", "hints", NULL
},
3782 handle_show_hints
, NULL
,
3785 static struct ast_cli_entry cli_show_globals_deprecated
= {
3786 { "show", "globals", NULL
},
3787 handle_show_globals
, NULL
,
3790 static struct ast_cli_entry cli_show_function_deprecated
= {
3791 { "show" , "function", NULL
},
3792 handle_show_function_deprecated
, NULL
,
3793 NULL
, complete_show_function
};
3795 static struct ast_cli_entry cli_show_application_deprecated
= {
3796 { "show", "application", NULL
},
3797 handle_show_application_deprecated
, NULL
,
3798 NULL
, complete_show_application
};
3800 static struct ast_cli_entry cli_show_dialplan_deprecated
= {
3801 { "show", "dialplan", NULL
},
3802 handle_show_dialplan
, NULL
,
3803 NULL
, complete_show_dialplan_context
};
3805 static struct ast_cli_entry cli_set_global_deprecated
= {
3806 { "set", "global", NULL
},
3807 handle_set_global_deprecated
, NULL
,
3810 static struct ast_cli_entry pbx_cli
[] = {
3811 { { "core", "show", "applications", NULL
},
3812 handle_show_applications
, "Shows registered dialplan applications",
3813 show_applications_help
, complete_show_applications
, &cli_show_applications_deprecated
},
3815 { { "core", "show", "functions", NULL
},
3816 handle_show_functions
, "Shows registered dialplan functions",
3817 show_functions_help
, NULL
, &cli_show_functions_deprecated
},
3819 { { "core", "show", "switches", NULL
},
3820 handle_show_switches
, "Show alternative switches",
3821 show_switches_help
, NULL
, &cli_show_switches_deprecated
},
3823 { { "core", "show", "hints", NULL
},
3824 handle_show_hints
, "Show dialplan hints",
3825 show_hints_help
, NULL
, &cli_show_hints_deprecated
},
3827 { { "core", "show", "globals", NULL
},
3828 handle_show_globals
, "Show global dialplan variables",
3829 show_globals_help
, NULL
, &cli_show_globals_deprecated
},
3831 { { "core", "show" , "function", NULL
},
3832 handle_show_function
, "Describe a specific dialplan function",
3833 show_function_help
, complete_show_function
, &cli_show_function_deprecated
},
3835 { { "core", "show", "application", NULL
},
3836 handle_show_application
, "Describe a specific dialplan application",
3837 show_application_help
, complete_show_application
, &cli_show_application_deprecated
},
3839 { { "core", "set", "global", NULL
},
3840 handle_set_global
, "Set global dialplan variable",
3841 set_global_help
, NULL
, &cli_set_global_deprecated
},
3843 { { "dialplan", "show", NULL
},
3844 handle_show_dialplan
, "Show dialplan",
3845 show_dialplan_help
, complete_show_dialplan_context
, &cli_show_dialplan_deprecated
},
3848 int ast_unregister_application(const char *app
)
3850 struct ast_app
*tmp
;
3852 AST_LIST_LOCK(&apps
);
3853 AST_LIST_TRAVERSE_SAFE_BEGIN(&apps
, tmp
, list
) {
3854 if (!strcasecmp(app
, tmp
->name
)) {
3855 AST_LIST_REMOVE_CURRENT(&apps
, list
);
3856 if (option_verbose
> 1)
3857 ast_verbose( VERBOSE_PREFIX_2
"Unregistered application '%s'\n", tmp
->name
);
3862 AST_LIST_TRAVERSE_SAFE_END
3863 AST_LIST_UNLOCK(&apps
);
3865 return tmp
? 0 : -1;
3868 static struct ast_context
*__ast_context_create(struct ast_context
**extcontexts
, const char *name
, const char *registrar
, int existsokay
)
3870 struct ast_context
*tmp
, **local_contexts
;
3871 int length
= sizeof(struct ast_context
) + strlen(name
) + 1;
3874 ast_rdlock_contexts();
3875 local_contexts
= &contexts
;
3877 local_contexts
= extcontexts
;
3879 for (tmp
= *local_contexts
; tmp
; tmp
= tmp
->next
) {
3880 if (!strcasecmp(tmp
->name
, name
)) {
3882 ast_log(LOG_WARNING
, "Tried to register context '%s', already in use\n", name
);
3886 ast_unlock_contexts();
3892 ast_unlock_contexts();
3894 if ((tmp
= ast_calloc(1, length
))) {
3895 ast_mutex_init(&tmp
->lock
);
3896 ast_mutex_init(&tmp
->macrolock
);
3897 strcpy(tmp
->name
, name
);
3898 tmp
->registrar
= registrar
;
3900 ast_wrlock_contexts();
3901 tmp
->next
= *local_contexts
;
3902 *local_contexts
= tmp
;
3904 ast_unlock_contexts();
3906 ast_log(LOG_DEBUG
, "Registered context '%s'\n", tmp
->name
);
3907 if (option_verbose
> 2)
3908 ast_verbose( VERBOSE_PREFIX_3
"Registered extension context '%s'\n", tmp
->name
);
3914 struct ast_context
*ast_context_create(struct ast_context
**extcontexts
, const char *name
, const char *registrar
)
3916 return __ast_context_create(extcontexts
, name
, registrar
, 0);
3919 struct ast_context
*ast_context_find_or_create(struct ast_context
**extcontexts
, const char *name
, const char *registrar
)
3921 return __ast_context_create(extcontexts
, name
, registrar
, 1);
3923 void __ast_context_destroy(struct ast_context
*con
, const char *registrar
);
3928 struct ast_state_cb
*callbacks
;
3930 AST_LIST_ENTRY(store_hint
) list
;
3934 AST_LIST_HEAD(store_hints
, store_hint
);
3936 /* XXX this does not check that multiple contexts are merged */
3937 void ast_merge_contexts_and_delete(struct ast_context
**extcontexts
, const char *registrar
)
3939 struct ast_context
*tmp
, *lasttmp
= NULL
;
3940 struct store_hints store
= AST_LIST_HEAD_INIT_VALUE
;
3941 struct store_hint
*this;
3942 struct ast_hint
*hint
;
3943 struct ast_exten
*exten
;
3945 struct ast_state_cb
*thiscb
, *prevcb
;
3947 /* it is very important that this function hold the hint list lock _and_ the conlock
3948 during its operation; not only do we need to ensure that the list of contexts
3949 and extensions does not change, but also that no hint callbacks (watchers) are
3950 added or removed during the merge/delete process
3952 in addition, the locks _must_ be taken in this order, because there are already
3953 other code paths that use this order
3955 ast_wrlock_contexts();
3956 AST_LIST_LOCK(&hints
);
3958 /* preserve all watchers for hints associated with this registrar */
3959 AST_LIST_TRAVERSE(&hints
, hint
, list
) {
3960 if (hint
->callbacks
&& !strcmp(registrar
, hint
->exten
->parent
->registrar
)) {
3961 length
= strlen(hint
->exten
->exten
) + strlen(hint
->exten
->parent
->name
) + 2 + sizeof(*this);
3962 if (!(this = ast_calloc(1, length
)))
3964 this->callbacks
= hint
->callbacks
;
3965 hint
->callbacks
= NULL
;
3966 this->laststate
= hint
->laststate
;
3967 this->context
= this->data
;
3968 strcpy(this->data
, hint
->exten
->parent
->name
);
3969 this->exten
= this->data
+ strlen(this->context
) + 1;
3970 strcpy(this->exten
, hint
->exten
->exten
);
3971 AST_LIST_INSERT_HEAD(&store
, this, list
);
3977 /* XXX remove previous contexts from same registrar */
3979 ast_log(LOG_DEBUG
, "must remove any reg %s\n", registrar
);
3980 __ast_context_destroy(NULL
,registrar
);
3986 /* XXX remove contexts with the same name */
3988 ast_log(LOG_WARNING
, "must remove %s reg %s\n", tmp
->name
, tmp
->registrar
);
3989 __ast_context_destroy(tmp
,tmp
->registrar
);
3995 lasttmp
->next
= contexts
;
3996 contexts
= *extcontexts
;
3997 *extcontexts
= NULL
;
3999 ast_log(LOG_WARNING
, "Requested contexts didn't get merged\n");
4001 /* restore the watchers for hints that can be found; notify those that
4004 while ((this = AST_LIST_REMOVE_HEAD(&store
, list
))) {
4005 struct pbx_find_info q
= { .stacklen
= 0 };
4006 exten
= pbx_find_extension(NULL
, NULL
, &q
, this->context
, this->exten
, PRIORITY_HINT
, NULL
, "", E_MATCH
);
4007 /* Find the hint in the list of hints */
4008 AST_LIST_TRAVERSE(&hints
, hint
, list
) {
4009 if (hint
->exten
== exten
)
4012 if (!exten
|| !hint
) {
4013 /* this hint has been removed, notify the watchers */
4015 thiscb
= this->callbacks
;
4018 thiscb
= thiscb
->next
;
4019 prevcb
->callback(this->context
, this->exten
, AST_EXTENSION_REMOVED
, prevcb
->data
);
4023 thiscb
= this->callbacks
;
4024 while (thiscb
->next
)
4025 thiscb
= thiscb
->next
;
4026 thiscb
->next
= hint
->callbacks
;
4027 hint
->callbacks
= this->callbacks
;
4028 hint
->laststate
= this->laststate
;
4033 AST_LIST_UNLOCK(&hints
);
4034 ast_unlock_contexts();
4041 * EBUSY - can't lock
4042 * ENOENT - no existence of context
4044 int ast_context_add_include(const char *context
, const char *include
, const char *registrar
)
4047 struct ast_context
*c
= find_context_locked(context
);
4050 ret
= ast_context_add_include2(c
, include
, registrar
);
4051 ast_unlock_contexts();
4056 /*! \brief Helper for get_range.
4057 * return the index of the matching entry, starting from 1.
4058 * If names is not supplied, try numeric values.
4060 static int lookup_name(const char *s
, char *const names
[], int max
)
4065 for (i
= 0; names
[i
]; i
++) {
4066 if (!strcasecmp(s
, names
[i
]))
4069 } else if (sscanf(s
, "%d", &i
) == 1 && i
>= 1 && i
<= max
) {
4072 return 0; /* error return */
4075 /*! \brief helper function to return a range up to max (7, 12, 31 respectively).
4076 * names, if supplied, is an array of names that should be mapped to numbers.
4078 static unsigned get_range(char *src
, int max
, char *const names
[], const char *msg
)
4080 int s
, e
; /* start and ending position */
4081 unsigned int mask
= 0;
4083 /* Check for whole range */
4084 if (ast_strlen_zero(src
) || !strcmp(src
, "*")) {
4088 /* Get start and ending position */
4089 char *c
= strchr(src
, '-');
4092 /* Find the start */
4093 s
= lookup_name(src
, names
, max
);
4095 ast_log(LOG_WARNING
, "Invalid %s '%s', assuming none\n", msg
, src
);
4099 if (c
) { /* find end of range */
4100 e
= lookup_name(c
, names
, max
);
4102 ast_log(LOG_WARNING
, "Invalid end %s '%s', assuming none\n", msg
, c
);
4109 /* Fill the mask. Remember that ranges are cyclic */
4110 mask
= 1 << e
; /* initialize with last element */
4123 /*! \brief store a bitmask of valid times, one bit each 2 minute */
4124 static void get_timerange(struct ast_timing
*i
, char *times
)
4132 /* start disabling all times, fill the fields with 0's, as they may contain garbage */
4133 memset(i
->minmask
, 0, sizeof(i
->minmask
));
4135 /* 2-minutes per bit, since the mask has only 32 bits :( */
4136 /* Star is all times */
4137 if (ast_strlen_zero(times
) || !strcmp(times
, "*")) {
4138 for (x
=0; x
<24; x
++)
4139 i
->minmask
[x
] = 0x3fffffff; /* 30 bits */
4142 /* Otherwise expect a range */
4143 e
= strchr(times
, '-');
4145 ast_log(LOG_WARNING
, "Time range is not valid. Assuming no restrictions based on time.\n");
4149 /* XXX why skip non digits ? */
4150 while (*e
&& !isdigit(*e
))
4153 ast_log(LOG_WARNING
, "Invalid time range. Assuming no restrictions based on time.\n");
4156 if (sscanf(times
, "%d:%d", &s1
, &s2
) != 2) {
4157 ast_log(LOG_WARNING
, "%s isn't a time. Assuming no restrictions based on time.\n", times
);
4160 if (sscanf(e
, "%d:%d", &e1
, &e2
) != 2) {
4161 ast_log(LOG_WARNING
, "%s isn't a time. Assuming no restrictions based on time.\n", e
);
4164 /* XXX this needs to be optimized */
4166 s1
= s1
* 30 + s2
/2;
4167 if ((s1
< 0) || (s1
>= 24*30)) {
4168 ast_log(LOG_WARNING
, "%s isn't a valid start time. Assuming no time.\n", times
);
4171 e1
= e1
* 30 + e2
/2;
4172 if ((e1
< 0) || (e1
>= 24*30)) {
4173 ast_log(LOG_WARNING
, "%s isn't a valid end time. Assuming no time.\n", e
);
4176 /* Go through the time and enable each appropriate bit */
4177 for (x
=s1
;x
!= e1
;x
= (x
+ 1) % (24 * 30)) {
4178 i
->minmask
[x
/30] |= (1 << (x
% 30));
4180 /* Do the last one */
4181 i
->minmask
[x
/30] |= (1 << (x
% 30));
4183 for (cth
=0; cth
<24; cth
++) {
4184 /* Initialize masks to blank */
4185 i
->minmask
[cth
] = 0;
4186 for (ctm
=0; ctm
<30; ctm
++) {
4188 /* First hour with more than one hour */
4189 (((cth
== s1
) && (ctm
>= s2
)) &&
4192 || (((cth
== s1
) && (ctm
>= s2
)) &&
4193 ((cth
== e1
) && (ctm
<= e2
)))
4194 /* In between first and last hours (more than 2 hours) */
4197 /* Last hour with more than one hour */
4199 ((cth
== e1
) && (ctm
<= e2
)))
4201 i
->minmask
[cth
] |= (1 << (ctm
/ 2));
4209 static char *days
[] =
4221 static char *months
[] =
4238 int ast_build_timing(struct ast_timing
*i
, const char *info_in
)
4240 char info_save
[256];
4243 /* Check for empty just in case */
4244 if (ast_strlen_zero(info_in
))
4246 /* make a copy just in case we were passed a static string */
4247 ast_copy_string(info_save
, info_in
, sizeof(info_save
));
4249 /* Assume everything except time */
4250 i
->monthmask
= 0xfff; /* 12 bits */
4251 i
->daymask
= 0x7fffffffU
; /* 31 bits */
4252 i
->dowmask
= 0x7f; /* 7 bits */
4253 /* on each call, use strsep() to move info to the next argument */
4254 get_timerange(i
, strsep(&info
, "|"));
4256 i
->dowmask
= get_range(strsep(&info
, "|"), 7, days
, "day of week");
4258 i
->daymask
= get_range(strsep(&info
, "|"), 31, NULL
, "day");
4260 i
->monthmask
= get_range(strsep(&info
, "|"), 12, months
, "month");
4264 int ast_check_timing(const struct ast_timing
*i
)
4267 time_t t
= time(NULL
);
4269 ast_localtime(&t
, &tm
, NULL
);
4271 /* If it's not the right month, return */
4272 if (!(i
->monthmask
& (1 << tm
.tm_mon
)))
4275 /* If it's not that time of the month.... */
4276 /* Warning, tm_mday has range 1..31! */
4277 if (!(i
->daymask
& (1 << (tm
.tm_mday
-1))))
4280 /* If it's not the right day of the week */
4281 if (!(i
->dowmask
& (1 << tm
.tm_wday
)))
4284 /* Sanity check the hour just to be safe */
4285 if ((tm
.tm_hour
< 0) || (tm
.tm_hour
> 23)) {
4286 ast_log(LOG_WARNING
, "Insane time...\n");
4290 /* Now the tough part, we calculate if it fits
4291 in the right time based on min/hour */
4292 if (!(i
->minmask
[tm
.tm_hour
] & (1 << (tm
.tm_min
/ 2))))
4295 /* If we got this far, then we're good */
4301 * ENOMEM - out of memory
4302 * EBUSY - can't lock
4303 * EEXIST - already included
4304 * EINVAL - there is no existence of context for inclusion
4306 int ast_context_add_include2(struct ast_context
*con
, const char *value
,
4307 const char *registrar
)
4309 struct ast_include
*new_include
;
4311 struct ast_include
*i
, *il
= NULL
; /* include, include_last */
4315 length
= sizeof(struct ast_include
);
4316 length
+= 2 * (strlen(value
) + 1);
4318 /* allocate new include structure ... */
4319 if (!(new_include
= ast_calloc(1, length
)))
4321 /* Fill in this structure. Use 'p' for assignments, as the fields
4322 * in the structure are 'const char *'
4324 p
= new_include
->stuff
;
4325 new_include
->name
= p
;
4327 p
+= strlen(value
) + 1;
4328 new_include
->rname
= p
;
4330 /* Strip off timing info, and process if it is there */
4331 if ( (c
= strchr(p
, '|')) ) {
4333 new_include
->hastime
= ast_build_timing(&(new_include
->timing
), c
);
4335 new_include
->next
= NULL
;
4336 new_include
->registrar
= registrar
;
4338 ast_mutex_lock(&con
->lock
);
4340 /* ... go to last include and check if context is already included too... */
4341 for (i
= con
->includes
; i
; i
= i
->next
) {
4342 if (!strcasecmp(i
->name
, new_include
->name
)) {
4344 ast_mutex_unlock(&con
->lock
);
4351 /* ... include new context into context list, unlock, return */
4353 il
->next
= new_include
;
4355 con
->includes
= new_include
;
4356 if (option_verbose
> 2)
4357 ast_verbose(VERBOSE_PREFIX_3
"Including context '%s' in context '%s'\n", new_include
->name
, ast_get_context_name(con
));
4358 ast_mutex_unlock(&con
->lock
);
4365 * EBUSY - can't lock
4366 * ENOENT - no existence of context
4368 int ast_context_add_switch(const char *context
, const char *sw
, const char *data
, int eval
, const char *registrar
)
4371 struct ast_context
*c
= find_context_locked(context
);
4373 if (c
) { /* found, add switch to this context */
4374 ret
= ast_context_add_switch2(c
, sw
, data
, eval
, registrar
);
4375 ast_unlock_contexts();
4382 * ENOMEM - out of memory
4383 * EBUSY - can't lock
4384 * EEXIST - already included
4385 * EINVAL - there is no existence of context for inclusion
4387 int ast_context_add_switch2(struct ast_context
*con
, const char *value
,
4388 const char *data
, int eval
, const char *registrar
)
4390 struct ast_sw
*new_sw
;
4395 length
= sizeof(struct ast_sw
);
4396 length
+= strlen(value
) + 1;
4398 length
+= strlen(data
);
4401 /* allocate new sw structure ... */
4402 if (!(new_sw
= ast_calloc(1, length
)))
4404 /* ... fill in this structure ... */
4407 strcpy(new_sw
->name
, value
);
4408 p
+= strlen(value
) + 1;
4411 strcpy(new_sw
->data
, data
);
4412 p
+= strlen(data
) + 1;
4414 strcpy(new_sw
->data
, "");
4417 new_sw
->eval
= eval
;
4418 new_sw
->registrar
= registrar
;
4420 /* ... try to lock this context ... */
4421 ast_mutex_lock(&con
->lock
);
4423 /* ... go to last sw and check if context is already swd too... */
4424 AST_LIST_TRAVERSE(&con
->alts
, i
, list
) {
4425 if (!strcasecmp(i
->name
, new_sw
->name
) && !strcasecmp(i
->data
, new_sw
->data
)) {
4427 ast_mutex_unlock(&con
->lock
);
4433 /* ... sw new context into context list, unlock, return */
4434 AST_LIST_INSERT_TAIL(&con
->alts
, new_sw
, list
);
4436 if (option_verbose
> 2)
4437 ast_verbose(VERBOSE_PREFIX_3
"Including switch '%s/%s' in context '%s'\n", new_sw
->name
, new_sw
->data
, ast_get_context_name(con
));
4439 ast_mutex_unlock(&con
->lock
);
4445 * EBUSY - can't lock
4446 * ENOENT - there is not context existence
4448 int ast_context_remove_ignorepat(const char *context
, const char *ignorepat
, const char *registrar
)
4451 struct ast_context
*c
= find_context_locked(context
);
4454 ret
= ast_context_remove_ignorepat2(c
, ignorepat
, registrar
);
4455 ast_unlock_contexts();
4460 int ast_context_remove_ignorepat2(struct ast_context
*con
, const char *ignorepat
, const char *registrar
)
4462 struct ast_ignorepat
*ip
, *ipl
= NULL
;
4464 ast_mutex_lock(&con
->lock
);
4466 for (ip
= con
->ignorepats
; ip
; ip
= ip
->next
) {
4467 if (!strcmp(ip
->pattern
, ignorepat
) &&
4468 (!registrar
|| (registrar
== ip
->registrar
))) {
4470 ipl
->next
= ip
->next
;
4473 con
->ignorepats
= ip
->next
;
4476 ast_mutex_unlock(&con
->lock
);
4482 ast_mutex_unlock(&con
->lock
);
4488 * EBUSY - can't lock
4489 * ENOENT - there is no existence of context
4491 int ast_context_add_ignorepat(const char *context
, const char *value
, const char *registrar
)
4494 struct ast_context
*c
= find_context_locked(context
);
4497 ret
= ast_context_add_ignorepat2(c
, value
, registrar
);
4498 ast_unlock_contexts();
4503 int ast_context_add_ignorepat2(struct ast_context
*con
, const char *value
, const char *registrar
)
4505 struct ast_ignorepat
*ignorepat
, *ignorepatc
, *ignorepatl
= NULL
;
4507 length
= sizeof(struct ast_ignorepat
);
4508 length
+= strlen(value
) + 1;
4509 if (!(ignorepat
= ast_calloc(1, length
)))
4511 /* The cast to char * is because we need to write the initial value.
4512 * The field is not supposed to be modified otherwise
4514 strcpy((char *)ignorepat
->pattern
, value
);
4515 ignorepat
->next
= NULL
;
4516 ignorepat
->registrar
= registrar
;
4517 ast_mutex_lock(&con
->lock
);
4518 for (ignorepatc
= con
->ignorepats
; ignorepatc
; ignorepatc
= ignorepatc
->next
) {
4519 ignorepatl
= ignorepatc
;
4520 if (!strcasecmp(ignorepatc
->pattern
, value
)) {
4522 ast_mutex_unlock(&con
->lock
);
4528 ignorepatl
->next
= ignorepat
;
4530 con
->ignorepats
= ignorepat
;
4531 ast_mutex_unlock(&con
->lock
);
4536 int ast_ignore_pattern(const char *context
, const char *pattern
)
4538 struct ast_context
*con
= ast_context_find(context
);
4540 struct ast_ignorepat
*pat
;
4541 for (pat
= con
->ignorepats
; pat
; pat
= pat
->next
) {
4542 if (ast_extension_match(pat
->pattern
, pattern
))
4551 * EBUSY - can't lock
4552 * ENOENT - no existence of context
4555 int ast_add_extension(const char *context
, int replace
, const char *extension
,
4556 int priority
, const char *label
, const char *callerid
,
4557 const char *application
, void *data
, void (*datad
)(void *), const char *registrar
)
4560 struct ast_context
*c
= find_context_locked(context
);
4563 ret
= ast_add_extension2(c
, replace
, extension
, priority
, label
, callerid
,
4564 application
, data
, datad
, registrar
);
4565 ast_unlock_contexts();
4570 int ast_explicit_goto(struct ast_channel
*chan
, const char *context
, const char *exten
, int priority
)
4575 ast_channel_lock(chan
);
4577 if (!ast_strlen_zero(context
))
4578 ast_copy_string(chan
->context
, context
, sizeof(chan
->context
));
4579 if (!ast_strlen_zero(exten
))
4580 ast_copy_string(chan
->exten
, exten
, sizeof(chan
->exten
));
4581 if (priority
> -1) {
4582 chan
->priority
= priority
;
4583 /* see flag description in channel.h for explanation */
4584 if (ast_test_flag(chan
, AST_FLAG_IN_AUTOLOOP
))
4588 ast_channel_unlock(chan
);
4593 int ast_async_goto(struct ast_channel
*chan
, const char *context
, const char *exten
, int priority
)
4597 ast_channel_lock(chan
);
4599 if (chan
->pbx
) { /* This channel is currently in the PBX */
4600 ast_explicit_goto(chan
, context
, exten
, priority
);
4601 ast_softhangup_nolock(chan
, AST_SOFTHANGUP_ASYNCGOTO
);
4603 /* In order to do it when the channel doesn't really exist within
4604 the PBX, we have to make a new channel, masquerade, and start the PBX
4605 at the new location */
4606 struct ast_channel
*tmpchan
= ast_channel_alloc(0, chan
->_state
, 0, 0, chan
->accountcode
, chan
->exten
, chan
->context
, chan
->amaflags
, "AsyncGoto/%s", chan
->name
);
4608 ast_cdr_discard(tmpchan
->cdr
);
4609 tmpchan
->cdr
= ast_cdr_dup(chan
->cdr
); /* share the love */
4614 /* Make formats okay */
4615 tmpchan
->readformat
= chan
->readformat
;
4616 tmpchan
->writeformat
= chan
->writeformat
;
4617 /* Setup proper location */
4618 ast_explicit_goto(tmpchan
,
4619 S_OR(context
, chan
->context
), S_OR(exten
, chan
->exten
), priority
);
4621 /* Masquerade into temp channel */
4622 ast_channel_masquerade(tmpchan
, chan
);
4624 /* Grab the locks and get going */
4625 ast_channel_lock(tmpchan
);
4626 ast_do_masquerade(tmpchan
);
4627 ast_channel_unlock(tmpchan
);
4628 /* Start the PBX going on our stolen channel */
4629 if (ast_pbx_start(tmpchan
)) {
4630 ast_log(LOG_WARNING
, "Unable to start PBX on %s\n", tmpchan
->name
);
4631 ast_hangup(tmpchan
);
4636 ast_channel_unlock(chan
);
4640 int ast_async_goto_by_name(const char *channame
, const char *context
, const char *exten
, int priority
)
4642 struct ast_channel
*chan
;
4645 chan
= ast_get_channel_by_name_locked(channame
);
4647 res
= ast_async_goto(chan
, context
, exten
, priority
);
4648 ast_channel_unlock(chan
);
4653 /*! \brief copy a string skipping whitespace */
4654 static int ext_strncpy(char *dst
, const char *src
, int len
)
4658 while (*src
&& (count
< len
- 1)) {
4661 /* otherwise exten => [a-b],1,... doesn't work */
4677 /*! \brief add the extension in the priority chain.
4678 * returns 0 on success, -1 on failure
4680 static int add_pri(struct ast_context
*con
, struct ast_exten
*tmp
,
4681 struct ast_exten
*el
, struct ast_exten
*e
, int replace
)
4683 struct ast_exten
*ep
;
4685 for (ep
= NULL
; e
; ep
= e
, e
= e
->peer
) {
4686 if (e
->priority
>= tmp
->priority
)
4689 if (!e
) { /* go at the end, and ep is surely set because the list is not empty */
4691 return 0; /* success */
4693 if (e
->priority
== tmp
->priority
) {
4694 /* Can't have something exactly the same. Is this a
4695 replacement? If so, replace, otherwise, bonk. */
4697 ast_log(LOG_WARNING
, "Unable to register extension '%s', priority %d in '%s', already in use\n", tmp
->exten
, tmp
->priority
, con
->name
);
4699 tmp
->datad(tmp
->data
);
4703 /* we are replacing e, so copy the link fields and then update
4704 * whoever pointed to e to point to us
4706 tmp
->next
= e
->next
; /* not meaningful if we are not first in the peer list */
4707 tmp
->peer
= e
->peer
; /* always meaningful */
4708 if (ep
) /* We're in the peer list, just insert ourselves */
4710 else if (el
) /* We're the first extension. Take over e's functions */
4712 else /* We're the very first extension. */
4714 if (tmp
->priority
== PRIORITY_HINT
)
4715 ast_change_hint(e
,tmp
);
4716 /* Destroy the old one */
4720 } else { /* Slip ourselves in just before e */
4722 tmp
->next
= e
->next
; /* extension chain, or NULL if e is not the first extension */
4723 if (ep
) /* Easy enough, we're just in the peer list */
4725 else { /* we are the first in some peer list, so link in the ext list */
4727 el
->next
= tmp
; /* in the middle... */
4729 con
->root
= tmp
; /* ... or at the head */
4730 e
->next
= NULL
; /* e is no more at the head, so e->next must be reset */
4732 /* And immediately return success. */
4733 if (tmp
->priority
== PRIORITY_HINT
)
4740 * Main interface to add extensions to the list for out context.
4742 * We sort extensions in order of matching preference, so that we can
4743 * stop the search as soon as we find a suitable match.
4744 * This ordering also takes care of wildcards such as '.' (meaning
4745 * "one or more of any character") and '!' (which is 'earlymatch',
4746 * meaning "zero or more of any character" but also impacts the
4747 * return value from CANMATCH and EARLYMATCH.
4749 * The extension match rules defined in the devmeeting 2006.05.05 are
4750 * quite simple: WE SELECT THE LONGEST MATCH.
4751 * In detail, "longest" means the number of matched characters in
4752 * the extension. In case of ties (e.g. _XXX and 333) in the length
4753 * of a pattern, we give priority to entries with the smallest cardinality
4754 * (e.g, [5-9] comes before [2-8] before the former has only 5 elements,
4755 * while the latter has 7, etc.
4756 * In case of same cardinality, the first element in the range counts.
4757 * If we still have a tie, any final '!' will make this as a possibly
4758 * less specific pattern.
4760 * EBUSY - can't lock
4761 * EEXIST - extension with the same priority exist and no replace is set
4764 int ast_add_extension2(struct ast_context
*con
,
4765 int replace
, const char *extension
, int priority
, const char *label
, const char *callerid
,
4766 const char *application
, void *data
, void (*datad
)(void *),
4767 const char *registrar
)
4770 * Sort extensions (or patterns) according to the rules indicated above.
4771 * These are implemented by the function ext_cmp()).
4772 * All priorities for the same ext/pattern/cid are kept in a list,
4773 * using the 'peer' field as a link field..
4775 struct ast_exten
*tmp
, *e
, *el
= NULL
;
4779 char expand_buf
[VAR_BUF_SIZE
] = { 0, };
4781 /* if we are adding a hint, and there are global variables, and the hint
4782 contains variable references, then expand them
4784 ast_mutex_lock(&globalslock
);
4785 if (priority
== PRIORITY_HINT
&& AST_LIST_FIRST(&globals
) && strstr(application
, "${")) {
4786 pbx_substitute_variables_varshead(&globals
, application
, expand_buf
, sizeof(expand_buf
));
4787 application
= expand_buf
;
4789 ast_mutex_unlock(&globalslock
);
4791 length
= sizeof(struct ast_exten
);
4792 length
+= strlen(extension
) + 1;
4793 length
+= strlen(application
) + 1;
4795 length
+= strlen(label
) + 1;
4797 length
+= strlen(callerid
) + 1;
4799 length
++; /* just the '\0' */
4801 /* Be optimistic: Build the extension structure first */
4802 if (!(tmp
= ast_calloc(1, length
)))
4805 /* use p as dst in assignments, as the fields are const char * */
4810 p
+= strlen(label
) + 1;
4813 p
+= ext_strncpy(p
, extension
, strlen(extension
) + 1) + 1;
4814 tmp
->priority
= priority
;
4815 tmp
->cidmatch
= p
; /* but use p for assignments below */
4817 p
+= ext_strncpy(p
, callerid
, strlen(callerid
) + 1) + 1;
4824 strcpy(p
, application
);
4828 tmp
->registrar
= registrar
;
4830 ast_mutex_lock(&con
->lock
);
4831 res
= 0; /* some compilers will think it is uninitialized otherwise */
4832 for (e
= con
->root
; e
; el
= e
, e
= e
->next
) { /* scan the extension list */
4833 res
= ext_cmp(e
->exten
, extension
);
4834 if (res
== 0) { /* extension match, now look at cidmatch */
4835 if (!e
->matchcid
&& !tmp
->matchcid
)
4837 else if (tmp
->matchcid
&& !e
->matchcid
)
4839 else if (e
->matchcid
&& !tmp
->matchcid
)
4842 res
= strcasecmp(e
->cidmatch
, tmp
->cidmatch
);
4847 if (e
&& res
== 0) { /* exact match, insert in the pri chain */
4848 res
= add_pri(con
, tmp
, el
, e
, replace
);
4849 ast_mutex_unlock(&con
->lock
);
4851 errno
= EEXIST
; /* XXX do we care ? */
4852 return 0; /* XXX should we return -1 maybe ? */
4856 * not an exact match, this is the first entry with this pattern,
4857 * so insert in the main list right before 'e' (if any)
4864 ast_mutex_unlock(&con
->lock
);
4865 if (tmp
->priority
== PRIORITY_HINT
)
4869 if (tmp
->matchcid
) {
4871 ast_log(LOG_DEBUG
, "Added extension '%s' priority %d (CID match '%s') to %s\n",
4872 tmp
->exten
, tmp
->priority
, tmp
->cidmatch
, con
->name
);
4875 ast_log(LOG_DEBUG
, "Added extension '%s' priority %d to %s\n",
4876 tmp
->exten
, tmp
->priority
, con
->name
);
4879 if (option_verbose
> 2) {
4880 if (tmp
->matchcid
) {
4881 ast_verbose( VERBOSE_PREFIX_3
"Added extension '%s' priority %d (CID match '%s')to %s\n",
4882 tmp
->exten
, tmp
->priority
, tmp
->cidmatch
, con
->name
);
4884 ast_verbose( VERBOSE_PREFIX_3
"Added extension '%s' priority %d to %s\n",
4885 tmp
->exten
, tmp
->priority
, con
->name
);
4893 struct ast_channel
*chan
;
4894 char context
[AST_MAX_CONTEXT
];
4895 char exten
[AST_MAX_EXTENSION
];
4898 char app
[AST_MAX_EXTENSION
];
4902 static void *async_wait(void *data
)
4904 struct async_stat
*as
= data
;
4905 struct ast_channel
*chan
= as
->chan
;
4906 int timeout
= as
->timeout
;
4908 struct ast_frame
*f
;
4909 struct ast_app
*app
;
4911 while (timeout
&& (chan
->_state
!= AST_STATE_UP
)) {
4912 res
= ast_waitfor(chan
, timeout
);
4920 if (f
->frametype
== AST_FRAME_CONTROL
) {
4921 if ((f
->subclass
== AST_CONTROL_BUSY
) ||
4922 (f
->subclass
== AST_CONTROL_CONGESTION
) ) {
4929 if (chan
->_state
== AST_STATE_UP
) {
4930 if (!ast_strlen_zero(as
->app
)) {
4931 app
= pbx_findapp(as
->app
);
4933 if (option_verbose
> 2)
4934 ast_verbose(VERBOSE_PREFIX_3
"Launching %s(%s) on %s\n", as
->app
, as
->appdata
, chan
->name
);
4935 pbx_exec(chan
, app
, as
->appdata
);
4937 ast_log(LOG_WARNING
, "No such application '%s'\n", as
->app
);
4939 if (!ast_strlen_zero(as
->context
))
4940 ast_copy_string(chan
->context
, as
->context
, sizeof(chan
->context
));
4941 if (!ast_strlen_zero(as
->exten
))
4942 ast_copy_string(chan
->exten
, as
->exten
, sizeof(chan
->exten
));
4943 if (as
->priority
> 0)
4944 chan
->priority
= as
->priority
;
4946 if (ast_pbx_run(chan
)) {
4947 ast_log(LOG_ERROR
, "Failed to start PBX on %s\n", chan
->name
);
4949 /* PBX will have taken care of this */
4960 /*! Function to post an empty cdr after a spool call fails.
4962 * This function posts an empty cdr for a failed spool call
4965 static int ast_pbx_outgoing_cdr_failed(void)
4967 /* allocate a channel */
4968 struct ast_channel
*chan
= ast_channel_alloc(0, AST_STATE_DOWN
, 0, 0, "", "", "", 0, 0);
4971 return -1; /* failure */
4974 /* allocation of the cdr failed */
4975 ast_channel_free(chan
); /* free the channel */
4976 return -1; /* return failure */
4979 /* allocation of the cdr was successful */
4980 ast_cdr_init(chan
->cdr
, chan
); /* initilize our channel's cdr */
4981 ast_cdr_start(chan
->cdr
); /* record the start and stop time */
4982 ast_cdr_end(chan
->cdr
);
4983 ast_cdr_failed(chan
->cdr
); /* set the status to failed */
4984 ast_cdr_detach(chan
->cdr
); /* post and free the record */
4985 ast_channel_free(chan
); /* free the channel */
4987 return 0; /* success */
4990 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
)
4992 struct ast_channel
*chan
;
4993 struct async_stat
*as
;
4994 int res
= -1, cdr_res
= -1;
4995 struct outgoing_helper oh
;
4996 pthread_attr_t attr
;
5000 chan
= __ast_request_and_dial(type
, format
, data
, timeout
, reason
, cid_num
, cid_name
, &oh
);
5004 ast_channel_lock(chan
);
5007 if (chan
->_state
== AST_STATE_UP
) {
5009 if (option_verbose
> 3)
5010 ast_verbose(VERBOSE_PREFIX_4
"Channel %s was answered.\n", chan
->name
);
5014 ast_channel_unlock(chan
);
5015 if (ast_pbx_run(chan
)) {
5016 ast_log(LOG_ERROR
, "Unable to run PBX on %s\n", chan
->name
);
5024 if (ast_pbx_start(chan
)) {
5025 ast_log(LOG_ERROR
, "Unable to start PBX on %s\n", chan
->name
);
5028 ast_channel_unlock(chan
);
5036 if (option_verbose
> 3)
5037 ast_verbose(VERBOSE_PREFIX_4
"Channel %s was never answered.\n", chan
->name
);
5039 if (chan
->cdr
) { /* update the cdr */
5040 /* here we update the status of the call, which sould be busy.
5041 * if that fails then we set the status to failed */
5042 if (ast_cdr_disposition(chan
->cdr
, chan
->hangupcause
))
5043 ast_cdr_failed(chan
->cdr
);
5048 ast_channel_unlock(chan
);
5055 if (res
< 0) { /* the call failed for some reason */
5056 if (*reason
== 0) { /* if the call failed (not busy or no answer)
5057 * update the cdr with the failed message */
5058 cdr_res
= ast_pbx_outgoing_cdr_failed();
5061 goto outgoing_exten_cleanup
;
5065 /* create a fake channel and execute the "failed" extension (if it exists) within the requested context */
5066 /* check if "failed" exists */
5067 if (ast_exists_extension(chan
, context
, "failed", 1, NULL
)) {
5068 chan
= ast_channel_alloc(0, AST_STATE_DOWN
, 0, 0, "", "", "", 0, "OutgoingSpoolFailed");
5070 char failed_reason
[4] = "";
5071 if (!ast_strlen_zero(context
))
5072 ast_copy_string(chan
->context
, context
, sizeof(chan
->context
));
5073 set_ext_pri(chan
, "failed", 1);
5074 ast_set_variables(chan
, vars
);
5075 snprintf(failed_reason
, sizeof(failed_reason
), "%d", *reason
);
5076 pbx_builtin_setvar_helper(chan
, "REASON", failed_reason
);
5078 ast_cdr_setaccount(chan
, account
);
5079 if (ast_pbx_run(chan
)) {
5080 ast_log(LOG_ERROR
, "Unable to run PBX on %s\n", chan
->name
);
5088 if (!(as
= ast_calloc(1, sizeof(*as
)))) {
5090 goto outgoing_exten_cleanup
;
5092 chan
= ast_request_and_dial(type
, format
, data
, timeout
, reason
, cid_num
, cid_name
);
5096 ast_channel_lock(chan
);
5101 goto outgoing_exten_cleanup
;
5104 ast_copy_string(as
->context
, context
, sizeof(as
->context
));
5105 set_ext_pri(as
->chan
, exten
, priority
);
5106 as
->timeout
= timeout
;
5107 ast_set_variables(chan
, vars
);
5109 ast_cdr_setaccount(chan
, account
);
5110 pthread_attr_init(&attr
);
5111 pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
5112 if (ast_pthread_create(&as
->p
, &attr
, async_wait
, as
)) {
5113 ast_log(LOG_WARNING
, "Failed to start async wait\n");
5117 ast_channel_unlock(chan
);
5121 pthread_attr_destroy(&attr
);
5122 goto outgoing_exten_cleanup
;
5124 pthread_attr_destroy(&attr
);
5127 outgoing_exten_cleanup
:
5128 ast_variables_destroy(vars
);
5135 struct ast_channel
*chan
;
5139 /*! \brief run the application and free the descriptor once done */
5140 static void *ast_pbx_run_app(void *data
)
5142 struct app_tmp
*tmp
= data
;
5143 struct ast_app
*app
;
5144 app
= pbx_findapp(tmp
->app
);
5146 if (option_verbose
> 3)
5147 ast_verbose(VERBOSE_PREFIX_4
"Launching %s(%s) on %s\n", tmp
->app
, tmp
->data
, tmp
->chan
->name
);
5148 pbx_exec(tmp
->chan
, app
, tmp
->data
);
5150 ast_log(LOG_WARNING
, "No such application '%s'\n", tmp
->app
);
5151 ast_hangup(tmp
->chan
);
5156 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
)
5158 struct ast_channel
*chan
;
5159 struct app_tmp
*tmp
;
5160 int res
= -1, cdr_res
= -1;
5161 struct outgoing_helper oh
;
5162 pthread_attr_t attr
;
5164 memset(&oh
, 0, sizeof(oh
));
5166 oh
.account
= account
;
5169 *locked_channel
= NULL
;
5170 if (ast_strlen_zero(app
)) {
5172 goto outgoing_app_cleanup
;
5175 chan
= __ast_request_and_dial(type
, format
, data
, timeout
, reason
, cid_num
, cid_name
, &oh
);
5177 if (!chan
->cdr
) { /* check if the channel already has a cdr record, if not give it one */
5178 chan
->cdr
= ast_cdr_alloc(); /* allocate a cdr for the channel */
5180 /* allocation of the cdr failed */
5183 goto outgoing_app_cleanup
;
5185 /* allocation of the cdr was successful */
5186 ast_cdr_init(chan
->cdr
, chan
); /* initilize our channel's cdr */
5187 ast_cdr_start(chan
->cdr
);
5189 ast_set_variables(chan
, vars
);
5191 ast_cdr_setaccount(chan
, account
);
5192 if (chan
->_state
== AST_STATE_UP
) {
5194 if (option_verbose
> 3)
5195 ast_verbose(VERBOSE_PREFIX_4
"Channel %s was answered.\n", chan
->name
);
5196 tmp
= ast_calloc(1, sizeof(*tmp
));
5200 ast_copy_string(tmp
->app
, app
, sizeof(tmp
->app
));
5202 ast_copy_string(tmp
->data
, appdata
, sizeof(tmp
->data
));
5206 ast_channel_unlock(chan
);
5207 ast_pbx_run_app(tmp
);
5209 pthread_attr_init(&attr
);
5210 pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
5212 ast_channel_lock(chan
);
5213 if (ast_pthread_create(&tmp
->t
, &attr
, ast_pbx_run_app
, tmp
)) {
5214 ast_log(LOG_WARNING
, "Unable to spawn execute thread on %s: %s\n", chan
->name
, strerror(errno
));
5217 ast_channel_unlock(chan
);
5222 *locked_channel
= chan
;
5224 pthread_attr_destroy(&attr
);
5228 if (option_verbose
> 3)
5229 ast_verbose(VERBOSE_PREFIX_4
"Channel %s was never answered.\n", chan
->name
);
5230 if (chan
->cdr
) { /* update the cdr */
5231 /* here we update the status of the call, which sould be busy.
5232 * if that fails then we set the status to failed */
5233 if (ast_cdr_disposition(chan
->cdr
, chan
->hangupcause
))
5234 ast_cdr_failed(chan
->cdr
);
5240 if (res
< 0) { /* the call failed for some reason */
5241 if (*reason
== 0) { /* if the call failed (not busy or no answer)
5242 * update the cdr with the failed message */
5243 cdr_res
= ast_pbx_outgoing_cdr_failed();
5246 goto outgoing_app_cleanup
;
5252 struct async_stat
*as
;
5253 if (!(as
= ast_calloc(1, sizeof(*as
)))) {
5255 goto outgoing_app_cleanup
;
5257 chan
= __ast_request_and_dial(type
, format
, data
, timeout
, reason
, cid_num
, cid_name
, &oh
);
5261 goto outgoing_app_cleanup
;
5264 ast_copy_string(as
->app
, app
, sizeof(as
->app
));
5266 ast_copy_string(as
->appdata
, appdata
, sizeof(as
->appdata
));
5267 as
->timeout
= timeout
;
5268 ast_set_variables(chan
, vars
);
5270 ast_cdr_setaccount(chan
, account
);
5271 /* Start a new thread, and get something handling this channel. */
5272 pthread_attr_init(&attr
);
5273 pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
5275 ast_channel_lock(chan
);
5276 if (ast_pthread_create(&as
->p
, &attr
, async_wait
, as
)) {
5277 ast_log(LOG_WARNING
, "Failed to start async wait\n");
5280 ast_channel_unlock(chan
);
5283 pthread_attr_destroy(&attr
);
5284 goto outgoing_app_cleanup
;
5287 *locked_channel
= chan
;
5289 pthread_attr_destroy(&attr
);
5292 outgoing_app_cleanup
:
5293 ast_variables_destroy(vars
);
5297 void __ast_context_destroy(struct ast_context
*con
, const char *registrar
)
5299 struct ast_context
*tmp
, *tmpl
=NULL
;
5300 struct ast_include
*tmpi
;
5302 struct ast_exten
*e
, *el
, *en
;
5303 struct ast_ignorepat
*ipi
;
5305 for (tmp
= contexts
; tmp
; ) {
5306 struct ast_context
*next
; /* next starting point */
5307 for (; tmp
; tmpl
= tmp
, tmp
= tmp
->next
) {
5309 ast_log(LOG_DEBUG
, "check ctx %s %s\n", tmp
->name
, tmp
->registrar
);
5310 if ( (!registrar
|| !strcasecmp(registrar
, tmp
->registrar
)) &&
5311 (!con
|| !strcasecmp(tmp
->name
, con
->name
)) )
5312 break; /* found it */
5314 if (!tmp
) /* not found, we are done */
5316 ast_mutex_lock(&tmp
->lock
);
5318 ast_log(LOG_DEBUG
, "delete ctx %s %s\n", tmp
->name
, tmp
->registrar
);
5324 /* Okay, now we're safe to let it go -- in a sense, we were
5325 ready to let it go as soon as we locked it. */
5326 ast_mutex_unlock(&tmp
->lock
);
5327 for (tmpi
= tmp
->includes
; tmpi
; ) { /* Free includes */
5328 struct ast_include
*tmpil
= tmpi
;
5332 for (ipi
= tmp
->ignorepats
; ipi
; ) { /* Free ignorepats */
5333 struct ast_ignorepat
*ipl
= ipi
;
5337 while ((sw
= AST_LIST_REMOVE_HEAD(&tmp
->alts
, list
)))
5339 for (e
= tmp
->root
; e
;) {
5340 for (en
= e
->peer
; en
;) {
5349 ast_mutex_destroy(&tmp
->lock
);
5351 /* if we have a specific match, we are done, otherwise continue */
5352 tmp
= con
? NULL
: next
;
5356 void ast_context_destroy(struct ast_context
*con
, const char *registrar
)
5358 ast_wrlock_contexts();
5359 __ast_context_destroy(con
,registrar
);
5360 ast_unlock_contexts();
5363 static void wait_for_hangup(struct ast_channel
*chan
, void *data
)
5366 struct ast_frame
*f
;
5369 if (ast_strlen_zero(data
) || (sscanf(data
, "%d", &waittime
) != 1) || (waittime
< 0))
5371 if (waittime
> -1) {
5372 ast_safe_sleep(chan
, waittime
* 1000);
5374 res
= ast_waitfor(chan
, -1);
5384 * \ingroup applications
5386 static int pbx_builtin_progress(struct ast_channel
*chan
, void *data
)
5388 ast_indicate(chan
, AST_CONTROL_PROGRESS
);
5393 * \ingroup applications
5395 static int pbx_builtin_ringing(struct ast_channel
*chan
, void *data
)
5397 ast_indicate(chan
, AST_CONTROL_RINGING
);
5402 * \ingroup applications
5404 static int pbx_builtin_busy(struct ast_channel
*chan
, void *data
)
5406 ast_indicate(chan
, AST_CONTROL_BUSY
);
5407 /* Don't change state of an UP channel, just indicate
5409 if (chan
->_state
!= AST_STATE_UP
)
5410 ast_setstate(chan
, AST_STATE_BUSY
);
5411 wait_for_hangup(chan
, data
);
5416 * \ingroup applications
5418 static int pbx_builtin_congestion(struct ast_channel
*chan
, void *data
)
5420 ast_indicate(chan
, AST_CONTROL_CONGESTION
);
5421 /* Don't change state of an UP channel, just indicate
5422 congestion in audio */
5423 if (chan
->_state
!= AST_STATE_UP
)
5424 ast_setstate(chan
, AST_STATE_BUSY
);
5425 wait_for_hangup(chan
, data
);
5430 * \ingroup applications
5432 static int pbx_builtin_answer(struct ast_channel
*chan
, void *data
)
5437 if (chan
->_state
== AST_STATE_UP
)
5439 else if (!ast_strlen_zero(data
))
5442 res
= ast_answer(chan
);
5447 res
= ast_safe_sleep(chan
, delay
);
5452 AST_APP_OPTIONS(resetcdr_opts
, {
5453 AST_APP_OPTION('w', AST_CDR_FLAG_POSTED
),
5454 AST_APP_OPTION('a', AST_CDR_FLAG_LOCKED
),
5455 AST_APP_OPTION('v', AST_CDR_FLAG_KEEP_VARS
),
5459 * \ingroup applications
5461 static int pbx_builtin_resetcdr(struct ast_channel
*chan
, void *data
)
5464 struct ast_flags flags
= { 0 };
5466 if (!ast_strlen_zero(data
)) {
5467 args
= ast_strdupa(data
);
5468 ast_app_parse_options(resetcdr_opts
, &flags
, NULL
, args
);
5471 ast_cdr_reset(chan
->cdr
, &flags
);
5477 * \ingroup applications
5479 static int pbx_builtin_setamaflags(struct ast_channel
*chan
, void *data
)
5481 /* Copy the AMA Flags as specified */
5482 ast_cdr_setamaflags(chan
, data
? data
: "");
5487 * \ingroup applications
5489 static int pbx_builtin_hangup(struct ast_channel
*chan
, void *data
)
5491 if (!ast_strlen_zero(data
)) {
5495 if ((cause
= ast_str2cause(data
)) > -1) {
5496 chan
->hangupcause
= cause
;
5500 cause
= strtol((const char *) data
, &endptr
, 10);
5501 if (cause
!= 0 || (data
!= endptr
)) {
5502 chan
->hangupcause
= cause
;
5506 ast_log(LOG_NOTICE
, "Invalid cause given to Hangup(): \"%s\"\n", (char *) data
);
5509 if (!chan
->hangupcause
) {
5510 chan
->hangupcause
= AST_CAUSE_NORMAL_CLEARING
;
5517 * \ingroup applications
5519 static int pbx_builtin_gotoiftime(struct ast_channel
*chan
, void *data
)
5523 struct ast_timing timing
;
5525 if (ast_strlen_zero(data
)) {
5526 ast_log(LOG_WARNING
, "GotoIfTime requires an argument:\n <time range>|<days of week>|<days of month>|<months>?[[context|]extension|]priority\n");
5530 ts
= s
= ast_strdupa(data
);
5532 /* Separate the Goto path */
5535 /* struct ast_include include contained garbage here, fixed by zeroing it on get_timerange */
5536 if (ast_build_timing(&timing
, s
) && ast_check_timing(&timing
))
5537 res
= pbx_builtin_goto(chan
, ts
);
5543 * \ingroup applications
5545 static int pbx_builtin_execiftime(struct ast_channel
*chan
, void *data
)
5548 struct ast_timing timing
;
5549 struct ast_app
*app
;
5550 static const char *usage
= "ExecIfTime requires an argument:\n <time range>|<days of week>|<days of month>|<months>?<appname>[|<appargs>]";
5552 if (ast_strlen_zero(data
)) {
5553 ast_log(LOG_WARNING
, "%s\n", usage
);
5557 appname
= ast_strdupa(data
);
5559 s
= strsep(&appname
,"?"); /* Separate the timerange and application name/data */
5560 if (!appname
) { /* missing application */
5561 ast_log(LOG_WARNING
, "%s\n", usage
);
5565 if (!ast_build_timing(&timing
, s
)) {
5566 ast_log(LOG_WARNING
, "Invalid Time Spec: %s\nCorrect usage: %s\n", s
, usage
);
5570 if (!ast_check_timing(&timing
)) /* outside the valid time window, just return */
5573 /* now split appname|appargs */
5574 if ((s
= strchr(appname
, '|')))
5577 if ((app
= pbx_findapp(appname
))) {
5578 return pbx_exec(chan
, app
, S_OR(s
, ""));
5580 ast_log(LOG_WARNING
, "Cannot locate application %s\n", appname
);
5586 * \ingroup applications
5588 static int pbx_builtin_wait(struct ast_channel
*chan
, void *data
)
5593 /* Wait for "n" seconds */
5594 if (data
&& (s
= atof(data
)) > 0) {
5596 return ast_safe_sleep(chan
, ms
);
5602 * \ingroup applications
5604 static int pbx_builtin_waitexten(struct ast_channel
*chan
, void *data
)
5608 struct ast_flags flags
= {0};
5609 char *opts
[1] = { NULL
};
5611 AST_DECLARE_APP_ARGS(args
,
5612 AST_APP_ARG(timeout
);
5613 AST_APP_ARG(options
);
5616 if (!ast_strlen_zero(data
)) {
5617 parse
= ast_strdupa(data
);
5618 AST_STANDARD_APP_ARGS(args
, parse
);
5620 memset(&args
, 0, sizeof(args
));
5623 ast_app_parse_options(waitexten_opts
, &flags
, opts
, args
.options
);
5625 if (ast_test_flag(&flags
, WAITEXTEN_MOH
) && !opts
[0] ) {
5626 ast_log(LOG_WARNING
, "The 'm' option has been specified for WaitExten without a class.\n");
5627 } else if (ast_test_flag(&flags
, WAITEXTEN_MOH
))
5628 ast_indicate_data(chan
, AST_CONTROL_HOLD
, opts
[0], strlen(opts
[0]));
5630 /* Wait for "n" seconds */
5631 if (args
.timeout
&& (sec
= atof(args
.timeout
)) > 0.0)
5634 ms
= chan
->pbx
->rtimeout
* 1000;
5637 res
= ast_waitfordigit(chan
, ms
);
5639 if (ast_exists_extension(chan
, chan
->context
, chan
->exten
, chan
->priority
+ 1, chan
->cid
.cid_num
)) {
5640 if (option_verbose
> 2)
5641 ast_verbose(VERBOSE_PREFIX_3
"Timeout on %s, continuing...\n", chan
->name
);
5642 } else if (chan
->_softhangup
== AST_SOFTHANGUP_TIMEOUT
) {
5643 if (option_verbose
> 2)
5644 ast_verbose(VERBOSE_PREFIX_3
"Call timeout on %s, checking for 'T'\n", chan
->name
);
5646 } else if (ast_exists_extension(chan
, chan
->context
, "t", 1, chan
->cid
.cid_num
)) {
5647 if (option_verbose
> 2)
5648 ast_verbose(VERBOSE_PREFIX_3
"Timeout on %s, going to 't'\n", chan
->name
);
5649 set_ext_pri(chan
, "t", 0); /* 0 will become 1, next time through the loop */
5651 ast_log(LOG_WARNING
, "Timeout but no rule 't' in context '%s'\n", chan
->context
);
5656 if (ast_test_flag(&flags
, WAITEXTEN_MOH
))
5657 ast_indicate(chan
, AST_CONTROL_UNHOLD
);
5663 * \ingroup applications
5665 static int pbx_builtin_background(struct ast_channel
*chan
, void *data
)
5668 struct ast_flags flags
= {0};
5670 AST_DECLARE_APP_ARGS(args
,
5671 AST_APP_ARG(filename
);
5672 AST_APP_ARG(options
);
5674 AST_APP_ARG(context
);
5677 if (ast_strlen_zero(data
)) {
5678 ast_log(LOG_WARNING
, "Background requires an argument (filename)\n");
5682 parse
= ast_strdupa(data
);
5684 AST_STANDARD_APP_ARGS(args
, parse
);
5686 if (ast_strlen_zero(args
.lang
))
5687 args
.lang
= (char *)chan
->language
; /* XXX this is const */
5689 if (ast_strlen_zero(args
.context
))
5690 args
.context
= chan
->context
;
5693 if (!strcasecmp(args
.options
, "skip"))
5694 flags
.flags
= BACKGROUND_SKIP
;
5695 else if (!strcasecmp(args
.options
, "noanswer"))
5696 flags
.flags
= BACKGROUND_NOANSWER
;
5698 ast_app_parse_options(background_opts
, &flags
, NULL
, args
.options
);
5701 /* Answer if need be */
5702 if (chan
->_state
!= AST_STATE_UP
) {
5703 if (ast_test_flag(&flags
, BACKGROUND_SKIP
)) {
5705 } else if (!ast_test_flag(&flags
, BACKGROUND_NOANSWER
)) {
5706 res
= ast_answer(chan
);
5711 char *back
= args
.filename
;
5713 ast_stopstream(chan
); /* Stop anything playing */
5714 /* Stream the list of files */
5715 while (!res
&& (front
= strsep(&back
, "&")) ) {
5716 if ( (res
= ast_streamfile(chan
, front
, args
.lang
)) ) {
5717 ast_log(LOG_WARNING
, "ast_streamfile failed on %s for %s\n", chan
->name
, (char*)data
);
5721 if (ast_test_flag(&flags
, BACKGROUND_PLAYBACK
)) {
5722 res
= ast_waitstream(chan
, "");
5723 } else if (ast_test_flag(&flags
, BACKGROUND_MATCHEXTEN
)) {
5724 res
= ast_waitstream_exten(chan
, args
.context
);
5726 res
= ast_waitstream(chan
, AST_DIGIT_ANY
);
5728 ast_stopstream(chan
);
5731 if (args
.context
!= chan
->context
&& res
) {
5732 snprintf(chan
->exten
, sizeof(chan
->exten
), "%c", res
);
5733 ast_copy_string(chan
->context
, args
.context
, sizeof(chan
->context
));
5741 * \ingroup applications
5743 static int pbx_builtin_goto(struct ast_channel
*chan
, void *data
)
5745 int res
= ast_parseable_goto(chan
, data
);
5746 if (!res
&& (option_verbose
> 2))
5747 ast_verbose( VERBOSE_PREFIX_3
"Goto (%s,%s,%d)\n", chan
->context
,chan
->exten
, chan
->priority
+1);
5752 int pbx_builtin_serialize_variables(struct ast_channel
*chan
, char *buf
, size_t size
)
5754 struct ast_var_t
*variables
;
5755 const char *var
, *val
;
5761 memset(buf
, 0, size
);
5763 ast_channel_lock(chan
);
5765 AST_LIST_TRAVERSE(&chan
->varshead
, variables
, entries
) {
5766 if ((var
=ast_var_name(variables
)) && (val
=ast_var_value(variables
))
5767 /* && !ast_strlen_zero(var) && !ast_strlen_zero(val) */
5769 if (ast_build_string(&buf
, &size
, "%s=%s\n", var
, val
)) {
5770 ast_log(LOG_ERROR
, "Data Buffer Size Exceeded!\n");
5778 ast_channel_unlock(chan
);
5783 const char *pbx_builtin_getvar_helper(struct ast_channel
*chan
, const char *name
)
5785 struct ast_var_t
*variables
;
5786 const char *ret
= NULL
;
5788 struct varshead
*places
[2] = { NULL
, &globals
};
5794 ast_channel_lock(chan
);
5795 places
[0] = &chan
->varshead
;
5798 for (i
= 0; i
< 2; i
++) {
5801 if (places
[i
] == &globals
)
5802 ast_mutex_lock(&globalslock
);
5803 AST_LIST_TRAVERSE(places
[i
], variables
, entries
) {
5804 if (!strcmp(name
, ast_var_name(variables
))) {
5805 ret
= ast_var_value(variables
);
5809 if (places
[i
] == &globals
)
5810 ast_mutex_unlock(&globalslock
);
5816 ast_channel_unlock(chan
);
5821 void pbx_builtin_pushvar_helper(struct ast_channel
*chan
, const char *name
, const char *value
)
5823 struct ast_var_t
*newvariable
;
5824 struct varshead
*headp
;
5826 if (name
[strlen(name
)-1] == ')') {
5827 char *function
= ast_strdupa(name
);
5829 ast_log(LOG_WARNING
, "Cannot push a value onto a function\n");
5830 ast_func_write(chan
, function
, value
);
5835 ast_channel_lock(chan
);
5836 headp
= &chan
->varshead
;
5838 ast_mutex_lock(&globalslock
);
5843 if ((option_verbose
> 1) && (headp
== &globals
))
5844 ast_verbose(VERBOSE_PREFIX_2
"Setting global variable '%s' to '%s'\n", name
, value
);
5845 newvariable
= ast_var_assign(name
, value
);
5846 AST_LIST_INSERT_HEAD(headp
, newvariable
, entries
);
5850 ast_channel_unlock(chan
);
5852 ast_mutex_unlock(&globalslock
);
5855 void pbx_builtin_setvar_helper(struct ast_channel
*chan
, const char *name
, const char *value
)
5857 struct ast_var_t
*newvariable
;
5858 struct varshead
*headp
;
5859 const char *nametail
= name
;
5861 if (name
[strlen(name
)-1] == ')') {
5862 char *function
= ast_strdupa(name
);
5864 ast_func_write(chan
, function
, value
);
5869 ast_channel_lock(chan
);
5870 headp
= &chan
->varshead
;
5872 ast_mutex_lock(&globalslock
);
5876 /* For comparison purposes, we have to strip leading underscores */
5877 if (*nametail
== '_') {
5879 if (*nametail
== '_')
5883 AST_LIST_TRAVERSE (headp
, newvariable
, entries
) {
5884 if (strcasecmp(ast_var_name(newvariable
), nametail
) == 0) {
5885 /* there is already such a variable, delete it */
5886 AST_LIST_REMOVE(headp
, newvariable
, entries
);
5887 ast_var_delete(newvariable
);
5893 if ((option_verbose
> 1) && (headp
== &globals
))
5894 ast_verbose(VERBOSE_PREFIX_2
"Setting global variable '%s' to '%s'\n", name
, value
);
5895 newvariable
= ast_var_assign(name
, value
);
5896 AST_LIST_INSERT_HEAD(headp
, newvariable
, entries
);
5900 ast_channel_unlock(chan
);
5902 ast_mutex_unlock(&globalslock
);
5905 int pbx_builtin_setvar(struct ast_channel
*chan
, void *data
)
5907 char *name
, *value
, *mydata
;
5909 char *argv
[24]; /* this will only support a maximum of 24 variables being set in a single operation */
5913 if (ast_strlen_zero(data
)) {
5914 ast_log(LOG_WARNING
, "Set requires at least one variable name/value pair.\n");
5918 mydata
= ast_strdupa(data
);
5919 argc
= ast_app_separate_args(mydata
, '|', argv
, sizeof(argv
) / sizeof(argv
[0]));
5921 /* check for a trailing flags argument */
5922 if ((argc
> 1) && !strchr(argv
[argc
-1], '=')) {
5924 if (strchr(argv
[argc
], 'g')) {
5925 ast_log(LOG_WARNING
, "The use of the 'g' flag is deprecated. Please use Set(GLOBAL(foo)=bar) instead\n");
5931 ast_log(LOG_WARNING
, "Setting multiple variables at once within Set is deprecated. Please separate each name/value pair into its own line.\n");
5933 for (x
= 0; x
< argc
; x
++) {
5935 if ((value
= strchr(name
, '='))) {
5937 pbx_builtin_setvar_helper((global
) ? NULL
: chan
, name
, value
);
5939 ast_log(LOG_WARNING
, "Ignoring entry '%s' with no = (and not last 'options' entry)\n", name
);
5945 int pbx_builtin_importvar(struct ast_channel
*chan
, void *data
)
5950 char tmp
[VAR_BUF_SIZE
]="";
5952 if (ast_strlen_zero(data
)) {
5953 ast_log(LOG_WARNING
, "Ignoring, since there is no variable to set\n");
5957 value
= ast_strdupa(data
);
5958 name
= strsep(&value
,"=");
5959 channel
= strsep(&value
,"|");
5960 if (channel
&& value
&& name
) { /*! \todo XXX should do !ast_strlen_zero(..) of the args ? */
5961 struct ast_channel
*chan2
= ast_get_channel_by_name_locked(channel
);
5963 char *s
= alloca(strlen(value
) + 4);
5965 sprintf(s
, "${%s}", value
);
5966 pbx_substitute_variables_helper(chan2
, s
, tmp
, sizeof(tmp
) - 1);
5968 ast_channel_unlock(chan2
);
5970 pbx_builtin_setvar_helper(chan
, name
, tmp
);
5976 /*! \todo XXX overwrites data ? */
5977 static int pbx_builtin_setglobalvar(struct ast_channel
*chan
, void *data
)
5980 char *stringp
= data
;
5981 static int dep_warning
= 0;
5983 if (ast_strlen_zero(data
)) {
5984 ast_log(LOG_WARNING
, "Ignoring, since there is no variable to set\n");
5988 name
= strsep(&stringp
, "=");
5992 ast_log(LOG_WARNING
, "SetGlobalVar is deprecated. Please use Set(GLOBAL(%s)=%s) instead.\n", name
, stringp
);
5995 /*! \todo XXX watch out, leading whitespace ? */
5996 pbx_builtin_setvar_helper(NULL
, name
, stringp
);
6001 static int pbx_builtin_noop(struct ast_channel
*chan
, void *data
)
6006 void pbx_builtin_clear_globals(void)
6008 struct ast_var_t
*vardata
;
6010 ast_mutex_lock(&globalslock
);
6011 while ((vardata
= AST_LIST_REMOVE_HEAD(&globals
, entries
)))
6012 ast_var_delete(vardata
);
6013 ast_mutex_unlock(&globalslock
);
6016 int pbx_checkcondition(const char *condition
)
6018 if (ast_strlen_zero(condition
)) /* NULL or empty strings are false */
6020 else if (*condition
>= '0' && *condition
<= '9') /* Numbers are evaluated for truth */
6021 return atoi(condition
);
6022 else /* Strings are true */
6026 static int pbx_builtin_gotoif(struct ast_channel
*chan
, void *data
)
6028 char *condition
, *branch1
, *branch2
, *branch
;
6032 if (ast_strlen_zero(data
)) {
6033 ast_log(LOG_WARNING
, "Ignoring, since there is no variable to check\n");
6037 stringp
= ast_strdupa(data
);
6038 condition
= strsep(&stringp
,"?");
6039 branch1
= strsep(&stringp
,":");
6040 branch2
= strsep(&stringp
,"");
6041 branch
= pbx_checkcondition(condition
) ? branch1
: branch2
;
6043 if (ast_strlen_zero(branch
)) {
6045 ast_log(LOG_DEBUG
, "Not taking any branch\n");
6049 rc
= pbx_builtin_goto(chan
, branch
);
6054 static int pbx_builtin_saynumber(struct ast_channel
*chan
, void *data
)
6060 if (ast_strlen_zero(data
)) {
6061 ast_log(LOG_WARNING
, "SayNumber requires an argument (number)\n");
6064 ast_copy_string(tmp
, data
, sizeof(tmp
));
6065 strsep(&number
, "|");
6066 options
= strsep(&number
, "|");
6068 if ( strcasecmp(options
, "f") && strcasecmp(options
,"m") &&
6069 strcasecmp(options
, "c") && strcasecmp(options
, "n") ) {
6070 ast_log(LOG_WARNING
, "SayNumber gender option is either 'f', 'm', 'c' or 'n'\n");
6074 return ast_say_number(chan
, atoi(tmp
), "", chan
->language
, options
);
6077 static int pbx_builtin_saydigits(struct ast_channel
*chan
, void *data
)
6082 res
= ast_say_digit_str(chan
, data
, "", chan
->language
);
6086 static int pbx_builtin_saycharacters(struct ast_channel
*chan
, void *data
)
6091 res
= ast_say_character_str(chan
, data
, "", chan
->language
);
6095 static int pbx_builtin_sayphonetic(struct ast_channel
*chan
, void *data
)
6100 res
= ast_say_phonetic_str(chan
, data
, "", chan
->language
);
6108 /* Initialize the PBX */
6109 if (option_verbose
) {
6110 ast_verbose( "Asterisk PBX Core Initializing\n");
6111 ast_verbose( "Registering builtin applications:\n");
6113 ast_cli_register_multiple(pbx_cli
, sizeof(pbx_cli
) / sizeof(struct ast_cli_entry
));
6115 /* Register builtin applications */
6116 for (x
=0; x
<sizeof(builtins
) / sizeof(struct pbx_builtin
); x
++) {
6118 ast_verbose( VERBOSE_PREFIX_1
"[%s]\n", builtins
[x
].name
);
6119 if (ast_register_application(builtins
[x
].name
, builtins
[x
].execute
, builtins
[x
].synopsis
, builtins
[x
].description
)) {
6120 ast_log(LOG_ERROR
, "Unable to register builtin application '%s'\n", builtins
[x
].name
);
6128 * Lock context list functions ...
6130 int ast_lock_contexts()
6132 return ast_rwlock_wrlock(&conlock
);
6135 int ast_rdlock_contexts(void)
6137 return ast_rwlock_rdlock(&conlock
);
6140 int ast_wrlock_contexts(void)
6142 return ast_rwlock_wrlock(&conlock
);
6145 int ast_unlock_contexts()
6147 return ast_rwlock_unlock(&conlock
);
6153 int ast_lock_context(struct ast_context
*con
)
6155 return ast_mutex_lock(&con
->lock
);
6158 int ast_unlock_context(struct ast_context
*con
)
6160 return ast_mutex_unlock(&con
->lock
);
6164 * Name functions ...
6166 const char *ast_get_context_name(struct ast_context
*con
)
6168 return con
? con
->name
: NULL
;
6171 struct ast_context
*ast_get_extension_context(struct ast_exten
*exten
)
6173 return exten
? exten
->parent
: NULL
;
6176 const char *ast_get_extension_name(struct ast_exten
*exten
)
6178 return exten
? exten
->exten
: NULL
;
6181 const char *ast_get_extension_label(struct ast_exten
*exten
)
6183 return exten
? exten
->label
: NULL
;
6186 const char *ast_get_include_name(struct ast_include
*inc
)
6188 return inc
? inc
->name
: NULL
;
6191 const char *ast_get_ignorepat_name(struct ast_ignorepat
*ip
)
6193 return ip
? ip
->pattern
: NULL
;
6196 int ast_get_extension_priority(struct ast_exten
*exten
)
6198 return exten
? exten
->priority
: -1;
6202 * Registrar info functions ...
6204 const char *ast_get_context_registrar(struct ast_context
*c
)
6206 return c
? c
->registrar
: NULL
;
6209 const char *ast_get_extension_registrar(struct ast_exten
*e
)
6211 return e
? e
->registrar
: NULL
;
6214 const char *ast_get_include_registrar(struct ast_include
*i
)
6216 return i
? i
->registrar
: NULL
;
6219 const char *ast_get_ignorepat_registrar(struct ast_ignorepat
*ip
)
6221 return ip
? ip
->registrar
: NULL
;
6224 int ast_get_extension_matchcid(struct ast_exten
*e
)
6226 return e
? e
->matchcid
: 0;
6229 const char *ast_get_extension_cidmatch(struct ast_exten
*e
)
6231 return e
? e
->cidmatch
: NULL
;
6234 const char *ast_get_extension_app(struct ast_exten
*e
)
6236 return e
? e
->app
: NULL
;
6239 void *ast_get_extension_app_data(struct ast_exten
*e
)
6241 return e
? e
->data
: NULL
;
6244 const char *ast_get_switch_name(struct ast_sw
*sw
)
6246 return sw
? sw
->name
: NULL
;
6249 const char *ast_get_switch_data(struct ast_sw
*sw
)
6251 return sw
? sw
->data
: NULL
;
6254 const char *ast_get_switch_registrar(struct ast_sw
*sw
)
6256 return sw
? sw
->registrar
: NULL
;
6260 * Walking functions ...
6262 struct ast_context
*ast_walk_contexts(struct ast_context
*con
)
6264 return con
? con
->next
: contexts
;
6267 struct ast_exten
*ast_walk_context_extensions(struct ast_context
*con
,
6268 struct ast_exten
*exten
)
6271 return con
? con
->root
: NULL
;
6276 struct ast_sw
*ast_walk_context_switches(struct ast_context
*con
,
6280 return con
? AST_LIST_FIRST(&con
->alts
) : NULL
;
6282 return AST_LIST_NEXT(sw
, list
);
6285 struct ast_exten
*ast_walk_extension_priorities(struct ast_exten
*exten
,
6286 struct ast_exten
*priority
)
6288 return priority
? priority
->peer
: exten
;
6291 struct ast_include
*ast_walk_context_includes(struct ast_context
*con
,
6292 struct ast_include
*inc
)
6295 return con
? con
->includes
: NULL
;
6300 struct ast_ignorepat
*ast_walk_context_ignorepats(struct ast_context
*con
,
6301 struct ast_ignorepat
*ip
)
6304 return con
? con
->ignorepats
: NULL
;
6309 int ast_context_verify_includes(struct ast_context
*con
)
6311 struct ast_include
*inc
= NULL
;
6314 while ( (inc
= ast_walk_context_includes(con
, inc
)) ) {
6315 if (ast_context_find(inc
->rname
))
6319 ast_log(LOG_WARNING
, "Context '%s' tries includes nonexistent context '%s'\n",
6320 ast_get_context_name(con
), inc
->rname
);
6328 static int __ast_goto_if_exists(struct ast_channel
*chan
, const char *context
, const char *exten
, int priority
, int async
)
6330 int (*goto_func
)(struct ast_channel
*chan
, const char *context
, const char *exten
, int priority
);
6335 if (context
== NULL
)
6336 context
= chan
->context
;
6338 exten
= chan
->exten
;
6340 goto_func
= (async
) ? ast_async_goto
: ast_explicit_goto
;
6341 if (ast_exists_extension(chan
, context
, exten
, priority
, chan
->cid
.cid_num
))
6342 return goto_func(chan
, context
, exten
, priority
);
6347 int ast_goto_if_exists(struct ast_channel
*chan
, const char* context
, const char *exten
, int priority
)
6349 return __ast_goto_if_exists(chan
, context
, exten
, priority
, 0);
6352 int ast_async_goto_if_exists(struct ast_channel
*chan
, const char * context
, const char *exten
, int priority
)
6354 return __ast_goto_if_exists(chan
, context
, exten
, priority
, 1);
6357 int ast_parseable_goto(struct ast_channel
*chan
, const char *goto_string
)
6359 char *exten
, *pri
, *context
;
6364 if (ast_strlen_zero(goto_string
)) {
6365 ast_log(LOG_WARNING
, "Goto requires an argument (optional context|optional extension|priority)\n");
6368 stringp
= ast_strdupa(goto_string
);
6369 context
= strsep(&stringp
, "|"); /* guaranteed non-null */
6370 exten
= strsep(&stringp
, "|");
6371 pri
= strsep(&stringp
, "|");
6372 if (!exten
) { /* Only a priority in this one */
6376 } else if (!pri
) { /* Only an extension and priority in this one */
6384 } else if (*pri
== '-') {
6388 if (sscanf(pri
, "%d", &ipri
) != 1) {
6389 if ((ipri
= ast_findlabel_extension(chan
, context
? context
: chan
->context
, exten
? exten
: chan
->exten
,
6390 pri
, chan
->cid
.cid_num
)) < 1) {
6391 ast_log(LOG_WARNING
, "Priority '%s' must be a number > 0, or valid label\n", pri
);
6396 /* At this point we have a priority and maybe an extension and a context */
6399 ipri
= chan
->priority
+ (ipri
* mode
);
6401 ast_explicit_goto(chan
, context
, exten
, ipri
);
6402 ast_cdr_update(chan
);