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