Add the ability to dynamically specify weights for responses to DUNDi queries.
[asterisk/asterisk.git] / main / pbx.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2006, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
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.
13  *
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.
17  */
18
19 /*! \file
20  *
21  * \brief Core PBX routines.
22  *
23  * \author Mark Spencer <markster@digium.com>
24  */
25
26 #include "asterisk.h"
27
28 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
29
30 #include <sys/types.h>
31 #include <string.h>
32 #include <unistd.h>
33 #include <stdlib.h>
34 #include <stdio.h>
35 #include <ctype.h>
36 #include <errno.h>
37 #include <time.h>
38 #include <sys/time.h>
39 #include <limits.h>
40
41 #include "asterisk/lock.h"
42 #include "asterisk/cli.h"
43 #include "asterisk/pbx.h"
44 #include "asterisk/channel.h"
45 #include "asterisk/options.h"
46 #include "asterisk/logger.h"
47 #include "asterisk/file.h"
48 #include "asterisk/callerid.h"
49 #include "asterisk/cdr.h"
50 #include "asterisk/config.h"
51 #include "asterisk/term.h"
52 #include "asterisk/manager.h"
53 #include "asterisk/ast_expr.h"
54 #include "asterisk/linkedlists.h"
55 #define SAY_STUBS       /* generate declarations and stubs for say methods */
56 #include "asterisk/say.h"
57 #include "asterisk/utils.h"
58 #include "asterisk/causes.h"
59 #include "asterisk/musiconhold.h"
60 #include "asterisk/app.h"
61 #include "asterisk/devicestate.h"
62 #include "asterisk/stringfields.h"
63
64 /*!
65  * \note I M P O R T A N T :
66  *
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 ;-)
71  *
72  */
73
74 #ifdef LOW_MEMORY
75 #define EXT_DATA_SIZE 256
76 #else
77 #define EXT_DATA_SIZE 8192
78 #endif
79
80 #define SWITCH_DATA_LENGTH 256
81
82 #define VAR_BUF_SIZE 4096
83
84 #define VAR_NORMAL              1
85 #define VAR_SOFTTRAN    2
86 #define VAR_HARDTRAN    3
87
88 #define BACKGROUND_SKIP         (1 << 0)
89 #define BACKGROUND_NOANSWER     (1 << 1)
90 #define BACKGROUND_MATCHEXTEN   (1 << 2)
91 #define BACKGROUND_PLAYBACK     (1 << 3)
92
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),
98 });
99
100 #define WAITEXTEN_MOH           (1 << 0)
101
102 AST_APP_OPTIONS(waitexten_opts, {
103         AST_APP_OPTION_ARG('m', WAITEXTEN_MOH, 0),
104 });
105
106 struct ast_context;
107 struct ast_app;
108
109 /*!
110    \brief ast_exten: An extension
111         The dialplan is saved as a linked list with each context
112         having it's own linked list of extensions - one item per
113         priority.
114 */
115 struct ast_exten {
116         char *exten;                    /*!< Extension name */
117         int matchcid;                   /*!< Match caller id ? */
118         const char *cidmatch;           /*!< Caller id to match for this extension */
119         int priority;                   /*!< Priority */
120         const char *label;              /*!< Label */
121         struct ast_context *parent;     /*!< The context this extension belongs to  */
122         const char *app;                /*!< Application to execute */
123         struct ast_app *cached_app;     /*!< Cached location of application */
124         void *data;                     /*!< Data to use (arguments) */
125         void (*datad)(void *);          /*!< Data destructor */
126         struct ast_exten *peer;         /*!< Next higher priority with our extension */
127         const char *registrar;          /*!< Registrar */
128         struct ast_exten *next;         /*!< Extension with a greater ID */
129         char stuff[0];
130 };
131
132 /*! \brief ast_include: include= support in extensions.conf */
133 struct ast_include {
134         const char *name;
135         const char *rname;                      /*!< Context to include */
136         const char *registrar;                  /*!< Registrar */
137         int hastime;                            /*!< If time construct exists */
138         struct ast_timing timing;               /*!< time construct */
139         struct ast_include *next;               /*!< Link them together */
140         char stuff[0];
141 };
142
143 /*! \brief ast_sw: Switch statement in extensions.conf */
144 struct ast_sw {
145         char *name;
146         const char *registrar;                  /*!< Registrar */
147         char *data;                             /*!< Data load */
148         int eval;
149         AST_LIST_ENTRY(ast_sw) list;
150         char *tmpdata;
151         char stuff[0];
152 };
153
154 /*! \brief ast_ignorepat: Ignore patterns in dial plan */
155 struct ast_ignorepat {
156         const char *registrar;
157         struct ast_ignorepat *next;
158         const char pattern[0];
159 };
160
161 /*! \brief ast_context: An extension context */
162 struct ast_context {
163         ast_rwlock_t lock;                      /*!< A lock to prevent multiple threads from clobbering the context */
164         struct ast_exten *root;                 /*!< The root of the list of extensions */
165         struct ast_context *next;               /*!< Link them together */
166         struct ast_include *includes;           /*!< Include other contexts */
167         struct ast_ignorepat *ignorepats;       /*!< Patterns for which to continue playing dialtone */
168         const char *registrar;                  /*!< Registrar */
169         AST_LIST_HEAD_NOLOCK(, ast_sw) alts;    /*!< Alternative switches */
170         ast_mutex_t macrolock;                  /*!< A lock to implement "exclusive" macros - held whilst a call is executing in the macro */
171         char name[0];                           /*!< Name of the context */
172 };
173
174
175 /*! \brief ast_app: A registered application */
176 struct ast_app {
177         int (*execute)(struct ast_channel *chan, void *data);
178         const char *synopsis;                   /*!< Synopsis text for 'show applications' */
179         const char *description;                /*!< Description (help text) for 'show application &lt;name&gt;' */
180         AST_RWLIST_ENTRY(ast_app) list;         /*!< Next app in list */
181         struct module *module;                  /*!< Module this app belongs to */
182         char name[0];                           /*!< Name of the application */
183 };
184
185 /*! \brief ast_state_cb: An extension state notify register item */
186 struct ast_state_cb {
187         int id;
188         void *data;
189         ast_state_cb_type callback;
190         struct ast_state_cb *next;
191 };
192
193 /*! \brief Structure for dial plan hints
194
195   \note Hints are pointers from an extension in the dialplan to one or
196   more devices (tech/name) 
197         - See \ref AstExtState
198 */
199 struct ast_hint {
200         struct ast_exten *exten;        /*!< Extension */
201         int laststate;                  /*!< Last known state */
202         struct ast_state_cb *callbacks; /*!< Callback list for this extension */
203         AST_RWLIST_ENTRY(ast_hint) list;/*!< Pointer to next hint in list */
204 };
205
206 static const struct cfextension_states {
207         int extension_state;
208         const char * const text;
209 } extension_states[] = {
210         { AST_EXTENSION_NOT_INUSE,                     "Idle" },
211         { AST_EXTENSION_INUSE,                         "InUse" },
212         { AST_EXTENSION_BUSY,                          "Busy" },
213         { AST_EXTENSION_UNAVAILABLE,                   "Unavailable" },
214         { AST_EXTENSION_RINGING,                       "Ringing" },
215         { AST_EXTENSION_INUSE | AST_EXTENSION_RINGING, "InUse&Ringing" },
216         { AST_EXTENSION_ONHOLD,                        "Hold" },
217         { AST_EXTENSION_INUSE | AST_EXTENSION_ONHOLD,  "InUse&Hold" }
218 };
219
220 static int pbx_builtin_answer(struct ast_channel *, void *);
221 static int pbx_builtin_goto(struct ast_channel *, void *);
222 static int pbx_builtin_hangup(struct ast_channel *, void *);
223 static int pbx_builtin_background(struct ast_channel *, void *);
224 static int pbx_builtin_wait(struct ast_channel *, void *);
225 static int pbx_builtin_waitexten(struct ast_channel *, void *);
226 static int pbx_builtin_resetcdr(struct ast_channel *, void *);
227 static int pbx_builtin_setamaflags(struct ast_channel *, void *);
228 static int pbx_builtin_ringing(struct ast_channel *, void *);
229 static int pbx_builtin_progress(struct ast_channel *, void *);
230 static int pbx_builtin_congestion(struct ast_channel *, void *);
231 static int pbx_builtin_busy(struct ast_channel *, void *);
232 static int pbx_builtin_noop(struct ast_channel *, void *);
233 static int pbx_builtin_gotoif(struct ast_channel *, void *);
234 static int pbx_builtin_gotoiftime(struct ast_channel *, void *);
235 static int pbx_builtin_execiftime(struct ast_channel *, void *);
236 static int pbx_builtin_saynumber(struct ast_channel *, void *);
237 static int pbx_builtin_saydigits(struct ast_channel *, void *);
238 static int pbx_builtin_saycharacters(struct ast_channel *, void *);
239 static int pbx_builtin_sayphonetic(struct ast_channel *, void *);
240 int pbx_builtin_setvar(struct ast_channel *, void *);
241 static int pbx_builtin_importvar(struct ast_channel *, void *);
242
243 AST_RWLOCK_DEFINE_STATIC(globalslock);
244 static struct varshead globals = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
245
246 static int autofallthrough = 1;
247
248 AST_MUTEX_DEFINE_STATIC(maxcalllock);
249 static int countcalls;
250
251 static AST_RWLIST_HEAD_STATIC(acf_root, ast_custom_function);
252
253 /*! \brief Declaration of builtin applications */
254 static struct pbx_builtin {
255         char name[AST_MAX_APP];
256         int (*execute)(struct ast_channel *chan, void *data);
257         char *synopsis;
258         char *description;
259 } builtins[] =
260 {
261         /* These applications are built into the PBX core and do not
262            need separate modules */
263
264         { "Answer", pbx_builtin_answer,
265         "Answer a channel if ringing",
266         "  Answer([delay]): If the call has not been answered, this application will\n"
267         "answer it. Otherwise, it has no effect on the call. If a delay is specified,\n"
268         "Asterisk will wait this number of milliseconds before returning to\n"
269         "the dialplan after answering the call.\n"
270         },
271
272         { "BackGround", pbx_builtin_background,
273         "Play an audio file while waiting for digits of an extension to go to.",
274         "  Background(filename1[&filename2...][|options[|langoverride][|context]]):\n"
275         "This application will play the given list of files while waiting for an\n"
276         "extension to be dialed by the calling channel. To continue waiting for digits\n"
277         "after this application has finished playing files, the WaitExten application\n"
278         "should be used. The 'langoverride' option explicitly specifies which language\n"
279         "to attempt to use for the requested sound files. If a 'context' is specified,\n"
280         "this is the dialplan context that this application will use when exiting to a\n"
281         "dialed extension."
282         "  If one of the requested sound files does not exist, call processing will be\n"
283         "terminated.\n"
284         "  Options:\n"
285         "    s - Causes the playback of the message to be skipped\n"
286         "          if the channel is not in the 'up' state (i.e. it\n"
287         "          hasn't been answered yet). If this happens, the\n"
288         "          application will return immediately.\n"
289         "    n - Don't answer the channel before playing the files.\n"
290         "    m - Only break if a digit hit matches a one digit\n"
291         "          extension in the destination context.\n"
292         "This application sets the following channel variable upon completion:\n"
293         " BACKGROUNDSTATUS    The status of the background attempt as a text string, one of\n"
294         "               SUCCESS | FAILED\n"
295         },
296
297         { "Busy", pbx_builtin_busy,
298         "Indicate the Busy condition",
299         "  Busy([timeout]): This application will indicate the busy condition to\n"
300         "the calling channel. If the optional timeout is specified, the calling channel\n"
301         "will be hung up after the specified number of seconds. Otherwise, this\n"
302         "application will wait until the calling channel hangs up.\n"
303         },
304
305         { "Congestion", pbx_builtin_congestion,
306         "Indicate the Congestion condition",
307         "  Congestion([timeout]): This application will indicate the congestion\n"
308         "condition to the calling channel. If the optional timeout is specified, the\n"
309         "calling channel will be hung up after the specified number of seconds.\n"
310         "Otherwise, this application will wait until the calling channel hangs up.\n"
311         },
312
313         { "ExecIfTime", pbx_builtin_execiftime,
314         "Conditional application execution based on the current time",
315         "  ExecIfTime(<times>|<weekdays>|<mdays>|<months>?appname[|appargs]):\n"
316         "This application will execute the specified dialplan application, with optional\n"
317         "arguments, if the current time matches the given time specification.\n"
318         },
319
320         { "Goto", pbx_builtin_goto,
321         "Jump to a particular priority, extension, or context",
322         "  Goto([[context|]extension|]priority): This application will set the current\n"
323         "context, extension, and priority in the channel structure. After it completes, the\n"
324         "pbx engine will continue dialplan execution at the specified location.\n"
325         "If no specific extension, or extension and context, are specified, then this\n"
326         "application will just set the specified priority of the current extension.\n"
327         "  At least a priority is required as an argument, or the goto will return a -1,\n"
328         "and the channel and call will be terminated.\n"
329         "  If the location that is put into the channel information is bogus, and asterisk cannot\n"
330         "find that location in the dialplan,\n"
331         "then the execution engine will try to find and execute the code in the 'i' (invalid)\n"
332         "extension in the current context. If that does not exist, it will try to execute the\n"
333         "'h' extension. If either or neither the 'h' or 'i' extensions have been defined, the\n"
334         "channel is hung up, and the execution of instructions on the channel is terminated.\n"
335         "What this means is that, for example, you specify a context that does not exist, then\n"
336         "it will not be possible to find the 'h' or 'i' extensions, and the call will terminate!\n"
337         },
338
339         { "GotoIf", pbx_builtin_gotoif,
340         "Conditional goto",
341         "  GotoIf(condition?[labeliftrue]:[labeliffalse]): This application will set the current\n"
342         "context, extension, and priority in the channel structure based on the evaluation of\n"
343         "the given condition. After this application completes, the\n"
344         "pbx engine will continue dialplan execution at the specified location in the dialplan.\n"
345         "The channel will continue at\n"
346         "'labeliftrue' if the condition is true, or 'labeliffalse' if the condition is\n"
347         "false. The labels are specified with the same syntax as used within the Goto\n"
348         "application.  If the label chosen by the condition is omitted, no jump is\n"
349         "performed, and the execution passes to the next instruction.\n"
350         "If the target location is bogus, and does not exist, the execution engine will try \n"
351         "to find and execute the code in the 'i' (invalid)\n"
352         "extension in the current context. If that does not exist, it will try to execute the\n"
353         "'h' extension. If either or neither the 'h' or 'i' extensions have been defined, the\n"
354         "channel is hung up, and the execution of instructions on the channel is terminated.\n"
355         "Remember that this command can set the current context, and if the context specified\n"
356         "does not exist, then it will not be able to find any 'h' or 'i' extensions there, and\n"
357         "the channel and call will both be terminated!\n"
358         },
359
360         { "GotoIfTime", pbx_builtin_gotoiftime,
361         "Conditional Goto based on the current time",
362         "  GotoIfTime(<times>|<weekdays>|<mdays>|<months>?[[context|]exten|]priority):\n"
363         "This application will set the context, extension, and priority in the channel structure\n"
364         "if the current time matches the given time specification. Otherwise, nothing is done.\n"
365         "Further information on the time specification can be found in examples\n"
366         "illustrating how to do time-based context includes in the dialplan.\n" 
367         "If the target jump location is bogus, the same actions would be taken as for Goto.\n"
368         },
369
370         { "ImportVar", pbx_builtin_importvar,
371         "Import a variable from a channel into a new variable",
372         "  ImportVar(newvar=channelname|variable): This application imports a variable\n"
373         "from the specified channel (as opposed to the current one) and stores it as\n"
374         "a variable in the current channel (the channel that is calling this\n"
375         "application). Variables created by this application have the same inheritance\n"
376         "properties as those created with the Set application. See the documentation for\n"
377         "Set for more information.\n"
378         },
379
380         { "Hangup", pbx_builtin_hangup,
381         "Hang up the calling channel",
382         "  Hangup([causecode]): This application will hang up the calling channel.\n"
383         "If a causecode is given the channel's hangup cause will be set to the given\n"
384         "value.\n"
385         },
386
387         { "NoOp", pbx_builtin_noop,
388         "Do Nothing",
389         "  NoOp(): This applicatiion does nothing. However, it is useful for debugging\n"
390         "purposes. Any text that is provided as arguments to this application can be\n"
391         "viewed at the Asterisk CLI. This method can be used to see the evaluations of\n"
392         "variables or functions without having any effect."
393         },
394
395         { "Progress", pbx_builtin_progress,
396         "Indicate progress",
397         "  Progress(): This application will request that in-band progress information\n"
398         "be provided to the calling channel.\n"
399         },
400
401         { "ResetCDR", pbx_builtin_resetcdr,
402         "Resets the Call Data Record",
403         "  ResetCDR([options]):  This application causes the Call Data Record to be\n"
404         "reset.\n"
405         "  Options:\n"
406         "    w -- Store the current CDR record before resetting it.\n"
407         "    a -- Store any stacked records.\n"
408         "    v -- Save CDR variables.\n"
409         },
410
411         { "Ringing", pbx_builtin_ringing,
412         "Indicate ringing tone",
413         "  Ringing(): This application will request that the channel indicate a ringing\n"
414         "tone to the user.\n"
415         },
416
417         { "SayAlpha", pbx_builtin_saycharacters,
418         "Say Alpha",
419         "  SayAlpha(string): This application will play the sounds that correspond to\n"
420         "the letters of the given string.\n"
421         },
422
423         { "SayDigits", pbx_builtin_saydigits,
424         "Say Digits",
425         "  SayDigits(digits): This application will play the sounds that correspond\n"
426         "to the digits of the given number. This will use the language that is currently\n"
427         "set for the channel. See the LANGUAGE function for more information on setting\n"
428         "the language for the channel.\n"
429         },
430
431         { "SayNumber", pbx_builtin_saynumber,
432         "Say Number",
433         "  SayNumber(digits[,gender]): This application will play the sounds that\n"
434         "correspond to the given number. Optionally, a gender may be specified.\n"
435         "This will use the language that is currently set for the channel. See the\n"
436         "LANGUAGE function for more information on setting the language for the channel.\n"
437         },
438
439         { "SayPhonetic", pbx_builtin_sayphonetic,
440         "Say Phonetic",
441         "  SayPhonetic(string): This application will play the sounds from the phonetic\n"
442         "alphabet that correspond to the letters in the given string.\n"
443         },
444
445         { "Set", pbx_builtin_setvar,
446         "Set channel variable(s) or function value(s)",
447         "  Set(name1=value1|name2=value2|..[|options])\n"
448         "This function can be used to set the value of channel variables or dialplan\n"
449         "functions. It will accept up to 24 name/value pairs. When setting variables,\n"
450         "if the variable name is prefixed with _, the variable will be inherited into\n"
451         "channels created from the current channel. If the variable name is prefixed\n"
452         "with __, the variable will be inherited into channels created from the current\n"
453         "channel and all children channels.\n"
454         "  Options:\n"
455         "    g - Set variable globally instead of on the channel\n"
456         "        (applies only to variables, not functions)\n"
457         },
458
459         { "SetAMAFlags", pbx_builtin_setamaflags,
460         "Set the AMA Flags",
461         "  SetAMAFlags([flag]): This application will set the channel's AMA Flags for\n"
462         "  billing purposes.\n"
463         },
464
465         { "Wait", pbx_builtin_wait,
466         "Waits for some time",
467         "  Wait(seconds): This application waits for a specified number of seconds.\n"
468         "Then, dialplan execution will continue at the next priority.\n"
469         "  Note that the seconds can be passed with fractions of a second. For example,\n"
470         "'1.5' will ask the application to wait for 1.5 seconds.\n"
471         },
472
473         { "WaitExten", pbx_builtin_waitexten,
474         "Waits for an extension to be entered",
475         "  WaitExten([seconds][|options]): This application waits for the user to enter\n"
476         "a new extension for a specified number of seconds.\n"
477         "  Note that the seconds can be passed with fractions of a second. For example,\n"
478         "'1.5' will ask the application to wait for 1.5 seconds.\n"
479         "  Options:\n"
480         "    m[(x)] - Provide music on hold to the caller while waiting for an extension.\n"
481         "               Optionally, specify the class for music on hold within parenthesis.\n"
482         },
483
484 };
485
486 static struct ast_context *contexts;
487 AST_RWLOCK_DEFINE_STATIC(conlock);              /*!< Lock for the ast_context list */
488
489 static AST_RWLIST_HEAD_STATIC(apps, ast_app);
490
491 static AST_RWLIST_HEAD_STATIC(switches, ast_switch);
492
493 static int stateid = 1;
494 /* WARNING:
495    When holding this list's lock, do _not_ do anything that will cause conlock
496    to be taken, unless you _already_ hold it. The ast_merge_contexts_and_delete
497    function will take the locks in conlock/hints order, so any other
498    paths that require both locks must also take them in that order.
499 */
500 static AST_RWLIST_HEAD_STATIC(hints, ast_hint);
501 struct ast_state_cb *statecbs;
502
503 /*
504    \note This function is special. It saves the stack so that no matter
505    how many times it is called, it returns to the same place */
506 int pbx_exec(struct ast_channel *c,             /*!< Channel */
507              struct ast_app *app,               /*!< Application */
508              void *data)                        /*!< Data for execution */
509 {
510         int res;
511
512         const char *saved_c_appl;
513         const char *saved_c_data;
514
515         if (c->cdr)
516                 ast_cdr_setapp(c->cdr, app->name, data);
517
518         /* save channel values */
519         saved_c_appl= c->appl;
520         saved_c_data= c->data;
521
522         c->appl = app->name;
523         c->data = data;
524         /* XXX remember what to to when we have linked apps to modules */
525         if (app->module) {
526                 /* XXX LOCAL_USER_ADD(app->module) */
527         }
528         res = app->execute(c, data);
529         if (app->module) {
530                 /* XXX LOCAL_USER_REMOVE(app->module) */
531         }
532         /* restore channel values */
533         c->appl = saved_c_appl;
534         c->data = saved_c_data;
535         return res;
536 }
537
538
539 /*! Go no deeper than this through includes (not counting loops) */
540 #define AST_PBX_MAX_STACK       128
541
542 /*! \brief Find application handle in linked list
543  */
544 struct ast_app *pbx_findapp(const char *app)
545 {
546         struct ast_app *tmp;
547
548         AST_RWLIST_RDLOCK(&apps);
549         AST_RWLIST_TRAVERSE(&apps, tmp, list) {
550                 if (!strcasecmp(tmp->name, app))
551                         break;
552         }
553         AST_RWLIST_UNLOCK(&apps);
554
555         return tmp;
556 }
557
558 static struct ast_switch *pbx_findswitch(const char *sw)
559 {
560         struct ast_switch *asw;
561
562         AST_RWLIST_RDLOCK(&switches);
563         AST_RWLIST_TRAVERSE(&switches, asw, list) {
564                 if (!strcasecmp(asw->name, sw))
565                         break;
566         }
567         AST_RWLIST_UNLOCK(&switches);
568
569         return asw;
570 }
571
572 static inline int include_valid(struct ast_include *i)
573 {
574         if (!i->hastime)
575                 return 1;
576
577         return ast_check_timing(&(i->timing));
578 }
579
580 static void pbx_destroy(struct ast_pbx *p)
581 {
582         free(p);
583 }
584
585 /*
586  * Special characters used in patterns:
587  *      '_'     underscore is the leading character of a pattern.
588  *              In other position it is treated as a regular char.
589  *      ' ' '-' space and '-' are separator and ignored.
590  *      .       one or more of any character. Only allowed at the end of
591  *              a pattern.
592  *      !       zero or more of anything. Also impacts the result of CANMATCH
593  *              and MATCHMORE. Only allowed at the end of a pattern.
594  *              In the core routine, ! causes a match with a return code of 2.
595  *              In turn, depending on the search mode: (XXX check if it is implemented)
596  *              - E_MATCH retuns 1 (does match)
597  *              - E_MATCHMORE returns 0 (no match)
598  *              - E_CANMATCH returns 1 (does match)
599  *
600  *      /       should not appear as it is considered the separator of the CID info.
601  *              XXX at the moment we may stop on this char.
602  *
603  *      X Z N   match ranges 0-9, 1-9, 2-9 respectively.
604  *      [       denotes the start of a set of character. Everything inside
605  *              is considered literally. We can have ranges a-d and individual
606  *              characters. A '[' and '-' can be considered literally if they
607  *              are just before ']'.
608  *              XXX currently there is no way to specify ']' in a range, nor \ is
609  *              considered specially.
610  *
611  * When we compare a pattern with a specific extension, all characters in the extension
612  * itself are considered literally with the only exception of '-' which is considered
613  * as a separator and thus ignored.
614  * XXX do we want to consider space as a separator as well ?
615  * XXX do we want to consider the separators in non-patterns as well ?
616  */
617
618 /*!
619  * \brief helper functions to sort extensions and patterns in the desired way,
620  * so that more specific patterns appear first.
621  *
622  * ext_cmp1 compares individual characters (or sets of), returning
623  * an int where bits 0-7 are the ASCII code of the first char in the set,
624  * while bit 8-15 are the cardinality of the set minus 1.
625  * This way more specific patterns (smaller cardinality) appear first.
626  * Wildcards have a special value, so that we can directly compare them to
627  * sets by subtracting the two values. In particular:
628  *      0x000xx         one character, xx
629  *      0x0yyxx         yy character set starting with xx
630  *      0x10000         '.' (one or more of anything)
631  *      0x20000         '!' (zero or more of anything)
632  *      0x30000         NUL (end of string)
633  *      0x40000         error in set.
634  * The pointer to the string is advanced according to needs.
635  * NOTES:
636  *      1. the empty set is equivalent to NUL.
637  *      2. given that a full set has always 0 as the first element,
638  *         we could encode the special cases as 0xffXX where XX
639  *         is 1, 2, 3, 4 as used above.
640  */
641 static int ext_cmp1(const char **p)
642 {
643         uint32_t chars[8];
644         int c, cmin = 0xff, count = 0;
645         const char *end;
646
647         /* load, sign extend and advance pointer until we find
648          * a valid character.
649          */
650         while ( (c = *(*p)++) && (c == ' ' || c == '-') )
651                 ;       /* ignore some characters */
652
653         /* always return unless we have a set of chars */
654         switch (c) {
655         default:        /* ordinary character */
656                 return 0x0000 | (c & 0xff);
657
658         case 'N':       /* 2..9 */
659                 return 0x0700 | '2' ;
660
661         case 'X':       /* 0..9 */
662                 return 0x0900 | '0';
663
664         case 'Z':       /* 1..9 */
665                 return 0x0800 | '1';
666
667         case '.':       /* wildcard */
668                 return 0x10000;
669
670         case '!':       /* earlymatch */
671                 return 0x20000; /* less specific than NULL */
672
673         case '\0':      /* empty string */
674                 *p = NULL;
675                 return 0x30000;
676
677         case '[':       /* pattern */
678                 break;
679         }
680         /* locate end of set */
681         end = strchr(*p, ']');  
682
683         if (end == NULL) {
684                 ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");
685                 return 0x40000; /* XXX make this entry go last... */
686         }
687
688         bzero(chars, sizeof(chars));    /* clear all chars in the set */
689         for (; *p < end  ; (*p)++) {
690                 unsigned char c1, c2;   /* first-last char in range */
691                 c1 = (unsigned char)((*p)[0]);
692                 if (*p + 2 < end && (*p)[1] == '-') { /* this is a range */
693                         c2 = (unsigned char)((*p)[2]);
694                         *p += 2;        /* skip a total of 3 chars */
695                 } else                  /* individual character */
696                         c2 = c1;
697                 if (c1 < cmin)
698                         cmin = c1;
699                 for (; c1 <= c2; c1++) {
700                         uint32_t mask = 1 << (c1 % 32);
701                         if ( (chars[ c1 / 32 ] & mask) == 0)
702                                 count += 0x100;
703                         chars[ c1 / 32 ] |= mask;
704                 }
705         }
706         (*p)++;
707         return count == 0 ? 0x30000 : (count | cmin);
708 }
709
710 /*!
711  * \brief the full routine to compare extensions in rules.
712  */
713 static int ext_cmp(const char *a, const char *b)
714 {
715         /* make sure non-patterns come first.
716          * If a is not a pattern, it either comes first or
717          * we use strcmp to compare the strings.
718          */
719         int ret = 0;
720
721         if (a[0] != '_')
722                 return (b[0] == '_') ? -1 : strcmp(a, b);
723
724         /* Now we know a is a pattern; if b is not, a comes first */
725         if (b[0] != '_')
726                 return 1;
727 #if 0   /* old mode for ext matching */
728         return strcmp(a, b);
729 #endif
730         /* ok we need full pattern sorting routine */
731         while (!ret && a && b)
732                 ret = ext_cmp1(&a) - ext_cmp1(&b);
733         if (ret == 0)
734                 return 0;
735         else
736                 return (ret > 0) ? 1 : -1;
737 }
738
739 /*!
740  * When looking up extensions, we can have different requests
741  * identified by the 'action' argument, as follows.
742  * Note that the coding is such that the low 4 bits are the
743  * third argument to extension_match_core.
744  */
745 enum ext_match_t {
746         E_MATCHMORE =   0x00,   /* extension can match but only with more 'digits' */
747         E_CANMATCH =    0x01,   /* extension can match with or without more 'digits' */
748         E_MATCH =       0x02,   /* extension is an exact match */
749         E_MATCH_MASK =  0x03,   /* mask for the argument to extension_match_core() */
750         E_SPAWN =       0x12,   /* want to spawn an extension. Requires exact match */
751         E_FINDLABEL =   0x22    /* returns the priority for a given label. Requires exact match */
752 };
753
754 /*
755  * Internal function for ast_extension_{match|close}
756  * return 0 on no-match, 1 on match, 2 on early match.
757  * mode is as follows:
758  *      E_MATCH         success only on exact match
759  *      E_MATCHMORE     success only on partial match (i.e. leftover digits in pattern)
760  *      E_CANMATCH      either of the above.
761  */
762
763 static int _extension_match_core(const char *pattern, const char *data, enum ext_match_t mode)
764 {
765         mode &= E_MATCH_MASK;   /* only consider the relevant bits */
766
767         if ( (mode == E_MATCH) && (pattern[0] == '_') && (strcasecmp(pattern,data)==0) ) /* note: if this test is left out, then _x. will not match _x. !!! */
768                 return 1;
769
770         if (pattern[0] != '_') { /* not a pattern, try exact or partial match */
771                 int ld = strlen(data), lp = strlen(pattern);
772
773                 if (lp < ld)            /* pattern too short, cannot match */
774                         return 0;
775                 /* depending on the mode, accept full or partial match or both */
776                 if (mode == E_MATCH)
777                         return !strcmp(pattern, data); /* 1 on match, 0 on fail */
778                 if (ld == 0 || !strncasecmp(pattern, data, ld)) /* partial or full match */
779                         return (mode == E_MATCHMORE) ? lp > ld : 1; /* XXX should consider '!' and '/' ? */
780                 else
781                         return 0;
782         }
783         pattern++; /* skip leading _ */
784         /*
785          * XXX below we stop at '/' which is a separator for the CID info. However we should
786          * not store '/' in the pattern at all. When we insure it, we can remove the checks.
787          */
788         while (*data && *pattern && *pattern != '/') {
789                 const char *end;
790
791                 if (*data == '-') { /* skip '-' in data (just a separator) */
792                         data++;
793                         continue;
794                 }
795                 switch (toupper(*pattern)) {
796                 case '[':       /* a range */
797                         end = strchr(pattern+1, ']'); /* XXX should deal with escapes ? */
798                         if (end == NULL) {
799                                 ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");
800                                 return 0;       /* unconditional failure */
801                         }
802                         for (pattern++; pattern != end; pattern++) {
803                                 if (pattern+2 < end && pattern[1] == '-') { /* this is a range */
804                                         if (*data >= pattern[0] && *data <= pattern[2])
805                                                 break;  /* match found */
806                                         else {
807                                                 pattern += 2; /* skip a total of 3 chars */
808                                                 continue;
809                                         }
810                                 } else if (*data == pattern[0])
811                                         break;  /* match found */
812                         }
813                         if (pattern == end)
814                                 return 0;
815                         pattern = end;  /* skip and continue */
816                         break;
817                 case 'N':
818                         if (*data < '2' || *data > '9')
819                                 return 0;
820                         break;
821                 case 'X':
822                         if (*data < '0' || *data > '9')
823                                 return 0;
824                         break;
825                 case 'Z':
826                         if (*data < '1' || *data > '9')
827                                 return 0;
828                         break;
829                 case '.':       /* Must match, even with more digits */
830                         return 1;
831                 case '!':       /* Early match */
832                         return 2;
833                 case ' ':
834                 case '-':       /* Ignore these in patterns */
835                         data--; /* compensate the final data++ */
836                         break;
837                 default:
838                         if (*data != *pattern)
839                                 return 0;
840                 }
841                 data++;
842                 pattern++;
843         }
844         if (*data)                      /* data longer than pattern, no match */
845                 return 0;
846         /*
847          * match so far, but ran off the end of the data.
848          * Depending on what is next, determine match or not.
849          */
850         if (*pattern == '\0' || *pattern == '/')        /* exact match */
851                 return (mode == E_MATCHMORE) ? 0 : 1;   /* this is a failure for E_MATCHMORE */
852         else if (*pattern == '!')                       /* early match */
853                 return 2;
854         else                                            /* partial match */
855                 return (mode == E_MATCH) ? 0 : 1;       /* this is a failure for E_MATCH */
856 }
857
858 /*
859  * Wrapper around _extension_match_core() to do performance measurement
860  * using the profiling code.
861  */
862 static int extension_match_core(const char *pattern, const char *data, enum ext_match_t mode)
863 {
864         int i;
865         static int prof_id = -2;        /* marker for 'unallocated' id */
866         if (prof_id == -2)
867                 prof_id = ast_add_profile("ext_match", 0);
868         ast_mark(prof_id, 1);
869         i = _extension_match_core(pattern, data, mode);
870         ast_mark(prof_id, 0);
871         return i;
872 }
873
874 int ast_extension_match(const char *pattern, const char *data)
875 {
876         return extension_match_core(pattern, data, E_MATCH);
877 }
878
879 int ast_extension_close(const char *pattern, const char *data, int needmore)
880 {
881         if (needmore != E_MATCHMORE && needmore != E_CANMATCH)
882                 ast_log(LOG_WARNING, "invalid argument %d\n", needmore);
883         return extension_match_core(pattern, data, needmore);
884 }
885
886 struct ast_context *ast_context_find(const char *name)
887 {
888         struct ast_context *tmp = NULL;
889         ast_rdlock_contexts();
890         while ( (tmp = ast_walk_contexts(tmp)) ) {
891                 if (!name || !strcasecmp(name, tmp->name))
892                         break;
893         }
894         ast_unlock_contexts();
895         return tmp;
896 }
897
898 #define STATUS_NO_CONTEXT       1
899 #define STATUS_NO_EXTENSION     2
900 #define STATUS_NO_PRIORITY      3
901 #define STATUS_NO_LABEL         4
902 #define STATUS_SUCCESS          5
903
904 static int matchcid(const char *cidpattern, const char *callerid)
905 {
906         /* If the Caller*ID pattern is empty, then we're matching NO Caller*ID, so
907            failing to get a number should count as a match, otherwise not */
908
909         if (ast_strlen_zero(callerid))
910                 return ast_strlen_zero(cidpattern) ? 1 : 0;
911
912         return ast_extension_match(cidpattern, callerid);
913 }
914
915 /* request and result for pbx_find_extension */
916 struct pbx_find_info {
917 #if 0
918         const char *context;
919         const char *exten;
920         int priority;
921 #endif
922
923         char *incstack[AST_PBX_MAX_STACK];      /* filled during the search */
924         int stacklen;                   /* modified during the search */
925         int status;                     /* set on return */
926         struct ast_switch *swo;         /* set on return */
927         const char *data;               /* set on return */
928         const char *foundcontext;       /* set on return */
929 };
930
931 static struct ast_exten *pbx_find_extension(struct ast_channel *chan,
932         struct ast_context *bypass, struct pbx_find_info *q,
933         const char *context, const char *exten, int priority,
934         const char *label, const char *callerid, enum ext_match_t action)
935 {
936         int x, res;
937         struct ast_context *tmp;
938         struct ast_exten *e, *eroot;
939         struct ast_include *i;
940         struct ast_sw *sw;
941
942         /* Initialize status if appropriate */
943         if (q->stacklen == 0) {
944                 q->status = STATUS_NO_CONTEXT;
945                 q->swo = NULL;
946                 q->data = NULL;
947                 q->foundcontext = NULL;
948         } else if (q->stacklen >= AST_PBX_MAX_STACK) {
949                 ast_log(LOG_WARNING, "Maximum PBX stack exceeded\n");
950                 return NULL;
951         }
952
953         /* Check first to see if we've already been checked */
954         for (x = 0; x < q->stacklen; x++) {
955                 if (!strcasecmp(q->incstack[x], context))
956                         return NULL;
957         }
958
959         if (bypass)     /* bypass means we only look there */
960                 tmp = bypass;
961         else {  /* look in contexts */
962                 tmp = NULL;
963                 while ((tmp = ast_walk_contexts(tmp)) ) {
964                         if (!strcmp(tmp->name, context))
965                                 break;
966                 }
967                 if (!tmp)
968                         return NULL;
969         }
970
971         if (q->status < STATUS_NO_EXTENSION)
972                 q->status = STATUS_NO_EXTENSION;
973
974         /* scan the list trying to match extension and CID */
975         eroot = NULL;
976         while ( (eroot = ast_walk_context_extensions(tmp, eroot)) ) {
977                 int match = extension_match_core(eroot->exten, exten, action);
978                 /* 0 on fail, 1 on match, 2 on earlymatch */
979
980                 if (!match || (eroot->matchcid && !matchcid(eroot->cidmatch, callerid)))
981                         continue;       /* keep trying */
982                 if (match == 2 && action == E_MATCHMORE) {
983                         /* We match an extension ending in '!'.
984                          * The decision in this case is final and is NULL (no match).
985                          */
986                         return NULL;
987                 }
988                 /* found entry, now look for the right priority */
989                 if (q->status < STATUS_NO_PRIORITY)
990                         q->status = STATUS_NO_PRIORITY;
991                 e = NULL;
992                 while ( (e = ast_walk_extension_priorities(eroot, e)) ) {
993                         /* Match label or priority */
994                         if (action == E_FINDLABEL) {
995                                 if (q->status < STATUS_NO_LABEL)
996                                         q->status = STATUS_NO_LABEL;
997                                 if (label && e->label && !strcmp(label, e->label))
998                                         break;  /* found it */
999                         } else if (e->priority == priority) {
1000                                 break;  /* found it */
1001                         } /* else keep searching */
1002                 }
1003                 if (e) {        /* found a valid match */
1004                         q->status = STATUS_SUCCESS;
1005                         q->foundcontext = context;
1006                         return e;
1007                 }
1008         }
1009         /* Check alternative switches */
1010         AST_LIST_TRAVERSE(&tmp->alts, sw, list) {
1011                 struct ast_switch *asw = pbx_findswitch(sw->name);
1012                 ast_switch_f *aswf = NULL;
1013                 char *datap;
1014
1015                 if (!asw) {
1016                         ast_log(LOG_WARNING, "No such switch '%s'\n", sw->name);
1017                         continue;
1018                 }
1019                 /* Substitute variables now */
1020                 if (sw->eval)
1021                         pbx_substitute_variables_helper(chan, sw->data, sw->tmpdata, SWITCH_DATA_LENGTH - 1);
1022
1023                 /* equivalent of extension_match_core() at the switch level */
1024                 if (action == E_CANMATCH)
1025                         aswf = asw->canmatch;
1026                 else if (action == E_MATCHMORE)
1027                         aswf = asw->matchmore;
1028                 else /* action == E_MATCH */
1029                         aswf = asw->exists;
1030                 datap = sw->eval ? sw->tmpdata : sw->data;
1031                 res = !aswf ? 0 : aswf(chan, context, exten, priority, callerid, datap);
1032                 if (res) {      /* Got a match */
1033                         q->swo = asw;
1034                         q->data = datap;
1035                         q->foundcontext = context;
1036                         /* XXX keep status = STATUS_NO_CONTEXT ? */
1037                         return NULL;
1038                 }
1039         }
1040         q->incstack[q->stacklen++] = tmp->name; /* Setup the stack */
1041         /* Now try any includes we have in this context */
1042         for (i = tmp->includes; i; i = i->next) {
1043                 if (include_valid(i)) {
1044                         if ((e = pbx_find_extension(chan, bypass, q, i->rname, exten, priority, label, callerid, action)))
1045                                 return e;
1046                         if (q->swo)
1047                                 return NULL;
1048                 }
1049         }
1050         return NULL;
1051 }
1052
1053 /*! \brief extract offset:length from variable name.
1054  * Returns 1 if there is a offset:length part, which is
1055  * trimmed off (values go into variables)
1056  */
1057 static int parse_variable_name(char *var, int *offset, int *length, int *isfunc)
1058 {
1059         int parens=0;
1060
1061         *offset = 0;
1062         *length = INT_MAX;
1063         *isfunc = 0;
1064         for (; *var; var++) {
1065                 if (*var == '(') {
1066                         (*isfunc)++;
1067                         parens++;
1068                 } else if (*var == ')') {
1069                         parens--;
1070                 } else if (*var == ':' && parens == 0) {
1071                         *var++ = '\0';
1072                         sscanf(var, "%d:%d", offset, length);
1073                         return 1; /* offset:length valid */
1074                 }
1075         }
1076         return 0;
1077 }
1078
1079 /*! \brief takes a substring. It is ok to call with value == workspace.
1080  *
1081  * offset < 0 means start from the end of the string and set the beginning
1082  *   to be that many characters back.
1083  * length is the length of the substring.  A value less than 0 means to leave
1084  * that many off the end.
1085  * Always return a copy in workspace.
1086  */
1087 static char *substring(const char *value, int offset, int length, char *workspace, size_t workspace_len)
1088 {
1089         char *ret = workspace;
1090         int lr; /* length of the input string after the copy */
1091
1092         ast_copy_string(workspace, value, workspace_len); /* always make a copy */
1093
1094         lr = strlen(ret); /* compute length after copy, so we never go out of the workspace */
1095
1096         /* Quick check if no need to do anything */
1097         if (offset == 0 && length >= lr)        /* take the whole string */
1098                 return ret;
1099
1100         if (offset < 0) {       /* translate negative offset into positive ones */
1101                 offset = lr + offset;
1102                 if (offset < 0) /* If the negative offset was greater than the length of the string, just start at the beginning */
1103                         offset = 0;
1104         }
1105
1106         /* too large offset result in empty string so we know what to return */
1107         if (offset >= lr)
1108                 return ret + lr;        /* the final '\0' */
1109
1110         ret += offset;          /* move to the start position */
1111         if (length >= 0 && length < lr - offset)        /* truncate if necessary */
1112                 ret[length] = '\0';
1113         else if (length < 0) {
1114                 if (lr > offset - length) /* After we remove from the front and from the rear, is there anything left? */
1115                         ret[lr + length - offset] = '\0';
1116                 else
1117                         ret[0] = '\0';
1118         }
1119
1120         return ret;
1121 }
1122
1123 /*! \brief  Support for Asterisk built-in variables in the dialplan
1124
1125 \note   See also
1126         - \ref AstVar   Channel variables
1127         - \ref AstCauses The HANGUPCAUSE variable
1128  */
1129 void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp)
1130 {
1131         const char not_found = '\0';
1132         char *tmpvar;
1133         const char *s;  /* the result */
1134         int offset, length;
1135         int i, need_substring;
1136         struct varshead *places[2] = { headp, &globals };       /* list of places where we may look */
1137
1138         if (c) {
1139                 places[0] = &c->varshead;
1140         }
1141         /*
1142          * Make a copy of var because parse_variable_name() modifies the string.
1143          * Then if called directly, we might need to run substring() on the result;
1144          * remember this for later in 'need_substring', 'offset' and 'length'
1145          */
1146         tmpvar = ast_strdupa(var);      /* parse_variable_name modifies the string */
1147         need_substring = parse_variable_name(tmpvar, &offset, &length, &i /* ignored */);
1148
1149         /*
1150          * Look first into predefined variables, then into variable lists.
1151          * Variable 's' points to the result, according to the following rules:
1152          * s == &not_found (set at the beginning) means that we did not find a
1153          *      matching variable and need to look into more places.
1154          * If s != &not_found, s is a valid result string as follows:
1155          * s = NULL if the variable does not have a value;
1156          *      you typically do this when looking for an unset predefined variable.
1157          * s = workspace if the result has been assembled there;
1158          *      typically done when the result is built e.g. with an snprintf(),
1159          *      so we don't need to do an additional copy.
1160          * s != workspace in case we have a string, that needs to be copied
1161          *      (the ast_copy_string is done once for all at the end).
1162          *      Typically done when the result is already available in some string.
1163          */
1164         s = &not_found; /* default value */
1165         if (c) {        /* This group requires a valid channel */
1166                 /* Names with common parts are looked up a piece at a time using strncmp. */
1167                 if (!strncmp(var, "CALL", 4)) {
1168                         if (!strncmp(var + 4, "ING", 3)) {
1169                                 if (!strcmp(var + 7, "PRES")) {                 /* CALLINGPRES */
1170                                         snprintf(workspace, workspacelen, "%d", c->cid.cid_pres);
1171                                         s = workspace;
1172                                 } else if (!strcmp(var + 7, "ANI2")) {          /* CALLINGANI2 */
1173                                         snprintf(workspace, workspacelen, "%d", c->cid.cid_ani2);
1174                                         s = workspace;
1175                                 } else if (!strcmp(var + 7, "TON")) {           /* CALLINGTON */
1176                                         snprintf(workspace, workspacelen, "%d", c->cid.cid_ton);
1177                                         s = workspace;
1178                                 } else if (!strcmp(var + 7, "TNS")) {           /* CALLINGTNS */
1179                                         snprintf(workspace, workspacelen, "%d", c->cid.cid_tns);
1180                                         s = workspace;
1181                                 }
1182                         }
1183                 } else if (!strcmp(var, "HINT")) {
1184                         s = ast_get_hint(workspace, workspacelen, NULL, 0, c, c->context, c->exten) ? workspace : NULL;
1185                 } else if (!strcmp(var, "HINTNAME")) {
1186                         s = ast_get_hint(NULL, 0, workspace, workspacelen, c, c->context, c->exten) ? workspace : NULL;
1187                 } else if (!strcmp(var, "EXTEN")) {
1188                         s = c->exten;
1189                 } else if (!strcmp(var, "CONTEXT")) {
1190                         s = c->context;
1191                 } else if (!strcmp(var, "PRIORITY")) {
1192                         snprintf(workspace, workspacelen, "%d", c->priority);
1193                         s = workspace;
1194                 } else if (!strcmp(var, "CHANNEL")) {
1195                         s = c->name;
1196                 } else if (!strcmp(var, "UNIQUEID")) {
1197                         s = c->uniqueid;
1198                 } else if (!strcmp(var, "HANGUPCAUSE")) {
1199                         snprintf(workspace, workspacelen, "%d", c->hangupcause);
1200                         s = workspace;
1201                 }
1202         }
1203         if (s == &not_found) { /* look for more */
1204                 if (!strcmp(var, "EPOCH")) {
1205                         snprintf(workspace, workspacelen, "%u",(int)time(NULL));
1206                         s = workspace;
1207                 } else if (!strcmp(var, "SYSTEMNAME")) {
1208                         s = ast_config_AST_SYSTEM_NAME;
1209                 }
1210         }
1211         /* if not found, look into chanvars or global vars */
1212         for (i = 0; s == &not_found && i < (sizeof(places) / sizeof(places[0])); i++) {
1213                 struct ast_var_t *variables;
1214                 if (!places[i])
1215                         continue;
1216                 if (places[i] == &globals)
1217                         ast_rwlock_rdlock(&globalslock);
1218                 AST_LIST_TRAVERSE(places[i], variables, entries) {
1219                         if (strcasecmp(ast_var_name(variables), var)==0) {
1220                                 s = ast_var_value(variables);
1221                                 break;
1222                         }
1223                 }
1224                 if (places[i] == &globals)
1225                         ast_rwlock_unlock(&globalslock);
1226         }
1227         if (s == &not_found || s == NULL)
1228                 *ret = NULL;
1229         else {
1230                 if (s != workspace)
1231                         ast_copy_string(workspace, s, workspacelen);
1232                 *ret = workspace;
1233                 if (need_substring)
1234                         *ret = substring(*ret, offset, length, workspace, workspacelen);
1235         }
1236 }
1237
1238 static int handle_show_functions(int fd, int argc, char *argv[])
1239 {
1240         struct ast_custom_function *acf;
1241         int count_acf = 0;
1242         int like = 0;
1243
1244         if (argc == 5 && (!strcmp(argv[3], "like")) ) {
1245                 like = 1;
1246         } else if (argc != 3) {
1247                 return RESULT_SHOWUSAGE;
1248         }
1249
1250         ast_cli(fd, "%s Custom Functions:\n--------------------------------------------------------------------------------\n", like ? "Matching" : "Installed");
1251
1252         AST_RWLIST_RDLOCK(&acf_root);
1253         AST_RWLIST_TRAVERSE(&acf_root, acf, acflist) {
1254                 if (!like || strstr(acf->name, argv[4])) {
1255                         count_acf++;
1256                         ast_cli(fd, "%-20.20s  %-35.35s  %s\n", acf->name, acf->syntax, acf->synopsis);
1257                 }
1258         }
1259         AST_RWLIST_UNLOCK(&acf_root);
1260
1261         ast_cli(fd, "%d %scustom functions installed.\n", count_acf, like ? "matching " : "");
1262
1263         return RESULT_SUCCESS;
1264 }
1265
1266 static int handle_show_function(int fd, int argc, char *argv[])
1267 {
1268         struct ast_custom_function *acf;
1269         /* Maximum number of characters added by terminal coloring is 22 */
1270         char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
1271         char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
1272         char stxtitle[40], *syntax = NULL;
1273         int synopsis_size, description_size, syntax_size;
1274
1275         if (argc < 4)
1276                 return RESULT_SHOWUSAGE;
1277
1278         if (!(acf = ast_custom_function_find(argv[3]))) {
1279                 ast_cli(fd, "No function by that name registered.\n");
1280                 return RESULT_FAILURE;
1281
1282         }
1283
1284         if (acf->synopsis)
1285                 synopsis_size = strlen(acf->synopsis) + 23;
1286         else
1287                 synopsis_size = strlen("Not available") + 23;
1288         synopsis = alloca(synopsis_size);
1289
1290         if (acf->desc)
1291                 description_size = strlen(acf->desc) + 23;
1292         else
1293                 description_size = strlen("Not available") + 23;
1294         description = alloca(description_size);
1295
1296         if (acf->syntax)
1297                 syntax_size = strlen(acf->syntax) + 23;
1298         else
1299                 syntax_size = strlen("Not available") + 23;
1300         syntax = alloca(syntax_size);
1301
1302         snprintf(info, 64 + AST_MAX_APP, "\n  -= Info about function '%s' =- \n\n", acf->name);
1303         term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
1304         term_color(stxtitle, "[Syntax]\n", COLOR_MAGENTA, 0, 40);
1305         term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
1306         term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
1307         term_color(syntax,
1308                    acf->syntax ? acf->syntax : "Not available",
1309                    COLOR_CYAN, 0, syntax_size);
1310         term_color(synopsis,
1311                    acf->synopsis ? acf->synopsis : "Not available",
1312                    COLOR_CYAN, 0, synopsis_size);
1313         term_color(description,
1314                    acf->desc ? acf->desc : "Not available",
1315                    COLOR_CYAN, 0, description_size);
1316
1317         ast_cli(fd,"%s%s%s\n\n%s%s\n\n%s%s\n", infotitle, stxtitle, syntax, syntitle, synopsis, destitle, description);
1318
1319         return RESULT_SUCCESS;
1320 }
1321
1322 static char *complete_show_function(const char *line, const char *word, int pos, int state)
1323 {
1324         struct ast_custom_function *acf;
1325         char *ret = NULL;
1326         int which = 0;
1327         int wordlen = strlen(word);
1328
1329         /* case-insensitive for convenience in this 'complete' function */
1330         AST_RWLIST_RDLOCK(&acf_root);
1331         AST_RWLIST_TRAVERSE(&acf_root, acf, acflist) {
1332                 if (!strncasecmp(word, acf->name, wordlen) && ++which > state) {
1333                         ret = strdup(acf->name);
1334                         break;
1335                 }
1336         }
1337         AST_RWLIST_UNLOCK(&acf_root);
1338
1339         return ret;
1340 }
1341
1342 struct ast_custom_function *ast_custom_function_find(const char *name)
1343 {
1344         struct ast_custom_function *acf = NULL;
1345
1346         AST_RWLIST_RDLOCK(&acf_root);
1347         AST_RWLIST_TRAVERSE(&acf_root, acf, acflist) {
1348                 if (!strcmp(name, acf->name))
1349                         break;
1350         }
1351         AST_RWLIST_UNLOCK(&acf_root);
1352
1353         return acf;
1354 }
1355
1356 int ast_custom_function_unregister(struct ast_custom_function *acf)
1357 {
1358         struct ast_custom_function *cur;
1359
1360         if (!acf)
1361                 return -1;
1362
1363         AST_RWLIST_WRLOCK(&acf_root);
1364         AST_RWLIST_TRAVERSE_SAFE_BEGIN(&acf_root, cur, acflist) {
1365                 if (cur == acf) {
1366                         AST_RWLIST_REMOVE_CURRENT(&acf_root, acflist);
1367                         if (option_verbose > 1)
1368                                 ast_verbose(VERBOSE_PREFIX_2 "Unregistered custom function %s\n", acf->name);
1369                         break;
1370                 }
1371         }
1372         AST_RWLIST_TRAVERSE_SAFE_END
1373         AST_RWLIST_UNLOCK(&acf_root);
1374
1375         return acf ? 0 : -1;
1376 }
1377
1378 int ast_custom_function_register(struct ast_custom_function *acf)
1379 {
1380         struct ast_custom_function *cur;
1381
1382         if (!acf)
1383                 return -1;
1384
1385         AST_RWLIST_WRLOCK(&acf_root);
1386
1387         AST_RWLIST_TRAVERSE(&acf_root, cur, acflist) {
1388                 if (!strcmp(acf->name, cur->name)) {
1389                         ast_log(LOG_ERROR, "Function %s already registered.\n", acf->name);
1390                         AST_RWLIST_UNLOCK(&acf_root);
1391                         return -1;
1392                 }
1393         }
1394
1395         /* Store in alphabetical order */
1396         AST_RWLIST_TRAVERSE_SAFE_BEGIN(&acf_root, cur, acflist) {
1397                 if (strcasecmp(acf->name, cur->name) < 0) {
1398                         AST_RWLIST_INSERT_BEFORE_CURRENT(&acf_root, acf, acflist);
1399                         break;
1400                 }
1401         }
1402         AST_RWLIST_TRAVERSE_SAFE_END
1403         if (!cur)
1404                 AST_RWLIST_INSERT_TAIL(&acf_root, acf, acflist);
1405
1406         AST_RWLIST_UNLOCK(&acf_root);
1407
1408         if (option_verbose > 1)
1409                 ast_verbose(VERBOSE_PREFIX_2 "Registered custom function %s\n", acf->name);
1410
1411         return 0;
1412 }
1413
1414 /*! \brief return a pointer to the arguments of the function,
1415  * and terminates the function name with '\\0'
1416  */
1417 static char *func_args(char *function)
1418 {
1419         char *args = strchr(function, '(');
1420
1421         if (!args)
1422                 ast_log(LOG_WARNING, "Function doesn't contain parentheses.  Assuming null argument.\n");
1423         else {
1424                 char *p;
1425                 *args++ = '\0';
1426                 if ((p = strrchr(args, ')')) )
1427                         *p = '\0';
1428                 else
1429                         ast_log(LOG_WARNING, "Can't find trailing parenthesis?\n");
1430         }
1431         return args;
1432 }
1433
1434 int ast_func_read(struct ast_channel *chan, const char *function, char *workspace, size_t len)
1435 {
1436         char *copy = ast_strdupa(function);
1437         char *args = func_args(copy);
1438         struct ast_custom_function *acfptr = ast_custom_function_find(copy);
1439
1440         if (acfptr == NULL)
1441                 ast_log(LOG_ERROR, "Function %s not registered\n", copy);
1442         else if (!acfptr->read)
1443                 ast_log(LOG_ERROR, "Function %s cannot be read\n", copy);
1444         else
1445                 return acfptr->read(chan, copy, args, workspace, len);
1446         return -1;
1447 }
1448
1449 int ast_func_write(struct ast_channel *chan, const char *function, const char *value)
1450 {
1451         char *copy = ast_strdupa(function);
1452         char *args = func_args(copy);
1453         struct ast_custom_function *acfptr = ast_custom_function_find(copy);
1454
1455         if (acfptr == NULL)
1456                 ast_log(LOG_ERROR, "Function %s not registered\n", copy);
1457         else if (!acfptr->write)
1458                 ast_log(LOG_ERROR, "Function %s cannot be written to\n", copy);
1459         else
1460                 return acfptr->write(chan, copy, args, value);
1461
1462         return -1;
1463 }
1464
1465 static void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int count)
1466 {
1467         /* Substitutes variables into cp2, based on string cp1, and assuming cp2 to be
1468            zero-filled */
1469         char *cp4;
1470         const char *tmp, *whereweare;
1471         int length, offset, offset2, isfunction;
1472         char *workspace = NULL;
1473         char *ltmp = NULL, *var = NULL;
1474         char *nextvar, *nextexp, *nextthing;
1475         char *vars, *vare;
1476         int pos, brackets, needsub, len;
1477
1478         whereweare=tmp=cp1;
1479         while (!ast_strlen_zero(whereweare) && count) {
1480                 /* Assume we're copying the whole remaining string */
1481                 pos = strlen(whereweare);
1482                 nextvar = NULL;
1483                 nextexp = NULL;
1484                 nextthing = strchr(whereweare, '$');
1485                 if (nextthing) {
1486                         switch (nextthing[1]) {
1487                         case '{':
1488                                 nextvar = nextthing;
1489                                 pos = nextvar - whereweare;
1490                                 break;
1491                         case '[':
1492                                 nextexp = nextthing;
1493                                 pos = nextexp - whereweare;
1494                                 break;
1495                         }
1496                 }
1497
1498                 if (pos) {
1499                         /* Can't copy more than 'count' bytes */
1500                         if (pos > count)
1501                                 pos = count;
1502
1503                         /* Copy that many bytes */
1504                         memcpy(cp2, whereweare, pos);
1505
1506                         count -= pos;
1507                         cp2 += pos;
1508                         whereweare += pos;
1509                 }
1510
1511                 if (nextvar) {
1512                         /* We have a variable.  Find the start and end, and determine
1513                            if we are going to have to recursively call ourselves on the
1514                            contents */
1515                         vars = vare = nextvar + 2;
1516                         brackets = 1;
1517                         needsub = 0;
1518
1519                         /* Find the end of it */
1520                         while (brackets && *vare) {
1521                                 if ((vare[0] == '$') && (vare[1] == '{')) {
1522                                         needsub++;
1523                                 } else if (vare[0] == '{') {
1524                                         brackets++;
1525                                 } else if (vare[0] == '}') {
1526                                         brackets--;
1527                                 } else if ((vare[0] == '$') && (vare[1] == '['))
1528                                         needsub++;
1529                                 vare++;
1530                         }
1531                         if (brackets)
1532                                 ast_log(LOG_NOTICE, "Error in extension logic (missing '}')\n");
1533                         len = vare - vars - 1;
1534
1535                         /* Skip totally over variable string */
1536                         whereweare += (len + 3);
1537
1538                         if (!var)
1539                                 var = alloca(VAR_BUF_SIZE);
1540
1541                         /* Store variable name (and truncate) */
1542                         ast_copy_string(var, vars, len + 1);
1543
1544                         /* Substitute if necessary */
1545                         if (needsub) {
1546                                 if (!ltmp)
1547                                         ltmp = alloca(VAR_BUF_SIZE);
1548
1549                                 memset(ltmp, 0, VAR_BUF_SIZE);
1550                                 pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1);
1551                                 vars = ltmp;
1552                         } else {
1553                                 vars = var;
1554                         }
1555
1556                         if (!workspace)
1557                                 workspace = alloca(VAR_BUF_SIZE);
1558
1559                         workspace[0] = '\0';
1560
1561                         parse_variable_name(vars, &offset, &offset2, &isfunction);
1562                         if (isfunction) {
1563                                 /* Evaluate function */
1564                                 cp4 = ast_func_read(c, vars, workspace, VAR_BUF_SIZE) ? NULL : workspace;
1565                                 if (option_debug)
1566                                         ast_log(LOG_DEBUG, "Function result is '%s'\n", cp4 ? cp4 : "(null)");
1567                         } else {
1568                                 /* Retrieve variable value */
1569                                 pbx_retrieve_variable(c, vars, &cp4, workspace, VAR_BUF_SIZE, headp);
1570                         }
1571                         if (cp4) {
1572                                 cp4 = substring(cp4, offset, offset2, workspace, VAR_BUF_SIZE);
1573
1574                                 length = strlen(cp4);
1575                                 if (length > count)
1576                                         length = count;
1577                                 memcpy(cp2, cp4, length);
1578                                 count -= length;
1579                                 cp2 += length;
1580                         }
1581                 } else if (nextexp) {
1582                         /* We have an expression.  Find the start and end, and determine
1583                            if we are going to have to recursively call ourselves on the
1584                            contents */
1585                         vars = vare = nextexp + 2;
1586                         brackets = 1;
1587                         needsub = 0;
1588
1589                         /* Find the end of it */
1590                         while (brackets && *vare) {
1591                                 if ((vare[0] == '$') && (vare[1] == '[')) {
1592                                         needsub++;
1593                                         brackets++;
1594                                         vare++;
1595                                 } else if (vare[0] == '[') {
1596                                         brackets++;
1597                                 } else if (vare[0] == ']') {
1598                                         brackets--;
1599                                 } else if ((vare[0] == '$') && (vare[1] == '{')) {
1600                                         needsub++;
1601                                         vare++;
1602                                 }
1603                                 vare++;
1604                         }
1605                         if (brackets)
1606                                 ast_log(LOG_NOTICE, "Error in extension logic (missing ']')\n");
1607                         len = vare - vars - 1;
1608
1609                         /* Skip totally over expression */
1610                         whereweare += (len + 3);
1611
1612                         if (!var)
1613                                 var = alloca(VAR_BUF_SIZE);
1614
1615                         /* Store variable name (and truncate) */
1616                         ast_copy_string(var, vars, len + 1);
1617
1618                         /* Substitute if necessary */
1619                         if (needsub) {
1620                                 if (!ltmp)
1621                                         ltmp = alloca(VAR_BUF_SIZE);
1622
1623                                 memset(ltmp, 0, VAR_BUF_SIZE);
1624                                 pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1);
1625                                 vars = ltmp;
1626                         } else {
1627                                 vars = var;
1628                         }
1629
1630                         length = ast_expr(vars, cp2, count);
1631
1632                         if (length) {
1633                                 if (option_debug)
1634                                         ast_log(LOG_DEBUG, "Expression result is '%s'\n", cp2);
1635                                 count -= length;
1636                                 cp2 += length;
1637                         }
1638                 } else
1639                         break;
1640         }
1641 }
1642
1643 void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
1644 {
1645         pbx_substitute_variables_helper_full(c, (c) ? &c->varshead : NULL, cp1, cp2, count);
1646 }
1647
1648 void pbx_substitute_variables_varshead(struct varshead *headp, const char *cp1, char *cp2, int count)
1649 {
1650         pbx_substitute_variables_helper_full(NULL, headp, cp1, cp2, count);
1651 }
1652
1653 static void pbx_substitute_variables(char *passdata, int datalen, struct ast_channel *c, struct ast_exten *e)
1654 {
1655         memset(passdata, 0, datalen);
1656
1657         /* No variables or expressions in e->data, so why scan it? */
1658         if (e->data && !strchr(e->data, '$') && !strstr(e->data,"${") && !strstr(e->data,"$[") && !strstr(e->data,"$(")) {
1659                 ast_copy_string(passdata, e->data, datalen);
1660                 return;
1661         }
1662
1663         pbx_substitute_variables_helper(c, e->data, passdata, datalen - 1);
1664 }
1665
1666 /*! \brief The return value depends on the action:
1667  *
1668  * E_MATCH, E_CANMATCH, E_MATCHMORE require a real match,
1669  *      and return 0 on failure, -1 on match;
1670  * E_FINDLABEL maps the label to a priority, and returns
1671  *      the priority on success, ... XXX
1672  * E_SPAWN, spawn an application,
1673  *      and return 0 on success, -1 on failure.
1674  */
1675 static int pbx_extension_helper(struct ast_channel *c, struct ast_context *con,
1676         const char *context, const char *exten, int priority,
1677         const char *label, const char *callerid, enum ext_match_t action)
1678 {
1679         struct ast_exten *e;
1680         struct ast_app *app;
1681         int res;
1682         struct pbx_find_info q = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */
1683         char passdata[EXT_DATA_SIZE];
1684
1685         int matching_action = (action == E_MATCH || action == E_CANMATCH || action == E_MATCHMORE);
1686
1687         ast_rdlock_contexts();
1688         e = pbx_find_extension(c, con, &q, context, exten, priority, label, callerid, action);
1689         if (e) {
1690                 if (matching_action) {
1691                         ast_unlock_contexts();
1692                         return -1;      /* success, we found it */
1693                 } else if (action == E_FINDLABEL) { /* map the label to a priority */
1694                         res = e->priority;
1695                         ast_unlock_contexts();
1696                         return res;     /* the priority we were looking for */
1697                 } else {        /* spawn */
1698                         if (!e->cached_app)
1699                                 e->cached_app = pbx_findapp(e->app);
1700                         app = e->cached_app;
1701                         ast_unlock_contexts();
1702                         if (!app) {
1703                                 ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
1704                                 return -1;
1705                         }
1706                         if (c->context != context)
1707                                 ast_copy_string(c->context, context, sizeof(c->context));
1708                         if (c->exten != exten)
1709                                 ast_copy_string(c->exten, exten, sizeof(c->exten));
1710                         c->priority = priority;
1711                         pbx_substitute_variables(passdata, sizeof(passdata), c, e);
1712                         if (option_debug) {
1713                                 char atmp[80];
1714                                 char atmp2[EXT_DATA_SIZE+100];
1715                                 if (option_debug)
1716                                         ast_log(LOG_DEBUG, "Launching '%s'\n", app->name);
1717                                 snprintf(atmp, sizeof(atmp), "STACK-%s-%s-%d", context, exten, priority);
1718                                 snprintf(atmp2, sizeof(atmp2), "%s(\"%s\", \"%s\") %s",
1719                                         app->name, c->name, passdata, "in new stack");
1720                                 pbx_builtin_setvar_helper(c, atmp, atmp2);
1721                         }
1722                         if (option_verbose > 2) {
1723                                 char tmp[80], tmp2[80], tmp3[EXT_DATA_SIZE];
1724                                 ast_verbose( VERBOSE_PREFIX_3 "Executing [%s@%s:%d] %s(\"%s\", \"%s\") %s\n",
1725                                         exten, context, priority,
1726                                         term_color(tmp, app->name, COLOR_BRCYAN, 0, sizeof(tmp)),
1727                                         term_color(tmp2, c->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
1728                                         term_color(tmp3, passdata, COLOR_BRMAGENTA, 0, sizeof(tmp3)),
1729                                         "in new stack");
1730                         }
1731                         manager_event(EVENT_FLAG_CALL, "Newexten",
1732                                         "Channel: %s\r\n"
1733                                         "Context: %s\r\n"
1734                                         "Extension: %s\r\n"
1735                                         "Priority: %d\r\n"
1736                                         "Application: %s\r\n"
1737                                         "AppData: %s\r\n"
1738                                         "Uniqueid: %s\r\n",
1739                                         c->name, c->context, c->exten, c->priority, app->name, passdata, c->uniqueid);
1740                         return pbx_exec(c, app, passdata);      /* 0 on success, -1 on failure */
1741                 }
1742         } else if (q.swo) {     /* not found here, but in another switch */
1743                 ast_unlock_contexts();
1744                 if (matching_action)
1745                         return -1;
1746                 else {
1747                         if (!q.swo->exec) {
1748                                 ast_log(LOG_WARNING, "No execution engine for switch %s\n", q.swo->name);
1749                                 res = -1;
1750                         }
1751                         return q.swo->exec(c, q.foundcontext ? q.foundcontext : context, exten, priority, callerid, q.data);
1752                 }
1753         } else {        /* not found anywhere, see what happened */
1754                 ast_unlock_contexts();
1755                 switch (q.status) {
1756                 case STATUS_NO_CONTEXT:
1757                         if (!matching_action)
1758                                 ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", context);
1759                         break;
1760                 case STATUS_NO_EXTENSION:
1761                         if (!matching_action)
1762                                 ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, context);
1763                         break;
1764                 case STATUS_NO_PRIORITY:
1765                         if (!matching_action)
1766                                 ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, context);
1767                         break;
1768                 case STATUS_NO_LABEL:
1769                         if (context)
1770                                 ast_log(LOG_NOTICE, "No such label '%s' in extension '%s' in context '%s'\n", label, exten, context);
1771                         break;
1772                 default:
1773                         if (option_debug)
1774                                 ast_log(LOG_DEBUG, "Shouldn't happen!\n");
1775                 }
1776
1777                 return (matching_action) ? 0 : -1;
1778         }
1779 }
1780
1781 /*! \brief  ast_hint_extension: Find hint for given extension in context */
1782 static struct ast_exten *ast_hint_extension(struct ast_channel *c, const char *context, const char *exten)
1783 {
1784         struct ast_exten *e;
1785         struct pbx_find_info q = { .stacklen = 0 }; /* the rest is set in pbx_find_context */
1786
1787         ast_rdlock_contexts();
1788         e = pbx_find_extension(c, NULL, &q, context, exten, PRIORITY_HINT, NULL, "", E_MATCH);
1789         ast_unlock_contexts();
1790
1791         return e;
1792 }
1793
1794 /*! \brief  ast_extensions_state2: Check state of extension by using hints */
1795 static int ast_extension_state2(struct ast_exten *e)
1796 {
1797         char hint[AST_MAX_EXTENSION];
1798         char *cur, *rest;
1799         int allunavailable = 1, allbusy = 1, allfree = 1, allonhold = 1;
1800         int busy = 0, inuse = 0, ring = 0;
1801
1802         if (!e)
1803                 return -1;
1804
1805         ast_copy_string(hint, ast_get_extension_app(e), sizeof(hint));
1806
1807         rest = hint;    /* One or more devices separated with a & character */
1808         while ( (cur = strsep(&rest, "&")) ) {
1809                 int res = ast_device_state(cur);
1810                 switch (res) {
1811                 case AST_DEVICE_NOT_INUSE:
1812                         allunavailable = 0;
1813                         allbusy = 0;
1814                         allonhold = 0;
1815                         break;
1816                 case AST_DEVICE_INUSE:
1817                         inuse = 1;
1818                         allunavailable = 0;
1819                         allfree = 0;
1820                         allonhold = 0;
1821                         break;
1822                 case AST_DEVICE_RINGING:
1823                         ring = 1;
1824                         allunavailable = 0;
1825                         allfree = 0;
1826                         allonhold = 0;
1827                         break;
1828                 case AST_DEVICE_RINGINUSE:
1829                         inuse = 1;
1830                         ring = 1;
1831                         allunavailable = 0;
1832                         allfree = 0;
1833                         allonhold = 0;
1834                         break;
1835                 case AST_DEVICE_ONHOLD:
1836                         allunavailable = 0;
1837                         allfree = 0;
1838                         break;
1839                 case AST_DEVICE_BUSY:
1840                         allunavailable = 0;
1841                         allfree = 0;
1842                         allonhold = 0;
1843                         busy = 1;
1844                         break;
1845                 case AST_DEVICE_UNAVAILABLE:
1846                 case AST_DEVICE_INVALID:
1847                         allbusy = 0;
1848                         allfree = 0;
1849                         allonhold = 0;
1850                         break;
1851                 default:
1852                         allunavailable = 0;
1853                         allbusy = 0;
1854                         allfree = 0;
1855                         allonhold = 0;
1856                 }
1857         }
1858
1859         if (!inuse && ring)
1860                 return AST_EXTENSION_RINGING;
1861         if (inuse && ring)
1862                 return (AST_EXTENSION_INUSE | AST_EXTENSION_RINGING);
1863         if (inuse)
1864                 return AST_EXTENSION_INUSE;
1865         if (allfree)
1866                 return AST_EXTENSION_NOT_INUSE;
1867         if (allonhold)
1868                 return AST_EXTENSION_ONHOLD;
1869         if (allbusy)
1870                 return AST_EXTENSION_BUSY;
1871         if (allunavailable)
1872                 return AST_EXTENSION_UNAVAILABLE;
1873         if (busy)
1874                 return AST_EXTENSION_INUSE;
1875
1876         return AST_EXTENSION_NOT_INUSE;
1877 }
1878
1879 /*! \brief  ast_extension_state2str: Return extension_state as string */
1880 const char *ast_extension_state2str(int extension_state)
1881 {
1882         int i;
1883
1884         for (i = 0; (i < (sizeof(extension_states) / sizeof(extension_states[0]))); i++) {
1885                 if (extension_states[i].extension_state == extension_state)
1886                         return extension_states[i].text;
1887         }
1888         return "Unknown";
1889 }
1890
1891 /*! \brief  ast_extension_state: Check extension state for an extension by using hint */
1892 int ast_extension_state(struct ast_channel *c, const char *context, const char *exten)
1893 {
1894         struct ast_exten *e;
1895
1896         e = ast_hint_extension(c, context, exten);      /* Do we have a hint for this extension ? */
1897         if (!e)
1898                 return -1;                              /* No hint, return -1 */
1899
1900         return ast_extension_state2(e);                 /* Check all devices in the hint */
1901 }
1902
1903 void ast_hint_state_changed(const char *device)
1904 {
1905         struct ast_hint *hint;
1906
1907         AST_RWLIST_RDLOCK(&hints);
1908
1909         AST_RWLIST_TRAVERSE(&hints, hint, list) {
1910                 struct ast_state_cb *cblist;
1911                 char buf[AST_MAX_EXTENSION];
1912                 char *parse = buf;
1913                 char *cur;
1914                 int state;
1915
1916                 ast_copy_string(buf, ast_get_extension_app(hint->exten), sizeof(buf));
1917                 while ( (cur = strsep(&parse, "&")) ) {
1918                         if (!strcasecmp(cur, device))
1919                                 break;
1920                 }
1921                 if (!cur)
1922                         continue;
1923
1924                 /* Get device state for this hint */
1925                 state = ast_extension_state2(hint->exten);
1926
1927                 if ((state == -1) || (state == hint->laststate))
1928                         continue;
1929
1930                 /* Device state changed since last check - notify the watchers */
1931
1932                 /* For general callbacks */
1933                 for (cblist = statecbs; cblist; cblist = cblist->next)
1934                         cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data);
1935
1936                 /* For extension callbacks */
1937                 for (cblist = hint->callbacks; cblist; cblist = cblist->next)
1938                         cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data);
1939
1940                 hint->laststate = state;        /* record we saw the change */
1941         }
1942
1943         AST_RWLIST_UNLOCK(&hints);
1944 }
1945
1946 /*! \brief  ast_extension_state_add: Add watcher for extension states */
1947 int ast_extension_state_add(const char *context, const char *exten,
1948                             ast_state_cb_type callback, void *data)
1949 {
1950         struct ast_hint *hint;
1951         struct ast_state_cb *cblist;
1952         struct ast_exten *e;
1953
1954         /* If there's no context and extension:  add callback to statecbs list */
1955         if (!context && !exten) {
1956                 AST_RWLIST_WRLOCK(&hints);
1957
1958                 for (cblist = statecbs; cblist; cblist = cblist->next) {
1959                         if (cblist->callback == callback) {
1960                                 cblist->data = data;
1961                                 AST_RWLIST_UNLOCK(&hints);
1962                                 return 0;
1963                         }
1964                 }
1965
1966                 /* Now insert the callback */
1967                 if (!(cblist = ast_calloc(1, sizeof(*cblist)))) {
1968                         AST_RWLIST_UNLOCK(&hints);
1969                         return -1;
1970                 }
1971                 cblist->id = 0;
1972                 cblist->callback = callback;
1973                 cblist->data = data;
1974
1975                 cblist->next = statecbs;
1976                 statecbs = cblist;
1977
1978                 AST_RWLIST_UNLOCK(&hints);
1979                 return 0;
1980         }
1981
1982         if (!context || !exten)
1983                 return -1;
1984
1985         /* This callback type is for only one hint, so get the hint */
1986         e = ast_hint_extension(NULL, context, exten);
1987         if (!e) {
1988                 return -1;
1989         }
1990
1991         /* Find the hint in the list of hints */
1992         AST_RWLIST_WRLOCK(&hints);
1993
1994         AST_RWLIST_TRAVERSE(&hints, hint, list) {
1995                 if (hint->exten == e)
1996                         break;
1997         }
1998
1999         if (!hint) {
2000                 /* We have no hint, sorry */
2001                 AST_RWLIST_UNLOCK(&hints);
2002                 return -1;
2003         }
2004
2005         /* Now insert the callback in the callback list  */
2006         if (!(cblist = ast_calloc(1, sizeof(*cblist)))) {
2007                 AST_RWLIST_UNLOCK(&hints);
2008                 return -1;
2009         }
2010         cblist->id = stateid++;         /* Unique ID for this callback */
2011         cblist->callback = callback;    /* Pointer to callback routine */
2012         cblist->data = data;            /* Data for the callback */
2013
2014         cblist->next = hint->callbacks;
2015         hint->callbacks = cblist;
2016
2017         AST_RWLIST_UNLOCK(&hints);
2018         return cblist->id;
2019 }
2020
2021 /*! \brief  ast_extension_state_del: Remove a watcher from the callback list */
2022 int ast_extension_state_del(int id, ast_state_cb_type callback)
2023 {
2024         struct ast_state_cb **p_cur = NULL;     /* address of pointer to us */
2025         int ret = -1;
2026
2027         if (!id && !callback)
2028                 return -1;
2029
2030         AST_RWLIST_WRLOCK(&hints);
2031
2032         if (!id) {      /* id == 0 is a callback without extension */
2033                 for (p_cur = &statecbs; *p_cur; p_cur = &(*p_cur)->next) {
2034                         if ((*p_cur)->callback == callback)
2035                                 break;
2036                 }
2037         } else { /* callback with extension, find the callback based on ID */
2038                 struct ast_hint *hint;
2039                 AST_RWLIST_TRAVERSE(&hints, hint, list) {
2040                         for (p_cur = &hint->callbacks; *p_cur; p_cur = &(*p_cur)->next) {
2041                                 if ((*p_cur)->id == id)
2042                                         break;
2043                         }
2044                         if (*p_cur)     /* found in the inner loop */
2045                                 break;
2046                 }
2047         }
2048         if (p_cur && *p_cur) {
2049                 struct ast_state_cb *cur = *p_cur;
2050                 *p_cur = cur->next;
2051                 free(cur);
2052                 ret = 0;
2053         }
2054         AST_RWLIST_UNLOCK(&hints);
2055         return ret;
2056 }
2057
2058 /*! \brief  ast_add_hint: Add hint to hint list, check initial extension state */
2059 static int ast_add_hint(struct ast_exten *e)
2060 {
2061         struct ast_hint *hint;
2062
2063         if (!e)
2064                 return -1;
2065
2066         AST_RWLIST_WRLOCK(&hints);
2067
2068         /* Search if hint exists, do nothing */
2069         AST_RWLIST_TRAVERSE(&hints, hint, list) {
2070                 if (hint->exten == e) {
2071                         AST_RWLIST_UNLOCK(&hints);
2072                         if (option_debug > 1)
2073                                 ast_log(LOG_DEBUG, "HINTS: Not re-adding existing hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
2074                         return -1;
2075                 }
2076         }
2077
2078         if (option_debug > 1)
2079                 ast_log(LOG_DEBUG, "HINTS: Adding hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
2080
2081         if (!(hint = ast_calloc(1, sizeof(*hint)))) {
2082                 AST_RWLIST_UNLOCK(&hints);
2083                 return -1;
2084         }
2085         /* Initialize and insert new item at the top */
2086         hint->exten = e;
2087         hint->laststate = ast_extension_state2(e);
2088         AST_RWLIST_INSERT_HEAD(&hints, hint, list);
2089
2090         AST_RWLIST_UNLOCK(&hints);
2091         return 0;
2092 }
2093
2094 /*! \brief  ast_change_hint: Change hint for an extension */
2095 static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
2096 {
2097         struct ast_hint *hint;
2098         int res = -1;
2099
2100         AST_RWLIST_WRLOCK(&hints);
2101         AST_RWLIST_TRAVERSE(&hints, hint, list) {
2102                 if (hint->exten == oe) {
2103                         hint->exten = ne;
2104                         res = 0;
2105                         break;
2106                 }
2107         }
2108         AST_RWLIST_UNLOCK(&hints);
2109
2110         return res;
2111 }
2112
2113 /*! \brief  ast_remove_hint: Remove hint from extension */
2114 static int ast_remove_hint(struct ast_exten *e)
2115 {
2116         /* Cleanup the Notifys if hint is removed */
2117         struct ast_hint *hint;
2118         struct ast_state_cb *cblist, *cbprev;
2119         int res = -1;
2120
2121         if (!e)
2122                 return -1;
2123
2124         AST_RWLIST_TRAVERSE_SAFE_BEGIN(&hints, hint, list) {
2125                 if (hint->exten == e) {
2126                         cbprev = NULL;
2127                         cblist = hint->callbacks;
2128                         while (cblist) {
2129                                 /* Notify with -1 and remove all callbacks */
2130                                 cbprev = cblist;
2131                                 cblist = cblist->next;
2132                                 cbprev->callback(hint->exten->parent->name, hint->exten->exten, AST_EXTENSION_DEACTIVATED, cbprev->data);
2133                                 free(cbprev);
2134                         }
2135                         hint->callbacks = NULL;
2136                         AST_RWLIST_REMOVE_CURRENT(&hints, list);
2137                         free(hint);
2138                         res = 0;
2139                         break;
2140                 }
2141         }
2142         AST_RWLIST_TRAVERSE_SAFE_END
2143
2144         return res;
2145 }
2146
2147
2148 /*! \brief  ast_get_hint: Get hint for channel */
2149 int ast_get_hint(char *hint, int hintsize, char *name, int namesize, struct ast_channel *c, const char *context, const char *exten)
2150 {
2151         struct ast_exten *e = ast_hint_extension(c, context, exten);
2152
2153         if (e) {
2154                 if (hint)
2155                         ast_copy_string(hint, ast_get_extension_app(e), hintsize);
2156                 if (name) {
2157                         const char *tmp = ast_get_extension_app_data(e);
2158                         if (tmp)
2159                                 ast_copy_string(name, tmp, namesize);
2160                 }
2161                 return -1;
2162         }
2163         return 0;
2164 }
2165
2166 int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
2167 {
2168         return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_MATCH);
2169 }
2170
2171 int ast_findlabel_extension(struct ast_channel *c, const char *context, const char *exten, const char *label, const char *callerid)
2172 {
2173         return pbx_extension_helper(c, NULL, context, exten, 0, label, callerid, E_FINDLABEL);
2174 }
2175
2176 int ast_findlabel_extension2(struct ast_channel *c, struct ast_context *con, const char *exten, const char *label, const char *callerid)
2177 {
2178         return pbx_extension_helper(c, con, NULL, exten, 0, label, callerid, E_FINDLABEL);
2179 }
2180
2181 int ast_canmatch_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
2182 {
2183         return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_CANMATCH);
2184 }
2185
2186 int ast_matchmore_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
2187 {
2188         return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_MATCHMORE);
2189 }
2190
2191 int ast_spawn_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
2192 {
2193         return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_SPAWN);
2194 }
2195
2196 /* helper function to set extension and priority */
2197 static void set_ext_pri(struct ast_channel *c, const char *exten, int pri)
2198 {
2199         ast_copy_string(c->exten, exten, sizeof(c->exten));
2200         c->priority = pri;
2201 }
2202
2203 /*!
2204  * \brief collect digits from the channel into the buffer,
2205  * return -1 on error, 0 on timeout or done.
2206  */
2207 static int collect_digits(struct ast_channel *c, int waittime, char *buf, int buflen, int pos)
2208 {
2209         int digit;
2210
2211         buf[pos] = '\0';        /* make sure it is properly terminated */
2212         while (ast_matchmore_extension(c, c->context, buf, 1, c->cid.cid_num)) {
2213                 /* As long as we're willing to wait, and as long as it's not defined,
2214                    keep reading digits until we can't possibly get a right answer anymore.  */
2215                 digit = ast_waitfordigit(c, waittime * 1000);
2216                 if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
2217                         c->_softhangup = 0;
2218                 } else {
2219                         if (!digit)     /* No entry */
2220                                 break;
2221                         if (digit < 0)  /* Error, maybe a  hangup */
2222                                 return -1;
2223                         if (pos < buflen - 1) { /* XXX maybe error otherwise ? */
2224                                 buf[pos++] = digit;
2225                                 buf[pos] = '\0';
2226                         }
2227                         waittime = c->pbx->dtimeout;
2228                 }
2229         }
2230         return 0;
2231 }
2232
2233 static int __ast_pbx_run(struct ast_channel *c)
2234 {
2235         int found = 0;  /* set if we find at least one match */
2236         int res = 0;
2237         int autoloopflag;
2238         int error = 0;          /* set an error conditions */
2239
2240         /* A little initial setup here */
2241         if (c->pbx) {
2242                 ast_log(LOG_WARNING, "%s already has PBX structure??\n", c->name);
2243                 /* XXX and now what ? */
2244                 free(c->pbx);
2245         }
2246         if (!(c->pbx = ast_calloc(1, sizeof(*c->pbx))))
2247                 return -1;
2248         if (c->amaflags) {
2249                 if (!c->cdr) {
2250                         c->cdr = ast_cdr_alloc();
2251                         if (!c->cdr) {
2252                                 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
2253                                 free(c->pbx);
2254                                 return -1;
2255                         }
2256                         ast_cdr_init(c->cdr, c);
2257                 }
2258         }
2259         /* Set reasonable defaults */
2260         c->pbx->rtimeout = 10;
2261         c->pbx->dtimeout = 5;
2262
2263         autoloopflag = ast_test_flag(c, AST_FLAG_IN_AUTOLOOP);  /* save value to restore at the end */
2264         ast_set_flag(c, AST_FLAG_IN_AUTOLOOP);
2265
2266         /* Start by trying whatever the channel is set to */
2267         if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2268                 /* If not successful fall back to 's' */
2269                 if (option_verbose > 1)
2270                         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);
2271                 /* XXX the original code used the existing priority in the call to
2272                  * ast_exists_extension(), and reset it to 1 afterwards.
2273                  * I believe the correct thing is to set it to 1 immediately.
2274                  */
2275                 set_ext_pri(c, "s", 1);
2276                 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2277                         /* JK02: And finally back to default if everything else failed */
2278                         if (option_verbose > 1)
2279                                 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);
2280                         ast_copy_string(c->context, "default", sizeof(c->context));
2281                 }
2282         }
2283         if (c->cdr && ast_tvzero(c->cdr->start))
2284                 ast_cdr_start(c->cdr);
2285         for (;;) {
2286                 char dst_exten[256];    /* buffer to accumulate digits */
2287                 int pos = 0;            /* XXX should check bounds */
2288                 int digit = 0;
2289
2290                 /* loop on priorities in this context/exten */
2291                 while (ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2292                         found = 1;
2293                         if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
2294                                 /* Something bad happened, or a hangup has been requested. */
2295                                 if (strchr("0123456789ABCDEF*#", res)) {
2296                                         if (option_debug)
2297                                                 ast_log(LOG_DEBUG, "Oooh, got something to jump out with ('%c')!\n", res);
2298                                         pos = 0;
2299                                         dst_exten[pos++] = digit = res;
2300                                         dst_exten[pos] = '\0';
2301                                         break;
2302                                 }
2303                                 if (res == AST_PBX_KEEPALIVE) {
2304                                         if (option_debug)
2305                                                 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
2306                                         if (option_verbose > 1)
2307                                                 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
2308                                         error = 1;
2309                                         break;
2310                                 }
2311                                 if (option_debug)
2312                                         ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2313                                 if (option_verbose > 1)
2314                                         ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2315                                 if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
2316                                         c->_softhangup =0;
2317                                 } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
2318                                         /* atimeout, nothing bad */
2319                                 } else {
2320                                         if (c->cdr)
2321                                                 ast_cdr_update(c);
2322                                         error = 1;
2323                                         break;
2324                                 }
2325                         }
2326                         if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT && ast_exists_extension(c,c->context,"T",1,c->cid.cid_num)) {
2327                                 set_ext_pri(c, "T", 0); /* 0 will become 1 with the c->priority++; at the end */
2328                                 /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
2329                                 c->whentohangup = 0;
2330                                 c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
2331                         } else if (c->_softhangup) {
2332                                 if (option_debug)
2333                                         ast_log(LOG_DEBUG, "Extension %s, priority %d returned normally even though call was hung up\n",
2334                                                 c->exten, c->priority);
2335                                 error = 1;
2336                                 break;
2337                         }
2338                         c->priority++;
2339                 } /* end while  - from here on we can use 'break' to go out */
2340                 if (error)
2341                         break;
2342
2343                 /* XXX we get here on non-existing extension or a keypress or hangup ? */
2344
2345                 if (!ast_exists_extension(c, c->context, c->exten, 1, c->cid.cid_num)) {
2346                         /* If there is no match at priority 1, it is not a valid extension anymore.
2347                          * Try to continue at "i", 1 or exit if the latter does not exist.
2348                          */
2349                         if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
2350                                 if (option_verbose > 2)
2351                                         ast_verbose(VERBOSE_PREFIX_3 "Sent into invalid extension '%s' in context '%s' on %s\n", c->exten, c->context, c->name);
2352                                 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", c->exten);
2353                                 set_ext_pri(c, "i", 1);
2354                         } else {
2355                                 ast_log(LOG_WARNING, "Channel '%s' sent into invalid extension '%s' in context '%s', but no invalid handler\n",
2356                                         c->name, c->exten, c->context);
2357                                 error = 1; /* we know what to do with it */
2358                                 break;
2359                         }
2360                 } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
2361                         /* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */
2362                         c->_softhangup = 0;
2363                 } else {        /* keypress received, get more digits for a full extension */
2364                         int waittime = 0;
2365                         if (digit)
2366                                 waittime = c->pbx->dtimeout;
2367                         else if (!autofallthrough)
2368                                 waittime = c->pbx->rtimeout;
2369                         if (!waittime) {
2370                                 const char *status = pbx_builtin_getvar_helper(c, "DIALSTATUS");
2371                                 if (!status)
2372                                         status = "UNKNOWN";
2373                                 if (option_verbose > 2)
2374                                         ast_verbose(VERBOSE_PREFIX_2 "Auto fallthrough, channel '%s' status is '%s'\n", c->name, status);
2375                                 if (!strcasecmp(status, "CONGESTION"))
2376                                         res = pbx_builtin_congestion(c, "10");
2377                                 else if (!strcasecmp(status, "CHANUNAVAIL"))
2378                                         res = pbx_builtin_congestion(c, "10");
2379                                 else if (!strcasecmp(status, "BUSY"))
2380                                         res = pbx_builtin_busy(c, "10");
2381                                 error = 1; /* XXX disable message */
2382                                 break;  /* exit from the 'for' loop */
2383                         }
2384
2385                         if (collect_digits(c, waittime, dst_exten, sizeof(dst_exten), pos))
2386                                 break;
2387                         if (ast_exists_extension(c, c->context, dst_exten, 1, c->cid.cid_num)) /* Prepare the next cycle */
2388                                 set_ext_pri(c, dst_exten, 1);
2389                         else {
2390                                 /* No such extension */
2391                                 if (!ast_strlen_zero(dst_exten)) {
2392                                         /* An invalid extension */
2393                                         if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
2394                                                 if (option_verbose > 2)
2395                                                         ast_verbose( VERBOSE_PREFIX_3 "Invalid extension '%s' in context '%s' on %s\n", dst_exten, c->context, c->name);
2396                                                 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", dst_exten);
2397                                                 set_ext_pri(c, "i", 1);
2398                                         } else {
2399                                                 ast_log(LOG_WARNING, "Invalid extension '%s', but no rule 'i' in context '%s'\n", dst_exten, c->context);
2400                                                 found = 1; /* XXX disable message */
2401                                                 break;
2402                                         }
2403                                 } else {
2404                                         /* A simple timeout */
2405                                         if (ast_exists_extension(c, c->context, "t", 1, c->cid.cid_num)) {
2406                                                 if (option_verbose > 2)
2407                                                         ast_verbose( VERBOSE_PREFIX_3 "Timeout on %s\n", c->name);
2408                                                 set_ext_pri(c, "t", 1);
2409                                         } else {
2410                                                 ast_log(LOG_WARNING, "Timeout, but no rule 't' in context '%s'\n", c->context);
2411                                                 found = 1; /* XXX disable message */
2412                                                 break;
2413                                         }
2414                                 }
2415                         }
2416                         if (c->cdr) {
2417                                 if (option_verbose > 2)
2418                                         ast_verbose(VERBOSE_PREFIX_2 "CDR updated on %s\n",c->name);
2419                                 ast_cdr_update(c);
2420                         }
2421                 }
2422         }
2423         if (!found && !error)
2424                 ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", c->name);
2425         if ((res != AST_PBX_KEEPALIVE) && ast_exists_extension(c, c->context, "h", 1, c->cid.cid_num)) {
2426                 if (c->cdr && ast_opt_end_cdr_before_h_exten)
2427                         ast_cdr_end(c->cdr);
2428                 set_ext_pri(c, "h", 1);
2429                 while (ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2430                         if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
2431                                 /* Something bad happened, or a hangup has been requested. */
2432                                 if (option_debug)
2433                                         ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2434                                 if (option_verbose > 1)
2435                                         ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2436                                 break;
2437                         }
2438                         c->priority++;
2439                 }
2440         }
2441         ast_set2_flag(c, autoloopflag, AST_FLAG_IN_AUTOLOOP);
2442
2443         pbx_destroy(c->pbx);
2444         c->pbx = NULL;
2445         if (res != AST_PBX_KEEPALIVE)
2446                 ast_hangup(c);
2447         return 0;
2448 }
2449
2450 /* Returns 0 on success, non-zero if call limit was reached */
2451 static int increase_call_count(const struct ast_channel *c)
2452 {
2453         int failed = 0;
2454         double curloadavg;
2455         ast_mutex_lock(&maxcalllock);
2456         if (option_maxcalls) {
2457                 if (countcalls >= option_maxcalls) {
2458                         ast_log(LOG_NOTICE, "Maximum call limit of %d calls exceeded by '%s'!\n", option_maxcalls, c->name);
2459                         failed = -1;
2460                 }
2461         }
2462         if (option_maxload) {
2463                 getloadavg(&curloadavg, 1);
2464                 if (curloadavg >= option_maxload) {
2465                         ast_log(LOG_NOTICE, "Maximum loadavg limit of %f load exceeded by '%s' (currently %f)!\n", option_maxload, c->name, curloadavg);
2466                         failed = -1;
2467                 }
2468         }
2469         if (!failed)
2470                 countcalls++;
2471         ast_mutex_unlock(&maxcalllock);
2472
2473         return failed;
2474 }
2475
2476 static void decrease_call_count(void)
2477 {
2478         ast_mutex_lock(&maxcalllock);
2479         if (countcalls > 0)
2480                 countcalls--;
2481         ast_mutex_unlock(&maxcalllock);
2482 }
2483
2484 static void destroy_exten(struct ast_exten *e)
2485 {
2486         if (e->priority == PRIORITY_HINT)
2487                 ast_remove_hint(e);
2488
2489         if (e->datad)
2490                 e->datad(e->data);
2491         free(e);
2492 }
2493
2494 static void *pbx_thread(void *data)
2495 {
2496         /* Oh joyeous kernel, we're a new thread, with nothing to do but
2497            answer this channel and get it going.
2498         */
2499         /* NOTE:
2500            The launcher of this function _MUST_ increment 'countcalls'
2501            before invoking the function; it will be decremented when the
2502            PBX has finished running on the channel
2503          */
2504         struct ast_channel *c = data;
2505
2506         __ast_pbx_run(c);
2507         decrease_call_count();
2508
2509         pthread_exit(NULL);
2510
2511         return NULL;
2512 }
2513
2514 enum ast_pbx_result ast_pbx_start(struct ast_channel *c)
2515 {
2516         pthread_t t;
2517         pthread_attr_t attr;
2518
2519         if (!c) {
2520                 ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
2521                 return AST_PBX_FAILED;
2522         }
2523
2524         if (increase_call_count(c))
2525                 return AST_PBX_CALL_LIMIT;
2526
2527         /* Start a new thread, and get something handling this channel. */
2528         pthread_attr_init(&attr);
2529         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
2530         if (ast_pthread_create(&t, &attr, pbx_thread, c)) {
2531                 ast_log(LOG_WARNING, "Failed to create new channel thread\n");
2532                 pthread_attr_destroy(&attr);
2533                 return AST_PBX_FAILED;
2534         }
2535         pthread_attr_destroy(&attr);
2536
2537         return AST_PBX_SUCCESS;
2538 }
2539
2540 enum ast_pbx_result ast_pbx_run(struct ast_channel *c)
2541 {
2542         enum ast_pbx_result res = AST_PBX_SUCCESS;
2543
2544         if (increase_call_count(c))
2545                 return AST_PBX_CALL_LIMIT;
2546
2547         res = __ast_pbx_run(c);
2548         decrease_call_count();
2549
2550         return res;
2551 }
2552
2553 int ast_active_calls(void)
2554 {
2555         return countcalls;
2556 }
2557
2558 int pbx_set_autofallthrough(int newval)
2559 {
2560         int oldval = autofallthrough;
2561         autofallthrough = newval;
2562         return oldval;
2563 }
2564
2565 /* lookup for a context with a given name,
2566  * return with conlock held if found, NULL if not found
2567  */
2568 static struct ast_context *find_context_locked(const char *context)
2569 {
2570         struct ast_context *c = NULL;
2571
2572         ast_rdlock_contexts();
2573         while ( (c = ast_walk_contexts(c)) ) {
2574                 if (!strcmp(ast_get_context_name(c), context))
2575                         return c;
2576         }
2577         ast_unlock_contexts();
2578
2579         return NULL;
2580 }
2581
2582 /*
2583  * This function locks contexts list by &conlist, search for the right context
2584  * structure, leave context list locked and call ast_context_remove_include2
2585  * which removes include, unlock contexts list and return ...
2586  */
2587 int ast_context_remove_include(const char *context, const char *include, const char *registrar)
2588 {
2589         int ret = -1;
2590         struct ast_context *c = find_context_locked(context);
2591
2592         if (c) {
2593                 /* found, remove include from this context ... */
2594                 ret = ast_context_remove_include2(c, include, registrar);
2595                 ast_unlock_contexts();
2596         }
2597         return ret;
2598 }
2599
2600 /*
2601  * When we call this function, &conlock lock must be locked, because when
2602  * we giving *con argument, some process can remove/change this context
2603  * and after that there can be segfault.
2604  *
2605  * This function locks given context, removes include, unlock context and
2606  * return.
2607  */
2608 int ast_context_remove_include2(struct ast_context *con, const char *include, const char *registrar)
2609 {
2610         struct ast_include *i, *pi = NULL;
2611         int ret = -1;
2612
2613         ast_wrlock_context(con);
2614
2615         /* find our include */
2616         for (i = con->includes; i; pi = i, i = i->next) {
2617                 if (!strcmp(i->name, include) &&
2618                                 (!registrar || !strcmp(i->registrar, registrar))) {
2619                         /* remove from list */
2620                         if (pi)
2621                                 pi->next = i->next;
2622                         else
2623                                 con->includes = i->next;
2624                         /* free include and return */
2625                         free(i);
2626                         ret = 0;
2627                         break;
2628                 }
2629         }
2630
2631         ast_unlock_context(con);
2632
2633         return ret;
2634 }
2635
2636 /*!
2637  * \note This function locks contexts list by &conlist, search for the rigt context
2638  * structure, leave context list locked and call ast_context_remove_switch2
2639  * which removes switch, unlock contexts list and return ...
2640  */
2641 int ast_context_remove_switch(const char *context, const char *sw, const char *data, const char *registrar)
2642 {
2643         int ret = -1; /* default error return */
2644         struct ast_context *c = find_context_locked(context);
2645
2646         if (c) {
2647                 /* remove switch from this context ... */
2648                 ret = ast_context_remove_switch2(c, sw, data, registrar);
2649                 ast_unlock_contexts();
2650         }
2651         return ret;
2652 }
2653
2654 /*!
2655  * \brief This function locks given context, removes switch, unlock context and
2656  * return.
2657  * \note When we call this function, &conlock lock must be locked, because when
2658  * we giving *con argument, some process can remove/change this context
2659  * and after that there can be segfault.
2660  *
2661  */
2662 int ast_context_remove_switch2(struct ast_context *con, const char *sw, const char *data, const char *registrar)
2663 {
2664         struct ast_sw *i;
2665         int ret = -1;
2666
2667         ast_wrlock_context(con);
2668
2669         /* walk switches */
2670         AST_LIST_TRAVERSE_SAFE_BEGIN(&con->alts, i, list) {
2671                 if (!strcmp(i->name, sw) && !strcmp(i->data, data) &&
2672                         (!registrar || !strcmp(i->registrar, registrar))) {
2673                         /* found, remove from list */
2674                         AST_LIST_REMOVE_CURRENT(&con->alts, list);
2675                         free(i); /* free switch and return */
2676                         ret = 0;
2677                         break;
2678                 }
2679         }
2680         AST_LIST_TRAVERSE_SAFE_END
2681
2682         ast_unlock_context(con);
2683
2684         return ret;
2685 }
2686
2687 /*
2688  * \note This functions lock contexts list, search for the right context,
2689  * call ast_context_remove_extension2, unlock contexts list and return.
2690  * In this function we are using
2691  */
2692 int ast_context_remove_extension(const char *context, const char *extension, int priority, const char *registrar)
2693 {
2694         int ret = -1; /* default error return */
2695         struct ast_context *c = find_context_locked(context);
2696
2697         if (c) { /* ... remove extension ... */
2698                 ret = ast_context_remove_extension2(c, extension, priority, registrar);
2699                 ast_unlock_contexts();
2700         }
2701         return ret;
2702 }
2703
2704 /*!
2705  * \brief This functionc locks given context, search for the right extension and
2706  * fires out all peer in this extensions with given priority. If priority
2707  * is set to 0, all peers are removed. After that, unlock context and
2708  * return.
2709  * \note When do you want to call this function, make sure that &conlock is locked,
2710  * because some process can handle with your *con context before you lock
2711  * it.
2712  *
2713  */
2714 int ast_context_remove_extension2(struct ast_context *con, const char *extension, int priority, const char *registrar)
2715 {
2716         struct ast_exten *exten, *prev_exten = NULL;
2717         struct ast_exten *peer;
2718
2719         ast_wrlock_context(con);
2720
2721         /* scan the extension list to find matching extension-registrar */
2722         for (exten = con->root; exten; prev_exten = exten, exten = exten->next) {
2723                 if (!strcmp(exten->exten, extension) &&
2724                         (!registrar || !strcmp(exten->registrar, registrar)))
2725                         break;
2726         }
2727         if (!exten) {
2728                 /* we can't find right extension */
2729                 ast_unlock_context(con);
2730                 return -1;
2731         }
2732
2733         /* should we free all peers in this extension? (priority == 0)? */
2734         if (priority == 0) {
2735                 /* remove this extension from context list */
2736                 if (prev_exten)
2737                         prev_exten->next = exten->next;
2738                 else
2739                         con->root = exten->next;
2740
2741                 /* fire out all peers */
2742                 while ( (peer = exten) ) {
2743                         exten = peer->peer; /* prepare for next entry */
2744                         destroy_exten(peer);
2745                 }
2746         } else {
2747                 /* scan the priority list to remove extension with exten->priority == priority */
2748                 struct ast_exten *previous_peer = NULL;
2749
2750                 for (peer = exten; peer; previous_peer = peer, peer = peer->peer) {
2751                         if (peer->priority == priority &&
2752                                         (!registrar || !strcmp(peer->registrar, registrar) ))
2753                                 break; /* found our priority */
2754                 }
2755                 if (!peer) { /* not found */
2756                         ast_unlock_context(con);
2757                         return -1;
2758                 }
2759                 /* we are first priority extension? */
2760                 if (!previous_peer) {
2761                         /*
2762                          * We are first in the priority chain, so must update the extension chain.
2763                          * The next node is either the next priority or the next extension
2764                          */
2765                         struct ast_exten *next_node = peer->peer ? peer->peer : peer->next;
2766
2767                         if (!prev_exten)        /* change the root... */
2768                                 con->root = next_node;
2769                         else
2770                                 prev_exten->next = next_node; /* unlink */
2771                         if (peer->peer) /* XXX update the new head of the pri list */
2772                                 peer->peer->next = peer->next;
2773                 } else { /* easy, we are not first priority in extension */
2774                         previous_peer->peer = peer->peer;
2775                 }
2776
2777                 /* now, free whole priority extension */
2778                 destroy_exten(peer);
2779                 /* XXX should we return -1 ? */
2780         }
2781         ast_unlock_context(con);
2782         return 0;
2783 }
2784
2785
2786 /*!
2787  * \note This function locks contexts list by &conlist, searches for the right context
2788  * structure, and locks the macrolock mutex in that context.
2789  * macrolock is used to limit a macro to be executed by one call at a time.
2790  */
2791 int ast_context_lockmacro(const char *context)
2792 {
2793         struct ast_context *c = NULL;
2794         int ret = -1;
2795
2796         ast_rdlock_contexts();
2797
2798         while ((c = ast_walk_contexts(c))) {
2799                 if (!strcmp(ast_get_context_name(c), context)) {
2800                         ret = 0;
2801                         break;
2802                 }
2803         }
2804
2805         ast_unlock_contexts();
2806
2807         /* if we found context, lock macrolock */
2808         if (ret == 0) 
2809                 ret = ast_mutex_lock(&c->macrolock);
2810
2811         return ret;
2812 }
2813
2814 /*!
2815  * \note This function locks contexts list by &conlist, searches for the right context
2816  * structure, and unlocks the macrolock mutex in that context.
2817  * macrolock is used to limit a macro to be executed by one call at a time.
2818  */
2819 int ast_context_unlockmacro(const char *context)
2820 {
2821         struct ast_context *c = NULL;
2822         int ret = -1;
2823
2824         ast_rdlock_contexts();
2825
2826         while ((c = ast_walk_contexts(c))) {
2827                 if (!strcmp(ast_get_context_name(c), context)) {
2828                         ret = 0;
2829                         break;
2830                 }
2831         }
2832
2833         ast_unlock_contexts();
2834
2835         /* if we found context, unlock macrolock */
2836         if (ret == 0) 
2837                 ret = ast_mutex_unlock(&c->macrolock);
2838
2839         return ret;
2840 }
2841
2842 /*! \brief Dynamically register a new dial plan application */
2843 int ast_register_application(const char *app, int (*execute)(struct ast_channel *, void *), const char *synopsis, const char *description)
2844 {
2845         struct ast_app *tmp, *cur = NULL;
2846         char tmps[80];
2847         int length;
2848
2849         AST_RWLIST_WRLOCK(&apps);
2850         AST_RWLIST_TRAVERSE(&apps, tmp, list) {
2851                 if (!strcasecmp(app, tmp->name)) {
2852                         ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
2853                         AST_RWLIST_UNLOCK(&apps);
2854                         return -1;
2855                 }
2856         }
2857
2858         length = sizeof(*tmp) + strlen(app) + 1;
2859
2860         if (!(tmp = ast_calloc(1, length))) {
2861                 AST_RWLIST_UNLOCK(&apps);
2862                 return -1;
2863         }
2864
2865         strcpy(tmp->name, app);
2866         tmp->execute = execute;
2867         tmp->synopsis = synopsis;
2868         tmp->description = description;
2869
2870         /* Store in alphabetical order */
2871         AST_RWLIST_TRAVERSE_SAFE_BEGIN(&apps, cur, list) {
2872                 if (strcasecmp(tmp->name, cur->name) < 0) {
2873                         AST_RWLIST_INSERT_BEFORE_CURRENT(&apps, tmp, list);
2874                         break;
2875                 }
2876         }
2877         AST_RWLIST_TRAVERSE_SAFE_END
2878         if (!cur)
2879                 AST_RWLIST_INSERT_TAIL(&apps, tmp, list);
2880
2881         if (option_verbose > 1)
2882                 ast_verbose( VERBOSE_PREFIX_2 "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
2883
2884         AST_RWLIST_UNLOCK(&apps);
2885
2886         return 0;
2887 }
2888
2889 /*
2890  * Append to the list. We don't have a tail pointer because we need
2891  * to scan the list anyways to check for duplicates during insertion.
2892  */
2893 int ast_register_switch(struct ast_switch *sw)
2894 {
2895         struct ast_switch *tmp;
2896
2897         AST_RWLIST_WRLOCK(&switches);
2898         AST_RWLIST_TRAVERSE(&switches, tmp, list) {
2899                 if (!strcasecmp(tmp->name, sw->name)) {
2900                         AST_RWLIST_UNLOCK(&switches);
2901                         ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name);
2902                         return -1;
2903                 }
2904         }
2905         AST_RWLIST_INSERT_TAIL(&switches, sw, list);
2906         AST_RWLIST_UNLOCK(&switches);
2907
2908         return 0;
2909 }
2910
2911 void ast_unregister_switch(struct ast_switch *sw)
2912 {
2913         AST_RWLIST_WRLOCK(&switches);
2914         AST_RWLIST_REMOVE(&switches, sw, list);
2915         AST_RWLIST_UNLOCK(&switches);
2916 }
2917
2918 /*
2919  * Help for CLI commands ...
2920  */
2921 static char show_applications_help[] =
2922 "Usage: core show applications [{like|describing} <text>]\n"
2923 "       List applications which are currently available.\n"
2924 "       If 'like', <text> will be a substring of the app name\n"
2925 "       If 'describing', <text> will be a substring of the description\n";
2926
2927 static char show_functions_help[] =
2928 "Usage: core show functions [like <text>]\n"
2929 "       List builtin functions, optionally only those matching a given string\n";
2930
2931 static char show_switches_help[] =
2932 "Usage: core show switches\n"
2933 "       List registered switches\n";
2934
2935 static char show_hints_help[] =
2936 "Usage: core show hints\n"
2937 "       List registered hints\n";
2938
2939 static char show_globals_help[] =
2940 "Usage: core show globals\n"
2941 "       List current global dialplan variables and their values\n";
2942
2943 static char show_application_help[] =
2944 "Usage: core show application <application> [<application> [<application> [...]]]\n"
2945 "       Describes a particular application.\n";
2946
2947 static char show_function_help[] =
2948 "Usage: core show function <function>\n"
2949 "       Describe a particular dialplan function.\n";
2950
2951 static char show_dialplan_help[] =
2952 "Usage: core show dialplan [exten@][context]\n"
2953 "       Show dialplan\n";
2954
2955 static char set_global_help[] =
2956 "Usage: core set global <name> <value>\n"
2957 "       Set global dialplan variable <name> to <value>\n";
2958
2959
2960 /*
2961  * \brief 'show application' CLI command implementation functions ...
2962  */
2963
2964 /*
2965  * There is a possibility to show informations about more than one
2966  * application at one time. You can type 'show application Dial Echo' and
2967  * you will see informations about these two applications ...
2968  */
2969 static char *complete_show_application(const char *line, const char *word, int pos, int state)
2970 {
2971         struct ast_app *a;
2972         char *ret = NULL;
2973         int which = 0;
2974         int wordlen = strlen(word);
2975
2976         /* return the n-th [partial] matching entry */
2977         AST_RWLIST_RDLOCK(&apps);
2978         AST_RWLIST_TRAVERSE(&apps, a, list) {
2979                 if (!strncasecmp(word, a->name, wordlen) && ++which > state) {
2980                         ret = strdup(a->name);
2981                         break;
2982                 }
2983         }
2984         AST_RWLIST_UNLOCK(&apps);
2985
2986         return ret;
2987 }
2988
2989 static int handle_show_application(int fd, int argc, char *argv[])
2990 {
2991         struct ast_app *a;
2992         int app, no_registered_app = 1;
2993
2994         if (argc < 4)
2995                 return RESULT_SHOWUSAGE;
2996
2997         /* ... go through all applications ... */
2998         AST_RWLIST_RDLOCK(&apps);
2999         AST_RWLIST_TRAVERSE(&apps, a, list) {
3000                 /* ... compare this application name with all arguments given
3001                  * to 'show application' command ... */
3002                 for (app = 3; app < argc; app++) {
3003                         if (!strcasecmp(a->name, argv[app])) {
3004                                 /* Maximum number of characters added by terminal coloring is 22 */
3005                                 char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
3006                                 char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
3007                                 int synopsis_size, description_size;
3008
3009                                 no_registered_app = 0;
3010
3011                                 if (a->synopsis)
3012                                         synopsis_size = strlen(a->synopsis) + 23;
3013                                 else
3014                                         synopsis_size = strlen("Not available") + 23;
3015                                 synopsis = alloca(synopsis_size);
3016
3017                                 if (a->description)
3018                                         description_size = strlen(a->description) + 23;
3019                                 else
3020                                         description_size = strlen("Not available") + 23;
3021                                 description = alloca(description_size);
3022
3023                                 if (synopsis && description) {
3024                                         snprintf(info, 64 + AST_MAX_APP, "\n  -= Info about application '%s' =- \n\n", a->name);
3025                                         term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
3026                                         term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
3027                                         term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
3028                                         term_color(synopsis,
3029                                                                         a->synopsis ? a->synopsis : "Not available",
3030                                                                         COLOR_CYAN, 0, synopsis_size);
3031                                         term_color(description,
3032                                                                         a->description ? a->description : "Not available",
3033                                                                         COLOR_CYAN, 0, description_size);
3034
3035                                         ast_cli(fd,"%s%s%s\n\n%s%s\n", infotitle, syntitle, synopsis, destitle, description);
3036                                 } else {
3037                                         /* ... one of our applications, show info ...*/
3038                                         ast_cli(fd,"\n  -= Info about application '%s' =- \n\n"
3039                                                 "[Synopsis]\n  %s\n\n"
3040                                                 "[Description]\n%s\n",
3041                                                 a->name,
3042                                                 a->synopsis ? a->synopsis : "Not available",
3043                                                 a->description ? a->description : "Not available");
3044                                 }
3045                         }
3046                 }
3047         }
3048         AST_RWLIST_UNLOCK(&apps);
3049
3050         /* we found at least one app? no? */
3051         if (no_registered_app) {
3052                 ast_cli(fd, "Your application(s) is (are) not registered\n");
3053                 return RESULT_FAILURE;
3054         }
3055
3056         return RESULT_SUCCESS;
3057 }
3058
3059 /*! \brief  handle_show_hints: CLI support for listing registered dial plan hints */
3060 static int handle_show_hints(int fd, int argc, char *argv[])
3061 {
3062         struct ast_hint *hint;
3063         int num = 0;
3064         int watchers;
3065         struct ast_state_cb *watcher;
3066
3067         AST_RWLIST_RDLOCK(&hints);
3068         if (AST_RWLIST_EMPTY(&hints)) {
3069                 ast_cli(fd, "There are no registered dialplan hints\n");
3070                 AST_RWLIST_UNLOCK(&hints);
3071                 return RESULT_SUCCESS;
3072         }
3073         /* ... we have hints ... */
3074         ast_cli(fd, "\n    -= Registered Asterisk Dial Plan Hints =-\n");
3075         AST_RWLIST_TRAVERSE(&hints, hint, list) {
3076                 watchers = 0;
3077                 for (watcher = hint->callbacks; watcher; watcher = watcher->next)
3078                         watchers++;
3079                 ast_cli(fd, "   %20s@%-20.20s: %-20.20s  State:%-15.15s Watchers %2d\n",
3080                         ast_get_extension_name(hint->exten),
3081                         ast_get_context_name(ast_get_extension_context(hint->exten)),
3082                         ast_get_extension_app(hint->exten),
3083                         ast_extension_state2str(hint->laststate), watchers);
3084                 num++;
3085         }
3086         ast_cli(fd, "----------------\n");
3087         ast_cli(fd, "- %d hints registered\n", num);
3088         AST_RWLIST_UNLOCK(&hints);
3089         return RESULT_SUCCESS;
3090 }
3091
3092 /*! \brief  handle_show_switches: CLI support for listing registered dial plan switches */
3093 static int handle_show_switches(int fd, int argc, char *argv[])
3094 {
3095         struct ast_switch *sw;
3096
3097         AST_RWLIST_RDLOCK(&switches);
3098
3099         if (AST_RWLIST_EMPTY(&switches)) {
3100                 AST_RWLIST_UNLOCK(&switches);
3101                 ast_cli(fd, "There are no registered alternative switches\n");
3102                 return RESULT_SUCCESS;
3103         }
3104
3105         ast_cli(fd, "\n    -= Registered Asterisk Alternative Switches =-\n");
3106         AST_RWLIST_TRAVERSE(&switches, sw, list)
3107                 ast_cli(fd, "%s: %s\n", sw->name, sw->description);
3108
3109         AST_RWLIST_UNLOCK(&switches);
3110
3111         return RESULT_SUCCESS;
3112 }
3113
3114 static int handle_show_applications(int fd, int argc, char *argv[])
3115 {
3116         struct ast_app *a;
3117         int like = 0, describing = 0;
3118         int total_match = 0;    /* Number of matches in like clause */
3119         int total_apps = 0;     /* Number of apps registered */
3120
3121         AST_RWLIST_RDLOCK(&apps);
3122
3123         if (AST_RWLIST_EMPTY(&apps)) {
3124                 ast_cli(fd, "There are no registered applications\n");
3125                 AST_RWLIST_UNLOCK(&apps);
3126                 return -1;
3127         }
3128
3129         /* core list applications like <keyword> */
3130         if ((argc == 5) && (!strcmp(argv[3], "like"))) {
3131                 like = 1;