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