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