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