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"
65 * \note I M P O R T A N T :
67 * The speed of extension handling will likely be among the most important
68 * aspects of this PBX. The switching scheme as it exists right now isn't
69 * terribly bad (it's O(N+M), where N is the # of extensions and M is the avg #
70 * of priorities, but a constant search time here would be great ;-)
75 #define EXT_DATA_SIZE 256
77 #define EXT_DATA_SIZE 8192
80 #define SWITCH_DATA_LENGTH 256
82 #define VAR_BUF_SIZE 4096
85 #define VAR_SOFTTRAN 2
86 #define VAR_HARDTRAN 3
88 #define BACKGROUND_SKIP (1 << 0)
89 #define BACKGROUND_NOANSWER (1 << 1)
90 #define BACKGROUND_MATCHEXTEN (1 << 2)
91 #define BACKGROUND_PLAYBACK (1 << 3)
93 AST_APP_OPTIONS(background_opts
, {
94 AST_APP_OPTION('s', BACKGROUND_SKIP
),
95 AST_APP_OPTION('n', BACKGROUND_NOANSWER
),
96 AST_APP_OPTION('m', BACKGROUND_MATCHEXTEN
),
97 AST_APP_OPTION('p', BACKGROUND_PLAYBACK
),
100 #define WAITEXTEN_MOH (1 << 0)
102 AST_APP_OPTIONS(waitexten_opts
, {
103 AST_APP_OPTION_ARG('m', WAITEXTEN_MOH
, 0),
109 \brief ast_exten: An extension
110 The dialplan is saved as a linked list with each context
111 having it's own linked list of extensions - one item per
115 char *exten
; /*!< Extension name */
116 int matchcid
; /*!< Match caller id ? */
117 const char *cidmatch
; /*!< Caller id to match for this extension */
118 int priority
; /*!< Priority */
119 const char *label
; /*!< Label */
120 struct ast_context
*parent
; /*!< The context this extension belongs to */
121 const char *app
; /*!< Application to execute */
122 void *data
; /*!< Data to use (arguments) */
123 void (*datad
)(void *); /*!< Data destructor */
124 struct ast_exten
*peer
; /*!< Next higher priority with our extension */
125 const char *registrar
; /*!< Registrar */
126 struct ast_exten
*next
; /*!< Extension with a greater ID */
130 /*! \brief ast_include: include= support in extensions.conf */
133 const char *rname
; /*!< Context to include */
134 const char *registrar
; /*!< Registrar */
135 int hastime
; /*!< If time construct exists */
136 struct ast_timing timing
; /*!< time construct */
137 struct ast_include
*next
; /*!< Link them together */
141 /*! \brief ast_sw: Switch statement in extensions.conf */
144 const char *registrar
; /*!< Registrar */
145 char *data
; /*!< Data load */
147 AST_LIST_ENTRY(ast_sw
) list
;
152 /*! \brief ast_ignorepat: Ignore patterns in dial plan */
153 struct ast_ignorepat
{
154 const char *registrar
;
155 struct ast_ignorepat
*next
;
156 const char pattern
[0];
159 /*! \brief ast_context: An extension context */
161 ast_mutex_t lock
; /*!< A lock to prevent multiple threads from clobbering the context */
162 struct ast_exten
*root
; /*!< The root of the list of extensions */
163 struct ast_context
*next
; /*!< Link them together */
164 struct ast_include
*includes
; /*!< Include other contexts */
165 struct ast_ignorepat
*ignorepats
; /*!< Patterns for which to continue playing dialtone */
166 const char *registrar
; /*!< Registrar */
167 AST_LIST_HEAD_NOLOCK(, ast_sw
) alts
; /*!< Alternative switches */
168 ast_mutex_t macrolock
; /*!< A lock to implement "exclusive" macros - held whilst a call is executing in the macro */
169 char name
[0]; /*!< Name of the context */
173 /*! \brief ast_app: A registered application */
175 int (*execute
)(struct ast_channel
*chan
, void *data
);
176 const char *synopsis
; /*!< Synopsis text for 'show applications' */
177 const char *description
; /*!< Description (help text) for 'show application <name>' */
178 AST_LIST_ENTRY(ast_app
) list
; /*!< Next app in list */
179 struct module
*module
; /*!< Module this app belongs to */
180 char name
[0]; /*!< Name of the application */
183 /*! \brief ast_state_cb: An extension state notify register item */
184 struct ast_state_cb
{
187 ast_state_cb_type callback
;
188 struct ast_state_cb
*next
;
191 /*! \brief Structure for dial plan hints
193 \note Hints are pointers from an extension in the dialplan to one or
194 more devices (tech/name) */
196 struct ast_exten
*exten
; /*!< Extension */
197 int laststate
; /*!< Last known state */
198 struct ast_state_cb
*callbacks
; /*!< Callback list for this extension */
199 AST_LIST_ENTRY(ast_hint
) list
; /*!< Pointer to next hint in list */
202 static const struct cfextension_states
{
204 const char * const text
;
205 } extension_states
[] = {
206 { AST_EXTENSION_NOT_INUSE
, "Idle" },
207 { AST_EXTENSION_INUSE
, "InUse" },
208 { AST_EXTENSION_BUSY
, "Busy" },
209 { AST_EXTENSION_UNAVAILABLE
, "Unavailable" },
210 { AST_EXTENSION_RINGING
, "Ringing" },
211 { AST_EXTENSION_INUSE
| AST_EXTENSION_RINGING
, "InUse&Ringing" },
212 { AST_EXTENSION_ONHOLD
, "Hold" },
213 { AST_EXTENSION_INUSE
| AST_EXTENSION_ONHOLD
, "InUse&Hold" }
216 static int pbx_builtin_answer(struct ast_channel
*, void *);
217 static int pbx_builtin_goto(struct ast_channel
*, void *);
218 static int pbx_builtin_hangup(struct ast_channel
*, void *);
219 static int pbx_builtin_background(struct ast_channel
*, void *);
220 static int pbx_builtin_wait(struct ast_channel
*, void *);
221 static int pbx_builtin_waitexten(struct ast_channel
*, void *);
222 static int pbx_builtin_resetcdr(struct ast_channel
*, void *);
223 static int pbx_builtin_setamaflags(struct ast_channel
*, void *);
224 static int pbx_builtin_ringing(struct ast_channel
*, void *);
225 static int pbx_builtin_progress(struct ast_channel
*, void *);
226 static int pbx_builtin_congestion(struct ast_channel
*, void *);
227 static int pbx_builtin_busy(struct ast_channel
*, void *);
228 static int pbx_builtin_setglobalvar(struct ast_channel
*, void *);
229 static int pbx_builtin_noop(struct ast_channel
*, void *);
230 static int pbx_builtin_gotoif(struct ast_channel
*, void *);
231 static int pbx_builtin_gotoiftime(struct ast_channel
*, void *);
232 static int pbx_builtin_execiftime(struct ast_channel
*, void *);
233 static int pbx_builtin_saynumber(struct ast_channel
*, void *);
234 static int pbx_builtin_saydigits(struct ast_channel
*, void *);
235 static int pbx_builtin_saycharacters(struct ast_channel
*, void *);
236 static int pbx_builtin_sayphonetic(struct ast_channel
*, void *);
237 int pbx_builtin_setvar(struct ast_channel
*, void *);
238 static int pbx_builtin_importvar(struct ast_channel
*, void *);
240 AST_MUTEX_DEFINE_STATIC(globalslock
);
241 static struct varshead globals
= AST_LIST_HEAD_NOLOCK_INIT_VALUE
;
243 static int autofallthrough
= 1;
245 AST_MUTEX_DEFINE_STATIC(maxcalllock
);
246 static int countcalls
;
248 static AST_LIST_HEAD_STATIC(acf_root
, ast_custom_function
);
250 /*! \brief Declaration of builtin applications */
251 static struct pbx_builtin
{
252 char name
[AST_MAX_APP
];
253 int (*execute
)(struct ast_channel
*chan
, void *data
);
258 /* These applications are built into the PBX core and do not
259 need separate modules */
261 { "Answer", pbx_builtin_answer
,
262 "Answer a channel if ringing",
263 " Answer([delay]): If the call has not been answered, this application will\n"
264 "answer it. Otherwise, it has no effect on the call. If a delay is specified,\n"
265 "Asterisk will wait this number of milliseconds before returning to\n"
266 "the dialplan after answering the call.\n"
269 { "BackGround", pbx_builtin_background
,
270 "Play an audio file while waiting for digits of an extension to go to.",
271 " Background(filename1[&filename2...][|options[|langoverride][|context]]):\n"
272 "This application will play the given list of files (do not put extension)\n"
273 "while waiting for an extension to be dialed by the calling channel. To\n"
274 "continue waiting for digits after this application has finished playing\n"
275 "files, the WaitExten application should be used. The 'langoverride' option\n"
276 "explicitly specifies which language to attempt to use for the requested sound\n"
277 "files. If a 'context' is specified, this is the dialplan context that this\n"
278 "application will use when exiting to a dialed extension."
279 " If one of the requested sound files does not exist, call processing will be\n"
282 " s - Causes the playback of the message to be skipped\n"
283 " if the channel is not in the 'up' state (i.e. it\n"
284 " hasn't been answered yet). If this happens, the\n"
285 " application will return immediately.\n"
286 " n - Don't answer the channel before playing the files.\n"
287 " m - Only break if a digit hit matches a one digit\n"
288 " extension in the destination context.\n"
291 { "Busy", pbx_builtin_busy
,
292 "Indicate the Busy condition",
293 " Busy([timeout]): This application will indicate the busy condition to\n"
294 "the calling channel. If the optional timeout is specified, the calling channel\n"
295 "will be hung up after the specified number of seconds. Otherwise, this\n"
296 "application will wait until the calling channel hangs up.\n"
299 { "Congestion", pbx_builtin_congestion
,
300 "Indicate the Congestion condition",
301 " Congestion([timeout]): This application will indicate the congestion\n"
302 "condition to the calling channel. If the optional timeout is specified, the\n"
303 "calling channel will be hung up after the specified number of seconds.\n"
304 "Otherwise, this application will wait until the calling channel hangs up.\n"
307 { "Goto", pbx_builtin_goto
,
308 "Jump to a particular priority, extension, or context",
309 " Goto([[context|]extension|]priority): This application will set the current\n"
310 "context, extension, and priority in the channel structure. After it completes, the\n"
311 "pbx engine will continue dialplan execution at the specified location.\n"
312 "If no specific extension, or extension and context, are specified, then this\n"
313 "application will just set the specified priority of the current extension.\n"
314 " At least a priority is required as an argument, or the goto will return a -1,\n"
315 "and the channel and call will be terminated.\n"
316 " If the location that is put into the channel information is bogus, and asterisk cannot\n"
317 "find that location in the dialplan,\n"
318 "then the execution engine will try to find and execute the code in the 'i' (invalid)\n"
319 "extension in the current context. If that does not exist, it will try to execute the\n"
320 "'h' extension. If either or neither the 'h' or 'i' extensions have been defined, the\n"
321 "channel is hung up, and the execution of instructions on the channel is terminated.\n"
322 "What this means is that, for example, you specify a context that does not exist, then\n"
323 "it will not be possible to find the 'h' or 'i' extensions, and the call will terminate!\n"
326 { "GotoIf", pbx_builtin_gotoif
,
328 " GotoIf(condition?[labeliftrue]:[labeliffalse]): This application will set the current\n"
329 "context, extension, and priority in the channel structure based on the evaluation of\n"
330 "the given condition. After this application completes, the\n"
331 "pbx engine will continue dialplan execution at the specified location in the dialplan.\n"
332 "The channel will continue at\n"
333 "'labeliftrue' if the condition is true, or 'labeliffalse' if the condition is\n"
334 "false. The labels are specified with the same syntax as used within the Goto\n"
335 "application. If the label chosen by the condition is omitted, no jump is\n"
336 "performed, and the execution passes to the next instruction.\n"
337 "If the target location is bogus, and does not exist, the execution engine will try \n"
338 "to find and execute the code in the 'i' (invalid)\n"
339 "extension in the current context. If that does not exist, it will try to execute the\n"
340 "'h' extension. If either or neither the 'h' or 'i' extensions have been defined, the\n"
341 "channel is hung up, and the execution of instructions on the channel is terminated.\n"
342 "Remember that this command can set the current context, and if the context specified\n"
343 "does not exist, then it will not be able to find any 'h' or 'i' extensions there, and\n"
344 "the channel and call will both be terminated!\n"
347 { "GotoIfTime", pbx_builtin_gotoiftime
,
348 "Conditional Goto based on the current time",
349 " GotoIfTime(<times>|<weekdays>|<mdays>|<months>?[[context|]exten|]priority):\n"
350 "This application will set the context, extension, and priority in the channel structure\n"
351 "if the current time matches the given time specification. Otherwise, nothing is done.\n"
352 "Further information on the time specification can be found in examples\n"
353 "illustrating how to do time-based context includes in the dialplan.\n"
354 "If the target jump location is bogus, the same actions would be taken as for Goto.\n"
357 { "ExecIfTime", pbx_builtin_execiftime
,
358 "Conditional application execution based on the current time",
359 " ExecIfTime(<times>|<weekdays>|<mdays>|<months>?appname[|appargs]):\n"
360 "This application will execute the specified dialplan application, with optional\n"
361 "arguments, if the current time matches the given time specification.\n"
364 { "Hangup", pbx_builtin_hangup
,
365 "Hang up the calling channel",
366 " Hangup([causecode]): This application will hang up the calling channel.\n"
367 "If a causecode is given the channel's hangup cause will be set to the given\n"
371 { "NoOp", pbx_builtin_noop
,
373 " NoOp(): This applicatiion does nothing. However, it is useful for debugging\n"
374 "purposes. Any text that is provided as arguments to this application can be\n"
375 "viewed at the Asterisk CLI. This method can be used to see the evaluations of\n"
376 "variables or functions without having any effect."
379 { "Progress", pbx_builtin_progress
,
381 " Progress(): This application will request that in-band progress information\n"
382 "be provided to the calling channel.\n"
385 { "ResetCDR", pbx_builtin_resetcdr
,
386 "Resets the Call Data Record",
387 " ResetCDR([options]): This application causes the Call Data Record to be\n"
390 " w -- Store the current CDR record before resetting it.\n"
391 " a -- Store any stacked records.\n"
392 " v -- Save CDR variables.\n"
395 { "Ringing", pbx_builtin_ringing
,
396 "Indicate ringing tone",
397 " Ringing(): This application will request that the channel indicate a ringing\n"
398 "tone to the user.\n"
401 { "SayNumber", pbx_builtin_saynumber
,
403 " SayNumber(digits[,gender]): This application will play the sounds that\n"
404 "correspond to the given number. Optionally, a gender may be specified.\n"
405 "This will use the language that is currently set for the channel. See the\n"
406 "LANGUAGE function for more information on setting the language for the channel.\n"
409 { "SayDigits", pbx_builtin_saydigits
,
411 " SayDigits(digits): This application will play the sounds that correspond\n"
412 "to the digits of the given number. This will use the language that is currently\n"
413 "set for the channel. See the LANGUAGE function for more information on setting\n"
414 "the language for the channel.\n"
417 { "SayAlpha", pbx_builtin_saycharacters
,
419 " SayAlpha(string): This application will play the sounds that correspond to\n"
420 "the letters of the given string.\n"
423 { "SayPhonetic", pbx_builtin_sayphonetic
,
425 " SayPhonetic(string): This application will play the sounds from the phonetic\n"
426 "alphabet that correspond to the letters in the given string.\n"
429 { "SetAMAFlags", pbx_builtin_setamaflags
,
431 " SetAMAFlags([flag]): This application will set the channel's AMA Flags for\n"
432 " billing purposes.\n"
435 { "SetGlobalVar", pbx_builtin_setglobalvar
,
436 "Set a global variable to a given value",
437 " SetGlobalVar(variable=value): This application sets a given global variable to\n"
438 "the specified value.\n"
439 "\n\nThis application is deprecated in favor of Set(GLOBAL(var)=value)\n"
442 { "Set", pbx_builtin_setvar
,
443 "Set channel variable(s) or function value(s)",
444 " Set(name1=value1|name2=value2|..[|options])\n"
445 "This function can be used to set the value of channel variables or dialplan\n"
446 "functions. It will accept up to 24 name/value pairs. When setting variables,\n"
447 "if the variable name is prefixed with _, the variable will be inherited into\n"
448 "channels created from the current channel. If the variable name is prefixed\n"
449 "with __, the variable will be inherited into channels created from the current\n"
450 "channel and all children channels.\n"
452 " g - Set variable globally instead of on the channel\n"
453 " (applies only to variables, not functions)\n"
454 "\n\nThe use of Set to set multiple variables at once and the g flag have both\n"
455 "been deprecated. Please use multiple Set calls and the GLOBAL() dialplan\n"
456 "function instead.\n"
459 { "ImportVar", pbx_builtin_importvar
,
460 "Import a variable from a channel into a new variable",
461 " ImportVar(newvar=channelname|variable): This application imports a variable\n"
462 "from the specified channel (as opposed to the current one) and stores it as\n"
463 "a variable in the current channel (the channel that is calling this\n"
464 "application). Variables created by this application have the same inheritance\n"
465 "properties as those created with the Set application. See the documentation for\n"
466 "Set for more information.\n"
469 { "Wait", pbx_builtin_wait
,
470 "Waits for some time",
471 " Wait(seconds): This application waits for a specified number of seconds.\n"
472 "Then, dialplan execution will continue at the next priority.\n"
473 " Note that the seconds can be passed with fractions of a second. For example,\n"
474 "'1.5' will ask the application to wait for 1.5 seconds.\n"
477 { "WaitExten", pbx_builtin_waitexten
,
478 "Waits for an extension to be entered",
479 " WaitExten([seconds][|options]): This application waits for the user to enter\n"
480 "a new extension for a specified number of seconds.\n"
481 " Note that the seconds can be passed with fractions of a second. For example,\n"
482 "'1.5' will ask the application to wait for 1.5 seconds.\n"
484 " m[(x)] - Provide music on hold to the caller while waiting for an extension.\n"
485 " Optionally, specify the class for music on hold within parenthesis.\n"
490 static struct ast_context
*contexts
;
491 AST_RWLOCK_DEFINE_STATIC(conlock
); /*!< Lock for the ast_context list */
493 static AST_LIST_HEAD_STATIC(apps
, ast_app
);
495 static AST_LIST_HEAD_STATIC(switches
, ast_switch
);
497 static int stateid
= 1;
499 When holding this list's lock, do _not_ do anything that will cause conlock
500 to be taken, unless you _already_ hold it. The ast_merge_contexts_and_delete
501 function will take the locks in conlock/hints order, so any other
502 paths that require both locks must also take them in that order.
504 static AST_LIST_HEAD_STATIC(hints
, ast_hint
);
505 struct ast_state_cb
*statecbs
;
508 \note This function is special. It saves the stack so that no matter
509 how many times it is called, it returns to the same place */
510 int pbx_exec(struct ast_channel
*c
, /*!< Channel */
511 struct ast_app
*app
, /*!< Application */
512 void *data
) /*!< Data for execution */
516 const char *saved_c_appl
;
517 const char *saved_c_data
;
519 if (c
->cdr
&& !ast_check_hangup(c
))
520 ast_cdr_setapp(c
->cdr
, app
->name
, data
);
522 /* save channel values */
523 saved_c_appl
= c
->appl
;
524 saved_c_data
= c
->data
;
528 /* XXX remember what to to when we have linked apps to modules */
530 /* XXX LOCAL_USER_ADD(app->module) */
532 res
= app
->execute(c
, data
);
534 /* XXX LOCAL_USER_REMOVE(app->module) */
536 /* restore channel values */
537 c
->appl
= saved_c_appl
;
538 c
->data
= saved_c_data
;
543 /*! Go no deeper than this through includes (not counting loops) */
544 #define AST_PBX_MAX_STACK 128
546 /*! \brief Find application handle in linked list
548 struct ast_app
*pbx_findapp(const char *app
)
552 AST_LIST_LOCK(&apps
);
553 AST_LIST_TRAVERSE(&apps
, tmp
, list
) {
554 if (!strcasecmp(tmp
->name
, app
))
557 AST_LIST_UNLOCK(&apps
);
562 static struct ast_switch
*pbx_findswitch(const char *sw
)
564 struct ast_switch
*asw
;
566 AST_LIST_LOCK(&switches
);
567 AST_LIST_TRAVERSE(&switches
, asw
, list
) {
568 if (!strcasecmp(asw
->name
, sw
))
571 AST_LIST_UNLOCK(&switches
);
576 static inline int include_valid(struct ast_include
*i
)
581 return ast_check_timing(&(i
->timing
));
584 static void pbx_destroy(struct ast_pbx
*p
)
590 * Special characters used in patterns:
591 * '_' underscore is the leading character of a pattern.
592 * In other position it is treated as a regular char.
593 * ' ' '-' space and '-' are separator and ignored.
594 * . one or more of any character. Only allowed at the end of
596 * ! zero or more of anything. Also impacts the result of CANMATCH
597 * and MATCHMORE. Only allowed at the end of a pattern.
598 * In the core routine, ! causes a match with a return code of 2.
599 * In turn, depending on the search mode: (XXX check if it is implemented)
600 * - E_MATCH retuns 1 (does match)
601 * - E_MATCHMORE returns 0 (no match)
602 * - E_CANMATCH returns 1 (does match)
604 * / should not appear as it is considered the separator of the CID info.
605 * XXX at the moment we may stop on this char.
607 * X Z N match ranges 0-9, 1-9, 2-9 respectively.
608 * [ denotes the start of a set of character. Everything inside
609 * is considered literally. We can have ranges a-d and individual
610 * characters. A '[' and '-' can be considered literally if they
611 * are just before ']'.
612 * XXX currently there is no way to specify ']' in a range, nor \ is
613 * considered specially.
615 * When we compare a pattern with a specific extension, all characters in the extension
616 * itself are considered literally with the only exception of '-' which is considered
617 * as a separator and thus ignored.
618 * XXX do we want to consider space as a separator as well ?
619 * XXX do we want to consider the separators in non-patterns as well ?
623 * \brief helper functions to sort extensions and patterns in the desired way,
624 * so that more specific patterns appear first.
626 * ext_cmp1 compares individual characters (or sets of), returning
627 * an int where bits 0-7 are the ASCII code of the first char in the set,
628 * while bit 8-15 are the cardinality of the set minus 1.
629 * This way more specific patterns (smaller cardinality) appear first.
630 * Wildcards have a special value, so that we can directly compare them to
631 * sets by subtracting the two values. In particular:
632 * 0x000xx one character, xx
633 * 0x0yyxx yy character set starting with xx
634 * 0x10000 '.' (one or more of anything)
635 * 0x20000 '!' (zero or more of anything)
636 * 0x30000 NUL (end of string)
637 * 0x40000 error in set.
638 * The pointer to the string is advanced according to needs.
640 * 1. the empty set is equivalent to NUL.
641 * 2. given that a full set has always 0 as the first element,
642 * we could encode the special cases as 0xffXX where XX
643 * is 1, 2, 3, 4 as used above.
645 static int ext_cmp1(const char **p
)
648 int c
, cmin
= 0xff, count
= 0;
651 /* load, sign extend and advance pointer until we find
654 while ( (c
= *(*p
)++) && (c
== ' ' || c
== '-') )
655 ; /* ignore some characters */
657 /* always return unless we have a set of chars */
659 default: /* ordinary character */
660 return 0x0000 | (c
& 0xff);
663 return 0x0700 | '2' ;
671 case '.': /* wildcard */
674 case '!': /* earlymatch */
675 return 0x20000; /* less specific than NULL */
677 case '\0': /* empty string */
681 case '[': /* pattern */
684 /* locate end of set */
685 end
= strchr(*p
, ']');
688 ast_log(LOG_WARNING
, "Wrong usage of [] in the extension\n");
689 return 0x40000; /* XXX make this entry go last... */
692 bzero(chars
, sizeof(chars
)); /* clear all chars in the set */
693 for (; *p
< end
; (*p
)++) {
694 unsigned char c1
, c2
; /* first-last char in range */
695 c1
= (unsigned char)((*p
)[0]);
696 if (*p
+ 2 < end
&& (*p
)[1] == '-') { /* this is a range */
697 c2
= (unsigned char)((*p
)[2]);
698 *p
+= 2; /* skip a total of 3 chars */
699 } else /* individual character */
703 for (; c1
<= c2
; c1
++) {
704 uint32_t mask
= 1 << (c1
% 32);
705 if ( (chars
[ c1
/ 32 ] & mask
) == 0)
707 chars
[ c1
/ 32 ] |= mask
;
711 return count
== 0 ? 0x30000 : (count
| cmin
);
715 * \brief the full routine to compare extensions in rules.
717 static int ext_cmp(const char *a
, const char *b
)
719 /* make sure non-patterns come first.
720 * If a is not a pattern, it either comes first or
721 * we use strcmp to compare the strings.
726 return (b
[0] == '_') ? -1 : strcmp(a
, b
);
728 /* Now we know a is a pattern; if b is not, a comes first */
731 #if 0 /* old mode for ext matching */
734 /* ok we need full pattern sorting routine */
735 while (!ret
&& a
&& b
)
736 ret
= ext_cmp1(&a
) - ext_cmp1(&b
);
740 return (ret
> 0) ? 1 : -1;
744 * When looking up extensions, we can have different requests
745 * identified by the 'action' argument, as follows.
746 * Note that the coding is such that the low 4 bits are the
747 * third argument to extension_match_core.
750 E_MATCHMORE
= 0x00, /* extension can match but only with more 'digits' */
751 E_CANMATCH
= 0x01, /* extension can match with or without more 'digits' */
752 E_MATCH
= 0x02, /* extension is an exact match */
753 E_MATCH_MASK
= 0x03, /* mask for the argument to extension_match_core() */
754 E_SPAWN
= 0x12, /* want to spawn an extension. Requires exact match */
755 E_FINDLABEL
= 0x22 /* returns the priority for a given label. Requires exact match */
759 * Internal function for ast_extension_{match|close}
760 * return 0 on no-match, 1 on match, 2 on early match.
761 * mode is as follows:
762 * E_MATCH success only on exact match
763 * E_MATCHMORE success only on partial match (i.e. leftover digits in pattern)
764 * E_CANMATCH either of the above.
767 static int _extension_match_core(const char *pattern
, const char *data
, enum ext_match_t mode
)
769 mode
&= E_MATCH_MASK
; /* only consider the relevant bits */
771 if ( (mode
== E_MATCH
) && (pattern
[0] == '_') && (strcasecmp(pattern
,data
)==0) ) /* note: if this test is left out, then _x. will not match _x. !!! */
774 if (pattern
[0] != '_') { /* not a pattern, try exact or partial match */
775 int ld
= strlen(data
), lp
= strlen(pattern
);
777 if (lp
< ld
) /* pattern too short, cannot match */
779 /* depending on the mode, accept full or partial match or both */
781 return !strcmp(pattern
, data
); /* 1 on match, 0 on fail */
782 if (ld
== 0 || !strncasecmp(pattern
, data
, ld
)) /* partial or full match */
783 return (mode
== E_MATCHMORE
) ? lp
> ld
: 1; /* XXX should consider '!' and '/' ? */
787 pattern
++; /* skip leading _ */
789 * XXX below we stop at '/' which is a separator for the CID info. However we should
790 * not store '/' in the pattern at all. When we insure it, we can remove the checks.
792 while (*data
&& *pattern
&& *pattern
!= '/') {
795 if (*data
== '-') { /* skip '-' in data (just a separator) */
799 switch (toupper(*pattern
)) {
800 case '[': /* a range */
801 end
= strchr(pattern
+1, ']'); /* XXX should deal with escapes ? */
803 ast_log(LOG_WARNING
, "Wrong usage of [] in the extension\n");
804 return 0; /* unconditional failure */
806 for (pattern
++; pattern
!= end
; pattern
++) {
807 if (pattern
+2 < end
&& pattern
[1] == '-') { /* this is a range */
808 if (*data
>= pattern
[0] && *data
<= pattern
[2])
809 break; /* match found */
811 pattern
+= 2; /* skip a total of 3 chars */
814 } else if (*data
== pattern
[0])
815 break; /* match found */
819 pattern
= end
; /* skip and continue */
822 if (*data
< '2' || *data
> '9')
826 if (*data
< '0' || *data
> '9')
830 if (*data
< '1' || *data
> '9')
833 case '.': /* Must match, even with more digits */
835 case '!': /* Early match */
838 case '-': /* Ignore these in patterns */
839 data
--; /* compensate the final data++ */
842 if (*data
!= *pattern
)
848 if (*data
) /* data longer than pattern, no match */
851 * match so far, but ran off the end of the data.
852 * Depending on what is next, determine match or not.
854 if (*pattern
== '\0' || *pattern
== '/') /* exact match */
855 return (mode
== E_MATCHMORE
) ? 0 : 1; /* this is a failure for E_MATCHMORE */
856 else if (*pattern
== '!') /* early match */
858 else /* partial match */
859 return (mode
== E_MATCH
) ? 0 : 1; /* this is a failure for E_MATCH */
863 * Wrapper around _extension_match_core() to do performance measurement
864 * using the profiling code.
866 static int extension_match_core(const char *pattern
, const char *data
, enum ext_match_t mode
)
869 static int prof_id
= -2; /* marker for 'unallocated' id */
871 prof_id
= ast_add_profile("ext_match", 0);
872 ast_mark(prof_id
, 1);
873 i
= _extension_match_core(pattern
, data
, mode
);
874 ast_mark(prof_id
, 0);
878 int ast_extension_match(const char *pattern
, const char *data
)
880 return extension_match_core(pattern
, data
, E_MATCH
);
883 int ast_extension_close(const char *pattern
, const char *data
, int needmore
)
885 if (needmore
!= E_MATCHMORE
&& needmore
!= E_CANMATCH
)
886 ast_log(LOG_WARNING
, "invalid argument %d\n", needmore
);
887 return extension_match_core(pattern
, data
, needmore
);
890 struct ast_context
*ast_context_find(const char *name
)
892 struct ast_context
*tmp
= NULL
;
894 ast_rdlock_contexts();
896 while ( (tmp
= ast_walk_contexts(tmp
)) ) {
897 if (!name
|| !strcasecmp(name
, tmp
->name
))
901 ast_unlock_contexts();
906 #define STATUS_NO_CONTEXT 1
907 #define STATUS_NO_EXTENSION 2
908 #define STATUS_NO_PRIORITY 3
909 #define STATUS_NO_LABEL 4
910 #define STATUS_SUCCESS 5
912 static int matchcid(const char *cidpattern
, const char *callerid
)
914 /* If the Caller*ID pattern is empty, then we're matching NO Caller*ID, so
915 failing to get a number should count as a match, otherwise not */
917 if (ast_strlen_zero(callerid
))
918 return ast_strlen_zero(cidpattern
) ? 1 : 0;
920 return ast_extension_match(cidpattern
, callerid
);
923 /* request and result for pbx_find_extension */
924 struct pbx_find_info
{
931 char *incstack
[AST_PBX_MAX_STACK
]; /* filled during the search */
932 int stacklen
; /* modified during the search */
933 int status
; /* set on return */
934 struct ast_switch
*swo
; /* set on return */
935 const char *data
; /* set on return */
936 const char *foundcontext
; /* set on return */
939 static struct ast_exten
*pbx_find_extension(struct ast_channel
*chan
,
940 struct ast_context
*bypass
, struct pbx_find_info
*q
,
941 const char *context
, const char *exten
, int priority
,
942 const char *label
, const char *callerid
, enum ext_match_t action
)
945 struct ast_context
*tmp
;
946 struct ast_exten
*e
, *eroot
;
947 struct ast_include
*i
;
950 /* Initialize status if appropriate */
951 if (q
->stacklen
== 0) {
952 q
->status
= STATUS_NO_CONTEXT
;
955 q
->foundcontext
= NULL
;
957 /* Check for stack overflow */
958 if (q
->stacklen
>= AST_PBX_MAX_STACK
) {
959 ast_log(LOG_WARNING
, "Maximum PBX stack exceeded\n");
962 /* Check first to see if we've already been checked */
963 for (x
= 0; x
< q
->stacklen
; x
++) {
964 if (!strcasecmp(q
->incstack
[x
], context
))
967 if (bypass
) /* bypass means we only look there */
969 else { /* look in contexts */
971 while ((tmp
= ast_walk_contexts(tmp
)) ) {
972 if (!strcmp(tmp
->name
, context
))
978 if (q
->status
< STATUS_NO_EXTENSION
)
979 q
->status
= STATUS_NO_EXTENSION
;
981 /* scan the list trying to match extension and CID */
983 while ( (eroot
= ast_walk_context_extensions(tmp
, eroot
)) ) {
984 int match
= extension_match_core(eroot
->exten
, exten
, action
);
985 /* 0 on fail, 1 on match, 2 on earlymatch */
987 if (!match
|| (eroot
->matchcid
&& !matchcid(eroot
->cidmatch
, callerid
)))
988 continue; /* keep trying */
989 if (match
== 2 && action
== E_MATCHMORE
) {
990 /* We match an extension ending in '!'.
991 * The decision in this case is final and is NULL (no match).
995 /* found entry, now look for the right priority */
996 if (q
->status
< STATUS_NO_PRIORITY
)
997 q
->status
= STATUS_NO_PRIORITY
;
999 while ( (e
= ast_walk_extension_priorities(eroot
, e
)) ) {
1000 /* Match label or priority */
1001 if (action
== E_FINDLABEL
) {
1002 if (q
->status
< STATUS_NO_LABEL
)
1003 q
->status
= STATUS_NO_LABEL
;
1004 if (label
&& e
->label
&& !strcmp(label
, e
->label
))
1005 break; /* found it */
1006 } else if (e
->priority
== priority
) {
1007 break; /* found it */
1008 } /* else keep searching */
1010 if (e
) { /* found a valid match */
1011 q
->status
= STATUS_SUCCESS
;
1012 q
->foundcontext
= context
;
1016 /* Check alternative switches */
1017 AST_LIST_TRAVERSE(&tmp
->alts
, sw
, list
) {
1018 struct ast_switch
*asw
= pbx_findswitch(sw
->name
);
1019 ast_switch_f
*aswf
= NULL
;
1023 ast_log(LOG_WARNING
, "No such switch '%s'\n", sw
->name
);
1026 /* Substitute variables now */
1028 pbx_substitute_variables_helper(chan
, sw
->data
, sw
->tmpdata
, SWITCH_DATA_LENGTH
- 1);
1030 /* equivalent of extension_match_core() at the switch level */
1031 if (action
== E_CANMATCH
)
1032 aswf
= asw
->canmatch
;
1033 else if (action
== E_MATCHMORE
)
1034 aswf
= asw
->matchmore
;
1035 else /* action == E_MATCH */
1037 datap
= sw
->eval
? sw
->tmpdata
: sw
->data
;
1042 ast_autoservice_start(chan
);
1043 res
= aswf(chan
, context
, exten
, priority
, callerid
, datap
);
1045 ast_autoservice_stop(chan
);
1047 if (res
) { /* Got a match */
1050 q
->foundcontext
= context
;
1051 /* XXX keep status = STATUS_NO_CONTEXT ? */
1055 q
->incstack
[q
->stacklen
++] = tmp
->name
; /* Setup the stack */
1056 /* Now try any includes we have in this context */
1057 for (i
= tmp
->includes
; i
; i
= i
->next
) {
1058 if (include_valid(i
)) {
1059 if ((e
= pbx_find_extension(chan
, bypass
, q
, i
->rname
, exten
, priority
, label
, callerid
, action
)))
1068 /*! \brief extract offset:length from variable name.
1069 * Returns 1 if there is a offset:length part, which is
1070 * trimmed off (values go into variables)
1072 static int parse_variable_name(char *var
, int *offset
, int *length
, int *isfunc
)
1079 for (; *var
; var
++) {
1083 } else if (*var
== ')') {
1085 } else if (*var
== ':' && parens
== 0) {
1087 sscanf(var
, "%d:%d", offset
, length
);
1088 return 1; /* offset:length valid */
1094 /*! \brief takes a substring. It is ok to call with value == workspace.
1096 * offset < 0 means start from the end of the string and set the beginning
1097 * to be that many characters back.
1098 * length is the length of the substring. A value less than 0 means to leave
1099 * that many off the end.
1100 * Always return a copy in workspace.
1102 static char *substring(const char *value
, int offset
, int length
, char *workspace
, size_t workspace_len
)
1104 char *ret
= workspace
;
1105 int lr
; /* length of the input string after the copy */
1107 ast_copy_string(workspace
, value
, workspace_len
); /* always make a copy */
1109 lr
= strlen(ret
); /* compute length after copy, so we never go out of the workspace */
1111 /* Quick check if no need to do anything */
1112 if (offset
== 0 && length
>= lr
) /* take the whole string */
1115 if (offset
< 0) { /* translate negative offset into positive ones */
1116 offset
= lr
+ offset
;
1117 if (offset
< 0) /* If the negative offset was greater than the length of the string, just start at the beginning */
1121 /* too large offset result in empty string so we know what to return */
1123 return ret
+ lr
; /* the final '\0' */
1125 ret
+= offset
; /* move to the start position */
1126 if (length
>= 0 && length
< lr
- offset
) /* truncate if necessary */
1128 else if (length
< 0) {
1129 if (lr
> offset
- length
) /* After we remove from the front and from the rear, is there anything left? */
1130 ret
[lr
+ length
- offset
] = '\0';
1138 /*! \brief pbx_retrieve_variable: Support for Asterisk built-in variables
1140 void pbx_retrieve_variable(struct ast_channel
*c
, const char *var
, char **ret
, char *workspace
, int workspacelen
, struct varshead
*headp
)
1142 const char not_found
= '\0';
1144 const char *s
; /* the result */
1146 int i
, need_substring
;
1147 struct varshead
*places
[2] = { headp
, &globals
}; /* list of places where we may look */
1150 ast_channel_lock(c
);
1151 places
[0] = &c
->varshead
;
1154 * Make a copy of var because parse_variable_name() modifies the string.
1155 * Then if called directly, we might need to run substring() on the result;
1156 * remember this for later in 'need_substring', 'offset' and 'length'
1158 tmpvar
= ast_strdupa(var
); /* parse_variable_name modifies the string */
1159 need_substring
= parse_variable_name(tmpvar
, &offset
, &length
, &i
/* ignored */);
1162 * Look first into predefined variables, then into variable lists.
1163 * Variable 's' points to the result, according to the following rules:
1164 * s == ¬_found (set at the beginning) means that we did not find a
1165 * matching variable and need to look into more places.
1166 * If s != ¬_found, s is a valid result string as follows:
1167 * s = NULL if the variable does not have a value;
1168 * you typically do this when looking for an unset predefined variable.
1169 * s = workspace if the result has been assembled there;
1170 * typically done when the result is built e.g. with an snprintf(),
1171 * so we don't need to do an additional copy.
1172 * s != workspace in case we have a string, that needs to be copied
1173 * (the ast_copy_string is done once for all at the end).
1174 * Typically done when the result is already available in some string.
1176 s
= ¬_found
; /* default value */
1177 if (c
) { /* This group requires a valid channel */
1178 /* Names with common parts are looked up a piece at a time using strncmp. */
1179 if (!strncmp(var
, "CALL", 4)) {
1180 if (!strncmp(var
+ 4, "ING", 3)) {
1181 if (!strcmp(var
+ 7, "PRES")) { /* CALLINGPRES */
1182 snprintf(workspace
, workspacelen
, "%d", c
->cid
.cid_pres
);
1184 } else if (!strcmp(var
+ 7, "ANI2")) { /* CALLINGANI2 */
1185 snprintf(workspace
, workspacelen
, "%d", c
->cid
.cid_ani2
);
1187 } else if (!strcmp(var
+ 7, "TON")) { /* CALLINGTON */
1188 snprintf(workspace
, workspacelen
, "%d", c
->cid
.cid_ton
);
1190 } else if (!strcmp(var
+ 7, "TNS")) { /* CALLINGTNS */
1191 snprintf(workspace
, workspacelen
, "%d", c
->cid
.cid_tns
);
1195 } else if (!strcmp(var
, "HINT")) {
1196 s
= ast_get_hint(workspace
, workspacelen
, NULL
, 0, c
, c
->context
, c
->exten
) ? workspace
: NULL
;
1197 } else if (!strcmp(var
, "HINTNAME")) {
1198 s
= ast_get_hint(NULL
, 0, workspace
, workspacelen
, c
, c
->context
, c
->exten
) ? workspace
: NULL
;
1199 } else if (!strcmp(var
, "EXTEN")) {
1201 } else if (!strcmp(var
, "CONTEXT")) {
1203 } else if (!strcmp(var
, "PRIORITY")) {
1204 snprintf(workspace
, workspacelen
, "%d", c
->priority
);
1206 } else if (!strcmp(var
, "CHANNEL")) {
1208 } else if (!strcmp(var
, "UNIQUEID")) {
1210 } else if (!strcmp(var
, "HANGUPCAUSE")) {
1211 snprintf(workspace
, workspacelen
, "%d", c
->hangupcause
);
1215 if (s
== ¬_found
) { /* look for more */
1216 if (!strcmp(var
, "EPOCH")) {
1217 snprintf(workspace
, workspacelen
, "%u",(int)time(NULL
));
1219 } else if (!strcmp(var
, "SYSTEMNAME")) {
1220 s
= ast_config_AST_SYSTEM_NAME
;
1223 /* if not found, look into chanvars or global vars */
1224 for (i
= 0; s
== ¬_found
&& i
< (sizeof(places
) / sizeof(places
[0])); i
++) {
1225 struct ast_var_t
*variables
;
1228 if (places
[i
] == &globals
)
1229 ast_mutex_lock(&globalslock
);
1230 AST_LIST_TRAVERSE(places
[i
], variables
, entries
) {
1231 if (strcasecmp(ast_var_name(variables
), var
)==0) {
1232 s
= ast_var_value(variables
);
1236 if (places
[i
] == &globals
)
1237 ast_mutex_unlock(&globalslock
);
1239 if (s
== ¬_found
|| s
== NULL
)
1243 ast_copy_string(workspace
, s
, workspacelen
);
1246 *ret
= substring(*ret
, offset
, length
, workspace
, workspacelen
);
1250 ast_channel_unlock(c
);
1253 /*! \brief CLI function to show installed custom functions
1254 \addtogroup CLI_functions
1256 static int handle_show_functions_deprecated(int fd
, int argc
, char *argv
[])
1258 struct ast_custom_function
*acf
;
1262 if (argc
== 4 && (!strcmp(argv
[2], "like")) ) {
1264 } else if (argc
!= 2) {
1265 return RESULT_SHOWUSAGE
;
1268 ast_cli(fd
, "%s Custom Functions:\n--------------------------------------------------------------------------------\n", like
? "Matching" : "Installed");
1270 AST_LIST_LOCK(&acf_root
);
1271 AST_LIST_TRAVERSE(&acf_root
, acf
, acflist
) {
1272 if (!like
|| strstr(acf
->name
, argv
[3])) {
1274 ast_cli(fd
, "%-20.20s %-35.35s %s\n", acf
->name
, acf
->syntax
, acf
->synopsis
);
1277 AST_LIST_UNLOCK(&acf_root
);
1279 ast_cli(fd
, "%d %scustom functions installed.\n", count_acf
, like
? "matching " : "");
1281 return RESULT_SUCCESS
;
1283 static int handle_show_functions(int fd
, int argc
, char *argv
[])
1285 struct ast_custom_function
*acf
;
1289 if (argc
== 5 && (!strcmp(argv
[3], "like")) ) {
1291 } else if (argc
!= 3) {
1292 return RESULT_SHOWUSAGE
;
1295 ast_cli(fd
, "%s Custom Functions:\n--------------------------------------------------------------------------------\n", like
? "Matching" : "Installed");
1297 AST_LIST_LOCK(&acf_root
);
1298 AST_LIST_TRAVERSE(&acf_root
, acf
, acflist
) {
1299 if (!like
|| strstr(acf
->name
, argv
[4])) {
1301 ast_cli(fd
, "%-20.20s %-35.35s %s\n", acf
->name
, acf
->syntax
, acf
->synopsis
);
1304 AST_LIST_UNLOCK(&acf_root
);
1306 ast_cli(fd
, "%d %scustom functions installed.\n", count_acf
, like
? "matching " : "");
1308 return RESULT_SUCCESS
;
1311 static int handle_show_function_deprecated(int fd
, int argc
, char *argv
[])
1313 struct ast_custom_function
*acf
;
1314 /* Maximum number of characters added by terminal coloring is 22 */
1315 char infotitle
[64 + AST_MAX_APP
+ 22], syntitle
[40], destitle
[40];
1316 char info
[64 + AST_MAX_APP
], *synopsis
= NULL
, *description
= NULL
;
1317 char stxtitle
[40], *syntax
= NULL
;
1318 int synopsis_size
, description_size
, syntax_size
;
1321 return RESULT_SHOWUSAGE
;
1323 if (!(acf
= ast_custom_function_find(argv
[2]))) {
1324 ast_cli(fd
, "No function by that name registered.\n");
1325 return RESULT_FAILURE
;
1330 synopsis_size
= strlen(acf
->synopsis
) + 23;
1332 synopsis_size
= strlen("Not available") + 23;
1333 synopsis
= alloca(synopsis_size
);
1336 description_size
= strlen(acf
->desc
) + 23;
1338 description_size
= strlen("Not available") + 23;
1339 description
= alloca(description_size
);
1342 syntax_size
= strlen(acf
->syntax
) + 23;
1344 syntax_size
= strlen("Not available") + 23;
1345 syntax
= alloca(syntax_size
);
1347 snprintf(info
, 64 + AST_MAX_APP
, "\n -= Info about function '%s' =- \n\n", acf
->name
);
1348 term_color(infotitle
, info
, COLOR_MAGENTA
, 0, 64 + AST_MAX_APP
+ 22);
1349 term_color(stxtitle
, "[Syntax]\n", COLOR_MAGENTA
, 0, 40);
1350 term_color(syntitle
, "[Synopsis]\n", COLOR_MAGENTA
, 0, 40);
1351 term_color(destitle
, "[Description]\n", COLOR_MAGENTA
, 0, 40);
1353 acf
->syntax
? acf
->syntax
: "Not available",
1354 COLOR_CYAN
, 0, syntax_size
);
1355 term_color(synopsis
,
1356 acf
->synopsis
? acf
->synopsis
: "Not available",
1357 COLOR_CYAN
, 0, synopsis_size
);
1358 term_color(description
,
1359 acf
->desc
? acf
->desc
: "Not available",
1360 COLOR_CYAN
, 0, description_size
);
1362 ast_cli(fd
,"%s%s%s\n\n%s%s\n\n%s%s\n", infotitle
, stxtitle
, syntax
, syntitle
, synopsis
, destitle
, description
);
1364 return RESULT_SUCCESS
;
1367 static int handle_show_function(int fd
, int argc
, char *argv
[])
1369 struct ast_custom_function
*acf
;
1370 /* Maximum number of characters added by terminal coloring is 22 */
1371 char infotitle
[64 + AST_MAX_APP
+ 22], syntitle
[40], destitle
[40];
1372 char info
[64 + AST_MAX_APP
], *synopsis
= NULL
, *description
= NULL
;
1373 char stxtitle
[40], *syntax
= NULL
;
1374 int synopsis_size
, description_size
, syntax_size
;
1377 return RESULT_SHOWUSAGE
;
1379 if (!(acf
= ast_custom_function_find(argv
[3]))) {
1380 ast_cli(fd
, "No function by that name registered.\n");
1381 return RESULT_FAILURE
;
1386 synopsis_size
= strlen(acf
->synopsis
) + 23;
1388 synopsis_size
= strlen("Not available") + 23;
1389 synopsis
= alloca(synopsis_size
);
1392 description_size
= strlen(acf
->desc
) + 23;
1394 description_size
= strlen("Not available") + 23;
1395 description
= alloca(description_size
);
1398 syntax_size
= strlen(acf
->syntax
) + 23;
1400 syntax_size
= strlen("Not available") + 23;
1401 syntax
= alloca(syntax_size
);
1403 snprintf(info
, 64 + AST_MAX_APP
, "\n -= Info about function '%s' =- \n\n", acf
->name
);
1404 term_color(infotitle
, info
, COLOR_MAGENTA
, 0, 64 + AST_MAX_APP
+ 22);
1405 term_color(stxtitle
, "[Syntax]\n", COLOR_MAGENTA
, 0, 40);
1406 term_color(syntitle
, "[Synopsis]\n", COLOR_MAGENTA
, 0, 40);
1407 term_color(destitle
, "[Description]\n", COLOR_MAGENTA
, 0, 40);
1409 acf
->syntax
? acf
->syntax
: "Not available",
1410 COLOR_CYAN
, 0, syntax_size
);
1411 term_color(synopsis
,
1412 acf
->synopsis
? acf
->synopsis
: "Not available",
1413 COLOR_CYAN
, 0, synopsis_size
);
1414 term_color(description
,
1415 acf
->desc
? acf
->desc
: "Not available",
1416 COLOR_CYAN
, 0, description_size
);
1418 ast_cli(fd
,"%s%s%s\n\n%s%s\n\n%s%s\n", infotitle
, stxtitle
, syntax
, syntitle
, synopsis
, destitle
, description
);
1420 return RESULT_SUCCESS
;
1423 static char *complete_show_function(const char *line
, const char *word
, int pos
, int state
)
1425 struct ast_custom_function
*acf
;
1428 int wordlen
= strlen(word
);
1430 /* case-insensitive for convenience in this 'complete' function */
1431 AST_LIST_LOCK(&acf_root
);
1432 AST_LIST_TRAVERSE(&acf_root
, acf
, acflist
) {
1433 if (!strncasecmp(word
, acf
->name
, wordlen
) && ++which
> state
) {
1434 ret
= strdup(acf
->name
);
1438 AST_LIST_UNLOCK(&acf_root
);
1443 struct ast_custom_function
*ast_custom_function_find(const char *name
)
1445 struct ast_custom_function
*acf
= NULL
;
1447 AST_LIST_LOCK(&acf_root
);
1448 AST_LIST_TRAVERSE(&acf_root
, acf
, acflist
) {
1449 if (!strcmp(name
, acf
->name
))
1452 AST_LIST_UNLOCK(&acf_root
);
1457 int ast_custom_function_unregister(struct ast_custom_function
*acf
)
1459 struct ast_custom_function
*cur
;
1464 AST_LIST_LOCK(&acf_root
);
1465 AST_LIST_TRAVERSE_SAFE_BEGIN(&acf_root
, cur
, acflist
) {
1467 AST_LIST_REMOVE_CURRENT(&acf_root
, acflist
);
1468 if (option_verbose
> 1)
1469 ast_verbose(VERBOSE_PREFIX_2
"Unregistered custom function %s\n", acf
->name
);
1473 AST_LIST_TRAVERSE_SAFE_END
1474 AST_LIST_UNLOCK(&acf_root
);
1476 return acf
? 0 : -1;
1479 int ast_custom_function_register(struct ast_custom_function
*acf
)
1481 struct ast_custom_function
*cur
;
1486 AST_LIST_LOCK(&acf_root
);
1488 if (ast_custom_function_find(acf
->name
)) {
1489 ast_log(LOG_ERROR
, "Function %s already registered.\n", acf
->name
);
1490 AST_LIST_UNLOCK(&acf_root
);
1494 /* Store in alphabetical order */
1495 AST_LIST_TRAVERSE_SAFE_BEGIN(&acf_root
, cur
, acflist
) {
1496 if (strcasecmp(acf
->name
, cur
->name
) < 0) {
1497 AST_LIST_INSERT_BEFORE_CURRENT(&acf_root
, acf
, acflist
);
1501 AST_LIST_TRAVERSE_SAFE_END
1503 AST_LIST_INSERT_TAIL(&acf_root
, acf
, acflist
);
1505 AST_LIST_UNLOCK(&acf_root
);
1507 if (option_verbose
> 1)
1508 ast_verbose(VERBOSE_PREFIX_2
"Registered custom function %s\n", acf
->name
);
1513 /*! \brief return a pointer to the arguments of the function,
1514 * and terminates the function name with '\\0'
1516 static char *func_args(char *function
)
1518 char *args
= strchr(function
, '(');
1521 ast_log(LOG_WARNING
, "Function doesn't contain parentheses. Assuming null argument.\n");
1525 if ((p
= strrchr(args
, ')')) )
1528 ast_log(LOG_WARNING
, "Can't find trailing parenthesis?\n");
1533 int ast_func_read(struct ast_channel
*chan
, char *function
, char *workspace
, size_t len
)
1535 char *args
= func_args(function
);
1536 struct ast_custom_function
*acfptr
= ast_custom_function_find(function
);
1539 ast_log(LOG_ERROR
, "Function %s not registered\n", function
);
1540 else if (!acfptr
->read
)
1541 ast_log(LOG_ERROR
, "Function %s cannot be read\n", function
);
1543 return acfptr
->read(chan
, function
, args
, workspace
, len
);
1547 int ast_func_write(struct ast_channel
*chan
, char *function
, const char *value
)
1549 char *args
= func_args(function
);
1550 struct ast_custom_function
*acfptr
= ast_custom_function_find(function
);
1553 ast_log(LOG_ERROR
, "Function %s not registered\n", function
);
1554 else if (!acfptr
->write
)
1555 ast_log(LOG_ERROR
, "Function %s cannot be written to\n", function
);
1557 return acfptr
->write(chan
, function
, args
, value
);
1562 static void pbx_substitute_variables_helper_full(struct ast_channel
*c
, struct varshead
*headp
, const char *cp1
, char *cp2
, int count
)
1564 /* Substitutes variables into cp2, based on string cp1, and assuming cp2 to be
1567 const char *tmp
, *whereweare
;
1568 int length
, offset
, offset2
, isfunction
;
1569 char *workspace
= NULL
;
1570 char *ltmp
= NULL
, *var
= NULL
;
1571 char *nextvar
, *nextexp
, *nextthing
;
1573 int pos
, brackets
, needsub
, len
;
1576 while (!ast_strlen_zero(whereweare
) && count
) {
1577 /* Assume we're copying the whole remaining string */
1578 pos
= strlen(whereweare
);
1581 nextthing
= strchr(whereweare
, '$');
1583 switch(nextthing
[1]) {
1585 nextvar
= nextthing
;
1586 pos
= nextvar
- whereweare
;
1589 nextexp
= nextthing
;
1590 pos
= nextexp
- whereweare
;
1598 /* Can't copy more than 'count' bytes */
1602 /* Copy that many bytes */
1603 memcpy(cp2
, whereweare
, pos
);
1611 /* We have a variable. Find the start and end, and determine
1612 if we are going to have to recursively call ourselves on the
1614 vars
= vare
= nextvar
+ 2;
1618 /* Find the end of it */
1619 while (brackets
&& *vare
) {
1620 if ((vare
[0] == '$') && (vare
[1] == '{')) {
1622 } else if (vare
[0] == '{') {
1624 } else if (vare
[0] == '}') {
1626 } else if ((vare
[0] == '$') && (vare
[1] == '['))
1631 ast_log(LOG_NOTICE
, "Error in extension logic (missing '}')\n");
1632 len
= vare
- vars
- 1;
1634 /* Skip totally over variable string */
1635 whereweare
+= (len
+ 3);
1638 var
= alloca(VAR_BUF_SIZE
);
1640 /* Store variable name (and truncate) */
1641 ast_copy_string(var
, vars
, len
+ 1);
1643 /* Substitute if necessary */
1646 ltmp
= alloca(VAR_BUF_SIZE
);
1648 memset(ltmp
, 0, VAR_BUF_SIZE
);
1649 pbx_substitute_variables_helper_full(c
, headp
, var
, ltmp
, VAR_BUF_SIZE
- 1);
1656 workspace
= alloca(VAR_BUF_SIZE
);
1658 workspace
[0] = '\0';
1660 parse_variable_name(vars
, &offset
, &offset2
, &isfunction
);
1662 /* Evaluate function */
1664 cp4
= ast_func_read(c
, vars
, workspace
, VAR_BUF_SIZE
) ? NULL
: workspace
;
1666 struct varshead old
;
1667 struct ast_channel
*c
= ast_channel_alloc(0, 0, "", "", "", "", "", 0, "Bogus/%p", vars
);
1669 memcpy(&old
, &c
->varshead
, sizeof(old
));
1670 memcpy(&c
->varshead
, headp
, sizeof(c
->varshead
));
1671 cp4
= ast_func_read(c
, vars
, workspace
, VAR_BUF_SIZE
) ? NULL
: workspace
;
1672 /* Don't deallocate the varshead that was passed in */
1673 memcpy(&c
->varshead
, &old
, sizeof(c
->varshead
));
1674 ast_channel_free(c
);
1676 ast_log(LOG_ERROR
, "Unable to allocate bogus channel for variable substitution. Function results may be blank.\n");
1680 ast_log(LOG_DEBUG
, "Function result is '%s'\n", cp4
? cp4
: "(null)");
1682 /* Retrieve variable value */
1683 pbx_retrieve_variable(c
, vars
, &cp4
, workspace
, VAR_BUF_SIZE
, headp
);
1686 cp4
= substring(cp4
, offset
, offset2
, workspace
, VAR_BUF_SIZE
);
1688 length
= strlen(cp4
);
1691 memcpy(cp2
, cp4
, length
);
1695 } else if (nextexp
) {
1696 /* We have an expression. Find the start and end, and determine
1697 if we are going to have to recursively call ourselves on the
1699 vars
= vare
= nextexp
+ 2;
1703 /* Find the end of it */
1704 while(brackets
&& *vare
) {
1705 if ((vare
[0] == '$') && (vare
[1] == '[')) {
1709 } else if (vare
[0] == '[') {
1711 } else if (vare
[0] == ']') {
1713 } else if ((vare
[0] == '$') && (vare
[1] == '{')) {
1720 ast_log(LOG_NOTICE
, "Error in extension logic (missing ']')\n");
1721 len
= vare
- vars
- 1;
1723 /* Skip totally over expression */
1724 whereweare
+= (len
+ 3);
1727 var
= alloca(VAR_BUF_SIZE
);
1729 /* Store variable name (and truncate) */
1730 ast_copy_string(var
, vars
, len
+ 1);
1732 /* Substitute if necessary */
1735 ltmp
= alloca(VAR_BUF_SIZE
);
1737 memset(ltmp
, 0, VAR_BUF_SIZE
);
1738 pbx_substitute_variables_helper_full(c
, headp
, var
, ltmp
, VAR_BUF_SIZE
- 1);
1744 length
= ast_expr(vars
, cp2
, count
);
1748 ast_log(LOG_DEBUG
, "Expression result is '%s'\n", cp2
);
1756 void pbx_substitute_variables_helper(struct ast_channel
*c
, const char *cp1
, char *cp2
, int count
)
1758 pbx_substitute_variables_helper_full(c
, (c
) ? &c
->varshead
: NULL
, cp1
, cp2
, count
);
1761 void pbx_substitute_variables_varshead(struct varshead
*headp
, const char *cp1
, char *cp2
, int count
)
1763 pbx_substitute_variables_helper_full(NULL
, headp
, cp1
, cp2
, count
);
1766 static void pbx_substitute_variables(char *passdata
, int datalen
, struct ast_channel
*c
, struct ast_exten
*e
)
1768 memset(passdata
, 0, datalen
);
1770 /* No variables or expressions in e->data, so why scan it? */
1771 if (e
->data
&& !strchr(e
->data
, '$') && !strstr(e
->data
,"${") && !strstr(e
->data
,"$[") && !strstr(e
->data
,"$(")) {
1772 ast_copy_string(passdata
, e
->data
, datalen
);
1776 pbx_substitute_variables_helper(c
, e
->data
, passdata
, datalen
- 1);
1780 * \brief The return value depends on the action:
1782 * E_MATCH, E_CANMATCH, E_MATCHMORE require a real match,
1783 * and return 0 on failure, -1 on match;
1784 * E_FINDLABEL maps the label to a priority, and returns
1785 * the priority on success, ... XXX
1786 * E_SPAWN, spawn an application,
1787 * and return 0 on success, -1 on failure.
1789 * \note The channel is auto-serviced in this function, because doing an extension
1790 * match may block for a long time. For example, if the lookup has to use a network
1791 * dialplan switch, such as DUNDi or IAX2, it may take a while. However, the channel
1792 * auto-service code will queue up any important signalling frames to be processed
1793 * after this is done.
1795 static int pbx_extension_helper(struct ast_channel
*c
, struct ast_context
*con
,
1796 const char *context
, const char *exten
, int priority
,
1797 const char *label
, const char *callerid
, enum ext_match_t action
)
1799 struct ast_exten
*e
;
1800 struct ast_app
*app
;
1802 struct pbx_find_info q
= { .stacklen
= 0 }; /* the rest is reset in pbx_find_extension */
1803 char passdata
[EXT_DATA_SIZE
];
1805 int matching_action
= (action
== E_MATCH
|| action
== E_CANMATCH
|| action
== E_MATCHMORE
);
1807 ast_rdlock_contexts();
1808 e
= pbx_find_extension(c
, con
, &q
, context
, exten
, priority
, label
, callerid
, action
);
1810 if (matching_action
) {
1811 ast_unlock_contexts();
1812 return -1; /* success, we found it */
1813 } else if (action
== E_FINDLABEL
) { /* map the label to a priority */
1815 ast_unlock_contexts();
1816 return res
; /* the priority we were looking for */
1817 } else { /* spawn */
1818 app
= pbx_findapp(e
->app
);
1819 ast_unlock_contexts();
1821 ast_log(LOG_WARNING
, "No application '%s' for extension (%s, %s, %d)\n", e
->app
, context
, exten
, priority
);
1824 if (c
->context
!= context
)
1825 ast_copy_string(c
->context
, context
, sizeof(c
->context
));
1826 if (c
->exten
!= exten
)
1827 ast_copy_string(c
->exten
, exten
, sizeof(c
->exten
));
1828 c
->priority
= priority
;
1829 pbx_substitute_variables(passdata
, sizeof(passdata
), c
, e
);
1831 ast_log(LOG_DEBUG
, "Launching '%s'\n", app
->name
);
1833 if (option_verbose
> 2) {
1834 char tmp
[80], tmp2
[80], tmp3
[EXT_DATA_SIZE
];
1835 ast_verbose( VERBOSE_PREFIX_3
"Executing [%s@%s:%d] %s(\"%s\", \"%s\") %s\n",
1836 exten
, context
, priority
,
1837 term_color(tmp
, app
->name
, COLOR_BRCYAN
, 0, sizeof(tmp
)),
1838 term_color(tmp2
, c
->name
, COLOR_BRMAGENTA
, 0, sizeof(tmp2
)),
1839 term_color(tmp3
, passdata
, COLOR_BRMAGENTA
, 0, sizeof(tmp3
)),
1842 manager_event(EVENT_FLAG_CALL
, "Newexten",
1847 "Application: %s\r\n"
1850 c
->name
, c
->context
, c
->exten
, c
->priority
, app
->name
, passdata
, c
->uniqueid
);
1851 return pbx_exec(c
, app
, passdata
); /* 0 on success, -1 on failure */
1853 } else if (q
.swo
) { /* not found here, but in another switch */
1854 ast_unlock_contexts();
1855 if (matching_action
) {
1859 ast_log(LOG_WARNING
, "No execution engine for switch %s\n", q
.swo
->name
);
1862 return q
.swo
->exec(c
, q
.foundcontext
? q
.foundcontext
: context
, exten
, priority
, callerid
, q
.data
);
1864 } else { /* not found anywhere, see what happened */
1865 ast_unlock_contexts();
1867 case STATUS_NO_CONTEXT
:
1868 if (!matching_action
)
1869 ast_log(LOG_NOTICE
, "Cannot find extension context '%s'\n", context
);
1871 case STATUS_NO_EXTENSION
:
1872 if (!matching_action
)
1873 ast_log(LOG_NOTICE
, "Cannot find extension '%s' in context '%s'\n", exten
, context
);
1875 case STATUS_NO_PRIORITY
:
1876 if (!matching_action
)
1877 ast_log(LOG_NOTICE
, "No such priority %d in extension '%s' in context '%s'\n", priority
, exten
, context
);
1879 case STATUS_NO_LABEL
:
1881 ast_log(LOG_NOTICE
, "No such label '%s' in extension '%s' in context '%s'\n", label
, exten
, context
);
1885 ast_log(LOG_DEBUG
, "Shouldn't happen!\n");
1888 return (matching_action
) ? 0 : -1;
1892 /*! \brief ast_hint_extension: Find hint for given extension in context */
1893 static struct ast_exten
*ast_hint_extension(struct ast_channel
*c
, const char *context
, const char *exten
)
1895 struct ast_exten
*e
;
1896 struct pbx_find_info q
= { .stacklen
= 0 }; /* the rest is set in pbx_find_context */
1898 ast_rdlock_contexts();
1899 e
= pbx_find_extension(c
, NULL
, &q
, context
, exten
, PRIORITY_HINT
, NULL
, "", E_MATCH
);
1900 ast_unlock_contexts();
1905 /*! \brief ast_extensions_state2: Check state of extension by using hints */
1906 static int ast_extension_state2(struct ast_exten
*e
)
1908 char hint
[AST_MAX_EXTENSION
];
1910 int allunavailable
= 1, allbusy
= 1, allfree
= 1, allonhold
= 1;
1911 int busy
= 0, inuse
= 0, ring
= 0;
1916 ast_copy_string(hint
, ast_get_extension_app(e
), sizeof(hint
));
1918 rest
= hint
; /* One or more devices separated with a & character */
1919 while ( (cur
= strsep(&rest
, "&")) ) {
1920 int res
= ast_device_state(cur
);
1922 case AST_DEVICE_NOT_INUSE
:
1927 case AST_DEVICE_INUSE
:
1933 case AST_DEVICE_RINGING
:
1939 case AST_DEVICE_RINGINUSE
:
1946 case AST_DEVICE_ONHOLD
:
1950 case AST_DEVICE_BUSY
:
1956 case AST_DEVICE_UNAVAILABLE
:
1957 case AST_DEVICE_INVALID
:
1971 return AST_EXTENSION_RINGING
;
1973 return (AST_EXTENSION_INUSE
| AST_EXTENSION_RINGING
);
1975 return AST_EXTENSION_INUSE
;
1977 return AST_EXTENSION_NOT_INUSE
;
1979 return AST_EXTENSION_ONHOLD
;
1981 return AST_EXTENSION_BUSY
;
1983 return AST_EXTENSION_UNAVAILABLE
;
1985 return AST_EXTENSION_INUSE
;
1987 return AST_EXTENSION_NOT_INUSE
;
1990 /*! \brief ast_extension_state2str: Return extension_state as string */
1991 const char *ast_extension_state2str(int extension_state
)
1995 for (i
= 0; (i
< (sizeof(extension_states
) / sizeof(extension_states
[0]))); i
++) {
1996 if (extension_states
[i
].extension_state
== extension_state
)
1997 return extension_states
[i
].text
;
2002 /*! \brief ast_extension_state: Check extension state for an extension by using hint */
2003 int ast_extension_state(struct ast_channel
*c
, const char *context
, const char *exten
)
2005 struct ast_exten
*e
;
2007 e
= ast_hint_extension(c
, context
, exten
); /* Do we have a hint for this extension ? */
2009 return -1; /* No hint, return -1 */
2011 return ast_extension_state2(e
); /* Check all devices in the hint */
2014 void ast_hint_state_changed(const char *device
)
2016 struct ast_hint
*hint
;
2018 AST_LIST_LOCK(&hints
);
2020 AST_LIST_TRAVERSE(&hints
, hint
, list
) {
2021 struct ast_state_cb
*cblist
;
2022 char buf
[AST_MAX_EXTENSION
];
2027 ast_copy_string(buf
, ast_get_extension_app(hint
->exten
), sizeof(buf
));
2028 while ( (cur
= strsep(&parse
, "&")) ) {
2029 if (!strcasecmp(cur
, device
))
2035 /* Get device state for this hint */
2036 state
= ast_extension_state2(hint
->exten
);
2038 if ((state
== -1) || (state
== hint
->laststate
))
2041 /* Device state changed since last check - notify the watchers */
2043 /* For general callbacks */
2044 for (cblist
= statecbs
; cblist
; cblist
= cblist
->next
)
2045 cblist
->callback(hint
->exten
->parent
->name
, hint
->exten
->exten
, state
, cblist
->data
);
2047 /* For extension callbacks */
2048 for (cblist
= hint
->callbacks
; cblist
; cblist
= cblist
->next
)
2049 cblist
->callback(hint
->exten
->parent
->name
, hint
->exten
->exten
, state
, cblist
->data
);
2051 hint
->laststate
= state
; /* record we saw the change */
2054 AST_LIST_UNLOCK(&hints
);
2057 /*! \brief ast_extension_state_add: Add watcher for extension states */
2058 int ast_extension_state_add(const char *context
, const char *exten
,
2059 ast_state_cb_type callback
, void *data
)
2061 struct ast_hint
*hint
;
2062 struct ast_state_cb
*cblist
;
2063 struct ast_exten
*e
;
2065 /* If there's no context and extension: add callback to statecbs list */
2066 if (!context
&& !exten
) {
2067 AST_LIST_LOCK(&hints
);
2069 for (cblist
= statecbs
; cblist
; cblist
= cblist
->next
) {
2070 if (cblist
->callback
== callback
) {
2071 cblist
->data
= data
;
2072 AST_LIST_UNLOCK(&hints
);
2077 /* Now insert the callback */
2078 if (!(cblist
= ast_calloc(1, sizeof(*cblist
)))) {
2079 AST_LIST_UNLOCK(&hints
);
2083 cblist
->callback
= callback
;
2084 cblist
->data
= data
;
2086 cblist
->next
= statecbs
;
2089 AST_LIST_UNLOCK(&hints
);
2093 if (!context
|| !exten
)
2096 /* This callback type is for only one hint, so get the hint */
2097 e
= ast_hint_extension(NULL
, context
, exten
);
2102 /* Find the hint in the list of hints */
2103 AST_LIST_LOCK(&hints
);
2105 AST_LIST_TRAVERSE(&hints
, hint
, list
) {
2106 if (hint
->exten
== e
)
2111 /* We have no hint, sorry */
2112 AST_LIST_UNLOCK(&hints
);
2116 /* Now insert the callback in the callback list */
2117 if (!(cblist
= ast_calloc(1, sizeof(*cblist
)))) {
2118 AST_LIST_UNLOCK(&hints
);
2121 cblist
->id
= stateid
++; /* Unique ID for this callback */
2122 cblist
->callback
= callback
; /* Pointer to callback routine */
2123 cblist
->data
= data
; /* Data for the callback */
2125 cblist
->next
= hint
->callbacks
;
2126 hint
->callbacks
= cblist
;
2128 AST_LIST_UNLOCK(&hints
);
2132 /*! \brief ast_extension_state_del: Remove a watcher from the callback list */
2133 int ast_extension_state_del(int id
, ast_state_cb_type callback
)
2135 struct ast_state_cb
**p_cur
= NULL
; /* address of pointer to us */
2138 if (!id
&& !callback
)
2141 AST_LIST_LOCK(&hints
);
2143 if (!id
) { /* id == 0 is a callback without extension */
2144 for (p_cur
= &statecbs
; *p_cur
; p_cur
= &(*p_cur
)->next
) {
2145 if ((*p_cur
)->callback
== callback
)
2148 } else { /* callback with extension, find the callback based on ID */
2149 struct ast_hint
*hint
;
2150 AST_LIST_TRAVERSE(&hints
, hint
, list
) {
2151 for (p_cur
= &hint
->callbacks
; *p_cur
; p_cur
= &(*p_cur
)->next
) {
2152 if ((*p_cur
)->id
== id
)
2155 if (*p_cur
) /* found in the inner loop */
2159 if (p_cur
&& *p_cur
) {
2160 struct ast_state_cb
*cur
= *p_cur
;
2165 AST_LIST_UNLOCK(&hints
);
2169 /*! \brief ast_add_hint: Add hint to hint list, check initial extension state */
2170 static int ast_add_hint(struct ast_exten
*e
)
2172 struct ast_hint
*hint
;
2177 AST_LIST_LOCK(&hints
);
2179 /* Search if hint exists, do nothing */
2180 AST_LIST_TRAVERSE(&hints
, hint
, list
) {
2181 if (hint
->exten
== e
) {
2182 AST_LIST_UNLOCK(&hints
);
2183 if (option_debug
> 1)
2184 ast_log(LOG_DEBUG
, "HINTS: Not re-adding existing hint %s: %s\n", ast_get_extension_name(e
), ast_get_extension_app(e
));
2189 if (option_debug
> 1)
2190 ast_log(LOG_DEBUG
, "HINTS: Adding hint %s: %s\n", ast_get_extension_name(e
), ast_get_extension_app(e
));
2192 if (!(hint
= ast_calloc(1, sizeof(*hint
)))) {
2193 AST_LIST_UNLOCK(&hints
);
2196 /* Initialize and insert new item at the top */
2198 hint
->laststate
= ast_extension_state2(e
);
2199 AST_LIST_INSERT_HEAD(&hints
, hint
, list
);
2201 AST_LIST_UNLOCK(&hints
);
2205 /*! \brief ast_change_hint: Change hint for an extension */
2206 static int ast_change_hint(struct ast_exten
*oe
, struct ast_exten
*ne
)
2208 struct ast_hint
*hint
;
2211 AST_LIST_LOCK(&hints
);
2212 AST_LIST_TRAVERSE(&hints
, hint
, list
) {
2213 if (hint
->exten
== oe
) {
2219 AST_LIST_UNLOCK(&hints
);
2224 /*! \brief ast_remove_hint: Remove hint from extension */
2225 static int ast_remove_hint(struct ast_exten
*e
)
2227 /* Cleanup the Notifys if hint is removed */
2228 struct ast_hint
*hint
;
2229 struct ast_state_cb
*cblist
, *cbprev
;
2235 AST_LIST_LOCK(&hints
);
2236 AST_LIST_TRAVERSE_SAFE_BEGIN(&hints
, hint
, list
) {
2237 if (hint
->exten
== e
) {
2239 cblist
= hint
->callbacks
;
2241 /* Notify with -1 and remove all callbacks */
2243 cblist
= cblist
->next
;
2244 cbprev
->callback(hint
->exten
->parent
->name
, hint
->exten
->exten
, AST_EXTENSION_DEACTIVATED
, cbprev
->data
);
2247 hint
->callbacks
= NULL
;
2248 AST_LIST_REMOVE_CURRENT(&hints
, list
);
2254 AST_LIST_TRAVERSE_SAFE_END
2255 AST_LIST_UNLOCK(&hints
);
2261 /*! \brief ast_get_hint: Get hint for channel */
2262 int ast_get_hint(char *hint
, int hintsize
, char *name
, int namesize
, struct ast_channel
*c
, const char *context
, const char *exten
)
2264 struct ast_exten
*e
= ast_hint_extension(c
, context
, exten
);
2268 ast_copy_string(hint
, ast_get_extension_app(e
), hintsize
);
2270 const char *tmp
= ast_get_extension_app_data(e
);
2272 ast_copy_string(name
, tmp
, namesize
);
2279 int ast_exists_extension(struct ast_channel
*c
, const char *context
, const char *exten
, int priority
, const char *callerid
)
2281 return pbx_extension_helper(c
, NULL
, context
, exten
, priority
, NULL
, callerid
, E_MATCH
);
2284 int ast_findlabel_extension(struct ast_channel
*c
, const char *context
, const char *exten
, const char *label
, const char *callerid
)
2286 return pbx_extension_helper(c
, NULL
, context
, exten
, 0, label
, callerid
, E_FINDLABEL
);
2289 int ast_findlabel_extension2(struct ast_channel
*c
, struct ast_context
*con
, const char *exten
, const char *label
, const char *callerid
)
2291 return pbx_extension_helper(c
, con
, NULL
, exten
, 0, label
, callerid
, E_FINDLABEL
);
2294 int ast_canmatch_extension(struct ast_channel
*c
, const char *context
, const char *exten
, int priority
, const char *callerid
)
2296 return pbx_extension_helper(c
, NULL
, context
, exten
, priority
, NULL
, callerid
, E_CANMATCH
);
2299 int ast_matchmore_extension(struct ast_channel
*c
, const char *context
, const char *exten
, int priority
, const char *callerid
)
2301 return pbx_extension_helper(c
, NULL
, context
, exten
, priority
, NULL
, callerid
, E_MATCHMORE
);
2304 int ast_spawn_extension(struct ast_channel
*c
, const char *context
, const char *exten
, int priority
, const char *callerid
)
2306 return pbx_extension_helper(c
, NULL
, context
, exten
, priority
, NULL
, callerid
, E_SPAWN
);
2309 /* helper function to set extension and priority */
2310 static void set_ext_pri(struct ast_channel
*c
, const char *exten
, int pri
)
2312 ast_channel_lock(c
);
2313 ast_copy_string(c
->exten
, exten
, sizeof(c
->exten
));
2315 ast_channel_unlock(c
);
2319 * \brief collect digits from the channel into the buffer,
2320 * return -1 on error, 0 on timeout or done.
2322 static int collect_digits(struct ast_channel
*c
, int waittime
, char *buf
, int buflen
, int pos
)
2326 buf
[pos
] = '\0'; /* make sure it is properly terminated */
2327 while (ast_matchmore_extension(c
, c
->context
, buf
, 1, c
->cid
.cid_num
)) {
2328 /* As long as we're willing to wait, and as long as it's not defined,
2329 keep reading digits until we can't possibly get a right answer anymore. */
2330 digit
= ast_waitfordigit(c
, waittime
* 1000);
2331 if (c
->_softhangup
== AST_SOFTHANGUP_ASYNCGOTO
) {
2334 if (!digit
) /* No entry */
2336 if (digit
< 0) /* Error, maybe a hangup */
2338 if (pos
< buflen
- 1) { /* XXX maybe error otherwise ? */
2342 waittime
= c
->pbx
->dtimeout
;
2348 static int __ast_pbx_run(struct ast_channel
*c
)
2350 int found
= 0; /* set if we find at least one match */
2353 int error
= 0; /* set an error conditions */
2355 /* A little initial setup here */
2357 ast_log(LOG_WARNING
, "%s already has PBX structure??\n", c
->name
);
2358 /* XXX and now what ? */
2361 if (!(c
->pbx
= ast_calloc(1, sizeof(*c
->pbx
))))
2365 c
->cdr
= ast_cdr_alloc();
2367 ast_log(LOG_WARNING
, "Unable to create Call Detail Record\n");
2371 ast_cdr_init(c
->cdr
, c
);
2374 /* Set reasonable defaults */
2375 c
->pbx
->rtimeout
= 10;
2376 c
->pbx
->dtimeout
= 5;
2378 autoloopflag
= ast_test_flag(c
, AST_FLAG_IN_AUTOLOOP
); /* save value to restore at the end */
2379 ast_set_flag(c
, AST_FLAG_IN_AUTOLOOP
);
2381 /* Start by trying whatever the channel is set to */
2382 if (!ast_exists_extension(c
, c
->context
, c
->exten
, c
->priority
, c
->cid
.cid_num
)) {
2383 /* If not successful fall back to 's' */
2384 if (option_verbose
> 1)
2385 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
);
2386 /* XXX the original code used the existing priority in the call to
2387 * ast_exists_extension(), and reset it to 1 afterwards.
2388 * I believe the correct thing is to set it to 1 immediately.
2390 set_ext_pri(c
, "s", 1);
2391 if (!ast_exists_extension(c
, c
->context
, c
->exten
, c
->priority
, c
->cid
.cid_num
)) {
2392 /* JK02: And finally back to default if everything else failed */
2393 if (option_verbose
> 1)
2394 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
);
2395 ast_copy_string(c
->context
, "default", sizeof(c
->context
));
2398 if (c
->cdr
&& ast_tvzero(c
->cdr
->start
))
2399 ast_cdr_start(c
->cdr
);
2401 char dst_exten
[256]; /* buffer to accumulate digits */
2402 int pos
= 0; /* XXX should check bounds */
2405 /* loop on priorities in this context/exten */
2406 while (ast_exists_extension(c
, c
->context
, c
->exten
, c
->priority
, c
->cid
.cid_num
)) {
2408 if ((res
= ast_spawn_extension(c
, c
->context
, c
->exten
, c
->priority
, c
->cid
.cid_num
))) {
2409 /* Something bad happened, or a hangup has been requested. */
2410 if (strchr("0123456789ABCDEF*#", res
)) {
2412 ast_log(LOG_DEBUG
, "Oooh, got something to jump out with ('%c')!\n", res
);
2414 dst_exten
[pos
++] = digit
= res
;
2415 dst_exten
[pos
] = '\0';
2418 if (res
== AST_PBX_KEEPALIVE
) {
2420 ast_log(LOG_DEBUG
, "Spawn extension (%s,%s,%d) exited KEEPALIVE on '%s'\n", c
->context
, c
->exten
, c
->priority
, c
->name
);
2421 if (option_verbose
> 1)
2422 ast_verbose( VERBOSE_PREFIX_2
"Spawn extension (%s, %s, %d) exited KEEPALIVE on '%s'\n", c
->context
, c
->exten
, c
->priority
, c
->name
);
2427 ast_log(LOG_DEBUG
, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c
->context
, c
->exten
, c
->priority
, c
->name
);
2428 if (option_verbose
> 1)
2429 ast_verbose( VERBOSE_PREFIX_2
"Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c
->context
, c
->exten
, c
->priority
, c
->name
);
2430 if (c
->_softhangup
== AST_SOFTHANGUP_ASYNCGOTO
) {
2432 } else if (c
->_softhangup
== AST_SOFTHANGUP_TIMEOUT
) {
2433 /* atimeout, nothing bad */
2441 if (c
->_softhangup
== AST_SOFTHANGUP_TIMEOUT
&& ast_exists_extension(c
,c
->context
,"T",1,c
->cid
.cid_num
)) {
2442 set_ext_pri(c
, "T", 0); /* 0 will become 1 with the c->priority++; at the end */
2443 /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
2444 c
->whentohangup
= 0;
2445 c
->_softhangup
&= ~AST_SOFTHANGUP_TIMEOUT
;
2446 } else if (c
->_softhangup
) {
2448 ast_log(LOG_DEBUG
, "Extension %s, priority %d returned normally even though call was hung up\n",
2449 c
->exten
, c
->priority
);
2454 } /* end while - from here on we can use 'break' to go out */
2458 /* XXX we get here on non-existing extension or a keypress or hangup ? */
2460 if (!ast_exists_extension(c
, c
->context
, c
->exten
, 1, c
->cid
.cid_num
)) {
2461 /* If there is no match at priority 1, it is not a valid extension anymore.
2462 * Try to continue at "i", 1 or exit if the latter does not exist.
2464 if (ast_exists_extension(c
, c
->context
, "i", 1, c
->cid
.cid_num
)) {
2465 if (option_verbose
> 2)
2466 ast_verbose(VERBOSE_PREFIX_3
"Sent into invalid extension '%s' in context '%s' on %s\n", c
->exten
, c
->context
, c
->name
);
2467 pbx_builtin_setvar_helper(c
, "INVALID_EXTEN", c
->exten
);
2468 set_ext_pri(c
, "i", 1);
2470 ast_log(LOG_WARNING
, "Channel '%s' sent into invalid extension '%s' in context '%s', but no invalid handler\n",
2471 c
->name
, c
->exten
, c
->context
);
2472 error
= 1; /* we know what to do with it */
2475 } else if (c
->_softhangup
== AST_SOFTHANGUP_TIMEOUT
) {
2476 /* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */
2478 } else { /* keypress received, get more digits for a full extension */
2481 waittime
= c
->pbx
->dtimeout
;
2482 else if (!autofallthrough
)
2483 waittime
= c
->pbx
->rtimeout
;
2485 const char *status
= pbx_builtin_getvar_helper(c
, "DIALSTATUS");
2488 if (option_verbose
> 2)
2489 ast_verbose(VERBOSE_PREFIX_2
"Auto fallthrough, channel '%s' status is '%s'\n", c
->name
, status
);
2490 if (!strcasecmp(status
, "CONGESTION"))
2491 res
= pbx_builtin_congestion(c
, "10");
2492 else if (!strcasecmp(status
, "CHANUNAVAIL"))
2493 res
= pbx_builtin_congestion(c
, "10");
2494 else if (!strcasecmp(status
, "BUSY"))
2495 res
= pbx_builtin_busy(c
, "10");
2496 error
= 1; /* XXX disable message */
2497 break; /* exit from the 'for' loop */
2500 if (collect_digits(c
, waittime
, dst_exten
, sizeof(dst_exten
), pos
))
2502 if (ast_exists_extension(c
, c
->context
, dst_exten
, 1, c
->cid
.cid_num
)) /* Prepare the next cycle */
2503 set_ext_pri(c
, dst_exten
, 1);
2505 /* No such extension */
2506 if (!ast_strlen_zero(dst_exten
)) {
2507 /* An invalid extension */
2508 if (ast_exists_extension(c
, c
->context
, "i", 1, c
->cid
.cid_num
)) {
2509 if (option_verbose
> 2)
2510 ast_verbose( VERBOSE_PREFIX_3
"Invalid extension '%s' in context '%s' on %s\n", dst_exten
, c
->context
, c
->name
);
2511 pbx_builtin_setvar_helper(c
, "INVALID_EXTEN", dst_exten
);
2512 set_ext_pri(c
, "i", 1);
2514 ast_log(LOG_WARNING
, "Invalid extension '%s', but no rule 'i' in context '%s'\n", dst_exten
, c
->context
);
2515 found
= 1; /* XXX disable message */
2519 /* A simple timeout */
2520 if (ast_exists_extension(c
, c
->context
, "t", 1, c
->cid
.cid_num
)) {
2521 if (option_verbose
> 2)
2522 ast_verbose( VERBOSE_PREFIX_3
"Timeout on %s\n", c
->name
);
2523 set_ext_pri(c
, "t", 1);
2525 ast_log(LOG_WARNING
, "Timeout, but no rule 't' in context '%s'\n", c
->context
);
2526 found
= 1; /* XXX disable message */
2532 if (option_verbose
> 2)
2533 ast_verbose(VERBOSE_PREFIX_2
"CDR updated on %s\n",c
->name
);
2538 if (!found
&& !error
)
2539 ast_log(LOG_WARNING
, "Don't know what to do with '%s'\n", c
->name
);
2540 if (res
!= AST_PBX_KEEPALIVE
)
2541 ast_softhangup(c
, c
->hangupcause
? c
->hangupcause
: AST_CAUSE_NORMAL_CLEARING
);
2542 if ((res
!= AST_PBX_KEEPALIVE
) && ast_exists_extension(c
, c
->context
, "h", 1, c
->cid
.cid_num
)) {
2543 if (c
->cdr
&& ast_opt_end_cdr_before_h_exten
)
2544 ast_cdr_end(c
->cdr
);
2545 set_ext_pri(c
, "h", 1);
2546 while(ast_exists_extension(c
, c
->context
, c
->exten
, c
->priority
, c
->cid
.cid_num
)) {
2547 if ((res
= ast_spawn_extension(c
, c
->context
, c
->exten
, c
->priority
, c
->cid
.cid_num
))) {
2548 /* Something bad happened, or a hangup has been requested. */
2550 ast_log(LOG_DEBUG
, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c
->context
, c
->exten
, c
->priority
, c
->name
);
2551 if (option_verbose
> 1)
2552 ast_verbose( VERBOSE_PREFIX_2
"Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c
->context
, c
->exten
, c
->priority
, c
->name
);
2558 ast_set2_flag(c
, autoloopflag
, AST_FLAG_IN_AUTOLOOP
);
2560 pbx_destroy(c
->pbx
);
2562 if (res
!= AST_PBX_KEEPALIVE
)
2567 /* Returns 0 on success, non-zero if call limit was reached */
2568 static int increase_call_count(const struct ast_channel
*c
)
2572 ast_mutex_lock(&maxcalllock
);
2573 if (option_maxcalls
) {
2574 if (countcalls
>= option_maxcalls
) {
2575 ast_log(LOG_NOTICE
, "Maximum call limit of %d calls exceeded by '%s'!\n", option_maxcalls
, c
->name
);
2579 if (option_maxload
) {
2580 getloadavg(&curloadavg
, 1);
2581 if (curloadavg
>= option_maxload
) {
2582 ast_log(LOG_NOTICE
, "Maximum loadavg limit of %f load exceeded by '%s' (currently %f)!\n", option_maxload
, c
->name
, curloadavg
);
2588 ast_mutex_unlock(&maxcalllock
);
2593 static void decrease_call_count(void)
2595 ast_mutex_lock(&maxcalllock
);
2598 ast_mutex_unlock(&maxcalllock
);
2601 static void destroy_exten(struct ast_exten
*e
)
2603 if (e
->priority
== PRIORITY_HINT
)
2611 static void *pbx_thread(void *data
)
2613 /* Oh joyeous kernel, we're a new thread, with nothing to do but
2614 answer this channel and get it going.
2617 The launcher of this function _MUST_ increment 'countcalls'
2618 before invoking the function; it will be decremented when the
2619 PBX has finished running on the channel
2621 struct ast_channel
*c
= data
;
2624 decrease_call_count();
2631 enum ast_pbx_result
ast_pbx_start(struct ast_channel
*c
)
2634 pthread_attr_t attr
;
2637 ast_log(LOG_WARNING
, "Asked to start thread on NULL channel?\n");
2638 return AST_PBX_FAILED
;
2641 if (increase_call_count(c
))
2642 return AST_PBX_CALL_LIMIT
;
2644 /* Start a new thread, and get something handling this channel. */
2645 pthread_attr_init(&attr
);
2646 pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
2647 if (ast_pthread_create(&t
, &attr
, pbx_thread
, c
)) {
2648 ast_log(LOG_WARNING
, "Failed to create new channel thread\n");
2649 pthread_attr_destroy(&attr
);
2650 return AST_PBX_FAILED
;
2652 pthread_attr_destroy(&attr
);
2654 return AST_PBX_SUCCESS
;
2657 enum ast_pbx_result
ast_pbx_run(struct ast_channel
*c
)
2659 enum ast_pbx_result res
= AST_PBX_SUCCESS
;
2661 if (increase_call_count(c
))
2662 return AST_PBX_CALL_LIMIT
;
2664 res
= __ast_pbx_run(c
);
2665 decrease_call_count();
2670 int ast_active_calls(void)
2675 int pbx_set_autofallthrough(int newval
)
2677 int oldval
= autofallthrough
;
2678 autofallthrough
= newval
;
2682 /* lookup for a context with a given name,
2683 * return with conlock held if found, NULL if not found
2685 static struct ast_context
*find_context_locked(const char *context
)
2687 struct ast_context
*c
= NULL
;
2689 ast_rdlock_contexts();
2690 while ( (c
= ast_walk_contexts(c
)) ) {
2691 if (!strcmp(ast_get_context_name(c
), context
))
2694 ast_unlock_contexts();
2700 * This function locks contexts list by &conlist, search for the right context
2701 * structure, leave context list locked and call ast_context_remove_include2
2702 * which removes include, unlock contexts list and return ...
2704 int ast_context_remove_include(const char *context
, const char *include
, const char *registrar
)
2707 struct ast_context
*c
= find_context_locked(context
);
2710 /* found, remove include from this context ... */
2711 ret
= ast_context_remove_include2(c
, include
, registrar
);
2712 ast_unlock_contexts();
2718 * When we call this function, &conlock lock must be locked, because when
2719 * we giving *con argument, some process can remove/change this context
2720 * and after that there can be segfault.
2722 * This function locks given context, removes include, unlock context and
2725 int ast_context_remove_include2(struct ast_context
*con
, const char *include
, const char *registrar
)
2727 struct ast_include
*i
, *pi
= NULL
;
2730 ast_mutex_lock(&con
->lock
);
2732 /* find our include */
2733 for (i
= con
->includes
; i
; pi
= i
, i
= i
->next
) {
2734 if (!strcmp(i
->name
, include
) &&
2735 (!registrar
|| !strcmp(i
->registrar
, registrar
))) {
2736 /* remove from list */
2740 con
->includes
= i
->next
;
2741 /* free include and return */
2748 ast_mutex_unlock(&con
->lock
);
2753 * \note This function locks contexts list by &conlist, search for the rigt context
2754 * structure, leave context list locked and call ast_context_remove_switch2
2755 * which removes switch, unlock contexts list and return ...
2757 int ast_context_remove_switch(const char *context
, const char *sw
, const char *data
, const char *registrar
)
2759 int ret
= -1; /* default error return */
2760 struct ast_context
*c
= find_context_locked(context
);
2763 /* remove switch from this context ... */
2764 ret
= ast_context_remove_switch2(c
, sw
, data
, registrar
);
2765 ast_unlock_contexts();
2771 * \brief This function locks given context, removes switch, unlock context and
2773 * \note When we call this function, &conlock lock must be locked, because when
2774 * we giving *con argument, some process can remove/change this context
2775 * and after that there can be segfault.
2778 int ast_context_remove_switch2(struct ast_context
*con
, const char *sw
, const char *data
, const char *registrar
)
2783 ast_mutex_lock(&con
->lock
);
2786 AST_LIST_TRAVERSE_SAFE_BEGIN(&con
->alts
, i
, list
) {
2787 if (!strcmp(i
->name
, sw
) && !strcmp(i
->data
, data
) &&
2788 (!registrar
|| !strcmp(i
->registrar
, registrar
))) {
2789 /* found, remove from list */
2790 AST_LIST_REMOVE_CURRENT(&con
->alts
, list
);
2791 free(i
); /* free switch and return */
2796 AST_LIST_TRAVERSE_SAFE_END
2798 ast_mutex_unlock(&con
->lock
);
2804 * \note This functions lock contexts list, search for the right context,
2805 * call ast_context_remove_extension2, unlock contexts list and return.
2806 * In this function we are using
2808 int ast_context_remove_extension(const char *context
, const char *extension
, int priority
, const char *registrar
)
2810 int ret
= -1; /* default error return */
2811 struct ast_context
*c
= find_context_locked(context
);
2813 if (c
) { /* ... remove extension ... */
2814 ret
= ast_context_remove_extension2(c
, extension
, priority
, registrar
);
2815 ast_unlock_contexts();
2821 * \brief This functionc locks given context, search for the right extension and
2822 * fires out all peer in this extensions with given priority. If priority
2823 * is set to 0, all peers are removed. After that, unlock context and
2825 * \note When do you want to call this function, make sure that &conlock is locked,
2826 * because some process can handle with your *con context before you lock
2830 int ast_context_remove_extension2(struct ast_context
*con
, const char *extension
, int priority
, const char *registrar
)
2832 struct ast_exten
*exten
, *prev_exten
= NULL
;
2833 struct ast_exten
*peer
;
2835 ast_mutex_lock(&con
->lock
);
2837 /* scan the extension list to find matching extension-registrar */
2838 for (exten
= con
->root
; exten
; prev_exten
= exten
, exten
= exten
->next
) {
2839 if (!strcmp(exten
->exten
, extension
) &&
2840 (!registrar
|| !strcmp(exten
->registrar
, registrar
)))
2844 /* we can't find right extension */
2845 ast_mutex_unlock(&con
->lock
);
2849 /* should we free all peers in this extension? (priority == 0)? */
2850 if (priority
== 0) {
2851 /* remove this extension from context list */
2853 prev_exten
->next
= exten
->next
;
2855 con
->root
= exten
->next
;
2857 /* fire out all peers */
2858 while ( (peer
= exten
) ) {
2859 exten
= peer
->peer
; /* prepare for next entry */
2860 destroy_exten(peer
);
2863 /* scan the priority list to remove extension with exten->priority == priority */
2864 struct ast_exten
*previous_peer
= NULL
;
2866 for (peer
= exten
; peer
; previous_peer
= peer
, peer
= peer
->peer
) {
2867 if (peer
->priority
== priority
&&
2868 (!registrar
|| !strcmp(peer
->registrar
, registrar
) ))
2869 break; /* found our priority */
2871 if (!peer
) { /* not found */
2872 ast_mutex_unlock(&con
->lock
);
2875 /* we are first priority extension? */
2876 if (!previous_peer
) {
2878 * We are first in the priority chain, so must update the extension chain.
2879 * The next node is either the next priority or the next extension
2881 struct ast_exten
*next_node
= peer
->peer
? peer
->peer
: peer
->next
;
2883 if (!prev_exten
) /* change the root... */
2884 con
->root
= next_node
;
2886 prev_exten
->next
= next_node
; /* unlink */
2887 if (peer
->peer
) /* XXX update the new head of the pri list */
2888 peer
->peer
->next
= peer
->next
;
2889 } else { /* easy, we are not first priority in extension */
2890 previous_peer
->peer
= peer
->peer
;
2893 /* now, free whole priority extension */
2894 destroy_exten(peer
);
2895 /* XXX should we return -1 ? */
2897 ast_mutex_unlock(&con
->lock
);
2903 * \note This function locks contexts list by &conlist, searches for the right context
2904 * structure, and locks the macrolock mutex in that context.
2905 * macrolock is used to limit a macro to be executed by one call at a time.
2907 int ast_context_lockmacro(const char *context
)
2909 struct ast_context
*c
= NULL
;
2912 ast_rdlock_contexts();
2914 while ((c
= ast_walk_contexts(c
))) {
2915 if (!strcmp(ast_get_context_name(c
), context
)) {
2921 ast_unlock_contexts();
2923 /* if we found context, lock macrolock */
2925 ret
= ast_mutex_lock(&c
->macrolock
);
2931 * \note This function locks contexts list by &conlist, searches for the right context
2932 * structure, and unlocks the macrolock mutex in that context.
2933 * macrolock is used to limit a macro to be executed by one call at a time.
2935 int ast_context_unlockmacro(const char *context
)
2937 struct ast_context
*c
= NULL
;
2940 ast_rdlock_contexts();
2942 while ((c
= ast_walk_contexts(c
))) {
2943 if (!strcmp(ast_get_context_name(c
), context
)) {
2949 ast_unlock_contexts();
2951 /* if we found context, unlock macrolock */
2953 ret
= ast_mutex_unlock(&c
->macrolock
);
2958 /*! \brief Dynamically register a new dial plan application */
2959 int ast_register_application(const char *app
, int (*execute
)(struct ast_channel
*, void *), const char *synopsis
, const char *description
)
2961 struct ast_app
*tmp
, *cur
= NULL
;
2965 AST_LIST_LOCK(&apps
);
2966 AST_LIST_TRAVERSE(&apps
, tmp
, list
) {
2967 if (!strcasecmp(app
, tmp
->name
)) {
2968 ast_log(LOG_WARNING
, "Already have an application '%s'\n", app
);
2969 AST_LIST_UNLOCK(&apps
);
2974 length
= sizeof(*tmp
) + strlen(app
) + 1;
2976 if (!(tmp
= ast_calloc(1, length
))) {
2977 AST_LIST_UNLOCK(&apps
);
2981 strcpy(tmp
->name
, app
);
2982 tmp
->execute
= execute
;
2983 tmp
->synopsis
= synopsis
;
2984 tmp
->description
= description
;
2986 /* Store in alphabetical order */
2987 AST_LIST_TRAVERSE_SAFE_BEGIN(&apps
, cur
, list
) {
2988 if (strcasecmp(tmp
->name
, cur
->name
) < 0) {
2989 AST_LIST_INSERT_BEFORE_CURRENT(&apps
, tmp
, list
);
2993 AST_LIST_TRAVERSE_SAFE_END
2995 AST_LIST_INSERT_TAIL(&apps
, tmp
, list
);
2997 if (option_verbose
> 1)
2998 ast_verbose( VERBOSE_PREFIX_2
"Registered application '%s'\n", term_color(tmps
, tmp
->name
, COLOR_BRCYAN
, 0, sizeof(tmps
)));
3000 AST_LIST_UNLOCK(&apps
);
3006 * Append to the list. We don't have a tail pointer because we need
3007 * to scan the list anyways to check for duplicates during insertion.
3009 int ast_register_switch(struct ast_switch
*sw
)
3011 struct ast_switch
*tmp
;
3013 AST_LIST_LOCK(&switches
);
3014 AST_LIST_TRAVERSE(&switches
, tmp
, list
) {
3015 if (!strcasecmp(tmp
->name
, sw
->name
)) {
3016 AST_LIST_UNLOCK(&switches
);
3017 ast_log(LOG_WARNING
, "Switch '%s' already found\n", sw
->name
);
3021 AST_LIST_INSERT_TAIL(&switches
, sw
, list
);
3022 AST_LIST_UNLOCK(&switches
);
3027 void ast_unregister_switch(struct ast_switch
*sw
)
3029 AST_LIST_LOCK(&switches
);
3030 AST_LIST_REMOVE(&switches
, sw
, list
);
3031 AST_LIST_UNLOCK(&switches
);
3035 * Help for CLI commands ...
3037 static char show_applications_help
[] =
3038 "Usage: core show applications [{like|describing} <text>]\n"
3039 " List applications which are currently available.\n"
3040 " If 'like', <text> will be a substring of the app name\n"
3041 " If 'describing', <text> will be a substring of the description\n";
3043 static char show_functions_help
[] =
3044 "Usage: core show functions [like <text>]\n"
3045 " List builtin functions, optionally only those matching a given string\n";
3047 static char show_switches_help
[] =
3048 "Usage: core show switches\n"
3049 " List registered switches\n";
3051 static char show_hints_help
[] =
3052 "Usage: core show hints\n"
3053 " List registered hints\n";
3055 static char show_globals_help
[] =
3056 "Usage: core show globals\n"
3057 " List current global dialplan variables and their values\n";
3059 static char show_application_help
[] =
3060 "Usage: core show application <application> [<application> [<application> [...]]]\n"
3061 " Describes a particular application.\n";
3063 static char show_function_help
[] =
3064 "Usage: core show function <function>\n"
3065 " Describe a particular dialplan function.\n";
3067 static char show_dialplan_help
[] =
3068 "Usage: dialplan show [exten@][context]\n"
3071 static char set_global_help
[] =
3072 "Usage: core set global <name> <value>\n"
3073 " Set global dialplan variable <name> to <value>\n";
3077 * \brief 'show application' CLI command implementation functions ...
3081 * There is a possibility to show informations about more than one
3082 * application at one time. You can type 'show application Dial Echo' and
3083 * you will see informations about these two applications ...
3085 static char *complete_show_application(const char *line
, const char *word
, int pos
, int state
)
3090 int wordlen
= strlen(word
);
3092 /* return the n-th [partial] matching entry */
3093 AST_LIST_LOCK(&apps
);
3094 AST_LIST_TRAVERSE(&apps
, a
, list
) {
3095 if (!strncasecmp(word
, a
->name
, wordlen
) && ++which
> state
) {
3096 ret
= strdup(a
->name
);
3100 AST_LIST_UNLOCK(&apps
);
3105 static int handle_show_application_deprecated(int fd
, int argc
, char *argv
[])
3108 int app
, no_registered_app
= 1;
3111 return RESULT_SHOWUSAGE
;
3113 /* ... go through all applications ... */
3114 AST_LIST_LOCK(&apps
);
3115 AST_LIST_TRAVERSE(&apps
, a
, list
) {
3116 /* ... compare this application name with all arguments given
3117 * to 'show application' command ... */
3118 for (app
= 2; app
< argc
; app
++) {
3119 if (!strcasecmp(a
->name
, argv
[app
])) {
3120 /* Maximum number of characters added by terminal coloring is 22 */
3121 char infotitle
[64 + AST_MAX_APP
+ 22], syntitle
[40], destitle
[40];
3122 char info
[64 + AST_MAX_APP
], *synopsis
= NULL
, *description
= NULL
;
3123 int synopsis_size
, description_size
;
3125 no_registered_app
= 0;
3128 synopsis_size
= strlen(a
->synopsis
) + 23;
3130 synopsis_size
= strlen("Not available") + 23;
3131 synopsis
= alloca(synopsis_size
);
3134 description_size
= strlen(a
->description
) + 23;
3136 description_size
= strlen("Not available") + 23;
3137 description
= alloca(description_size
);
3139 if (synopsis
&& description
) {
3140 snprintf(info
, 64 + AST_MAX_APP
, "\n -= Info about application '%s' =- \n\n", a
->name
);
3141 term_color(infotitle
, info
, COLOR_MAGENTA
, 0, 64 + AST_MAX_APP
+ 22);
3142 term_color(syntitle
, "[Synopsis]\n", COLOR_MAGENTA
, 0, 40);
3143 term_color(destitle
, "[Description]\n", COLOR_MAGENTA
, 0, 40);
3144 term_color(synopsis
,
3145 a
->synopsis
? a
->synopsis
: "Not available",
3146 COLOR_CYAN
, 0, synopsis_size
);
3147 term_color(description
,
3148 a
->description
? a
->description
: "Not available",
3149 COLOR_CYAN
, 0, description_size
);
3151 ast_cli(fd
,"%s%s%s\n\n%s%s\n", infotitle
, syntitle
, synopsis
, destitle
, description
);
3153 /* ... one of our applications, show info ...*/
3154 ast_cli(fd
,"\n -= Info about application '%s' =- \n\n"
3155 "[Synopsis]\n %s\n\n"
3156 "[Description]\n%s\n",
3158 a
->synopsis
? a
->synopsis
: "Not available",
3159 a
->description
? a
->description
: "Not available");
3164 AST_LIST_UNLOCK(&apps
);
3166 /* we found at least one app? no? */
3167 if (no_registered_app
) {
3168 ast_cli(fd
, "Your application(s) is (are) not registered\n");
3169 return RESULT_FAILURE
;
3172 return RESULT_SUCCESS
;
3175 static int handle_show_application(int fd
, int argc
, char *argv
[])
3178 int app
, no_registered_app
= 1;
3181 return RESULT_SHOWUSAGE
;
3183 /* ... go through all applications ... */
3184 AST_LIST_LOCK(&apps
);
3185 AST_LIST_TRAVERSE(&apps
, a
, list
) {
3186 /* ... compare this application name with all arguments given
3187 * to 'show application' command ... */
3188 for (app
= 3; app
< argc
; app
++) {
3189 if (!strcasecmp(a
->name
, argv
[app
])) {
3190 /* Maximum number of characters added by terminal coloring is 22 */
3191 char infotitle
[64 + AST_MAX_APP
+ 22], syntitle
[40], destitle
[40];
3192 char info
[64 + AST_MAX_APP
], *synopsis
= NULL
, *description
= NULL
;
3193 int synopsis_size
, description_size
;
3195 no_registered_app
= 0;
3198 synopsis_size
= strlen(a
->synopsis
) + 23;
3200 synopsis_size
= strlen("Not available") + 23;
3201 synopsis
= alloca(synopsis_size
);
3204 description_size
= strlen(a
->description
) + 23;
3206 description_size
= strlen("Not available") + 23;
3207 description
= alloca(description_size
);
3209 if (synopsis
&& description
) {
3210 snprintf(info
, 64 + AST_MAX_APP
, "\n -= Info about application '%s' =- \n\n", a
->name
);
3211 term_color(infotitle
, info
, COLOR_MAGENTA
, 0, 64 + AST_MAX_APP
+ 22);
3212 term_color(syntitle
, "[Synopsis]\n", COLOR_MAGENTA
, 0, 40);
3213 term_color(destitle
, "[Description]\n", COLOR_MAGENTA
, 0, 40);
3214 term_color(synopsis
,
3215 a
->synopsis
? a
->synopsis
: "Not available",
3216 COLOR_CYAN
, 0, synopsis_size
);
3217 term_color(description
,
3218 a
->description
? a
->description
: "Not available",
3219 COLOR_CYAN
, 0, description_size
);
3221 ast_cli(fd
,"%s%s%s\n\n%s%s\n", infotitle
, syntitle
, synopsis
, destitle
, description
);
3223 /* ... one of our applications, show info ...*/
3224 ast_cli(fd
,"\n -= Info about application '%s' =- \n\n"
3225 "[Synopsis]\n %s\n\n"
3226 "[Description]\n%s\n",
3228 a
->synopsis
? a
->synopsis
: "Not available",
3229 a
->description
? a
->description
: "Not available");
3234 AST_LIST_UNLOCK(&apps
);
3236 /* we found at least one app? no? */
3237 if (no_registered_app
) {
3238 ast_cli(fd
, "Your application(s) is (are) not registered\n");
3239 return RESULT_FAILURE
;
3242 return RESULT_SUCCESS
;
3245 /*! \brief handle_show_hints: CLI support for listing registred dial plan hints */
3246 static int handle_show_hints(int fd
, int argc
, char *argv
[])
3248 struct ast_hint
*hint
;
3251 struct ast_state_cb
*watcher
;
3253 if (AST_LIST_EMPTY(&hints
)) {
3254 ast_cli(fd
, "There are no registered dialplan hints\n");
3255 return RESULT_SUCCESS
;
3257 /* ... we have hints ... */
3258 ast_cli(fd
, "\n -= Registered Asterisk Dial Plan Hints =-\n");
3259 AST_LIST_LOCK(&hints
);
3260 AST_LIST_TRAVERSE(&hints
, hint
, list
) {
3262 for (watcher
= hint
->callbacks
; watcher
; watcher
= watcher
->next
)
3264 ast_cli(fd
, " %20s@%-20.20s: %-20.20s State:%-15.15s Watchers %2d\n",
3265 ast_get_extension_name(hint
->exten
),
3266 ast_get_context_name(ast_get_extension_context(hint
->exten
)),
3267 ast_get_extension_app(hint
->exten
),
3268 ast_extension_state2str(hint
->laststate
), watchers
);
3271 ast_cli(fd
, "----------------\n");
3272 ast_cli(fd
, "- %d hints registered\n", num
);
3273 AST_LIST_UNLOCK(&hints
);
3274 return RESULT_SUCCESS
;
3277 /*! \brief handle_show_switches: CLI support for listing registred dial plan switches */
3278 static int handle_show_switches(int fd
, int argc
, char *argv
[])
3280 struct ast_switch
*sw
;
3282 AST_LIST_LOCK(&switches
);
3284 if (AST_LIST_EMPTY(&switches
)) {
3285 AST_LIST_UNLOCK(&switches
);
3286 ast_cli(fd
, "There are no registered alternative switches\n");
3287 return RESULT_SUCCESS
;
3290 ast_cli(fd
, "\n -= Registered Asterisk Alternative Switches =-\n");
3291 AST_LIST_TRAVERSE(&switches
, sw
, list
)
3292 ast_cli(fd
, "%s: %s\n", sw
->name
, sw
->description
);
3294 AST_LIST_UNLOCK(&switches
);
3296 return RESULT_SUCCESS
;
3300 * 'show applications' CLI command implementation functions ...
3302 static int handle_show_applications_deprecated(int fd
, int argc
, char *argv
[])
3305 int like
= 0, describing
= 0;
3306 int total_match
= 0; /* Number of matches in like clause */
3307 int total_apps
= 0; /* Number of apps registered */
3309 AST_LIST_LOCK(&apps
);
3311 if (AST_LIST_EMPTY(&apps
)) {
3312 ast_cli(fd
, "There are no registered applications\n");
3313 AST_LIST_UNLOCK(&apps
);
3317 /* show applications like <keyword> */
3318 if ((argc
== 4) && (!strcmp(argv
[2], "like"))) {
3320 } else if ((argc
> 3) && (!strcmp(argv
[2], "describing"))) {
3324 /* show applications describing <keyword1> [<keyword2>] [...] */
3325 if ((!like
) && (!describing
)) {
3326 ast_cli(fd
, " -= Registered Asterisk Applications =-\n");
3328 ast_cli(fd
, " -= Matching Asterisk Applications =-\n");
3331 AST_LIST_TRAVERSE(&apps
, a
, list
) {
3335 if (strcasestr(a
->name
, argv
[3])) {
3339 } else if (describing
) {
3340 if (a
->description
) {
3341 /* Match all words on command line */
3344 for (i
= 3; i
< argc
; i
++) {
3345 if (!strcasestr(a
->description
, argv
[i
])) {
3357 ast_cli(fd
," %20s: %s\n", a
->name
, a
->synopsis
? a
->synopsis
: "<Synopsis not available>");
3360 if ((!like
) && (!describing
)) {
3361 ast_cli(fd
, " -= %d Applications Registered =-\n",total_apps
);
3363 ast_cli(fd
, " -= %d Applications Matching =-\n",total_match
);
3366 AST_LIST_UNLOCK(&apps
);
3368 return RESULT_SUCCESS
;
3370 static int handle_show_applications(int fd
, int argc
, char *argv
[])
3373 int like
= 0, describing
= 0;
3374 int total_match
= 0; /* Number of matches in like clause */
3375 int total_apps
= 0; /* Number of apps registered */
3377 AST_LIST_LOCK(&apps
);
3379 if (AST_LIST_EMPTY(&apps
)) {
3380 ast_cli(fd
, "There are no registered applications\n");
3381 AST_LIST_UNLOCK(&apps
);
3385 /* core list applications like <keyword> */
3386 if ((argc
== 5) && (!strcmp(argv
[3], "like"))) {
3388 } else if ((argc
> 4) && (!strcmp(argv
[3], "describing"))) {
3392 /* core list applications describing <keyword1> [<keyword2>] [...] */
3393 if ((!like
) && (!describing
)) {
3394 ast_cli(fd
, " -= Registered Asterisk Applications =-\n");
3396 ast_cli(fd
, " -= Matching Asterisk Applications =-\n");
3399 AST_LIST_TRAVERSE(&apps
, a
, list
) {
3403 if (strcasestr(a
->name
, argv
[4])) {
3407 } else if (describing
) {
3408 if (a
->description
) {
3409 /* Match all words on command line */
3412 for (i
= 4; i
< argc
; i
++) {
3413 if (!strcasestr(a
->description
, argv
[i
])) {
3425 ast_cli(fd
," %20s: %s\n", a
->name
, a
->synopsis
? a
->synopsis
: "<Synopsis not available>");
3428 if ((!like
) && (!describing
)) {
3429 ast_cli(fd
, " -= %d Applications Registered =-\n",total_apps
);
3431 ast_cli(fd
, " -= %d Applications Matching =-\n",total_match
);
3434 AST_LIST_UNLOCK(&apps
);
3436 return RESULT_SUCCESS
;
3439 static char *complete_show_applications_deprecated(const char *line
, const char *word
, int pos
, int state
)
3441 static char* choices
[] = { "like", "describing", NULL
};
3443 return (pos
!= 2) ? NULL
: ast_cli_complete(word
, choices
, state
);
3446 static char *complete_show_applications(const char *line
, const char *word
, int pos
, int state
)
3448 static char* choices
[] = { "like", "describing", NULL
};
3450 return (pos
!= 3) ? NULL
: ast_cli_complete(word
, choices
, state
);
3454 * 'show dialplan' CLI command implementation functions ...
3456 static char *complete_show_dialplan_context(const char *line
, const char *word
, int pos
,
3459 struct ast_context
*c
= NULL
;
3464 /* we are do completion of [exten@]context on second position only */
3468 ast_rdlock_contexts();
3470 wordlen
= strlen(word
);
3472 /* walk through all contexts and return the n-th match */
3473 while ( (c
= ast_walk_contexts(c
)) ) {
3474 if (!strncasecmp(word
, ast_get_context_name(c
), wordlen
) && ++which
> state
) {
3475 ret
= ast_strdup(ast_get_context_name(c
));
3480 ast_unlock_contexts();
3485 struct dialplan_counters
{
3489 int context_existence
;
3490 int extension_existence
;
3493 /*! \brief helper function to print an extension */
3494 static void print_ext(struct ast_exten
*e
, char * buf
, int buflen
)
3496 int prio
= ast_get_extension_priority(e
);
3497 if (prio
== PRIORITY_HINT
) {
3498 snprintf(buf
, buflen
, "hint: %s",
3499 ast_get_extension_app(e
));
3501 snprintf(buf
, buflen
, "%d. %s(%s)",
3502 prio
, ast_get_extension_app(e
),
3503 (!ast_strlen_zero(ast_get_extension_app_data(e
)) ? (char *)ast_get_extension_app_data(e
) : ""));
3507 /* XXX not verified */
3508 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
[])
3510 struct ast_context
*c
= NULL
;
3511 int res
= 0, old_total_exten
= dpc
->total_exten
;
3513 ast_rdlock_contexts();
3515 /* walk all contexts ... */
3516 while ( (c
= ast_walk_contexts(c
)) ) {
3517 struct ast_exten
*e
;
3518 struct ast_include
*i
;
3519 struct ast_ignorepat
*ip
;
3520 char buf
[256], buf2
[256];
3521 int context_info_printed
= 0;
3523 if (context
&& strcmp(ast_get_context_name(c
), context
))
3524 continue; /* skip this one, name doesn't match */
3526 dpc
->context_existence
= 1;
3528 ast_lock_context(c
);
3530 /* are we looking for exten too? if yes, we print context
3531 * only if we find our extension.
3532 * Otherwise print context even if empty ?
3533 * XXX i am not sure how the rinclude is handled.
3534 * I think it ought to go inside.
3537 dpc
->total_context
++;
3538 ast_cli(fd
, "[ Context '%s' created by '%s' ]\n",
3539 ast_get_context_name(c
), ast_get_context_registrar(c
));
3540 context_info_printed
= 1;
3543 /* walk extensions ... */
3545 while ( (e
= ast_walk_context_extensions(c
, e
)) ) {
3546 struct ast_exten
*p
;
3548 if (exten
&& !ast_extension_match(ast_get_extension_name(e
), exten
))
3549 continue; /* skip, extension match failed */
3551 dpc
->extension_existence
= 1;
3553 /* may we print context info? */
3554 if (!context_info_printed
) {
3555 dpc
->total_context
++;
3556 if (rinclude
) { /* TODO Print more info about rinclude */
3557 ast_cli(fd
, "[ Included context '%s' created by '%s' ]\n",
3558 ast_get_context_name(c
), ast_get_context_registrar(c
));
3560 ast_cli(fd
, "[ Context '%s' created by '%s' ]\n",
3561 ast_get_context_name(c
), ast_get_context_registrar(c
));
3563 context_info_printed
= 1;
3567 /* write extension name and first peer */
3568 snprintf(buf
, sizeof(buf
), "'%s' =>", ast_get_extension_name(e
));
3570 print_ext(e
, buf2
, sizeof(buf2
));
3572 ast_cli(fd
, " %-17s %-45s [%s]\n", buf
, buf2
,
3573 ast_get_extension_registrar(e
));
3576 /* walk next extension peers */
3577 p
= e
; /* skip the first one, we already got it */
3578 while ( (p
= ast_walk_extension_priorities(e
, p
)) ) {
3579 const char *el
= ast_get_extension_label(p
);
3582 snprintf(buf
, sizeof(buf
), " [%s]", el
);
3585 print_ext(p
, buf2
, sizeof(buf2
));
3587 ast_cli(fd
," %-17s %-45s [%s]\n", buf
, buf2
,
3588 ast_get_extension_registrar(p
));
3592 /* walk included and write info ... */
3594 while ( (i
= ast_walk_context_includes(c
, i
)) ) {
3595 snprintf(buf
, sizeof(buf
), "'%s'", ast_get_include_name(i
));
3597 /* Check all includes for the requested extension */
3598 if (includecount
>= AST_PBX_MAX_STACK
) {
3599 ast_log(LOG_NOTICE
, "Maximum include depth exceeded!\n");
3603 for (x
=0;x
<includecount
;x
++) {
3604 if (!strcasecmp(includes
[x
], ast_get_include_name(i
))) {
3610 includes
[includecount
] = ast_get_include_name(i
);
3611 show_dialplan_helper(fd
, ast_get_include_name(i
), exten
, dpc
, i
, includecount
+ 1, includes
);
3613 ast_log(LOG_WARNING
, "Avoiding circular include of %s within %s\n", ast_get_include_name(i
), context
);
3617 ast_cli(fd
, " Include => %-45s [%s]\n",
3618 buf
, ast_get_include_registrar(i
));
3622 /* walk ignore patterns and write info ... */
3624 while ( (ip
= ast_walk_context_ignorepats(c
, ip
)) ) {
3625 const char *ipname
= ast_get_ignorepat_name(ip
);
3626 char ignorepat
[AST_MAX_EXTENSION
];
3627 snprintf(buf
, sizeof(buf
), "'%s'", ipname
);
3628 snprintf(ignorepat
, sizeof(ignorepat
), "_%s.", ipname
);
3629 if (!exten
|| ast_extension_match(ignorepat
, exten
)) {
3630 ast_cli(fd
, " Ignore pattern => %-45s [%s]\n",
3631 buf
, ast_get_ignorepat_registrar(ip
));
3635 struct ast_sw
*sw
= NULL
;
3636 while ( (sw
= ast_walk_context_switches(c
, sw
)) ) {
3637 snprintf(buf
, sizeof(buf
), "'%s/%s'",
3638 ast_get_switch_name(sw
),
3639 ast_get_switch_data(sw
));
3640 ast_cli(fd
, " Alt. Switch => %-45s [%s]\n",
3641 buf
, ast_get_switch_registrar(sw
));
3645 ast_unlock_context(c
);
3647 /* if we print something in context, make an empty line */
3648 if (context_info_printed
)
3649 ast_cli(fd
, "\r\n");
3651 ast_unlock_contexts();
3653 return (dpc
->total_exten
== old_total_exten
) ? -1 : res
;
3656 static int handle_show_dialplan(int fd
, int argc
, char *argv
[])
3658 char *exten
= NULL
, *context
= NULL
;
3659 /* Variables used for different counters */
3660 struct dialplan_counters counters
;
3662 const char *incstack
[AST_PBX_MAX_STACK
];
3663 memset(&counters
, 0, sizeof(counters
));
3665 if (argc
!= 2 && argc
!= 3)
3666 return RESULT_SHOWUSAGE
;
3668 /* we obtain [exten@]context? if yes, split them ... */
3670 if (strchr(argv
[2], '@')) { /* split into exten & context */
3671 context
= ast_strdupa(argv
[2]);
3672 exten
= strsep(&context
, "@");
3673 /* change empty strings to NULL */
3674 if (ast_strlen_zero(exten
))
3676 } else { /* no '@' char, only context given */
3679 if (ast_strlen_zero(context
))
3682 /* else Show complete dial plan, context and exten are NULL */
3683 show_dialplan_helper(fd
, context
, exten
, &counters
, NULL
, 0, incstack
);
3685 /* check for input failure and throw some error messages */
3686 if (context
&& !counters
.context_existence
) {
3687 ast_cli(fd
, "There is no existence of '%s' context\n", context
);
3688 return RESULT_FAILURE
;
3691 if (exten
&& !counters
.extension_existence
) {
3693 ast_cli(fd
, "There is no existence of %s@%s extension\n",
3697 "There is no existence of '%s' extension in all contexts\n",
3699 return RESULT_FAILURE
;
3702 ast_cli(fd
,"-= %d %s (%d %s) in %d %s. =-\n",
3703 counters
.total_exten
, counters
.total_exten
== 1 ? "extension" : "extensions",
3704 counters
.total_prio
, counters
.total_prio
== 1 ? "priority" : "priorities",
3705 counters
.total_context
, counters
.total_context
== 1 ? "context" : "contexts");
3708 return RESULT_SUCCESS
;
3711 /*! \brief CLI support for listing global variables in a parseable way */
3712 static int handle_show_globals(int fd
, int argc
, char *argv
[])
3715 struct ast_var_t
*newvariable
;
3717 ast_mutex_lock(&globalslock
);
3718 AST_LIST_TRAVERSE (&globals
, newvariable
, entries
) {
3720 ast_cli(fd
, " %s=%s\n", ast_var_name(newvariable
), ast_var_value(newvariable
));
3722 ast_mutex_unlock(&globalslock
);
3723 ast_cli(fd
, "\n -- %d variables\n", i
);
3725 return RESULT_SUCCESS
;
3728 /*! \brief CLI support for setting global variables */
3729 static int handle_set_global_deprecated(int fd
, int argc
, char *argv
[])
3732 return RESULT_SHOWUSAGE
;
3734 pbx_builtin_setvar_helper(NULL
, argv
[2], argv
[3]);
3735 ast_cli(fd
, "\n -- Global variable %s set to %s\n", argv
[2], argv
[3]);
3737 return RESULT_SUCCESS
;
3741 static int handle_set_global(int fd
, int argc
, char *argv
[])
3744 return RESULT_SHOWUSAGE
;
3746 pbx_builtin_setvar_helper(NULL
, argv
[3], argv
[4]);
3747 ast_cli(fd
, "\n -- Global variable %s set to %s\n", argv
[3], argv
[4]);
3749 return RESULT_SUCCESS
;
3755 * CLI entries for upper commands ...
3757 static struct ast_cli_entry cli_show_applications_deprecated
= {
3758 { "show", "applications", NULL
},
3759 handle_show_applications_deprecated
, NULL
,
3760 NULL
, complete_show_applications_deprecated
};
3762 static struct ast_cli_entry cli_show_functions_deprecated
= {
3763 { "show", "functions", NULL
},
3764 handle_show_functions_deprecated
, NULL
,
3767 static struct ast_cli_entry cli_show_switches_deprecated
= {
3768 { "show", "switches", NULL
},
3769 handle_show_switches
, NULL
,
3772 static struct ast_cli_entry cli_show_hints_deprecated
= {
3773 { "show", "hints", NULL
},
3774 handle_show_hints
, NULL
,
3777 static struct ast_cli_entry cli_show_globals_deprecated
= {
3778 { "show", "globals", NULL
},
3779 handle_show_globals
, NULL
,
3782 static struct ast_cli_entry cli_show_function_deprecated
= {
3783 { "show" , "function", NULL
},
3784 handle_show_function_deprecated
, NULL
,
3785 NULL
, complete_show_function
};
3787 static struct ast_cli_entry cli_show_application_deprecated
= {
3788 { "show", "application", NULL
},
3789 handle_show_application_deprecated
, NULL
,
3790 NULL
, complete_show_application
};
3792 static struct ast_cli_entry cli_show_dialplan_deprecated
= {
3793 { "show", "dialplan", NULL
},
3794 handle_show_dialplan
, NULL
,
3795 NULL
, complete_show_dialplan_context
};
3797 static struct ast_cli_entry cli_set_global_deprecated
= {
3798 { "set", "global", NULL
},
3799 handle_set_global_deprecated
, NULL
,
3802 static struct ast_cli_entry pbx_cli
[] = {
3803 { { "core", "show", "applications", NULL
},
3804 handle_show_applications
, "Shows registered dialplan applications",
3805 show_applications_help
, complete_show_applications
, &cli_show_applications_deprecated
},
3807 { { "core", "show", "functions", NULL
},
3808 handle_show_functions
, "Shows registered dialplan functions",
3809 show_functions_help
, NULL
, &cli_show_functions_deprecated
},
3811 { { "core", "show", "switches", NULL
},
3812 handle_show_switches
, "Show alternative switches",
3813 show_switches_help
, NULL
, &cli_show_switches_deprecated
},
3815 { { "core", "show", "hints", NULL
},
3816 handle_show_hints
, "Show dialplan hints",
3817 show_hints_help
, NULL
, &cli_show_hints_deprecated
},
3819 { { "core", "show", "globals", NULL
},
3820 handle_show_globals
, "Show global dialplan variables",
3821 show_globals_help
, NULL
, &cli_show_globals_deprecated
},
3823 { { "core", "show" , "function", NULL
},
3824 handle_show_function
, "Describe a specific dialplan function",
3825 show_function_help
, complete_show_function
, &cli_show_function_deprecated
},
3827 { { "core", "show", "application", NULL
},
3828 handle_show_application
, "Describe a specific dialplan application",
3829 show_application_help
, complete_show_application
, &cli_show_application_deprecated
},
3831 { { "core", "set", "global", NULL
},
3832 handle_set_global
, "Set global dialplan variable",
3833 set_global_help
, NULL
, &cli_set_global_deprecated
},
3835 { { "dialplan", "show", NULL
},
3836 handle_show_dialplan
, "Show dialplan",
3837 show_dialplan_help
, complete_show_dialplan_context
, &cli_show_dialplan_deprecated
},
3840 int ast_unregister_application(const char *app
)
3842 struct ast_app
*tmp
;
3844 AST_LIST_LOCK(&apps
);
3845 AST_LIST_TRAVERSE_SAFE_BEGIN(&apps
, tmp
, list
) {
3846 if (!strcasecmp(app
, tmp
->name
)) {
3847 AST_LIST_REMOVE_CURRENT(&apps
, list
);
3848 if (option_verbose
> 1)
3849 ast_verbose( VERBOSE_PREFIX_2
"Unregistered application '%s'\n", tmp
->name
);
3854 AST_LIST_TRAVERSE_SAFE_END
3855 AST_LIST_UNLOCK(&apps
);
3857 return tmp
? 0 : -1;
3860 static struct ast_context
*__ast_context_create(struct ast_context
**extcontexts
, const char *name
, const char *registrar
, int existsokay
)
3862 struct ast_context
*tmp
, **local_contexts
;
3863 int length
= sizeof(struct ast_context
) + strlen(name
) + 1;
3866 ast_rdlock_contexts();
3867 local_contexts
= &contexts
;
3869 local_contexts
= extcontexts
;
3871 for (tmp
= *local_contexts
; tmp
; tmp
= tmp
->next
) {
3872 if (!strcasecmp(tmp
->name
, name
)) {
3874 ast_log(LOG_WARNING
, "Tried to register context '%s', already in use\n", name
);
3878 ast_unlock_contexts();
3884 ast_unlock_contexts();
3886 if ((tmp
= ast_calloc(1, length
))) {
3887 ast_mutex_init(&tmp
->lock
);
3888 ast_mutex_init(&tmp
->macrolock
);
3889 strcpy(tmp
->name
, name
);
3890 tmp
->registrar
= registrar
;
3892 ast_wrlock_contexts();
3893 tmp
->next
= *local_contexts
;
3894 *local_contexts
= tmp
;
3896 ast_unlock_contexts();
3898 ast_log(LOG_DEBUG
, "Registered context '%s'\n", tmp
->name
);
3899 if (option_verbose
> 2)
3900 ast_verbose( VERBOSE_PREFIX_3
"Registered extension context '%s'\n", tmp
->name
);
3906 struct ast_context
*ast_context_create(struct ast_context
**extcontexts
, const char *name
, const char *registrar
)
3908 return __ast_context_create(extcontexts
, name
, registrar
, 0);
3911 struct ast_context
*ast_context_find_or_create(struct ast_context
**extcontexts
, const char *name
, const char *registrar
)
3913 return __ast_context_create(extcontexts
, name
, registrar
, 1);
3915 void __ast_context_destroy(struct ast_context
*con
, const char *registrar
);
3920 struct ast_state_cb
*callbacks
;
3922 AST_LIST_ENTRY(store_hint
) list
;
3926 AST_LIST_HEAD(store_hints
, store_hint
);
3928 /* XXX this does not check that multiple contexts are merged */
3929 void ast_merge_contexts_and_delete(struct ast_context
**extcontexts
, const char *registrar
)
3931 struct ast_context
*tmp
, *lasttmp
= NULL
;
3932 struct store_hints store
= AST_LIST_HEAD_INIT_VALUE
;
3933 struct store_hint
*this;
3934 struct ast_hint
*hint
;
3935 struct ast_exten
*exten
;
3937 struct ast_state_cb
*thiscb
, *prevcb
;
3939 /* it is very important that this function hold the hint list lock _and_ the conlock
3940 during its operation; not only do we need to ensure that the list of contexts
3941 and extensions does not change, but also that no hint callbacks (watchers) are
3942 added or removed during the merge/delete process
3944 in addition, the locks _must_ be taken in this order, because there are already
3945 other code paths that use this order
3947 ast_wrlock_contexts();
3948 AST_LIST_LOCK(&hints
);
3950 /* preserve all watchers for hints associated with this registrar */
3951 AST_LIST_TRAVERSE(&hints
, hint
, list
) {
3952 if (hint
->callbacks
&& !strcmp(registrar
, hint
->exten
->parent
->registrar
)) {
3953 length
= strlen(hint
->exten
->exten
) + strlen(hint
->exten
->parent
->name
) + 2 + sizeof(*this);
3954 if (!(this = ast_calloc(1, length
)))
3956 this->callbacks
= hint
->callbacks
;
3957 hint
->callbacks
= NULL
;
3958 this->laststate
= hint
->laststate
;
3959 this->context
= this->data
;
3960 strcpy(this->data
, hint
->exten
->parent
->name
);
3961 this->exten
= this->data
+ strlen(this->context
) + 1;
3962 strcpy(this->exten
, hint
->exten
->exten
);
3963 AST_LIST_INSERT_HEAD(&store
, this, list
);
3969 /* XXX remove previous contexts from same registrar */
3971 ast_log(LOG_DEBUG
, "must remove any reg %s\n", registrar
);
3972 __ast_context_destroy(NULL
,registrar
);
3978 /* XXX remove contexts with the same name */
3980 ast_log(LOG_WARNING
, "must remove %s reg %s\n", tmp
->name
, tmp
->registrar
);
3981 __ast_context_destroy(tmp
,tmp
->registrar
);
3987 lasttmp
->next
= contexts
;
3988 contexts
= *extcontexts
;
3989 *extcontexts
= NULL
;
3991 ast_log(LOG_WARNING
, "Requested contexts didn't get merged\n");
3993 /* restore the watchers for hints that can be found; notify those that
3996 while ((this = AST_LIST_REMOVE_HEAD(&store
, list
))) {
3997 struct pbx_find_info q
= { .stacklen
= 0 };
3998 exten
= pbx_find_extension(NULL
, NULL
, &q
, this->context
, this->exten
, PRIORITY_HINT
, NULL
, "", E_MATCH
);
3999 /* Find the hint in the list of hints */
4000 AST_LIST_TRAVERSE(&hints
, hint
, list
) {
4001 if (hint
->exten
== exten
)
4004 if (!exten
|| !hint
) {
4005 /* this hint has been removed, notify the watchers */
4007 thiscb
= this->callbacks
;
4010 thiscb
= thiscb
->next
;
4011 prevcb
->callback(this->context
, this->exten
, AST_EXTENSION_REMOVED
, prevcb
->data
);
4015 thiscb
= this->callbacks
;
4016 while (thiscb
->next
)
4017 thiscb
= thiscb
->next
;
4018 thiscb
->next
= hint
->callbacks
;
4019 hint
->callbacks
= this->callbacks
;
4020 hint
->laststate
= this->laststate
;
4025 AST_LIST_UNLOCK(&hints
);
4026 ast_unlock_contexts();
4033 * EBUSY - can't lock
4034 * ENOENT - no existence of context
4036 int ast_context_add_include(const char *context
, const char *include
, const char *registrar
)
4039 struct ast_context
*c
= find_context_locked(context
);
4042 ret
= ast_context_add_include2(c
, include
, registrar
);
4043 ast_unlock_contexts();
4048 /*! \brief Helper for get_range.
4049 * return the index of the matching entry, starting from 1.
4050 * If names is not supplied, try numeric values.
4052 static int lookup_name(const char *s
, char *const names
[], int max
)
4057 for (i
= 0; names
[i
]; i
++) {
4058 if (!strcasecmp(s
, names
[i
]))
4061 } else if (sscanf(s
, "%d", &i
) == 1 && i
>= 1 && i
<= max
) {
4064 return 0; /* error return */
4067 /*! \brief helper function to return a range up to max (7, 12, 31 respectively).
4068 * names, if supplied, is an array of names that should be mapped to numbers.
4070 static unsigned get_range(char *src
, int max
, char *const names
[], const char *msg
)
4072 int s
, e
; /* start and ending position */
4073 unsigned int mask
= 0;
4075 /* Check for whole range */
4076 if (ast_strlen_zero(src
) || !strcmp(src
, "*")) {
4080 /* Get start and ending position */
4081 char *c
= strchr(src
, '-');
4084 /* Find the start */
4085 s
= lookup_name(src
, names
, max
);
4087 ast_log(LOG_WARNING
, "Invalid %s '%s', assuming none\n", msg
, src
);
4091 if (c
) { /* find end of range */
4092 e
= lookup_name(c
, names
, max
);
4094 ast_log(LOG_WARNING
, "Invalid end %s '%s', assuming none\n", msg
, c
);
4101 /* Fill the mask. Remember that ranges are cyclic */
4102 mask
= 1 << e
; /* initialize with last element */
4115 /*! \brief store a bitmask of valid times, one bit each 2 minute */
4116 static void get_timerange(struct ast_timing
*i
, char *times
)
4124 /* start disabling all times, fill the fields with 0's, as they may contain garbage */
4125 memset(i
->minmask
, 0, sizeof(i
->minmask
));
4127 /* 2-minutes per bit, since the mask has only 32 bits :( */
4128 /* Star is all times */
4129 if (ast_strlen_zero(times
) || !strcmp(times
, "*")) {
4130 for (x
=0; x
<24; x
++)
4131 i
->minmask
[x
] = 0x3fffffff; /* 30 bits */
4134 /* Otherwise expect a range */
4135 e
= strchr(times
, '-');
4137 ast_log(LOG_WARNING
, "Time range is not valid. Assuming no restrictions based on time.\n");
4141 /* XXX why skip non digits ? */
4142 while (*e
&& !isdigit(*e
))
4145 ast_log(LOG_WARNING
, "Invalid time range. Assuming no restrictions based on time.\n");
4148 if (sscanf(times
, "%d:%d", &s1
, &s2
) != 2) {
4149 ast_log(LOG_WARNING
, "%s isn't a time. Assuming no restrictions based on time.\n", times
);
4152 if (sscanf(e
, "%d:%d", &e1
, &e2
) != 2) {
4153 ast_log(LOG_WARNING
, "%s isn't a time. Assuming no restrictions based on time.\n", e
);
4156 /* XXX this needs to be optimized */
4158 s1
= s1
* 30 + s2
/2;
4159 if ((s1
< 0) || (s1
>= 24*30)) {
4160 ast_log(LOG_WARNING
, "%s isn't a valid start time. Assuming no time.\n", times
);
4163 e1
= e1
* 30 + e2
/2;
4164 if ((e1
< 0) || (e1
>= 24*30)) {
4165 ast_log(LOG_WARNING
, "%s isn't a valid end time. Assuming no time.\n", e
);
4168 /* Go through the time and enable each appropriate bit */
4169 for (x
=s1
;x
!= e1
;x
= (x
+ 1) % (24 * 30)) {
4170 i
->minmask
[x
/30] |= (1 << (x
% 30));
4172 /* Do the last one */
4173 i
->minmask
[x
/30] |= (1 << (x
% 30));
4175 for (cth
=0; cth
<24; cth
++) {
4176 /* Initialize masks to blank */
4177 i
->minmask
[cth
] = 0;
4178 for (ctm
=0; ctm
<30; ctm
++) {
4180 /* First hour with more than one hour */
4181 (((cth
== s1
) && (ctm
>= s2
)) &&
4184 || (((cth
== s1
) && (ctm
>= s2
)) &&
4185 ((cth
== e1
) && (ctm
<= e2
)))
4186 /* In between first and last hours (more than 2 hours) */
4189 /* Last hour with more than one hour */
4191 ((cth
== e1
) && (ctm
<= e2
)))
4193 i
->minmask
[cth
] |= (1 << (ctm
/ 2));
4201 static char *days
[] =
4213 static char *months
[] =
4230 int ast_build_timing(struct ast_timing
*i
, const char *info_in
)
4232 char info_save
[256];
4235 /* Check for empty just in case */
4236 if (ast_strlen_zero(info_in
))
4238 /* make a copy just in case we were passed a static string */
4239 ast_copy_string(info_save
, info_in
, sizeof(info_save
));
4241 /* Assume everything except time */
4242 i
->monthmask
= 0xfff; /* 12 bits */
4243 i
->daymask
= 0x7fffffffU
; /* 31 bits */
4244 i
->dowmask
= 0x7f; /* 7 bits */
4245 /* on each call, use strsep() to move info to the next argument */
4246 get_timerange(i
, strsep(&info
, "|"));
4248 i
->dowmask
= get_range(strsep(&info
, "|"), 7, days
, "day of week");
4250 i
->daymask
= get_range(strsep(&info
, "|"), 31, NULL
, "day");
4252 i
->monthmask
= get_range(strsep(&info
, "|"), 12, months
, "month");
4256 int ast_check_timing(const struct ast_timing
*i
)
4259 time_t t
= time(NULL
);
4261 ast_localtime(&t
, &tm
, NULL
);
4263 /* If it's not the right month, return */
4264 if (!(i
->monthmask
& (1 << tm
.tm_mon
)))
4267 /* If it's not that time of the month.... */
4268 /* Warning, tm_mday has range 1..31! */
4269 if (!(i
->daymask
& (1 << (tm
.tm_mday
-1))))
4272 /* If it's not the right day of the week */
4273 if (!(i
->dowmask
& (1 << tm
.tm_wday
)))
4276 /* Sanity check the hour just to be safe */
4277 if ((tm
.tm_hour
< 0) || (tm
.tm_hour
> 23)) {
4278 ast_log(LOG_WARNING
, "Insane time...\n");
4282 /* Now the tough part, we calculate if it fits
4283 in the right time based on min/hour */
4284 if (!(i
->minmask
[tm
.tm_hour
] & (1 << (tm
.tm_min
/ 2))))
4287 /* If we got this far, then we're good */
4293 * ENOMEM - out of memory
4294 * EBUSY - can't lock
4295 * EEXIST - already included
4296 * EINVAL - there is no existence of context for inclusion
4298 int ast_context_add_include2(struct ast_context
*con
, const char *value
,
4299 const char *registrar
)
4301 struct ast_include
*new_include
;
4303 struct ast_include
*i
, *il
= NULL
; /* include, include_last */
4307 length
= sizeof(struct ast_include
);
4308 length
+= 2 * (strlen(value
) + 1);
4310 /* allocate new include structure ... */
4311 if (!(new_include
= ast_calloc(1, length
)))
4313 /* Fill in this structure. Use 'p' for assignments, as the fields
4314 * in the structure are 'const char *'
4316 p
= new_include
->stuff
;
4317 new_include
->name
= p
;
4319 p
+= strlen(value
) + 1;
4320 new_include
->rname
= p
;
4322 /* Strip off timing info, and process if it is there */
4323 if ( (c
= strchr(p
, '|')) ) {
4325 new_include
->hastime
= ast_build_timing(&(new_include
->timing
), c
);
4327 new_include
->next
= NULL
;
4328 new_include
->registrar
= registrar
;
4330 ast_mutex_lock(&con
->lock
);
4332 /* ... go to last include and check if context is already included too... */
4333 for (i
= con
->includes
; i
; i
= i
->next
) {
4334 if (!strcasecmp(i
->name
, new_include
->name
)) {
4336 ast_mutex_unlock(&con
->lock
);
4343 /* ... include new context into context list, unlock, return */
4345 il
->next
= new_include
;
4347 con
->includes
= new_include
;
4348 if (option_verbose
> 2)
4349 ast_verbose(VERBOSE_PREFIX_3
"Including context '%s' in context '%s'\n", new_include
->name
, ast_get_context_name(con
));
4350 ast_mutex_unlock(&con
->lock
);
4357 * EBUSY - can't lock
4358 * ENOENT - no existence of context
4360 int ast_context_add_switch(const char *context
, const char *sw
, const char *data
, int eval
, const char *registrar
)
4363 struct ast_context
*c
= find_context_locked(context
);
4365 if (c
) { /* found, add switch to this context */
4366 ret
= ast_context_add_switch2(c
, sw
, data
, eval
, registrar
);
4367 ast_unlock_contexts();
4374 * ENOMEM - out of memory
4375 * EBUSY - can't lock
4376 * EEXIST - already included
4377 * EINVAL - there is no existence of context for inclusion
4379 int ast_context_add_switch2(struct ast_context
*con
, const char *value
,
4380 const char *data
, int eval
, const char *registrar
)
4382 struct ast_sw
*new_sw
;
4387 length
= sizeof(struct ast_sw
);
4388 length
+= strlen(value
) + 1;
4390 length
+= strlen(data
);
4393 /* Create buffer for evaluation of variables */
4394 length
+= SWITCH_DATA_LENGTH
;
4398 /* allocate new sw structure ... */
4399 if (!(new_sw
= ast_calloc(1, length
)))
4401 /* ... fill in this structure ... */
4404 strcpy(new_sw
->name
, value
);
4405 p
+= strlen(value
) + 1;
4408 strcpy(new_sw
->data
, data
);
4409 p
+= strlen(data
) + 1;
4411 strcpy(new_sw
->data
, "");
4415 new_sw
->tmpdata
= p
;
4416 new_sw
->eval
= eval
;
4417 new_sw
->registrar
= registrar
;
4419 /* ... try to lock this context ... */
4420 ast_mutex_lock(&con
->lock
);
4422 /* ... go to last sw and check if context is already swd too... */
4423 AST_LIST_TRAVERSE(&con
->alts
, i
, list
) {
4424 if (!strcasecmp(i
->name
, new_sw
->name
) && !strcasecmp(i
->data
, new_sw
->data
)) {
4426 ast_mutex_unlock(&con
->lock
);
4432 /* ... sw new context into context list, unlock, return */
4433 AST_LIST_INSERT_TAIL(&con
->alts
, new_sw
, list
);
4435 if (option_verbose
> 2)
4436 ast_verbose(VERBOSE_PREFIX_3
"Including switch '%s/%s' in context '%s'\n", new_sw
->name
, new_sw
->data
, ast_get_context_name(con
));
4438 ast_mutex_unlock(&con
->lock
);
4444 * EBUSY - can't lock
4445 * ENOENT - there is not context existence
4447 int ast_context_remove_ignorepat(const char *context
, const char *ignorepat
, const char *registrar
)
4450 struct ast_context
*c
= find_context_locked(context
);
4453 ret
= ast_context_remove_ignorepat2(c
, ignorepat
, registrar
);
4454 ast_unlock_contexts();
4459 int ast_context_remove_ignorepat2(struct ast_context
*con
, const char *ignorepat
, const char *registrar
)
4461 struct ast_ignorepat
*ip
, *ipl
= NULL
;
4463 ast_mutex_lock(&con
->lock
);
4465 for (ip
= con
->ignorepats
; ip
; ip
= ip
->next
) {
4466 if (!strcmp(ip
->pattern
, ignorepat
) &&
4467 (!registrar
|| (registrar
== ip
->registrar
))) {
4469 ipl
->next
= ip
->next
;
4472 con
->ignorepats
= ip
->next
;
4475 ast_mutex_unlock(&con
->lock
);
4481 ast_mutex_unlock(&con
->lock
);
4487 * EBUSY - can't lock
4488 * ENOENT - there is no existence of context
4490 int ast_context_add_ignorepat(const char *context
, const char *value
, const char *registrar
)
4493 struct ast_context
*c
= find_context_locked(context
);
4496 ret
= ast_context_add_ignorepat2(c
, value
, registrar
);
4497 ast_unlock_contexts();
4502 int ast_context_add_ignorepat2(struct ast_context
*con
, const char *value
, const char *registrar
)
4504 struct ast_ignorepat
*ignorepat
, *ignorepatc
, *ignorepatl
= NULL
;
4506 length
= sizeof(struct ast_ignorepat
);
4507 length
+= strlen(value
) + 1;
4508 if (!(ignorepat
= ast_calloc(1, length
)))
4510 /* The cast to char * is because we need to write the initial value.
4511 * The field is not supposed to be modified otherwise
4513 strcpy((char *)ignorepat
->pattern
, value
);
4514 ignorepat
->next
= NULL
;
4515 ignorepat
->registrar
= registrar
;
4516 ast_mutex_lock(&con
->lock
);
4517 for (ignorepatc
= con
->ignorepats
; ignorepatc
; ignorepatc
= ignorepatc
->next
) {
4518 ignorepatl
= ignorepatc
;
4519 if (!strcasecmp(ignorepatc
->pattern
, value
)) {
4521 ast_mutex_unlock(&con
->lock
);
4527 ignorepatl
->next
= ignorepat
;
4529 con
->ignorepats
= ignorepat
;
4530 ast_mutex_unlock(&con
->lock
);
4535 int ast_ignore_pattern(const char *context
, const char *pattern
)
4537 struct ast_context
*con
= ast_context_find(context
);
4539 struct ast_ignorepat
*pat
;
4540 for (pat
= con
->ignorepats
; pat
; pat
= pat
->next
) {
4541 if (ast_extension_match(pat
->pattern
, pattern
))
4550 * EBUSY - can't lock
4551 * ENOENT - no existence of context
4554 int ast_add_extension(const char *context
, int replace
, const char *extension
,
4555 int priority
, const char *label
, const char *callerid
,
4556 const char *application
, void *data
, void (*datad
)(void *), const char *registrar
)
4559 struct ast_context
*c
= find_context_locked(context
);
4562 ret
= ast_add_extension2(c
, replace
, extension
, priority
, label
, callerid
,
4563 application
, data
, datad
, registrar
);
4564 ast_unlock_contexts();
4569 int ast_explicit_goto(struct ast_channel
*chan
, const char *context
, const char *exten
, int priority
)
4574 ast_channel_lock(chan
);
4576 if (!ast_strlen_zero(context
))
4577 ast_copy_string(chan
->context
, context
, sizeof(chan
->context
));
4578 if (!ast_strlen_zero(exten
))
4579 ast_copy_string(chan
->exten
, exten
, sizeof(chan
->exten
));
4580 if (priority
> -1) {
4581 chan
->priority
= priority
;
4582 /* see flag description in channel.h for explanation */
4583 if (ast_test_flag(chan
, AST_FLAG_IN_AUTOLOOP
))
4587 ast_channel_unlock(chan
);
4592 int ast_async_goto(struct ast_channel
*chan
, const char *context
, const char *exten
, int priority
)
4596 ast_channel_lock(chan
);
4598 if (chan
->pbx
) { /* This channel is currently in the PBX */
4599 ast_explicit_goto(chan
, context
, exten
, priority
);
4600 ast_softhangup_nolock(chan
, AST_SOFTHANGUP_ASYNCGOTO
);
4602 /* In order to do it when the channel doesn't really exist within
4603 the PBX, we have to make a new channel, masquerade, and start the PBX
4604 at the new location */
4605 struct ast_channel
*tmpchan
= ast_channel_alloc(0, chan
->_state
, 0, 0, chan
->accountcode
, chan
->exten
, chan
->context
, chan
->amaflags
, "AsyncGoto/%s", chan
->name
);
4607 ast_cdr_discard(tmpchan
->cdr
);
4608 tmpchan
->cdr
= ast_cdr_dup(chan
->cdr
); /* share the love */
4613 /* Make formats okay */
4614 tmpchan
->readformat
= chan
->readformat
;
4615 tmpchan
->writeformat
= chan
->writeformat
;
4616 /* Setup proper location */
4617 ast_explicit_goto(tmpchan
,
4618 S_OR(context
, chan
->context
), S_OR(exten
, chan
->exten
), priority
);
4620 /* Masquerade into temp channel */
4621 ast_channel_masquerade(tmpchan
, chan
);
4623 /* Grab the locks and get going */
4624 ast_channel_lock(tmpchan
);
4625 ast_do_masquerade(tmpchan
);
4626 ast_channel_unlock(tmpchan
);
4627 /* Start the PBX going on our stolen channel */
4628 if (ast_pbx_start(tmpchan
)) {
4629 ast_log(LOG_WARNING
, "Unable to start PBX on %s\n", tmpchan
->name
);
4630 ast_hangup(tmpchan
);
4635 ast_channel_unlock(chan
);
4639 int ast_async_goto_by_name(const char *channame
, const char *context
, const char *exten
, int priority
)
4641 struct ast_channel
*chan
;
4644 chan
= ast_get_channel_by_name_locked(channame
);
4646 res
= ast_async_goto(chan
, context
, exten
, priority
);
4647 ast_channel_unlock(chan
);
4652 /*! \brief copy a string skipping whitespace */
4653 static int ext_strncpy(char *dst
, const char *src
, int len
)
4657 while (*src
&& (count
< len
- 1)) {
4660 /* otherwise exten => [a-b],1,... doesn't work */
4676 /*! \brief add the extension in the priority chain.
4677 * returns 0 on success, -1 on failure
4679 static int add_pri(struct ast_context
*con
, struct ast_exten
*tmp
,
4680 struct ast_exten
*el
, struct ast_exten
*e
, int replace
)
4682 struct ast_exten
*ep
;
4684 for (ep
= NULL
; e
; ep
= e
, e
= e
->peer
) {
4685 if (e
->priority
>= tmp
->priority
)
4688 if (!e
) { /* go at the end, and ep is surely set because the list is not empty */
4690 return 0; /* success */
4692 if (e
->priority
== tmp
->priority
) {
4693 /* Can't have something exactly the same. Is this a
4694 replacement? If so, replace, otherwise, bonk. */
4696 ast_log(LOG_WARNING
, "Unable to register extension '%s', priority %d in '%s', already in use\n", tmp
->exten
, tmp
->priority
, con
->name
);
4698 tmp
->datad(tmp
->data
);
4702 /* we are replacing e, so copy the link fields and then update
4703 * whoever pointed to e to point to us
4705 tmp
->next
= e
->next
; /* not meaningful if we are not first in the peer list */
4706 tmp
->peer
= e
->peer
; /* always meaningful */
4707 if (ep
) /* We're in the peer list, just insert ourselves */
4709 else if (el
) /* We're the first extension. Take over e's functions */
4711 else /* We're the very first extension. */
4713 if (tmp
->priority
== PRIORITY_HINT
)
4714 ast_change_hint(e
,tmp
);
4715 /* Destroy the old one */
4719 } else { /* Slip ourselves in just before e */
4721 tmp
->next
= e
->next
; /* extension chain, or NULL if e is not the first extension */
4722 if (ep
) /* Easy enough, we're just in the peer list */
4724 else { /* we are the first in some peer list, so link in the ext list */
4726 el
->next
= tmp
; /* in the middle... */
4728 con
->root
= tmp
; /* ... or at the head */
4729 e
->next
= NULL
; /* e is no more at the head, so e->next must be reset */
4731 /* And immediately return success. */
4732 if (tmp
->priority
== PRIORITY_HINT
)
4739 * Main interface to add extensions to the list for out context.
4741 * We sort extensions in order of matching preference, so that we can
4742 * stop the search as soon as we find a suitable match.
4743 * This ordering also takes care of wildcards such as '.' (meaning
4744 * "one or more of any character") and '!' (which is 'earlymatch',
4745 * meaning "zero or more of any character" but also impacts the
4746 * return value from CANMATCH and EARLYMATCH.
4748 * The extension match rules defined in the devmeeting 2006.05.05 are
4749 * quite simple: WE SELECT THE LONGEST MATCH.
4750 * In detail, "longest" means the number of matched characters in
4751 * the extension. In case of ties (e.g. _XXX and 333) in the length
4752 * of a pattern, we give priority to entries with the smallest cardinality
4753 * (e.g, [5-9] comes before [2-8] before the former has only 5 elements,
4754 * while the latter has 7, etc.
4755 * In case of same cardinality, the first element in the range counts.
4756 * If we still have a tie, any final '!' will make this as a possibly
4757 * less specific pattern.
4759 * EBUSY - can't lock
4760 * EEXIST - extension with the same priority exist and no replace is set
4763 int ast_add_extension2(struct ast_context
*con
,
4764 int replace
, const char *extension
, int priority
, const char *label
, const char *callerid
,
4765 const char *application
, void *data
, void (*datad
)(void *),
4766 const char *registrar
)
4769 * Sort extensions (or patterns) according to the rules indicated above.
4770 * These are implemented by the function ext_cmp()).
4771 * All priorities for the same ext/pattern/cid are kept in a list,
4772 * using the 'peer' field as a link field..
4774 struct ast_exten
*tmp
, *e
, *el
= NULL
;
4778 char expand_buf
[VAR_BUF_SIZE
] = { 0, };
4780 /* if we are adding a hint, and there are global variables, and the hint
4781 contains variable references, then expand them
4783 ast_mutex_lock(&globalslock
);
4784 if (priority
== PRIORITY_HINT
&& AST_LIST_FIRST(&globals
) && strstr(application
, "${")) {
4785 pbx_substitute_variables_varshead(&globals
, application
, expand_buf
, sizeof(expand_buf
));
4786 application
= expand_buf
;
4788 ast_mutex_unlock(&globalslock
);
4790 length
= sizeof(struct ast_exten
);
4791 length
+= strlen(extension
) + 1;
4792 length
+= strlen(application
) + 1;
4794 length
+= strlen(label
) + 1;
4796 length
+= strlen(callerid
) + 1;
4798 length
++; /* just the '\0' */
4800 /* Be optimistic: Build the extension structure first */
4801 if (!(tmp
= ast_calloc(1, length
)))
4804 /* use p as dst in assignments, as the fields are const char * */
4809 p
+= strlen(label
) + 1;
4812 p
+= ext_strncpy(p
, extension
, strlen(extension
) + 1) + 1;
4813 tmp
->priority
= priority
;
4814 tmp
->cidmatch
= p
; /* but use p for assignments below */
4816 p
+= ext_strncpy(p
, callerid
, strlen(callerid
) + 1) + 1;
4823 strcpy(p
, application
);
4827 tmp
->registrar
= registrar
;
4829 ast_mutex_lock(&con
->lock
);
4830 res
= 0; /* some compilers will think it is uninitialized otherwise */
4831 for (e
= con
->root
; e
; el
= e
, e
= e
->next
) { /* scan the extension list */
4832 res
= ext_cmp(e
->exten
, extension
);
4833 if (res
== 0) { /* extension match, now look at cidmatch */
4834 if (!e
->matchcid
&& !tmp
->matchcid
)
4836 else if (tmp
->matchcid
&& !e
->matchcid
)
4838 else if (e
->matchcid
&& !tmp
->matchcid
)
4841 res
= strcasecmp(e
->cidmatch
, tmp
->cidmatch
);
4846 if (e
&& res
== 0) { /* exact match, insert in the pri chain */
4847 res
= add_pri(con
, tmp
, el
, e
, replace
);
4848 ast_mutex_unlock(&con
->lock
);
4850 errno
= EEXIST
; /* XXX do we care ? */
4851 return 0; /* XXX should we return -1 maybe ? */
4855 * not an exact match, this is the first entry with this pattern,
4856 * so insert in the main list right before 'e' (if any)
4863 ast_mutex_unlock(&con
->lock
);
4864 if (tmp
->priority
== PRIORITY_HINT
)
4868 if (tmp
->matchcid
) {
4870 ast_log(LOG_DEBUG
, "Added extension '%s' priority %d (CID match '%s') to %s\n",
4871 tmp
->exten
, tmp
->priority
, tmp
->cidmatch
, con
->name
);
4874 ast_log(LOG_DEBUG
, "Added extension '%s' priority %d to %s\n",
4875 tmp
->exten
, tmp
->priority
, con
->name
);
4878 if (option_verbose
> 2) {
4879 if (tmp
->matchcid
) {
4880 ast_verbose( VERBOSE_PREFIX_3
"Added extension '%s' priority %d (CID match '%s')to %s\n",
4881 tmp
->exten
, tmp
->priority
, tmp
->cidmatch
, con
->name
);
4883 ast_verbose( VERBOSE_PREFIX_3
"Added extension '%s' priority %d to %s\n",
4884 tmp
->exten
, tmp
->priority
, con
->name
);
4892 struct ast_channel
*chan
;
4893 char context
[AST_MAX_CONTEXT
];
4894 char exten
[AST_MAX_EXTENSION
];
4897 char app
[AST_MAX_EXTENSION
];
4901 static void *async_wait(void *data
)
4903 struct async_stat
*as
= data
;
4904 struct ast_channel
*chan
= as
->chan
;
4905 int timeout
= as
->timeout
;
4907 struct ast_frame
*f
;
4908 struct ast_app
*app
;
4910 while (timeout
&& (chan
->_state
!= AST_STATE_UP
)) {
4911 res
= ast_waitfor(chan
, timeout
);
4919 if (f
->frametype
== AST_FRAME_CONTROL
) {
4920 if ((f
->subclass
== AST_CONTROL_BUSY
) ||
4921 (f
->subclass
== AST_CONTROL_CONGESTION
) ) {
4928 if (chan
->_state
== AST_STATE_UP
) {
4929 if (!ast_strlen_zero(as
->app
)) {
4930 app
= pbx_findapp(as
->app
);
4932 if (option_verbose
> 2)
4933 ast_verbose(VERBOSE_PREFIX_3
"Launching %s(%s) on %s\n", as
->app
, as
->appdata
, chan
->name
);
4934 pbx_exec(chan
, app
, as
->appdata
);
4936 ast_log(LOG_WARNING
, "No such application '%s'\n", as
->app
);
4938 if (!ast_strlen_zero(as
->context
))
4939 ast_copy_string(chan
->context
, as
->context
, sizeof(chan
->context
));
4940 if (!ast_strlen_zero(as
->exten
))
4941 ast_copy_string(chan
->exten
, as
->exten
, sizeof(chan
->exten
));
4942 if (as
->priority
> 0)
4943 chan
->priority
= as
->priority
;
4945 if (ast_pbx_run(chan
)) {
4946 ast_log(LOG_ERROR
, "Failed to start PBX on %s\n", chan
->name
);
4948 /* PBX will have taken care of this */
4959 /*! Function to post an empty cdr after a spool call fails.
4961 * This function posts an empty cdr for a failed spool call
4964 static int ast_pbx_outgoing_cdr_failed(void)
4966 /* allocate a channel */
4967 struct ast_channel
*chan
= ast_channel_alloc(0, AST_STATE_DOWN
, 0, 0, "", "", "", 0, 0);
4970 return -1; /* failure */
4973 /* allocation of the cdr failed */
4974 ast_channel_free(chan
); /* free the channel */
4975 return -1; /* return failure */
4978 /* allocation of the cdr was successful */
4979 ast_cdr_init(chan
->cdr
, chan
); /* initilize our channel's cdr */
4980 ast_cdr_start(chan
->cdr
); /* record the start and stop time */
4981 ast_cdr_end(chan
->cdr
);
4982 ast_cdr_failed(chan
->cdr
); /* set the status to failed */
4983 ast_cdr_detach(chan
->cdr
); /* post and free the record */
4984 ast_channel_free(chan
); /* free the channel */
4986 return 0; /* success */
4989 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
)
4991 struct ast_channel
*chan
;
4992 struct async_stat
*as
;
4993 int res
= -1, cdr_res
= -1;
4994 struct outgoing_helper oh
;
4995 pthread_attr_t attr
;
4999 chan
= __ast_request_and_dial(type
, format
, data
, timeout
, reason
, cid_num
, cid_name
, &oh
);
5003 ast_channel_lock(chan
);
5006 if (chan
->_state
== AST_STATE_UP
) {
5008 if (option_verbose
> 3)
5009 ast_verbose(VERBOSE_PREFIX_4
"Channel %s was answered.\n", chan
->name
);
5013 ast_channel_unlock(chan
);
5014 if (ast_pbx_run(chan
)) {
5015 ast_log(LOG_ERROR
, "Unable to run PBX on %s\n", chan
->name
);
5022 if (ast_pbx_start(chan
)) {
5023 ast_log(LOG_ERROR
, "Unable to start PBX on %s\n", chan
->name
);
5026 ast_channel_unlock(chan
);
5033 if (option_verbose
> 3)
5034 ast_verbose(VERBOSE_PREFIX_4
"Channel %s was never answered.\n", chan
->name
);
5036 if (chan
->cdr
) { /* update the cdr */
5037 /* here we update the status of the call, which sould be busy.
5038 * if that fails then we set the status to failed */
5039 if (ast_cdr_disposition(chan
->cdr
, chan
->hangupcause
))
5040 ast_cdr_failed(chan
->cdr
);
5045 ast_channel_unlock(chan
);
5051 if (res
< 0) { /* the call failed for some reason */
5052 if (*reason
== 0) { /* if the call failed (not busy or no answer)
5053 * update the cdr with the failed message */
5054 cdr_res
= ast_pbx_outgoing_cdr_failed();
5057 goto outgoing_exten_cleanup
;
5061 /* create a fake channel and execute the "failed" extension (if it exists) within the requested context */
5062 /* check if "failed" exists */
5063 if (ast_exists_extension(chan
, context
, "failed", 1, NULL
)) {
5064 chan
= ast_channel_alloc(0, AST_STATE_DOWN
, 0, 0, "", "", "", 0, "OutgoingSpoolFailed");
5066 char failed_reason
[4] = "";
5067 if (!ast_strlen_zero(context
))
5068 ast_copy_string(chan
->context
, context
, sizeof(chan
->context
));
5069 set_ext_pri(chan
, "failed", 1);
5070 ast_set_variables(chan
, vars
);
5071 snprintf(failed_reason
, sizeof(failed_reason
), "%d", *reason
);
5072 pbx_builtin_setvar_helper(chan
, "REASON", failed_reason
);
5074 ast_cdr_setaccount(chan
, account
);
5080 if (!(as
= ast_calloc(1, sizeof(*as
)))) {
5082 goto outgoing_exten_cleanup
;
5084 chan
= ast_request_and_dial(type
, format
, data
, timeout
, reason
, cid_num
, cid_name
);
5088 ast_channel_lock(chan
);
5093 goto outgoing_exten_cleanup
;
5096 ast_copy_string(as
->context
, context
, sizeof(as
->context
));
5097 set_ext_pri(as
->chan
, exten
, priority
);
5098 as
->timeout
= timeout
;
5099 ast_set_variables(chan
, vars
);
5101 ast_cdr_setaccount(chan
, account
);
5102 pthread_attr_init(&attr
);
5103 pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
5104 if (ast_pthread_create(&as
->p
, &attr
, async_wait
, as
)) {
5105 ast_log(LOG_WARNING
, "Failed to start async wait\n");
5109 ast_channel_unlock(chan
);
5113 pthread_attr_destroy(&attr
);
5114 goto outgoing_exten_cleanup
;
5116 pthread_attr_destroy(&attr
);
5119 outgoing_exten_cleanup
:
5120 ast_variables_destroy(vars
);
5127 struct ast_channel
*chan
;
5131 /*! \brief run the application and free the descriptor once done */
5132 static void *ast_pbx_run_app(void *data
)
5134 struct app_tmp
*tmp
= data
;
5135 struct ast_app
*app
;
5136 app
= pbx_findapp(tmp
->app
);
5138 if (option_verbose
> 3)
5139 ast_verbose(VERBOSE_PREFIX_4
"Launching %s(%s) on %s\n", tmp
->app
, tmp
->data
, tmp
->chan
->name
);
5140 pbx_exec(tmp
->chan
, app
, tmp
->data
);
5142 ast_log(LOG_WARNING
, "No such application '%s'\n", tmp
->app
);
5143 ast_hangup(tmp
->chan
);
5148 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
)
5150 struct ast_channel
*chan
;
5151 struct app_tmp
*tmp
;
5152 int res
= -1, cdr_res
= -1;
5153 struct outgoing_helper oh
;
5154 pthread_attr_t attr
;
5156 memset(&oh
, 0, sizeof(oh
));
5158 oh
.account
= account
;
5161 *locked_channel
= NULL
;
5162 if (ast_strlen_zero(app
)) {
5164 goto outgoing_app_cleanup
;
5167 chan
= __ast_request_and_dial(type
, format
, data
, timeout
, reason
, cid_num
, cid_name
, &oh
);
5169 if (chan
->cdr
) { /* check if the channel already has a cdr record, if not give it one */
5170 ast_log(LOG_WARNING
, "%s already has a call record??\n", chan
->name
);
5172 chan
->cdr
= ast_cdr_alloc(); /* allocate a cdr for the channel */
5174 /* allocation of the cdr failed */
5177 goto outgoing_app_cleanup
;
5179 /* allocation of the cdr was successful */
5180 ast_cdr_init(chan
->cdr
, chan
); /* initilize our channel's cdr */
5181 ast_cdr_start(chan
->cdr
);
5183 ast_set_variables(chan
, vars
);
5185 ast_cdr_setaccount(chan
, account
);
5186 if (chan
->_state
== AST_STATE_UP
) {
5188 if (option_verbose
> 3)
5189 ast_verbose(VERBOSE_PREFIX_4
"Channel %s was answered.\n", chan
->name
);
5190 tmp
= ast_calloc(1, sizeof(*tmp
));
5194 ast_copy_string(tmp
->app
, app
, sizeof(tmp
->app
));
5196 ast_copy_string(tmp
->data
, appdata
, sizeof(tmp
->data
));
5200 ast_channel_unlock(chan
);
5201 ast_pbx_run_app(tmp
);
5203 pthread_attr_init(&attr
);
5204 pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
5206 ast_channel_lock(chan
);
5207 if (ast_pthread_create(&tmp
->t
, &attr
, ast_pbx_run_app
, tmp
)) {
5208 ast_log(LOG_WARNING
, "Unable to spawn execute thread on %s: %s\n", chan
->name
, strerror(errno
));
5211 ast_channel_unlock(chan
);
5216 *locked_channel
= chan
;
5218 pthread_attr_destroy(&attr
);
5222 if (option_verbose
> 3)
5223 ast_verbose(VERBOSE_PREFIX_4
"Channel %s was never answered.\n", chan
->name
);
5224 if (chan
->cdr
) { /* update the cdr */
5225 /* here we update the status of the call, which sould be busy.
5226 * if that fails then we set the status to failed */
5227 if (ast_cdr_disposition(chan
->cdr
, chan
->hangupcause
))
5228 ast_cdr_failed(chan
->cdr
);
5234 if (res
< 0) { /* the call failed for some reason */
5235 if (*reason
== 0) { /* if the call failed (not busy or no answer)
5236 * update the cdr with the failed message */
5237 cdr_res
= ast_pbx_outgoing_cdr_failed();
5240 goto outgoing_app_cleanup
;
5246 struct async_stat
*as
;
5247 if (!(as
= ast_calloc(1, sizeof(*as
)))) {
5249 goto outgoing_app_cleanup
;
5251 chan
= __ast_request_and_dial(type
, format
, data
, timeout
, reason
, cid_num
, cid_name
, &oh
);
5255 goto outgoing_app_cleanup
;
5258 ast_copy_string(as
->app
, app
, sizeof(as
->app
));
5260 ast_copy_string(as
->appdata
, appdata
, sizeof(as
->appdata
));
5261 as
->timeout
= timeout
;
5262 ast_set_variables(chan
, vars
);
5264 ast_cdr_setaccount(chan
, account
);
5265 /* Start a new thread, and get something handling this channel. */
5266 pthread_attr_init(&attr
);
5267 pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
5269 ast_channel_lock(chan
);
5270 if (ast_pthread_create(&as
->p
, &attr
, async_wait
, as
)) {
5271 ast_log(LOG_WARNING
, "Failed to start async wait\n");
5274 ast_channel_unlock(chan
);
5277 pthread_attr_destroy(&attr
);
5278 goto outgoing_app_cleanup
;
5281 *locked_channel
= chan
;
5283 pthread_attr_destroy(&attr
);
5286 outgoing_app_cleanup
:
5287 ast_variables_destroy(vars
);
5291 void __ast_context_destroy(struct ast_context
*con
, const char *registrar
)
5293 struct ast_context
*tmp
, *tmpl
=NULL
;
5294 struct ast_include
*tmpi
;
5296 struct ast_exten
*e
, *el
, *en
;
5297 struct ast_ignorepat
*ipi
;
5299 for (tmp
= contexts
; tmp
; ) {
5300 struct ast_context
*next
; /* next starting point */
5301 for (; tmp
; tmpl
= tmp
, tmp
= tmp
->next
) {
5303 ast_log(LOG_DEBUG
, "check ctx %s %s\n", tmp
->name
, tmp
->registrar
);
5304 if ( (!registrar
|| !strcasecmp(registrar
, tmp
->registrar
)) &&
5305 (!con
|| !strcasecmp(tmp
->name
, con
->name
)) )
5306 break; /* found it */
5308 if (!tmp
) /* not found, we are done */
5310 ast_mutex_lock(&tmp
->lock
);
5312 ast_log(LOG_DEBUG
, "delete ctx %s %s\n", tmp
->name
, tmp
->registrar
);
5318 /* Okay, now we're safe to let it go -- in a sense, we were
5319 ready to let it go as soon as we locked it. */
5320 ast_mutex_unlock(&tmp
->lock
);
5321 for (tmpi
= tmp
->includes
; tmpi
; ) { /* Free includes */
5322 struct ast_include
*tmpil
= tmpi
;
5326 for (ipi
= tmp
->ignorepats
; ipi
; ) { /* Free ignorepats */
5327 struct ast_ignorepat
*ipl
= ipi
;
5331 while ((sw
= AST_LIST_REMOVE_HEAD(&tmp
->alts
, list
)))
5333 for (e
= tmp
->root
; e
;) {
5334 for (en
= e
->peer
; en
;) {
5343 ast_mutex_destroy(&tmp
->lock
);
5345 /* if we have a specific match, we are done, otherwise continue */
5346 tmp
= con
? NULL
: next
;
5350 void ast_context_destroy(struct ast_context
*con
, const char *registrar
)
5352 ast_wrlock_contexts();
5353 __ast_context_destroy(con
,registrar
);
5354 ast_unlock_contexts();
5357 static void wait_for_hangup(struct ast_channel
*chan
, void *data
)
5360 struct ast_frame
*f
;
5363 if (ast_strlen_zero(data
) || (sscanf(data
, "%d", &waittime
) != 1) || (waittime
< 0))
5365 if (waittime
> -1) {
5366 ast_safe_sleep(chan
, waittime
* 1000);
5368 res
= ast_waitfor(chan
, -1);
5378 * \ingroup applications
5380 static int pbx_builtin_progress(struct ast_channel
*chan
, void *data
)
5382 ast_indicate(chan
, AST_CONTROL_PROGRESS
);
5387 * \ingroup applications
5389 static int pbx_builtin_ringing(struct ast_channel
*chan
, void *data
)
5391 ast_indicate(chan
, AST_CONTROL_RINGING
);
5396 * \ingroup applications
5398 static int pbx_builtin_busy(struct ast_channel
*chan
, void *data
)
5400 ast_indicate(chan
, AST_CONTROL_BUSY
);
5401 /* Don't change state of an UP channel, just indicate
5403 if (chan
->_state
!= AST_STATE_UP
)
5404 ast_setstate(chan
, AST_STATE_BUSY
);
5405 wait_for_hangup(chan
, data
);
5410 * \ingroup applications
5412 static int pbx_builtin_congestion(struct ast_channel
*chan
, void *data
)
5414 ast_indicate(chan
, AST_CONTROL_CONGESTION
);
5415 /* Don't change state of an UP channel, just indicate
5416 congestion in audio */
5417 if (chan
->_state
!= AST_STATE_UP
)
5418 ast_setstate(chan
, AST_STATE_BUSY
);
5419 wait_for_hangup(chan
, data
);
5424 * \ingroup applications
5426 static int pbx_builtin_answer(struct ast_channel
*chan
, void *data
)
5431 if (chan
->_state
== AST_STATE_UP
)
5433 else if (!ast_strlen_zero(data
))
5436 res
= ast_answer(chan
);
5441 res
= ast_safe_sleep(chan
, delay
);
5446 AST_APP_OPTIONS(resetcdr_opts
, {
5447 AST_APP_OPTION('w', AST_CDR_FLAG_POSTED
),
5448 AST_APP_OPTION('a', AST_CDR_FLAG_LOCKED
),
5449 AST_APP_OPTION('v', AST_CDR_FLAG_KEEP_VARS
),
5453 * \ingroup applications
5455 static int pbx_builtin_resetcdr(struct ast_channel
*chan
, void *data
)
5458 struct ast_flags flags
= { 0 };
5460 if (!ast_strlen_zero(data
)) {
5461 args
= ast_strdupa(data
);
5462 ast_app_parse_options(resetcdr_opts
, &flags
, NULL
, args
);
5465 ast_cdr_reset(chan
->cdr
, &flags
);
5471 * \ingroup applications
5473 static int pbx_builtin_setamaflags(struct ast_channel
*chan
, void *data
)
5475 /* Copy the AMA Flags as specified */
5476 ast_cdr_setamaflags(chan
, data
? data
: "");
5481 * \ingroup applications
5483 static int pbx_builtin_hangup(struct ast_channel
*chan
, void *data
)
5485 if (!ast_strlen_zero(data
)) {
5489 if ((cause
= ast_str2cause(data
)) > -1) {
5490 chan
->hangupcause
= cause
;
5494 cause
= strtol((const char *) data
, &endptr
, 10);
5495 if (cause
!= 0 || (data
!= endptr
)) {
5496 chan
->hangupcause
= cause
;
5500 ast_log(LOG_NOTICE
, "Invalid cause given to Hangup(): \"%s\"\n", (char *) data
);
5503 if (!chan
->hangupcause
) {
5504 chan
->hangupcause
= AST_CAUSE_NORMAL_CLEARING
;
5511 * \ingroup applications
5513 static int pbx_builtin_gotoiftime(struct ast_channel
*chan
, void *data
)
5517 struct ast_timing timing
;
5519 if (ast_strlen_zero(data
)) {
5520 ast_log(LOG_WARNING
, "GotoIfTime requires an argument:\n <time range>|<days of week>|<days of month>|<months>?[[context|]extension|]priority\n");
5524 ts
= s
= ast_strdupa(data
);
5526 /* Separate the Goto path */
5529 /* struct ast_include include contained garbage here, fixed by zeroing it on get_timerange */
5530 if (ast_build_timing(&timing
, s
) && ast_check_timing(&timing
))
5531 res
= pbx_builtin_goto(chan
, ts
);
5537 * \ingroup applications
5539 static int pbx_builtin_execiftime(struct ast_channel
*chan
, void *data
)
5542 struct ast_timing timing
;
5543 struct ast_app
*app
;
5544 static const char *usage
= "ExecIfTime requires an argument:\n <time range>|<days of week>|<days of month>|<months>?<appname>[|<appargs>]";
5546 if (ast_strlen_zero(data
)) {
5547 ast_log(LOG_WARNING
, "%s\n", usage
);
5551 appname
= ast_strdupa(data
);
5553 s
= strsep(&appname
,"?"); /* Separate the timerange and application name/data */
5554 if (!appname
) { /* missing application */
5555 ast_log(LOG_WARNING
, "%s\n", usage
);
5559 if (!ast_build_timing(&timing
, s
)) {
5560 ast_log(LOG_WARNING
, "Invalid Time Spec: %s\nCorrect usage: %s\n", s
, usage
);
5564 if (!ast_check_timing(&timing
)) /* outside the valid time window, just return */
5567 /* now split appname|appargs */
5568 if ((s
= strchr(appname
, '|')))
5571 if ((app
= pbx_findapp(appname
))) {
5572 return pbx_exec(chan
, app
, S_OR(s
, ""));
5574 ast_log(LOG_WARNING
, "Cannot locate application %s\n", appname
);
5580 * \ingroup applications
5582 static int pbx_builtin_wait(struct ast_channel
*chan
, void *data
)
5587 /* Wait for "n" seconds */
5588 if (data
&& (s
= atof(data
)) > 0) {
5590 return ast_safe_sleep(chan
, ms
);
5596 * \ingroup applications
5598 static int pbx_builtin_waitexten(struct ast_channel
*chan
, void *data
)
5602 struct ast_flags flags
= {0};
5603 char *opts
[1] = { NULL
};
5605 AST_DECLARE_APP_ARGS(args
,
5606 AST_APP_ARG(timeout
);
5607 AST_APP_ARG(options
);
5610 if (!ast_strlen_zero(data
)) {
5611 parse
= ast_strdupa(data
);
5612 AST_STANDARD_APP_ARGS(args
, parse
);
5614 memset(&args
, 0, sizeof(args
));
5617 ast_app_parse_options(waitexten_opts
, &flags
, opts
, args
.options
);
5619 if (ast_test_flag(&flags
, WAITEXTEN_MOH
) && !opts
[0] ) {
5620 ast_log(LOG_WARNING
, "The 'm' option has been specified for WaitExten without a class.\n");
5621 } else if (ast_test_flag(&flags
, WAITEXTEN_MOH
))
5622 ast_indicate_data(chan
, AST_CONTROL_HOLD
, opts
[0], strlen(opts
[0]));
5624 /* Wait for "n" seconds */
5625 if (args
.timeout
&& (sec
= atof(args
.timeout
)) > 0.0)
5628 ms
= chan
->pbx
->rtimeout
* 1000;
5631 res
= ast_waitfordigit(chan
, ms
);
5633 if (ast_exists_extension(chan
, chan
->context
, chan
->exten
, chan
->priority
+ 1, chan
->cid
.cid_num
)) {
5634 if (option_verbose
> 2)
5635 ast_verbose(VERBOSE_PREFIX_3
"Timeout on %s, continuing...\n", chan
->name
);
5636 } else if (chan
->_softhangup
== AST_SOFTHANGUP_TIMEOUT
) {
5637 if (option_verbose
> 2)
5638 ast_verbose(VERBOSE_PREFIX_3
"Call timeout on %s, checking for 'T'\n", chan
->name
);
5640 } else if (ast_exists_extension(chan
, chan
->context
, "t", 1, chan
->cid
.cid_num
)) {
5641 if (option_verbose
> 2)
5642 ast_verbose(VERBOSE_PREFIX_3
"Timeout on %s, going to 't'\n", chan
->name
);
5643 set_ext_pri(chan
, "t", 0); /* 0 will become 1, next time through the loop */
5645 ast_log(LOG_WARNING
, "Timeout but no rule 't' in context '%s'\n", chan
->context
);
5650 if (ast_test_flag(&flags
, WAITEXTEN_MOH
))
5651 ast_indicate(chan
, AST_CONTROL_UNHOLD
);
5657 * \ingroup applications
5659 static int pbx_builtin_background(struct ast_channel
*chan
, void *data
)
5662 struct ast_flags flags
= {0};
5664 AST_DECLARE_APP_ARGS(args
,
5665 AST_APP_ARG(filename
);
5666 AST_APP_ARG(options
);
5668 AST_APP_ARG(context
);
5671 if (ast_strlen_zero(data
)) {
5672 ast_log(LOG_WARNING
, "Background requires an argument (filename)\n");
5676 parse
= ast_strdupa(data
);
5678 AST_STANDARD_APP_ARGS(args
, parse
);
5680 if (ast_strlen_zero(args
.lang
))
5681 args
.lang
= (char *)chan
->language
; /* XXX this is const */
5683 if (ast_strlen_zero(args
.context
))
5684 args
.context
= chan
->context
;
5687 if (!strcasecmp(args
.options
, "skip"))
5688 flags
.flags
= BACKGROUND_SKIP
;
5689 else if (!strcasecmp(args
.options
, "noanswer"))
5690 flags
.flags
= BACKGROUND_NOANSWER
;
5692 ast_app_parse_options(background_opts
, &flags
, NULL
, args
.options
);
5695 /* Answer if need be */
5696 if (chan
->_state
!= AST_STATE_UP
) {
5697 if (ast_test_flag(&flags
, BACKGROUND_SKIP
)) {
5699 } else if (!ast_test_flag(&flags
, BACKGROUND_NOANSWER
)) {
5700 res
= ast_answer(chan
);
5705 char *back
= args
.filename
;
5707 ast_stopstream(chan
); /* Stop anything playing */
5708 /* Stream the list of files */
5709 while (!res
&& (front
= strsep(&back
, "&")) ) {
5710 if ( (res
= ast_streamfile(chan
, front
, args
.lang
)) ) {
5711 ast_log(LOG_WARNING
, "ast_streamfile failed on %s for %s\n", chan
->name
, (char*)data
);
5715 if (ast_test_flag(&flags
, BACKGROUND_PLAYBACK
)) {
5716 res
= ast_waitstream(chan
, "");
5717 } else if (ast_test_flag(&flags
, BACKGROUND_MATCHEXTEN
)) {
5718 res
= ast_waitstream_exten(chan
, args
.context
);
5720 res
= ast_waitstream(chan
, AST_DIGIT_ANY
);
5722 ast_stopstream(chan
);
5725 if (args
.context
!= chan
->context
&& res
) {
5726 snprintf(chan
->exten
, sizeof(chan
->exten
), "%c", res
);
5727 ast_copy_string(chan
->context
, args
.context
, sizeof(chan
->context
));
5735 * \ingroup applications
5737 static int pbx_builtin_goto(struct ast_channel
*chan
, void *data
)
5739 int res
= ast_parseable_goto(chan
, data
);
5740 if (!res
&& (option_verbose
> 2))
5741 ast_verbose( VERBOSE_PREFIX_3
"Goto (%s,%s,%d)\n", chan
->context
,chan
->exten
, chan
->priority
+1);
5746 int pbx_builtin_serialize_variables(struct ast_channel
*chan
, char *buf
, size_t size
)
5748 struct ast_var_t
*variables
;
5749 const char *var
, *val
;
5755 memset(buf
, 0, size
);
5757 ast_channel_lock(chan
);
5759 AST_LIST_TRAVERSE(&chan
->varshead
, variables
, entries
) {
5760 if ((var
=ast_var_name(variables
)) && (val
=ast_var_value(variables
))
5761 /* && !ast_strlen_zero(var) && !ast_strlen_zero(val) */
5763 if (ast_build_string(&buf
, &size
, "%s=%s\n", var
, val
)) {
5764 ast_log(LOG_ERROR
, "Data Buffer Size Exceeded!\n");
5772 ast_channel_unlock(chan
);
5777 const char *pbx_builtin_getvar_helper(struct ast_channel
*chan
, const char *name
)
5779 struct ast_var_t
*variables
;
5780 const char *ret
= NULL
;
5782 struct varshead
*places
[2] = { NULL
, &globals
};
5788 ast_channel_lock(chan
);
5789 places
[0] = &chan
->varshead
;
5792 for (i
= 0; i
< 2; i
++) {
5795 if (places
[i
] == &globals
)
5796 ast_mutex_lock(&globalslock
);
5797 AST_LIST_TRAVERSE(places
[i
], variables
, entries
) {
5798 if (!strcmp(name
, ast_var_name(variables
))) {
5799 ret
= ast_var_value(variables
);
5803 if (places
[i
] == &globals
)
5804 ast_mutex_unlock(&globalslock
);
5810 ast_channel_unlock(chan
);
5815 void pbx_builtin_pushvar_helper(struct ast_channel
*chan
, const char *name
, const char *value
)
5817 struct ast_var_t
*newvariable
;
5818 struct varshead
*headp
;
5820 if (name
[strlen(name
)-1] == ')') {
5821 char *function
= ast_strdupa(name
);
5823 ast_log(LOG_WARNING
, "Cannot push a value onto a function\n");
5824 ast_func_write(chan
, function
, value
);
5829 ast_channel_lock(chan
);
5830 headp
= &chan
->varshead
;
5832 ast_mutex_lock(&globalslock
);
5837 if ((option_verbose
> 1) && (headp
== &globals
))
5838 ast_verbose(VERBOSE_PREFIX_2
"Setting global variable '%s' to '%s'\n", name
, value
);
5839 newvariable
= ast_var_assign(name
, value
);
5840 AST_LIST_INSERT_HEAD(headp
, newvariable
, entries
);
5844 ast_channel_unlock(chan
);
5846 ast_mutex_unlock(&globalslock
);
5849 void pbx_builtin_setvar_helper(struct ast_channel
*chan
, const char *name
, const char *value
)
5851 struct ast_var_t
*newvariable
;
5852 struct varshead
*headp
;
5853 const char *nametail
= name
;
5855 if (name
[strlen(name
)-1] == ')') {
5856 char *function
= ast_strdupa(name
);
5858 ast_func_write(chan
, function
, value
);
5863 ast_channel_lock(chan
);
5864 headp
= &chan
->varshead
;
5866 ast_mutex_lock(&globalslock
);
5870 /* For comparison purposes, we have to strip leading underscores */
5871 if (*nametail
== '_') {
5873 if (*nametail
== '_')
5877 AST_LIST_TRAVERSE (headp
, newvariable
, entries
) {
5878 if (strcasecmp(ast_var_name(newvariable
), nametail
) == 0) {
5879 /* there is already such a variable, delete it */
5880 AST_LIST_REMOVE(headp
, newvariable
, entries
);
5881 ast_var_delete(newvariable
);
5887 if ((option_verbose
> 1) && (headp
== &globals
))
5888 ast_verbose(VERBOSE_PREFIX_2
"Setting global variable '%s' to '%s'\n", name
, value
);
5889 newvariable
= ast_var_assign(name
, value
);
5890 AST_LIST_INSERT_HEAD(headp
, newvariable
, entries
);
5894 ast_channel_unlock(chan
);
5896 ast_mutex_unlock(&globalslock
);
5899 int pbx_builtin_setvar(struct ast_channel
*chan
, void *data
)
5901 char *name
, *value
, *mydata
;
5903 char *argv
[24]; /* this will only support a maximum of 24 variables being set in a single operation */
5907 if (ast_strlen_zero(data
)) {
5908 ast_log(LOG_WARNING
, "Set requires at least one variable name/value pair.\n");
5912 mydata
= ast_strdupa(data
);
5913 argc
= ast_app_separate_args(mydata
, '|', argv
, sizeof(argv
) / sizeof(argv
[0]));
5915 /* check for a trailing flags argument */
5916 if ((argc
> 1) && !strchr(argv
[argc
-1], '=')) {
5918 if (strchr(argv
[argc
], 'g')) {
5919 ast_log(LOG_WARNING
, "The use of the 'g' flag is deprecated. Please use Set(GLOBAL(foo)=bar) instead\n");
5925 ast_log(LOG_WARNING
, "Setting multiple variables at once within Set is deprecated. Please separate each name/value pair into its own line.\n");
5927 for (x
= 0; x
< argc
; x
++) {
5929 if ((value
= strchr(name
, '='))) {
5931 pbx_builtin_setvar_helper((global
) ? NULL
: chan
, name
, value
);
5933 ast_log(LOG_WARNING
, "Ignoring entry '%s' with no = (and not last 'options' entry)\n", name
);
5939 int pbx_builtin_importvar(struct ast_channel
*chan
, void *data
)
5944 char tmp
[VAR_BUF_SIZE
]="";
5946 if (ast_strlen_zero(data
)) {
5947 ast_log(LOG_WARNING
, "Ignoring, since there is no variable to set\n");
5951 value
= ast_strdupa(data
);
5952 name
= strsep(&value
,"=");
5953 channel
= strsep(&value
,"|");
5954 if (channel
&& value
&& name
) { /*! \todo XXX should do !ast_strlen_zero(..) of the args ? */
5955 struct ast_channel
*chan2
= ast_get_channel_by_name_locked(channel
);
5957 char *s
= alloca(strlen(value
) + 4);
5959 sprintf(s
, "${%s}", value
);
5960 pbx_substitute_variables_helper(chan2
, s
, tmp
, sizeof(tmp
) - 1);
5962 ast_channel_unlock(chan2
);
5964 pbx_builtin_setvar_helper(chan
, name
, tmp
);
5970 /*! \todo XXX overwrites data ? */
5971 static int pbx_builtin_setglobalvar(struct ast_channel
*chan
, void *data
)
5974 char *stringp
= data
;
5975 static int dep_warning
= 0;
5977 if (ast_strlen_zero(data
)) {
5978 ast_log(LOG_WARNING
, "Ignoring, since there is no variable to set\n");
5982 name
= strsep(&stringp
, "=");
5986 ast_log(LOG_WARNING
, "SetGlobalVar is deprecated. Please use Set(GLOBAL(%s)=%s) instead.\n", name
, stringp
);
5989 /*! \todo XXX watch out, leading whitespace ? */
5990 pbx_builtin_setvar_helper(NULL
, name
, stringp
);
5995 static int pbx_builtin_noop(struct ast_channel
*chan
, void *data
)
6000 void pbx_builtin_clear_globals(void)
6002 struct ast_var_t
*vardata
;
6004 ast_mutex_lock(&globalslock
);
6005 while ((vardata
= AST_LIST_REMOVE_HEAD(&globals
, entries
)))
6006 ast_var_delete(vardata
);
6007 ast_mutex_unlock(&globalslock
);
6010 int pbx_checkcondition(const char *condition
)
6012 if (ast_strlen_zero(condition
)) /* NULL or empty strings are false */
6014 else if (*condition
>= '0' && *condition
<= '9') /* Numbers are evaluated for truth */
6015 return atoi(condition
);
6016 else /* Strings are true */
6020 static int pbx_builtin_gotoif(struct ast_channel
*chan
, void *data
)
6022 char *condition
, *branch1
, *branch2
, *branch
;
6026 if (ast_strlen_zero(data
)) {
6027 ast_log(LOG_WARNING
, "Ignoring, since there is no variable to check\n");
6031 stringp
= ast_strdupa(data
);
6032 condition
= strsep(&stringp
,"?");
6033 branch1
= strsep(&stringp
,":");
6034 branch2
= strsep(&stringp
,"");
6035 branch
= pbx_checkcondition(condition
) ? branch1
: branch2
;
6037 if (ast_strlen_zero(branch
)) {
6039 ast_log(LOG_DEBUG
, "Not taking any branch\n");
6043 rc
= pbx_builtin_goto(chan
, branch
);
6048 static int pbx_builtin_saynumber(struct ast_channel
*chan
, void *data
)
6054 if (ast_strlen_zero(data
)) {
6055 ast_log(LOG_WARNING
, "SayNumber requires an argument (number)\n");
6058 ast_copy_string(tmp
, data
, sizeof(tmp
));
6059 strsep(&number
, "|");
6060 options
= strsep(&number
, "|");
6062 if ( strcasecmp(options
, "f") && strcasecmp(options
,"m") &&
6063 strcasecmp(options
, "c") && strcasecmp(options
, "n") ) {
6064 ast_log(LOG_WARNING
, "SayNumber gender option is either 'f', 'm', 'c' or 'n'\n");
6068 return ast_say_number(chan
, atoi(tmp
), "", chan
->language
, options
);
6071 static int pbx_builtin_saydigits(struct ast_channel
*chan
, void *data
)
6076 res
= ast_say_digit_str(chan
, data
, "", chan
->language
);
6080 static int pbx_builtin_saycharacters(struct ast_channel
*chan
, void *data
)
6085 res
= ast_say_character_str(chan
, data
, "", chan
->language
);
6089 static int pbx_builtin_sayphonetic(struct ast_channel
*chan
, void *data
)
6094 res
= ast_say_phonetic_str(chan
, data
, "", chan
->language
);
6102 /* Initialize the PBX */
6103 if (option_verbose
) {
6104 ast_verbose( "Asterisk PBX Core Initializing\n");
6105 ast_verbose( "Registering builtin applications:\n");
6107 ast_cli_register_multiple(pbx_cli
, sizeof(pbx_cli
) / sizeof(struct ast_cli_entry
));
6109 /* Register builtin applications */
6110 for (x
=0; x
<sizeof(builtins
) / sizeof(struct pbx_builtin
); x
++) {
6112 ast_verbose( VERBOSE_PREFIX_1
"[%s]\n", builtins
[x
].name
);
6113 if (ast_register_application(builtins
[x
].name
, builtins
[x
].execute
, builtins
[x
].synopsis
, builtins
[x
].description
)) {
6114 ast_log(LOG_ERROR
, "Unable to register builtin application '%s'\n", builtins
[x
].name
);
6122 * Lock context list functions ...
6124 int ast_lock_contexts()
6126 return ast_rwlock_wrlock(&conlock
);
6129 int ast_rdlock_contexts(void)
6131 return ast_rwlock_rdlock(&conlock
);
6134 int ast_wrlock_contexts(void)
6136 return ast_rwlock_wrlock(&conlock
);
6139 int ast_unlock_contexts()
6141 return ast_rwlock_unlock(&conlock
);
6147 int ast_lock_context(struct ast_context
*con
)
6149 return ast_mutex_lock(&con
->lock
);
6152 int ast_unlock_context(struct ast_context
*con
)
6154 return ast_mutex_unlock(&con
->lock
);
6158 * Name functions ...
6160 const char *ast_get_context_name(struct ast_context
*con
)
6162 return con
? con
->name
: NULL
;
6165 struct ast_context
*ast_get_extension_context(struct ast_exten
*exten
)
6167 return exten
? exten
->parent
: NULL
;
6170 const char *ast_get_extension_name(struct ast_exten
*exten
)
6172 return exten
? exten
->exten
: NULL
;
6175 const char *ast_get_extension_label(struct ast_exten
*exten
)
6177 return exten
? exten
->label
: NULL
;
6180 const char *ast_get_include_name(struct ast_include
*inc
)
6182 return inc
? inc
->name
: NULL
;
6185 const char *ast_get_ignorepat_name(struct ast_ignorepat
*ip
)
6187 return ip
? ip
->pattern
: NULL
;
6190 int ast_get_extension_priority(struct ast_exten
*exten
)
6192 return exten
? exten
->priority
: -1;
6196 * Registrar info functions ...
6198 const char *ast_get_context_registrar(struct ast_context
*c
)
6200 return c
? c
->registrar
: NULL
;
6203 const char *ast_get_extension_registrar(struct ast_exten
*e
)
6205 return e
? e
->registrar
: NULL
;
6208 const char *ast_get_include_registrar(struct ast_include
*i
)
6210 return i
? i
->registrar
: NULL
;
6213 const char *ast_get_ignorepat_registrar(struct ast_ignorepat
*ip
)
6215 return ip
? ip
->registrar
: NULL
;
6218 int ast_get_extension_matchcid(struct ast_exten
*e
)
6220 return e
? e
->matchcid
: 0;
6223 const char *ast_get_extension_cidmatch(struct ast_exten
*e
)
6225 return e
? e
->cidmatch
: NULL
;
6228 const char *ast_get_extension_app(struct ast_exten
*e
)
6230 return e
? e
->app
: NULL
;
6233 void *ast_get_extension_app_data(struct ast_exten
*e
)
6235 return e
? e
->data
: NULL
;
6238 const char *ast_get_switch_name(struct ast_sw
*sw
)
6240 return sw
? sw
->name
: NULL
;
6243 const char *ast_get_switch_data(struct ast_sw
*sw
)
6245 return sw
? sw
->data
: NULL
;
6248 const char *ast_get_switch_registrar(struct ast_sw
*sw
)
6250 return sw
? sw
->registrar
: NULL
;
6254 * Walking functions ...
6256 struct ast_context
*ast_walk_contexts(struct ast_context
*con
)
6258 return con
? con
->next
: contexts
;
6261 struct ast_exten
*ast_walk_context_extensions(struct ast_context
*con
,
6262 struct ast_exten
*exten
)
6265 return con
? con
->root
: NULL
;
6270 struct ast_sw
*ast_walk_context_switches(struct ast_context
*con
,
6274 return con
? AST_LIST_FIRST(&con
->alts
) : NULL
;
6276 return AST_LIST_NEXT(sw
, list
);
6279 struct ast_exten
*ast_walk_extension_priorities(struct ast_exten
*exten
,
6280 struct ast_exten
*priority
)
6282 return priority
? priority
->peer
: exten
;
6285 struct ast_include
*ast_walk_context_includes(struct ast_context
*con
,
6286 struct ast_include
*inc
)
6289 return con
? con
->includes
: NULL
;
6294 struct ast_ignorepat
*ast_walk_context_ignorepats(struct ast_context
*con
,
6295 struct ast_ignorepat
*ip
)
6298 return con
? con
->ignorepats
: NULL
;
6303 int ast_context_verify_includes(struct ast_context
*con
)
6305 struct ast_include
*inc
= NULL
;
6308 while ( (inc
= ast_walk_context_includes(con
, inc
)) )
6309 if (!ast_context_find(inc
->rname
)) {
6311 ast_log(LOG_WARNING
, "Context '%s' tries includes nonexistent context '%s'\n",
6312 ast_get_context_name(con
), inc
->rname
);
6318 static int __ast_goto_if_exists(struct ast_channel
*chan
, const char *context
, const char *exten
, int priority
, int async
)
6320 int (*goto_func
)(struct ast_channel
*chan
, const char *context
, const char *exten
, int priority
);
6325 if (context
== NULL
)
6326 context
= chan
->context
;
6328 exten
= chan
->exten
;
6330 goto_func
= (async
) ? ast_async_goto
: ast_explicit_goto
;
6331 if (ast_exists_extension(chan
, context
, exten
, priority
, chan
->cid
.cid_num
))
6332 return goto_func(chan
, context
, exten
, priority
);
6337 int ast_goto_if_exists(struct ast_channel
*chan
, const char* context
, const char *exten
, int priority
)
6339 return __ast_goto_if_exists(chan
, context
, exten
, priority
, 0);
6342 int ast_async_goto_if_exists(struct ast_channel
*chan
, const char * context
, const char *exten
, int priority
)
6344 return __ast_goto_if_exists(chan
, context
, exten
, priority
, 1);
6347 int ast_parseable_goto(struct ast_channel
*chan
, const char *goto_string
)
6349 char *exten
, *pri
, *context
;
6354 if (ast_strlen_zero(goto_string
)) {
6355 ast_log(LOG_WARNING
, "Goto requires an argument (optional context|optional extension|priority)\n");
6358 stringp
= ast_strdupa(goto_string
);
6359 context
= strsep(&stringp
, "|"); /* guaranteed non-null */
6360 exten
= strsep(&stringp
, "|");
6361 pri
= strsep(&stringp
, "|");
6362 if (!exten
) { /* Only a priority in this one */
6366 } else if (!pri
) { /* Only an extension and priority in this one */
6374 } else if (*pri
== '-') {
6378 if (sscanf(pri
, "%d", &ipri
) != 1) {
6379 if ((ipri
= ast_findlabel_extension(chan
, context
? context
: chan
->context
, exten
? exten
: chan
->exten
,
6380 pri
, chan
->cid
.cid_num
)) < 1) {
6381 ast_log(LOG_WARNING
, "Priority '%s' must be a number > 0, or valid label\n", pri
);
6386 /* At this point we have a priority and maybe an extension and a context */
6389 ipri
= chan
->priority
+ (ipri
* mode
);
6391 ast_explicit_goto(chan
, context
, exten
, ipri
);
6392 ast_cdr_update(chan
);