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