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