rename SetVar application to Set, deprecate SetVar
[asterisk/asterisk.git] / pbx.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Core PBX routines.
5  * 
6  * Copyright (C) 1999 - 2005, Digium, Inc.
7  *
8  * Mark Spencer <markster@digium.com>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  */
13
14 #include <sys/types.h>
15 #include <string.h>
16 #include <unistd.h>
17 #include <stdlib.h>
18 #include <stdio.h>
19 #include <setjmp.h>
20 #include <ctype.h>
21 #include <errno.h>
22 #include <time.h>
23 #include <sys/time.h>
24
25 #include "asterisk/lock.h"
26 #include "asterisk/cli.h"
27 #include "asterisk/pbx.h"
28 #include "asterisk/channel.h"
29 #include "asterisk/options.h"
30 #include "asterisk/logger.h"
31 #include "asterisk/file.h"
32 #include "asterisk/callerid.h"
33 #include "asterisk/cdr.h"
34 #include "asterisk/config.h"
35 #include "asterisk/term.h"
36 #include "asterisk/manager.h"
37 #include "asterisk/ast_expr.h"
38 #include "asterisk/linkedlists.h"
39 #include "asterisk/say.h"
40 #include "asterisk/utils.h"
41 #include "asterisk/causes.h"
42 #include "asterisk/musiconhold.h"
43 #include "asterisk/app.h"
44 #include "asterisk.h"
45
46 /*
47  * I M P O R T A N T :
48  *
49  *              The speed of extension handling will likely be among the most important
50  * aspects of this PBX.  The switching scheme as it exists right now isn't
51  * terribly bad (it's O(N+M), where N is the # of extensions and M is the avg #
52  * of priorities, but a constant search time here would be great ;-) 
53  *
54  */
55
56 #ifdef LOW_MEMORY
57 #define EXT_DATA_SIZE 256
58 #else
59 #define EXT_DATA_SIZE 8192
60 #endif
61
62 #define SWITCH_DATA_LENGTH 256
63
64
65 #define VAR_NORMAL              1
66 #define VAR_SOFTTRAN    2
67 #define VAR_HARDTRAN    3
68
69 #define BACKGROUND_SKIP         (1 << 0)
70 #define BACKGROUND_NOANSWER     (1 << 1)
71
72 AST_DECLARE_OPTIONS(background_opts,{
73         ['s'] = { BACKGROUND_SKIP },
74         ['n'] = { BACKGROUND_NOANSWER },
75 });
76
77 #define WAITEXTEN_MOH           (1 << 0)
78
79 AST_DECLARE_OPTIONS(waitexten_opts,{
80         ['m'] = { WAITEXTEN_MOH, 1 },
81 });
82
83 struct ast_context;
84
85 /* ast_exten: An extension */
86 struct ast_exten {
87         char *exten;                    /* Extension name */
88         int matchcid;                   /* Match caller id ? */
89         char *cidmatch;                 /* Caller id to match for this extension */
90         int priority;                   /* Priority */
91         char *label;                    /* Label */
92         struct ast_context *parent;     /* The context this extension belongs to  */
93         char *app;                      /* Application to execute */
94         void *data;                     /* Data to use (arguments) */
95         void (*datad)(void *);          /* Data destructor */
96         struct ast_exten *peer;         /* Next higher priority with our extension */
97         const char *registrar;          /* Registrar */
98         struct ast_exten *next;         /* Extension with a greater ID */
99         char stuff[0];
100 };
101
102 /* ast_include: include= support in extensions.conf */
103 struct ast_include {
104         char *name;             
105         char *rname;            /* Context to include */
106         const char *registrar;                  /* Registrar */
107         int hastime;                            /* If time construct exists */
108         struct ast_timing timing;               /* time construct */
109         struct ast_include *next;               /* Link them together */
110         char stuff[0];
111 };
112
113 /* ast_sw: Switch statement in extensions.conf */
114 struct ast_sw {
115         char *name;
116         const char *registrar;                  /* Registrar */
117         char *data;                             /* Data load */
118         int eval;
119         struct ast_sw *next;                    /* Link them together */
120         char *tmpdata;
121         char stuff[0];
122 };
123
124 struct ast_ignorepat {
125         const char *registrar;
126         struct ast_ignorepat *next;
127         char pattern[0];
128 };
129
130 /* ast_context: An extension context */
131 struct ast_context {
132         ast_mutex_t lock;                       /* A lock to prevent multiple threads from clobbering the context */
133         struct ast_exten *root;                 /* The root of the list of extensions */
134         struct ast_context *next;               /* Link them together */
135         struct ast_include *includes;           /* Include other contexts */
136         struct ast_ignorepat *ignorepats;       /* Patterns for which to continue playing dialtone */
137         const char *registrar;                  /* Registrar */
138         struct ast_sw *alts;                    /* Alternative switches */
139         char name[0];                           /* Name of the context */
140 };
141
142
143 /* ast_app: An application */
144 struct ast_app {
145         int (*execute)(struct ast_channel *chan, void *data);
146         const char *synopsis;                   /* Synopsis text for 'show applications' */
147         const char *description;                /* Description (help text) for 'show application <name>' */
148         struct ast_app *next;                   /* Next app in list */
149         char name[0];                           /* Name of the application */
150 };
151
152 /* ast_state_cb: An extension state notify */
153 struct ast_state_cb {
154         int id;
155         void *data;
156         ast_state_cb_type callback;
157         struct ast_state_cb *next;
158 };
159             
160 /* ast_devstate_cb: An extension state notify */
161 struct ast_devstate_cb {
162         void *data;
163         ast_devstate_cb_type callback;
164         struct ast_devstate_cb *next;
165 };
166
167 static struct ast_devstate_cb *devcbs;
168
169 /* Hints are pointers from an extension in the dialplan to one or more devices (tech/name) */
170 struct ast_hint {
171         struct ast_exten *exten;        /* Extension */
172         int laststate;                  /* Last known state */
173         struct ast_state_cb *callbacks; /* Callback list for this extension */
174         struct ast_hint *next;          /* Pointer to next hint in list */
175 };
176
177 int ast_pbx_outgoing_cdr_failed(void);
178
179 static int pbx_builtin_prefix(struct ast_channel *, void *);
180 static int pbx_builtin_suffix(struct ast_channel *, void *);
181 static int pbx_builtin_stripmsd(struct ast_channel *, void *);
182 static int pbx_builtin_answer(struct ast_channel *, void *);
183 static int pbx_builtin_goto(struct ast_channel *, void *);
184 static int pbx_builtin_hangup(struct ast_channel *, void *);
185 static int pbx_builtin_background(struct ast_channel *, void *);
186 static int pbx_builtin_dtimeout(struct ast_channel *, void *);
187 static int pbx_builtin_rtimeout(struct ast_channel *, void *);
188 static int pbx_builtin_atimeout(struct ast_channel *, void *);
189 static int pbx_builtin_wait(struct ast_channel *, void *);
190 static int pbx_builtin_waitexten(struct ast_channel *, void *);
191 static int pbx_builtin_setlanguage(struct ast_channel *, void *);
192 static int pbx_builtin_resetcdr(struct ast_channel *, void *);
193 static int pbx_builtin_setaccount(struct ast_channel *, void *);
194 static int pbx_builtin_setamaflags(struct ast_channel *, void *);
195 static int pbx_builtin_ringing(struct ast_channel *, void *);
196 static int pbx_builtin_progress(struct ast_channel *, void *);
197 static int pbx_builtin_congestion(struct ast_channel *, void *);
198 static int pbx_builtin_busy(struct ast_channel *, void *);
199 static int pbx_builtin_setglobalvar(struct ast_channel *, void *);
200 static int pbx_builtin_noop(struct ast_channel *, void *);
201 static int pbx_builtin_gotoif(struct ast_channel *, void *);
202 static int pbx_builtin_gotoiftime(struct ast_channel *, void *);
203 static int pbx_builtin_execiftime(struct ast_channel *, void *);
204 static int pbx_builtin_saynumber(struct ast_channel *, void *);
205 static int pbx_builtin_saydigits(struct ast_channel *, void *);
206 static int pbx_builtin_saycharacters(struct ast_channel *, void *);
207 static int pbx_builtin_sayphonetic(struct ast_channel *, void *);
208 static int pbx_builtin_setvar_old(struct ast_channel *, void *);
209 int pbx_builtin_setvar(struct ast_channel *, void *);
210 static int pbx_builtin_importvar(struct ast_channel *, void *);
211
212 static struct varshead globals;
213
214 static int autofallthrough = 0;
215
216 AST_MUTEX_DEFINE_STATIC(acflock);               /* Lock for the custom function list */
217 static struct ast_custom_function *acf_root = NULL;
218
219 static struct pbx_builtin {
220         char name[AST_MAX_APP];
221         int (*execute)(struct ast_channel *chan, void *data);
222         char *synopsis;
223         char *description;
224 } builtins[] = 
225 {
226         /* These applications are built into the PBX core and do not
227            need separate modules
228            
229             */
230
231         { "AbsoluteTimeout", pbx_builtin_atimeout,
232         "Set absolute maximum time of call",
233         "  AbsoluteTimeout(seconds): Set the absolute maximum amount of time permitted\n"
234         "for a call.  A setting of 0 disables the timeout.  Always returns 0.\n" 
235         "AbsoluteTimeout has been deprecated in favor of Set(TIMEOUT(absolute)=timeout)\n"
236         },
237
238         { "Answer", pbx_builtin_answer, 
239         "Answer a channel if ringing", 
240         "  Answer([delay]): If the channel is ringing, answer it, otherwise do nothing. \n"
241         "If delay is specified, asterisk will pause execution for the specified amount\n"
242         "of milliseconds if an answer is required, in order to give audio a chance to\n"
243         "become ready. Returns 0 unless it tries to answer the channel and fails.\n"   
244         },
245
246         { "BackGround", pbx_builtin_background,
247         "Play a file while awaiting extension",
248         "  Background(filename1[&filename2...][|options[|langoverride]]): Plays\n"
249         "given files, while simultaneously waiting for the user to begin typing\n"
250         "an extension. The timeouts do not count until the last BackGround\n"
251         "application has ended. Options may also be included following a pipe \n"
252         "symbol. The 'langoverride' may be a language to use for playing the prompt\n"
253         "which differs from the current language of the channel. Returns -1 if \n"
254         "the channel was hung up, or if the file does not exist. Returns 0 otherwise.\n\n"
255         "  Options:\n"
256         "    's' - causes the playback of the message to be skipped\n"
257         "          if the channel is not in the 'up' state (i.e. it\n"
258         "          hasn't been answered yet.) If this happens, the\n"
259         "          application will return immediately.\n"
260         "    'n' - don't answer the channel before playing the files\n"
261         },
262
263         { "Busy", pbx_builtin_busy,
264         "Indicate busy condition and stop",
265         "  Busy([timeout]): Requests that the channel indicate busy condition and\n"
266         "then waits for the user to hang up or the optional timeout to expire.\n"
267         "Always returns -1." 
268         },
269
270         { "Congestion", pbx_builtin_congestion,
271         "Indicate congestion and stop",
272         "  Congestion([timeout]): Requests that the channel indicate congestion\n"
273         "and then waits for the user to hang up or for the optional timeout to\n"
274         "expire.  Always returns -1." 
275         },
276
277         { "DigitTimeout", pbx_builtin_dtimeout,
278         "Set maximum timeout between digits",
279         "  DigitTimeout(seconds): Set the maximum amount of time permitted between\n"
280         "digits when the user is typing in an extension. When this timeout expires,\n"
281         "after the user has started to type in an extension, the extension will be\n"
282         "considered complete, and will be interpreted. Note that if an extension\n"
283         "typed in is valid, it will not have to timeout to be tested, so typically\n"
284         "at the expiry of this timeout, the extension will be considered invalid\n"
285         "(and thus control would be passed to the 'i' extension, or if it doesn't\n"
286         "exist the call would be terminated). The default timeout is 5 seconds.\n"
287         "Always returns 0.\n" 
288         "DigitTimeout has been deprecated in favor of Set(TIMEOUT(digit)=timeout)\n"
289         },
290
291         { "Goto", pbx_builtin_goto, 
292         "Goto a particular priority, extension, or context",
293         "  Goto([[context|]extension|]priority):  Set the  priority to the specified\n"
294         "value, optionally setting the extension and optionally the context as well.\n"
295         "The extension BYEXTENSION is special in that it uses the current extension,\n"
296         "thus  permitting you to go to a different context, without specifying a\n"
297         "specific extension. Always returns 0, even if the given context, extension,\n"
298         "or priority is invalid.\n" 
299         },
300
301         { "GotoIf", pbx_builtin_gotoif,
302         "Conditional goto",
303         "  GotoIf(Condition?label1:label2): Go to label 1 if condition is\n"
304         "true, to label2 if condition is false. Either label1 or label2 may be\n"
305         "omitted (in that case, we just don't take the particular branch) but not\n"
306         "both. Look for the condition syntax in examples or documentation." 
307         },
308
309         { "GotoIfTime", pbx_builtin_gotoiftime,
310         "Conditional goto on current time",
311         "  GotoIfTime(<times>|<weekdays>|<mdays>|<months>?[[context|]extension|]pri):\n"
312         "If the current time matches the specified time, then branch to the specified\n"
313         "extension. Each of the elements may be specified either as '*' (for always)\n"
314         "or as a range. See the 'include' syntax for details." 
315         },
316
317         { "ExecIfTime", pbx_builtin_execiftime,
318         "Conditional application execution on current time",
319         "  ExecIfTime(<times>|<weekdays>|<mdays>|<months>?<appname>[|<appdata>]):\n"
320         "If the current time matches the specified time, then execute the specified\n"
321         "application. Each of the elements may be specified either as '*' (for always)\n"
322         "or as a range. See the 'include' syntax for details. It will return whatever\n"
323         "<appname> returns, or a non-zero value if the application is not found.\n"
324         },
325         
326         { "Hangup", pbx_builtin_hangup,
327         "Unconditional hangup",
328         "  Hangup(): Unconditionally hangs up a given channel by returning -1 always.\n" 
329         },
330
331         { "NoOp", pbx_builtin_noop,
332         "No operation",
333         "  NoOp(): No-operation; Does nothing." 
334         },
335
336         { "Prefix", pbx_builtin_prefix, 
337         "Prepend leading digits",
338         "  Prefix(digits): Prepends the digit string specified by digits to the\n"
339         "channel's associated extension. For example, the number 1212 when prefixed\n"
340         "with '555' will become 5551212. This app always returns 0, and the PBX will\n"
341         "continue processing at the next priority for the *new* extension.\n"
342         "  So, for example, if priority  3  of 1212 is  Prefix  555, the next step\n"
343         "executed will be priority 4 of 5551212. If you switch into an extension\n"
344         "which has no first step, the PBX will treat it as though the user dialed an\n"
345         "invalid extension.\n" 
346         },
347
348         { "Progress", pbx_builtin_progress,
349         "Indicate progress",
350         "  Progress(): Request that the channel indicate in-band progress is \n"
351         "available to the user.\nAlways returns 0.\n" 
352         },
353
354         { "ResetCDR", pbx_builtin_resetcdr,
355         "Resets the Call Data Record",
356         "  ResetCDR([options]):  Causes the Call Data Record to be reset, optionally\n"
357         "storing the current CDR before zeroing it out\b"
358         " - if 'w' option is specified record will be stored.\n"
359         " - if 'a' option is specified any stacked records will be stored.\n"
360         " - if 'v' option is specified any variables will be saved.\n"
361         "Always returns 0.\n"  
362         },
363
364         { "ResponseTimeout", pbx_builtin_rtimeout,
365         "Set maximum timeout awaiting response",
366         "  ResponseTimeout(seconds): Set the maximum amount of time permitted after\n"
367         "falling through a series of priorities for a channel in which the user may\n"
368         "begin typing an extension. If the user does not type an extension in this\n"
369         "amount of time, control will pass to the 't' extension if it exists, and\n"
370         "if not the call would be terminated. The default timeout is 10 seconds.\n"
371         "Always returns 0.\n"  
372         "ResponseTimeout has been deprecated in favor of Set(TIMEOUT(response)=timeout)\n"
373         },
374
375         { "Ringing", pbx_builtin_ringing,
376         "Indicate ringing tone",
377         "  Ringing(): Request that the channel indicate ringing tone to the user.\n"
378         "Always returns 0.\n" 
379         },
380
381         { "SayNumber", pbx_builtin_saynumber,
382         "Say Number",
383         "  SayNumber(digits[,gender]): Says the passed number. SayNumber is using\n" 
384         "the current language setting for the channel. (See app SetLanguage).\n"
385         },
386
387         { "SayDigits", pbx_builtin_saydigits,
388         "Say Digits",
389         "  SayDigits(digits): Says the passed digits. SayDigits is using the\n" 
390         "current language setting for the channel. (See app setLanguage)\n"
391         },
392
393         { "SayAlpha", pbx_builtin_saycharacters,
394         "Say Alpha",
395         "  SayAlpha(string): Spells the passed string\n" 
396         },
397
398         { "SayPhonetic", pbx_builtin_sayphonetic,
399         "Say Phonetic",
400         "  SayPhonetic(string): Spells the passed string with phonetic alphabet\n" 
401         },
402
403         { "SetAccount", pbx_builtin_setaccount,
404         "Sets account code",
405         "  SetAccount([account]): Set the channel account code for billing\n"
406         "purposes. Always returns 0.\n"
407         },
408
409         { "SetAMAFlags", pbx_builtin_setamaflags,
410         "Sets AMA Flags",
411         "  SetAMAFlags([flag]): Set the channel AMA Flags for billing\n"
412         "purposes. Always returns 0.\n"
413         },
414
415         { "SetGlobalVar", pbx_builtin_setglobalvar,
416         "Set global variable to value",
417         "  SetGlobalVar(#n=value): Sets global variable n to value. Global\n" 
418         "variable are available across channels.\n"
419         },
420
421         { "SetLanguage", pbx_builtin_setlanguage,
422         "Sets channel language",
423         "  SetLanguage(language): Set the channel language to 'language'. This\n"
424         "information is used for the syntax in generation of numbers, and to choose\n"
425         "a natural language file when available.\n"
426         "  For example, if language is set to 'fr' and the file 'demo-congrats' is \n"
427         "requested to be played, if the file 'fr/demo-congrats' exists, then\n"
428         "it will play that file, and if not will play the normal 'demo-congrats'.\n"
429         "For some language codes, SetLanguage also changes the syntax of some\n"
430         "Asterisk functions, like SayNumber.\n"
431         "Always returns 0.\n"
432         "SetLanguage has been deprecated in favor of Set(LANGUAGE()=language)\n"
433         },
434
435         { "Set", pbx_builtin_setvar,
436           "Set channel variable(s) or function value(s)",
437           "  Set(name1=value1|name2=value2|..[|options])\n"
438           "This function can be used to set the value of channel variables\n"
439           "or dialplan functions. It will accept up to 24 name/value pairs.\n"
440           "When setting variables, if the variable name is prefixed with _,\n"
441           "the variable will be inherited into channels created from the\n"
442           "current channel. If the variable name is prefixed with __,\n"
443           "the variable will be inherited into channels created from the\n"
444           "current channel and all child channels.\n"
445           "The last argument, if it does not contain '=', is interpreted\n"
446           "as a string of options. The valid options are:\n"
447           "  g - Set variable globally instead of on the channel\n"
448           "      (applies only to variables, not functions)\n"
449         },
450
451         { "SetVar", pbx_builtin_setvar_old,
452           "Set channel variable(s)",
453           "  SetVar(name1=value1|name2=value2|..[|options])\n"
454           "SetVar has been deprecated in favor of Set.\n"
455         },
456
457         { "ImportVar", pbx_builtin_importvar,
458         "Import a variable from a channel into a new variable",
459         "  ImportVar(newvar=channelname|variable): This application imports a\n"
460         "variable from the specified channel (as opposed to the current one)\n"
461         "and stores it as a variable in the current channel (the channel that\n"
462         "is calling this application). If the new variable name is prefixed by\n"
463         "a single underscore \"_\", then it will be inherited into any channels\n"
464         "created from this one. If it is prefixed with two underscores,then\n"
465         "the variable will have infinite inheritance, meaning that it will be\n"
466         "present in any descendent channel of this one.\n"
467         },
468
469         { "StripMSD", pbx_builtin_stripmsd,
470         "Strip leading digits",
471         "  StripMSD(count): Strips the leading 'count' digits from the channel's\n"
472         "associated extension. For example, the number 5551212 when stripped with a\n"
473         "count of 3 would be changed to 1212. This app always returns 0, and the PBX\n"
474         "will continue processing at the next priority for the *new* extension.\n"
475         "  So, for example, if priority 3 of 5551212 is StripMSD 3, the next step\n"
476         "executed will be priority 4 of 1212. If you switch into an extension which\n"
477         "has no first step, the PBX will treat it as though the user dialed an\n"
478         "invalid extension.\n" 
479         },
480
481         { "Suffix", pbx_builtin_suffix, 
482         "Append trailing digits",
483         "  Suffix(digits): Appends the digit string specified by digits to the\n"
484         "channel's associated extension. For example, the number 555 when suffixed\n"
485         "with '1212' will become 5551212. This app always returns 0, and the PBX will\n"
486         "continue processing at the next priority for the *new* extension.\n"
487         "  So, for example, if priority 3 of 555 is Suffix 1212, the next step\n"
488         "executed will be priority 4 of 5551212. If you switch into an extension\n"
489         "which has no first step, the PBX will treat it as though the user dialed an\n"
490         "invalid extension.\n" 
491         },
492
493         { "Wait", pbx_builtin_wait, 
494         "Waits for some time", 
495         "  Wait(seconds): Waits for a specified number of seconds, then returns 0.\n"
496         "seconds can be passed with fractions of a second. (eg: 1.5 = 1.5 seconds)\n" 
497         },
498
499         { "WaitExten", pbx_builtin_waitexten, 
500         "Waits for an extension to be entered", 
501         "  WaitExten([seconds][|options]): Waits for the user to enter a new extension for the \n"
502         "specified number of seconds, then returns 0. Seconds can be passed with\n"
503         "fractions of a seconds (eg: 1.5 = 1.5 seconds) or if unspecified the\n"
504         "default extension timeout will be used.\n"
505         "  Options:\n"
506         "    'm[(x)]' - Provide music on hold to the caller while waiting for an extension.\n"
507         "               Optionally, specify the class for music on hold within parenthesis.\n"
508         },
509
510 };
511
512 static struct ast_context *contexts = NULL;
513 AST_MUTEX_DEFINE_STATIC(conlock);               /* Lock for the ast_context list */
514 static struct ast_app *apps = NULL;
515 AST_MUTEX_DEFINE_STATIC(applock);               /* Lock for the application list */
516
517 struct ast_switch *switches = NULL;
518 AST_MUTEX_DEFINE_STATIC(switchlock);            /* Lock for switches */
519
520 AST_MUTEX_DEFINE_STATIC(hintlock);              /* Lock for extension state notifys */
521 static int stateid = 1;
522 struct ast_hint *hints = NULL;
523 struct ast_state_cb *statecbs = NULL;
524
525 int pbx_exec(struct ast_channel *c,             /* Channel */
526                 struct ast_app *app,            /* Application */
527                 void *data,                     /* Data for execution */
528                 int newstack)                   /* Force stack increment */
529 {
530         /* This function is special. It saves the stack so that no matter
531            how many times it is called, it returns to the same place */
532         int res;
533         
534         char *saved_c_appl;
535         char *saved_c_data;
536         
537         int (*execute)(struct ast_channel *chan, void *data) = app->execute; 
538
539         if (newstack) {
540                 if (c->cdr)
541                         ast_cdr_setapp(c->cdr, app->name, data);
542
543                 /* save channel values */
544                 saved_c_appl= c->appl;
545                 saved_c_data= c->data;
546
547                 c->appl = app->name;
548                 c->data = data;         
549                 res = execute(c, data);
550                 /* restore channel values */
551                 c->appl= saved_c_appl;
552                 c->data= saved_c_data;
553                 return res;
554         } else
555                 ast_log(LOG_WARNING, "You really didn't want to call this function with newstack set to 0\n");
556         return -1;
557 }
558
559
560 /* Go no deeper than this through includes (not counting loops) */
561 #define AST_PBX_MAX_STACK       128
562
563 #define HELPER_EXISTS 0
564 #define HELPER_SPAWN 1
565 #define HELPER_EXEC 2
566 #define HELPER_CANMATCH 3
567 #define HELPER_MATCHMORE 4
568 #define HELPER_FINDLABEL 5
569
570 struct ast_app *pbx_findapp(const char *app) 
571 {
572         struct ast_app *tmp;
573
574         if (ast_mutex_lock(&applock)) {
575                 ast_log(LOG_WARNING, "Unable to obtain application lock\n");
576                 return NULL;
577         }
578         tmp = apps;
579         while(tmp) {
580                 if (!strcasecmp(tmp->name, app))
581                         break;
582                 tmp = tmp->next;
583         }
584         ast_mutex_unlock(&applock);
585         return tmp;
586 }
587
588 static struct ast_switch *pbx_findswitch(const char *sw)
589 {
590         struct ast_switch *asw;
591
592         if (ast_mutex_lock(&switchlock)) {
593                 ast_log(LOG_WARNING, "Unable to obtain application lock\n");
594                 return NULL;
595         }
596         asw = switches;
597         while(asw) {
598                 if (!strcasecmp(asw->name, sw))
599                         break;
600                 asw = asw->next;
601         }
602         ast_mutex_unlock(&switchlock);
603         return asw;
604 }
605
606 static inline int include_valid(struct ast_include *i)
607 {
608         if (!i->hastime)
609                 return 1;
610
611         return ast_check_timing(&(i->timing));
612 }
613
614 static void pbx_destroy(struct ast_pbx *p)
615 {
616         free(p);
617 }
618
619 #define EXTENSION_MATCH_CORE(data,pattern,match) {\
620         /* All patterns begin with _ */\
621         if (pattern[0] != '_') \
622                 return 0;\
623         /* Start optimistic */\
624         match=1;\
625         pattern++;\
626         while(match && *data && *pattern && (*pattern != '/')) {\
627                 while (*data == '-' && (*(data+1) != '\0')) data++;\
628                 switch(toupper(*pattern)) {\
629                 case '[': \
630                 {\
631                         int i,border=0;\
632                         char *where;\
633                         match=0;\
634                         pattern++;\
635                         where=strchr(pattern,']');\
636                         if (where)\
637                                 border=(int)(where-pattern);\
638                         if (!where || border > strlen(pattern)) {\
639                                 ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");\
640                                 return match;\
641                         }\
642                         for (i=0; i<border; i++) {\
643                                 int res=0;\
644                                 if (i+2<border)\
645                                         if (pattern[i+1]=='-') {\
646                                                 if (*data >= pattern[i] && *data <= pattern[i+2]) {\
647                                                         res=1;\
648                                                 } else {\
649                                                         i+=2;\
650                                                         continue;\
651                                                 }\
652                                         }\
653                                 if (res==1 || *data==pattern[i]) {\
654                                         match = 1;\
655                                         break;\
656                                 }\
657                         }\
658                         pattern+=border;\
659                         break;\
660                 }\
661                 case 'N':\
662                         if ((*data < '2') || (*data > '9'))\
663                                 match=0;\
664                         break;\
665                 case 'X':\
666                         if ((*data < '0') || (*data > '9'))\
667                                 match = 0;\
668                         break;\
669                 case 'Z':\
670                         if ((*data < '1') || (*data > '9'))\
671                                 match = 0;\
672                         break;\
673                 case '.':\
674                         /* Must match */\
675                         return 1;\
676                 case '!':\
677                         /* Early match */\
678                         return 2;\
679                 case ' ':\
680                 case '-':\
681                         /* Ignore these characters */\
682                         data--;\
683                         break;\
684                 default:\
685                         if (*data != *pattern)\
686                                 match =0;\
687                 }\
688                 data++;\
689                 pattern++;\
690         }\
691         /* If we ran off the end of the data and the pattern ends in '!', match */\
692         if (match && !*data && (*pattern == '!'))\
693                 return 2;\
694 }
695
696 int ast_extension_match(const char *pattern, const char *data)
697 {
698         int match;
699         /* If they're the same return */
700         if (!strcmp(pattern, data))
701                 return 1;
702         EXTENSION_MATCH_CORE(data,pattern,match);
703         /* Must be at the end of both */
704         if (*data || (*pattern && (*pattern != '/')))
705                 match = 0;
706         return match;
707 }
708
709 int ast_extension_close(const char *pattern, const char *data, int needmore)
710 {
711         int match;
712         /* If "data" is longer, it can'be a subset of pattern unless
713            pattern is a pattern match */
714         if ((strlen(pattern) < strlen(data)) && (pattern[0] != '_'))
715                 return 0;
716         
717         if ((ast_strlen_zero((char *)data) || !strncasecmp(pattern, data, strlen(data))) && 
718                 (!needmore || (strlen(pattern) > strlen(data)))) {
719                 return 1;
720         }
721         EXTENSION_MATCH_CORE(data,pattern,match);
722         /* If there's more or we don't care about more, or if it's a possible early match, 
723            return non-zero; otherwise it's a miss */
724         if (!needmore || *pattern || match == 2) {
725                 return match;
726         } else
727                 return 0;
728 }
729
730 struct ast_context *ast_context_find(const char *name)
731 {
732         struct ast_context *tmp;
733         ast_mutex_lock(&conlock);
734         if (name) {
735                 tmp = contexts;
736                 while(tmp) {
737                         if (!strcasecmp(name, tmp->name))
738                                 break;
739                         tmp = tmp->next;
740                 }
741         } else
742                 tmp = contexts;
743         ast_mutex_unlock(&conlock);
744         return tmp;
745 }
746
747 #define STATUS_NO_CONTEXT   1
748 #define STATUS_NO_EXTENSION 2
749 #define STATUS_NO_PRIORITY  3
750 #define STATUS_NO_LABEL         4
751 #define STATUS_SUCCESS      5
752
753 static int matchcid(const char *cidpattern, const char *callerid)
754 {
755         int failresult;
756         
757         /* If the Caller*ID pattern is empty, then we're matching NO Caller*ID, so
758            failing to get a number should count as a match, otherwise not */
759
760
761         if (!ast_strlen_zero(cidpattern))
762                 failresult = 0;
763         else
764                 failresult = 1;
765
766         if (!callerid)
767                 return failresult;
768
769         return ast_extension_match(cidpattern, callerid);
770 }
771
772 static struct ast_exten *pbx_find_extension(struct ast_channel *chan, struct ast_context *bypass, const char *context, const char *exten, int priority, const char *label, const char *callerid, int action, char *incstack[], int *stacklen, int *status, struct ast_switch **swo, char **data, const char **foundcontext)
773 {
774         int x, res;
775         struct ast_context *tmp;
776         struct ast_exten *e, *eroot;
777         struct ast_include *i;
778         struct ast_sw *sw;
779         struct ast_switch *asw;
780
781         /* Initialize status if appropriate */
782         if (!*stacklen) {
783                 *status = STATUS_NO_CONTEXT;
784                 *swo = NULL;
785                 *data = NULL;
786         }
787         /* Check for stack overflow */
788         if (*stacklen >= AST_PBX_MAX_STACK) {
789                 ast_log(LOG_WARNING, "Maximum PBX stack exceeded\n");
790                 return NULL;
791         }
792         /* Check first to see if we've already been checked */
793         for (x=0; x<*stacklen; x++) {
794                 if (!strcasecmp(incstack[x], context))
795                         return NULL;
796         }
797         if (bypass)
798                 tmp = bypass;
799         else
800                 tmp = contexts;
801         while(tmp) {
802                 /* Match context */
803                 if (bypass || !strcmp(tmp->name, context)) {
804                         struct ast_exten *earlymatch = NULL;
805
806                         if (*status < STATUS_NO_EXTENSION)
807                                 *status = STATUS_NO_EXTENSION;
808                         for (eroot = tmp->root; eroot; eroot=eroot->next) {
809                                 int match = 0;
810                                 /* Match extension */
811                                 if ((((action != HELPER_MATCHMORE) && ast_extension_match(eroot->exten, exten)) ||
812                                      ((action == HELPER_CANMATCH) && (ast_extension_close(eroot->exten, exten, 0))) ||
813                                      ((action == HELPER_MATCHMORE) && (match = ast_extension_close(eroot->exten, exten, 1)))) &&
814                                     (!eroot->matchcid || matchcid(eroot->cidmatch, callerid))) {
815
816                                         if (action == HELPER_MATCHMORE && match == 2 && !earlymatch) {
817                                                 /* It matched an extension ending in a '!' wildcard
818                                                    So ignore it for now, unless there's a better match */
819                                                 earlymatch = eroot;
820                                         } else {
821                                                 e = eroot;
822                                                 if (*status < STATUS_NO_PRIORITY)
823                                                         *status = STATUS_NO_PRIORITY;
824                                                 while(e) {
825                                                         /* Match priority */
826                                                         if (action == HELPER_FINDLABEL) {
827                                                                 if (*status < STATUS_NO_LABEL)
828                                                                         *status = STATUS_NO_LABEL;
829                                                                 if (label && e->label && !strcmp(label, e->label)) {
830                                                                         *status = STATUS_SUCCESS;
831                                                                         *foundcontext = context;
832                                                                         return e;
833                                                                 }
834                                                         } else if (e->priority == priority) {
835                                                                 *status = STATUS_SUCCESS;
836                                                                 *foundcontext = context;
837                                                                 return e;
838                                                         }
839                                                         e = e->peer;
840                                                 }
841                                         }
842                                 }
843                         }
844                         if (earlymatch) {
845                                 /* Bizarre logic for HELPER_MATCHMORE. We return zero to break out 
846                                    of the loop waiting for more digits, and _then_ match (normally)
847                                    the extension we ended up with. We got an early-matching wildcard
848                                    pattern, so return NULL to break out of the loop. */
849                                 return NULL;
850                         }
851                         /* Check alternative switches */
852                         sw = tmp->alts;
853                         while(sw) {
854                                 if ((asw = pbx_findswitch(sw->name))) {
855                                         /* Substitute variables now */
856                                         if (sw->eval) 
857                                                 pbx_substitute_variables_helper(chan, sw->data, sw->tmpdata, SWITCH_DATA_LENGTH - 1);
858                                         if (action == HELPER_CANMATCH)
859                                                 res = asw->canmatch ? asw->canmatch(chan, context, exten, priority, callerid, sw->eval ? sw->tmpdata : sw->data) : 0;
860                                         else if (action == HELPER_MATCHMORE)
861                                                 res = asw->matchmore ? asw->matchmore(chan, context, exten, priority, callerid, sw->eval ? sw->tmpdata : sw->data) : 0;
862                                         else
863                                                 res = asw->exists ? asw->exists(chan, context, exten, priority, callerid, sw->eval ? sw->tmpdata : sw->data) : 0;
864                                         if (res) {
865                                                 /* Got a match */
866                                                 *swo = asw;
867                                                 *data = sw->eval ? sw->tmpdata : sw->data;
868                                                 *foundcontext = context;
869                                                 return NULL;
870                                         }
871                                 } else {
872                                         ast_log(LOG_WARNING, "No such switch '%s'\n", sw->name);
873                                 }
874                                 sw = sw->next;
875                         }
876                         /* Setup the stack */
877                         incstack[*stacklen] = tmp->name;
878                         (*stacklen)++;
879                         /* Now try any includes we have in this context */
880                         i = tmp->includes;
881                         while(i) {
882                                 if (include_valid(i)) {
883                                         if ((e = pbx_find_extension(chan, bypass, i->rname, exten, priority, label, callerid, action, incstack, stacklen, status, swo, data, foundcontext))) 
884                                                 return e;
885                                         if (*swo) 
886                                                 return NULL;
887                                 }
888                                 i = i->next;
889                         }
890                         break;
891                 }
892                 tmp = tmp->next;
893         }
894         return NULL;
895 }
896
897 /*--- pbx_retrieve_variable: Support for Asterisk built-in variables and
898       functions in the dialplan
899   ---*/
900 void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp)
901 {
902         char *first,*second;
903         char tmpvar[80] = "";
904         time_t thistime;
905         struct tm brokentime;
906         int offset,offset2;
907         struct ast_var_t *variables;
908
909         if (c) 
910                 headp=&c->varshead;
911         *ret=NULL;
912         if ((first=strchr(var,':'))) {  /* : Remove characters counting from end or start of string */
913                 strncpy(tmpvar, var, sizeof(tmpvar) - 1);
914                 first = strchr(tmpvar, ':');
915                 if (!first)
916                         first = tmpvar + strlen(tmpvar);
917                 *first='\0';
918                 pbx_retrieve_variable(c,tmpvar,ret,workspace,workspacelen - 1, headp);
919                 if (!(*ret)) 
920                         return;
921                 offset=atoi(first+1);   /* The number of characters, 
922                                            positive: remove # of chars from start
923                                            negative: keep # of chars from end */
924                                                 
925                 if ((second=strchr(first+1,':'))) {     
926                         *second='\0';
927                         offset2 = atoi(second+1);               /* Number of chars to copy */
928                 } else if (offset >= 0) {
929                         offset2 = strlen(*ret)-offset;  /* Rest of string */
930                 } else {
931                         offset2 = abs(offset);
932                 }
933
934                 if (abs(offset) > strlen(*ret)) {       /* Offset beyond string */
935                         if (offset >= 0) 
936                                 offset=strlen(*ret);
937                         else 
938                                 offset=-strlen(*ret);   
939                 }
940                 if ((offset < 0 && offset2 > -offset) || (offset >= 0 && offset+offset2 > strlen(*ret))) {
941                         if (offset >= 0) 
942                                 offset2=strlen(*ret)-offset;
943                         else 
944                                 offset2=strlen(*ret)+offset;
945                 }
946                 if (offset >= 0)
947                         *ret += offset;
948                 else
949                         *ret += strlen(*ret)+offset;
950                 (*ret)[offset2] = '\0';         /* Cut at offset2 position */
951         } else if (c && !strncmp(var, "CALL", 4)) {
952                 if (!strncmp(var + 4, "ER", 2)) {
953                         if (!strncmp(var + 6, "ID", 2)) {
954                                 if (!var[8]) {                  /* CALLERID */
955                                         if (c->cid.cid_num) {
956                                                 if (c->cid.cid_name) {
957                                                         snprintf(workspace, workspacelen, "\"%s\" <%s>", c->cid.cid_name, c->cid.cid_num);
958                                                 } else {
959                                                         strncpy(workspace, c->cid.cid_num, workspacelen - 1);
960                                                 }
961                                                 *ret = workspace;
962                                         } else if (c->cid.cid_name) {
963                                                 strncpy(workspace, c->cid.cid_name, workspacelen - 1);
964                                                 *ret = workspace;
965                                         } else
966                                                 *ret = NULL;
967                                 } else if (!strcmp(var + 8, "NUM")) {
968                                         /* CALLERIDNUM */
969                                         if (c->cid.cid_num) {
970                                                 strncpy(workspace, c->cid.cid_num, workspacelen - 1);
971                                                 *ret = workspace;
972                                         } else
973                                                 *ret = NULL;
974                                 } else if (!strcmp(var + 8, "NAME")) {
975                                         /* CALLERIDNAME */
976                                         if (c->cid.cid_name) {
977                                                 strncpy(workspace, c->cid.cid_name, workspacelen - 1);
978                                                 *ret = workspace;
979                                         } else
980                                                 *ret = NULL;
981                                 }
982                         } else if (!strcmp(var + 6, "ANI")) {
983                                 /* CALLERANI */
984                                 if (c->cid.cid_ani) {
985                                         strncpy(workspace, c->cid.cid_ani, workspacelen - 1);
986                                         *ret = workspace;
987                                 } else
988                                         *ret = NULL;
989                         } else
990                                 goto icky;
991                 } else if (!strncmp(var + 4, "ING", 3)) {
992                         if (!strcmp(var + 7, "PRES")) {
993                                 /* CALLINGPRES */
994                                 snprintf(workspace, workspacelen, "%d", c->cid.cid_pres);
995                                 *ret = workspace;
996                         } else if (!strcmp(var + 7, "ANI2")) {
997                                 /* CALLINGANI2 */
998                                 snprintf(workspace, workspacelen, "%d", c->cid.cid_ani2);
999                                 *ret = workspace;
1000                         } else if (!strcmp(var + 7, "TON")) {
1001                                 /* CALLINGTON */
1002                                 snprintf(workspace, workspacelen, "%d", c->cid.cid_ton);
1003                                 *ret = workspace;
1004                         } else if (!strcmp(var + 7, "TNS")) {
1005                                 /* CALLINGTNS */
1006                                 snprintf(workspace, workspacelen, "%d", c->cid.cid_tns);
1007                                 *ret = workspace;
1008                         } else
1009                                 goto icky;
1010                 } else
1011                         goto icky;
1012         } else if (c && !strcmp(var, "DNID")) {
1013                 if (c->cid.cid_dnid) {
1014                         strncpy(workspace, c->cid.cid_dnid, workspacelen - 1);
1015                         *ret = workspace;
1016                 } else
1017                         *ret = NULL;
1018         } else if (c && !strcmp(var, "HINT")) {
1019                 if (!ast_get_hint(workspace, workspacelen, NULL, 0, c, c->context, c->exten))
1020                         *ret = NULL;
1021                 else
1022                         *ret = workspace;
1023         } else if (c && !strcmp(var, "HINTNAME")) {
1024                 if (!ast_get_hint(NULL, 0, workspace, workspacelen, c, c->context, c->exten))
1025                         *ret = NULL;
1026                 else
1027                         *ret = workspace;
1028         } else if (c && !strcmp(var, "EXTEN")) {
1029                 strncpy(workspace, c->exten, workspacelen - 1);
1030                 *ret = workspace;
1031         } else if (c && !strcmp(var, "RDNIS")) {
1032                 if (c->cid.cid_rdnis) {
1033                         strncpy(workspace, c->cid.cid_rdnis, workspacelen - 1);
1034                         *ret = workspace;
1035                 } else
1036                         *ret = NULL;
1037         } else if (c && !strcmp(var, "CONTEXT")) {
1038                 strncpy(workspace, c->context, workspacelen - 1);
1039                 *ret = workspace;
1040         } else if (c && !strcmp(var, "PRIORITY")) {
1041                 snprintf(workspace, workspacelen, "%d", c->priority);
1042                 *ret = workspace;
1043         } else if (c && !strcmp(var, "CHANNEL")) {
1044                 strncpy(workspace, c->name, workspacelen - 1);
1045                 *ret = workspace;
1046         } else if (!strcmp(var, "EPOCH")) {
1047                 snprintf(workspace, workspacelen, "%u",(int)time(NULL));
1048                 *ret = workspace;
1049         } else if (!strcmp(var, "DATETIME")) {
1050                 thistime=time(NULL);
1051                 localtime_r(&thistime, &brokentime);
1052                 snprintf(workspace, workspacelen, "%02d%02d%04d-%02d:%02d:%02d",
1053                         brokentime.tm_mday,
1054                         brokentime.tm_mon+1,
1055                         brokentime.tm_year+1900,
1056                         brokentime.tm_hour,
1057                         brokentime.tm_min,
1058                         brokentime.tm_sec
1059                 );
1060                 *ret = workspace;
1061         } else if (!strcmp(var, "TIMESTAMP")) {
1062                 thistime=time(NULL);
1063                 localtime_r(&thistime, &brokentime);
1064                 /* 20031130-150612 */
1065                 snprintf(workspace, workspacelen, "%04d%02d%02d-%02d%02d%02d",
1066                         brokentime.tm_year+1900,
1067                         brokentime.tm_mon+1,
1068                         brokentime.tm_mday,
1069                         brokentime.tm_hour,
1070                         brokentime.tm_min,
1071                         brokentime.tm_sec
1072                 );
1073                 *ret = workspace;
1074         } else if (c && !strcmp(var, "UNIQUEID")) {
1075                 snprintf(workspace, workspacelen, "%s", c->uniqueid);
1076                 *ret = workspace;
1077         } else if (c && !strcmp(var, "HANGUPCAUSE")) {
1078                 snprintf(workspace, workspacelen, "%d", c->hangupcause);
1079                 *ret = workspace;
1080         } else if (c && !strcmp(var, "ACCOUNTCODE")) {
1081                 strncpy(workspace, c->accountcode, workspacelen - 1);
1082                 *ret = workspace;
1083         } else if (c && !strcmp(var, "LANGUAGE")) {
1084                 strncpy(workspace, c->language, workspacelen - 1);
1085                 *ret = workspace;
1086         } else {
1087 icky:
1088                 if (headp) {
1089                         AST_LIST_TRAVERSE(headp,variables,entries) {
1090 #if 0
1091                                 ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",var,ast_var_name(variables));
1092 #endif
1093                                 if (strcasecmp(ast_var_name(variables),var)==0) {
1094                                         *ret=ast_var_value(variables);
1095                                         if (*ret) {
1096                                                 strncpy(workspace, *ret, workspacelen - 1);
1097                                                 *ret = workspace;
1098                                         }
1099                                         break;
1100                                 }
1101                         }
1102                 }
1103                 if (!(*ret)) {
1104                         /* Try globals */
1105                         AST_LIST_TRAVERSE(&globals,variables,entries) {
1106 #if 0
1107                                 ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",var,ast_var_name(variables));
1108 #endif
1109                                 if (strcasecmp(ast_var_name(variables),var)==0) {
1110                                         *ret=ast_var_value(variables);
1111                                         if (*ret) {
1112                                                 strncpy(workspace, *ret, workspacelen - 1);
1113                                                 *ret = workspace;
1114                                         }
1115                                 }
1116                         }
1117                 }
1118         }
1119 }
1120
1121 static int handle_show_functions(int fd, int argc, char *argv[])
1122 {
1123         struct ast_custom_function *acf;
1124
1125         ast_cli(fd, "Installed Custom Functions:\n--------------------------------------------------------------------------------\n");
1126         for (acf = acf_root ; acf; acf = acf->next) {
1127                 ast_cli(fd, "%-20.20s  %-35.35s  %s\n", acf->name, acf->syntax, acf->synopsis);
1128         }
1129         ast_cli(fd, "\n");
1130         return 0;
1131 }
1132
1133 static int handle_show_function(int fd, int argc, char *argv[])
1134 {
1135         struct ast_custom_function *acf;
1136         /* Maximum number of characters added by terminal coloring is 22 */
1137         char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
1138         char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
1139         char stxtitle[40], *syntax = NULL;
1140         int synopsis_size, description_size, syntax_size;
1141
1142         if (argc < 3) return RESULT_SHOWUSAGE;
1143
1144         if (!(acf = ast_custom_function_find(argv[2]))) {
1145                 ast_cli(fd, "No function by that name registered.\n");
1146                 return RESULT_FAILURE;
1147
1148         }
1149
1150         if (acf->synopsis)
1151                 synopsis_size = strlen(acf->synopsis) + 23;
1152         else
1153                 synopsis_size = strlen("Not available") + 23;
1154         synopsis = alloca(synopsis_size);
1155         
1156         if (acf->desc)
1157                 description_size = strlen(acf->desc) + 23;
1158         else
1159                 description_size = strlen("Not available") + 23;
1160         description = alloca(description_size);
1161
1162         if (acf->syntax)
1163                 syntax_size = strlen(acf->syntax) + 23;
1164         else
1165                 syntax_size = strlen("Not available") + 23;
1166         syntax = alloca(syntax_size);
1167
1168         snprintf(info, 64 + AST_MAX_APP, "\n  -= Info about function '%s' =- \n\n", acf->name);
1169         term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
1170         term_color(stxtitle, "[Syntax]\n", COLOR_MAGENTA, 0, 40);
1171         term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
1172         term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
1173         term_color(syntax,
1174                    acf->syntax ? acf->syntax : "Not available",
1175                    COLOR_CYAN, 0, syntax_size);
1176         term_color(synopsis,
1177                    acf->synopsis ? acf->synopsis : "Not available",
1178                    COLOR_CYAN, 0, synopsis_size);
1179         term_color(description,
1180                    acf->desc ? acf->desc : "Not available",
1181                    COLOR_CYAN, 0, description_size);
1182         
1183         ast_cli(fd,"%s%s%s\n\n%s%s\n\n%s%s\n", infotitle, stxtitle, syntax, syntitle, synopsis, destitle, description);
1184
1185         return RESULT_SUCCESS;
1186 }
1187
1188 static char *complete_show_function(char *line, char *word, int pos, int state)
1189 {
1190         struct ast_custom_function *acf;
1191         int which = 0;
1192
1193         /* try to lock functions list ... */
1194         if (ast_mutex_lock(&acflock)) {
1195                 ast_log(LOG_ERROR, "Unable to lock function list\n");
1196                 return NULL;
1197         }
1198
1199         acf = acf_root;
1200         while (acf) {
1201                 if (!strncasecmp(word, acf->name, strlen(word))) {
1202                         if (++which > state) {
1203                                 char *ret = strdup(acf->name);
1204                                 ast_mutex_unlock(&acflock);
1205                                 return ret;
1206                         }
1207                 }
1208                 acf = acf->next; 
1209         }
1210
1211         ast_mutex_unlock(&acflock);
1212         return NULL; 
1213 }
1214
1215 struct ast_custom_function* ast_custom_function_find(char *name) 
1216 {
1217         struct ast_custom_function *acfptr;
1218
1219         /* try to lock functions list ... */
1220         if (ast_mutex_lock(&acflock)) {
1221                 ast_log(LOG_ERROR, "Unable to lock function list\n");
1222                 return NULL;
1223         }
1224
1225         for (acfptr = acf_root; acfptr; acfptr = acfptr->next) {
1226                 if (!strcmp(name, acfptr->name)) {
1227                         break;
1228                 }
1229         }
1230
1231         ast_mutex_unlock(&acflock);
1232         
1233         return acfptr;
1234 }
1235
1236 int ast_custom_function_unregister(struct ast_custom_function *acf) 
1237 {
1238         struct ast_custom_function *acfptr, *lastacf = NULL;
1239         int res = -1;
1240
1241         if (!acf)
1242                 return -1;
1243
1244         /* try to lock functions list ... */
1245         if (ast_mutex_lock(&acflock)) {
1246                 ast_log(LOG_ERROR, "Unable to lock function list\n");
1247                 return -1;
1248         }
1249
1250         for (acfptr = acf_root; acfptr; acfptr = acfptr->next) {
1251                 if (acfptr == acf) {
1252                         if (lastacf) {
1253                                 lastacf->next = acf->next;
1254                         } else {
1255                                 acf_root = acf->next;
1256                         }
1257                         res = 0;
1258                         break;
1259                 }
1260                 lastacf = acfptr;
1261         }
1262
1263         ast_mutex_unlock(&acflock);
1264
1265         if (!res && (option_verbose > 1))
1266                 ast_verbose(VERBOSE_PREFIX_2 "Unregistered custom function %s\n", acf->name);
1267
1268         return res;
1269 }
1270
1271 int ast_custom_function_register(struct ast_custom_function *acf) 
1272 {
1273         if (!acf)
1274                 return -1;
1275
1276         /* try to lock functions list ... */
1277         if (ast_mutex_lock(&acflock)) {
1278                 ast_log(LOG_ERROR, "Unable to lock function list\n");
1279                 return -1;
1280         }
1281
1282         if (ast_custom_function_find(acf->name)) {
1283                 ast_log(LOG_ERROR, "Function %s already registered.\n", acf->name);
1284                 ast_mutex_unlock(&acflock);
1285                 return -1;
1286         }
1287
1288         acf->next = acf_root;
1289         acf_root = acf;
1290
1291         ast_mutex_unlock(&acflock);
1292
1293         if (option_verbose > 1)
1294                 ast_verbose(VERBOSE_PREFIX_2 "Registered custom function %s\n", acf->name);
1295
1296         return 0;
1297 }
1298
1299 char *ast_func_read(struct ast_channel *chan, const char *in, char *workspace, size_t len)
1300 {
1301         char *args = NULL, *function, *p;
1302         char *ret = "0";
1303         struct ast_custom_function *acfptr;
1304
1305         function = ast_strdupa(in);
1306         if (function) {
1307                 if ((args = strchr(function, '('))) {
1308                         *args = '\0';
1309                         args++;
1310                         if ((p = strrchr(args, ')'))) {
1311                                 *p = '\0';
1312                         } else {
1313                                 ast_log(LOG_WARNING, "Can't find trailing parenthesis?\n");
1314                         }
1315                 } else {
1316                         ast_log(LOG_WARNING, "Function doesn't contain parentheses.  Assuming null argument.\n");
1317                 }
1318
1319                 if ((acfptr = ast_custom_function_find(function))) {
1320                         /* run the custom function */
1321                         if (acfptr->read) {
1322                                 return acfptr->read(chan, function, args, workspace, len);
1323                         } else {
1324                                 ast_log(LOG_ERROR, "Function %s cannot be read\n", function);
1325                         }
1326                 } else {
1327                         ast_log(LOG_ERROR, "Function %s not registered\n", function);
1328                 }
1329         } else {
1330                 ast_log(LOG_ERROR, "Out of memory\n");
1331         }
1332         return ret;
1333 }
1334
1335 void ast_func_write(struct ast_channel *chan, const char *in, const char *value)
1336 {
1337         char *args = NULL, *function, *p;
1338         struct ast_custom_function *acfptr;
1339
1340         function = ast_strdupa(in);
1341         if (function) {
1342                 if ((args = strchr(function, '('))) {
1343                         *args = '\0';
1344                         args++;
1345                         if ((p = strrchr(args, ')'))) {
1346                                 *p = '\0';
1347                         } else {
1348                                 ast_log(LOG_WARNING, "Can't find trailing parenthesis?\n");
1349                         }
1350                 } else {
1351                         ast_log(LOG_WARNING, "Function doesn't contain parentheses.  Assuming null argument.\n");
1352                 }
1353
1354                 if ((acfptr = ast_custom_function_find(function))) {
1355                         /* run the custom function */
1356                         if (acfptr->write) {
1357                                 acfptr->write(chan, function, args, value);
1358                         } else {
1359                                 ast_log(LOG_ERROR, "Function %s cannot be written to\n", function);
1360                         }
1361                 } else {
1362                         ast_log(LOG_ERROR, "Function %s not registered\n", function);
1363                 }
1364         } else {
1365                 ast_log(LOG_ERROR, "Out of memory\n");
1366         }
1367 }
1368
1369 static void pbx_substitute_variables_helper_full(struct ast_channel *c, const char *cp1, char *cp2, int count, struct varshead *headp)
1370 {
1371         char *cp4;
1372         const char *tmp, *whereweare;
1373         int length;
1374         char workspace[4096];
1375         char ltmp[4096], var[4096];
1376         char *nextvar, *nextexp, *nextthing;
1377         char *vars, *vare;
1378         int pos, brackets, needsub, len;
1379         
1380         /* Substitutes variables into cp2, based on string cp1, and assuming cp2 to be
1381            zero-filled */
1382         whereweare=tmp=cp1;
1383         while(!ast_strlen_zero(whereweare) && count) {
1384                 /* Assume we're copying the whole remaining string */
1385                 pos = strlen(whereweare);
1386                 nextvar = NULL;
1387                 nextexp = NULL;
1388                 nextthing = strchr(whereweare, '$');
1389                 if (nextthing) {
1390                         switch(nextthing[1]) {
1391                         case '{':
1392                                 nextvar = nextthing;
1393                                 break;
1394                         case '[':
1395                                 nextexp = nextthing;
1396                                 break;
1397                         }
1398                 }
1399                 /* If there is one, we only go that far */
1400                 if (nextvar)
1401                         pos = nextvar - whereweare;
1402                 else if (nextexp)
1403                         pos = nextexp - whereweare;
1404
1405                 /* Can't copy more than 'count' bytes */
1406                 if (pos > count)
1407                         pos = count;
1408
1409                 /* Copy that many bytes */
1410                 memcpy(cp2, whereweare, pos);
1411
1412                 count -= pos;
1413                 cp2 += pos;
1414                 whereweare += pos;
1415                 
1416                 if (nextvar) {
1417                         /* We have a variable.  Find the start and end, and determine
1418                            if we are going to have to recursively call ourselves on the
1419                            contents */
1420                         vars = vare = nextvar + 2;
1421                         brackets = 1;
1422                         needsub = 0;
1423
1424                         /* Find the end of it */
1425                         while(brackets && *vare) {
1426                                 if ((vare[0] == '$') && (vare[1] == '{')) {
1427                                         needsub++;
1428                                         brackets++;
1429                                 } else if (vare[0] == '}') {
1430                                         brackets--;
1431                                 } else if ((vare[0] == '$') && (vare[1] == '['))
1432                                         needsub++;
1433                                 vare++;
1434                         }
1435                         if (brackets)
1436                                 ast_log(LOG_NOTICE, "Error in extension logic (missing '}')\n");
1437                         len = vare - vars - 1;
1438
1439                         /* Skip totally over variable name */
1440                         whereweare += ( len + 3);
1441
1442                         /* Store variable name (and truncate) */
1443                         memset(var, 0, sizeof(var));
1444                         strncpy(var, vars, sizeof(var) - 1);
1445                         var[len] = '\0';
1446
1447                         /* Substitute if necessary */
1448                         if (needsub) {
1449                                 memset(ltmp, 0, sizeof(ltmp));
1450                                 pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1);
1451                                 vars = ltmp;
1452                         } else {
1453                                 vars = var;
1454                         }
1455
1456                         workspace[0] = '\0';
1457
1458                         if (var[len - 1] == ')') {
1459                                 /* Evaluate function */
1460                                 cp4 = ast_func_read(c, vars, workspace, sizeof(workspace));
1461
1462                                 ast_log(LOG_DEBUG, "Function result is '%s'\n", cp4 ? cp4 : "(null)");
1463                         } else {
1464                                 /* Retrieve variable value */
1465                                 pbx_retrieve_variable(c, vars, &cp4, workspace, sizeof(workspace), headp);
1466                         }
1467                         if (cp4) {
1468                                 length = strlen(cp4);
1469                                 if (length > count)
1470                                         length = count;
1471                                 memcpy(cp2, cp4, length);
1472                                 count -= length;
1473                                 cp2 += length;
1474                         }
1475                 } else if (nextexp) {
1476                         /* We have an expression.  Find the start and end, and determine
1477                            if we are going to have to recursively call ourselves on the
1478                            contents */
1479                         vars = vare = nextexp + 2;
1480                         brackets = 1;
1481                         needsub = 0;
1482
1483                         /* Find the end of it */
1484                         while(brackets && *vare) {
1485                                 if ((vare[0] == '$') && (vare[1] == '[')) {
1486                                         needsub++;
1487                                         brackets++;
1488                                         vare++;
1489                                 } else if (vare[0] == '[') {
1490                                         brackets++;
1491                                 } else if (vare[0] == ']') {
1492                                         brackets--;
1493                                 } else if ((vare[0] == '$') && (vare[1] == '{')) {
1494                                         needsub++;
1495                                         vare++;
1496                                 }
1497                                 vare++;
1498                         }
1499                         if (brackets)
1500                                 ast_log(LOG_NOTICE, "Error in extension logic (missing ']')\n");
1501                         len = vare - vars - 1;
1502                         
1503                         /* Skip totally over variable name */
1504                         whereweare += ( len + 3);
1505                         
1506                         /* Store variable name (and truncate) */
1507                         memset(var, 0, sizeof(var));
1508                         strncpy(var, vars, sizeof(var) - 1);
1509                         var[len] = '\0';
1510                         
1511                         /* Substitute if necessary */
1512                         if (needsub) {
1513                                 memset(ltmp, 0, sizeof(ltmp));
1514                                 pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1);
1515                                 vars = ltmp;
1516                         } else {
1517                                 vars = var;
1518                         }
1519
1520                         /* Evaluate expression */                       
1521                         cp4 = ast_expr(vars);
1522                         
1523                         ast_log(LOG_DEBUG, "Expression is '%s'\n", cp4);
1524                         
1525                         if (cp4) {
1526                                 length = strlen(cp4);
1527                                 if (length > count)
1528                                         length = count;
1529                                 memcpy(cp2, cp4, length);
1530                                 count -= length;
1531                                 cp2 += length;
1532                                 free(cp4);
1533                         }
1534                 } else
1535                         break;
1536         }
1537 }
1538
1539 void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
1540 {
1541         pbx_substitute_variables_helper_full(c, cp1, cp2, count, NULL);
1542 }
1543
1544 void pbx_substitute_variables_varshead(struct varshead *headp, const char *cp1, char *cp2, int count)
1545 {
1546         pbx_substitute_variables_helper_full(NULL, cp1, cp2, count, headp);
1547 }
1548
1549 static void pbx_substitute_variables(char *passdata, int datalen, struct ast_channel *c, struct ast_exten *e)
1550 {
1551         memset(passdata, 0, datalen);
1552                 
1553         /* No variables or expressions in e->data, so why scan it? */
1554         if (!strstr(e->data,"${") && !strstr(e->data,"$[") && !strstr(e->data,"$(")) {
1555                 strncpy(passdata, e->data, datalen - 1);
1556                 passdata[datalen-1] = '\0';
1557                 return;
1558         }
1559         
1560         pbx_substitute_variables_helper(c, e->data, passdata, datalen - 1);
1561 }                                                               
1562
1563 static int pbx_extension_helper(struct ast_channel *c, struct ast_context *con, const char *context, const char *exten, int priority, const char *label, const char *callerid, int action) 
1564 {
1565         struct ast_exten *e;
1566         struct ast_app *app;
1567         struct ast_switch *sw;
1568         char *data;
1569         const char *foundcontext=NULL;
1570         int newstack = 0;
1571         int res;
1572         int status = 0;
1573         char *incstack[AST_PBX_MAX_STACK];
1574         char passdata[EXT_DATA_SIZE];
1575         int stacklen = 0;
1576         char tmp[80];
1577         char tmp2[80];
1578         char tmp3[EXT_DATA_SIZE];
1579         char atmp[80];
1580         char atmp2[EXT_DATA_SIZE+100];
1581
1582         if (ast_mutex_lock(&conlock)) {
1583                 ast_log(LOG_WARNING, "Unable to obtain lock\n");
1584                 if ((action == HELPER_EXISTS) || (action == HELPER_CANMATCH) || (action == HELPER_MATCHMORE))
1585                         return 0;
1586                 else
1587                         return -1;
1588         }
1589         e = pbx_find_extension(c, con, context, exten, priority, label, callerid, action, incstack, &stacklen, &status, &sw, &data, &foundcontext);
1590         if (e) {
1591                 switch(action) {
1592                 case HELPER_CANMATCH:
1593                         ast_mutex_unlock(&conlock);
1594                         return -1;
1595                 case HELPER_EXISTS:
1596                         ast_mutex_unlock(&conlock);
1597                         return -1;
1598                 case HELPER_FINDLABEL:
1599                         res = e->priority;
1600                         ast_mutex_unlock(&conlock);
1601                         return res;
1602                 case HELPER_MATCHMORE:
1603                         ast_mutex_unlock(&conlock);
1604                         return -1;
1605                 case HELPER_SPAWN:
1606                         newstack++;
1607                         /* Fall through */
1608                 case HELPER_EXEC:
1609                         app = pbx_findapp(e->app);
1610                         ast_mutex_unlock(&conlock);
1611                         if (app) {
1612                                 if (c->context != context)
1613                                         strncpy(c->context, context, sizeof(c->context)-1);
1614                                 if (c->exten != exten)
1615                                         strncpy(c->exten, exten, sizeof(c->exten)-1);
1616                                 c->priority = priority;
1617                                 pbx_substitute_variables(passdata, sizeof(passdata), c, e);
1618                                 if (option_debug) {
1619                                                 ast_log(LOG_DEBUG, "Launching '%s'\n", app->name);
1620                                                 snprintf(atmp, 80, "STACK-%s-%s-%d", context, exten, priority);
1621                                                 snprintf(atmp2, EXT_DATA_SIZE+100, "%s(\"%s\", \"%s\") %s", app->name, c->name, (!ast_strlen_zero(passdata) ? (char *)passdata : ""), (newstack ? "in new stack" : "in same stack"));
1622                                                 pbx_builtin_setvar_helper(c, atmp, atmp2);
1623                                 }
1624                                 if (option_verbose > 2)
1625                                                 ast_verbose( VERBOSE_PREFIX_3 "Executing %s(\"%s\", \"%s\") %s\n", 
1626                                                                 term_color(tmp, app->name, COLOR_BRCYAN, 0, sizeof(tmp)),
1627                                                                 term_color(tmp2, c->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
1628                                                                 term_color(tmp3, (!ast_strlen_zero(passdata) ? (char *)passdata : ""), COLOR_BRMAGENTA, 0, sizeof(tmp3)),
1629                                                                 (newstack ? "in new stack" : "in same stack"));
1630                                 manager_event(EVENT_FLAG_CALL, "Newexten", 
1631                                         "Channel: %s\r\n"
1632                                         "Context: %s\r\n"
1633                                         "Extension: %s\r\n"
1634                                         "Priority: %d\r\n"
1635                                         "Application: %s\r\n"
1636                                         "AppData: %s\r\n"
1637                                         "Uniqueid: %s\r\n",
1638                                         c->name, c->context, c->exten, c->priority, app->name, passdata ? passdata : "(NULL)", c->uniqueid);
1639                                 res = pbx_exec(c, app, passdata, newstack);
1640                                 return res;
1641                         } else {
1642                                 ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
1643                                 return -1;
1644                         }
1645                 default:
1646                         ast_log(LOG_WARNING, "Huh (%d)?\n", action);                    return -1;
1647                 }
1648         } else if (sw) {
1649                 switch(action) {
1650                 case HELPER_CANMATCH:
1651                         ast_mutex_unlock(&conlock);
1652                         return -1;
1653                 case HELPER_EXISTS:
1654                         ast_mutex_unlock(&conlock);
1655                         return -1;
1656                 case HELPER_MATCHMORE:
1657                         ast_mutex_unlock(&conlock);
1658                         return -1;
1659                 case HELPER_FINDLABEL:
1660                         ast_mutex_unlock(&conlock);
1661                         return -1;
1662                 case HELPER_SPAWN:
1663                         newstack++;
1664                         /* Fall through */
1665                 case HELPER_EXEC:
1666                         ast_mutex_unlock(&conlock);
1667                         if (sw->exec)
1668                                 res = sw->exec(c, foundcontext ? foundcontext : context, exten, priority, callerid, newstack, data);
1669                         else {
1670                                 ast_log(LOG_WARNING, "No execution engine for switch %s\n", sw->name);
1671                                 res = -1;
1672                         }
1673                         return res;
1674                 default:
1675                         ast_log(LOG_WARNING, "Huh (%d)?\n", action);
1676                         return -1;
1677                 }
1678         } else {
1679                 ast_mutex_unlock(&conlock);
1680                 switch(status) {
1681                 case STATUS_NO_CONTEXT:
1682                         if ((action != HELPER_EXISTS) && (action != HELPER_MATCHMORE))
1683                                 ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", context);
1684                         break;
1685                 case STATUS_NO_EXTENSION:
1686                         if ((action != HELPER_EXISTS) && (action !=  HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1687                                 ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, context);
1688                         break;
1689                 case STATUS_NO_PRIORITY:
1690                         if ((action != HELPER_EXISTS) && (action !=  HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1691                                 ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, context);
1692                         break;
1693                 case STATUS_NO_LABEL:
1694                         if (context)
1695                                 ast_log(LOG_NOTICE, "No such label '%s' in extension '%s' in context '%s'\n", label, exten, context);
1696                         break;
1697                 default:
1698                         ast_log(LOG_DEBUG, "Shouldn't happen!\n");
1699                 }
1700                 
1701                 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1702                         return -1;
1703                 else
1704                         return 0;
1705         }
1706
1707 }
1708
1709 /*--- ast_hint_extension: Find hint for given extension in context */
1710 static struct ast_exten *ast_hint_extension(struct ast_channel *c, const char *context, const char *exten)
1711 {
1712         struct ast_exten *e;
1713         struct ast_switch *sw;
1714         char *data;
1715         const char *foundcontext = NULL;
1716         int status = 0;
1717         char *incstack[AST_PBX_MAX_STACK];
1718         int stacklen = 0;
1719
1720         if (ast_mutex_lock(&conlock)) {
1721                 ast_log(LOG_WARNING, "Unable to obtain lock\n");
1722                 return NULL;
1723         }
1724         e = pbx_find_extension(c, NULL, context, exten, PRIORITY_HINT, NULL, "", HELPER_EXISTS, incstack, &stacklen, &status, &sw, &data, &foundcontext);
1725         ast_mutex_unlock(&conlock);     
1726         return e;
1727 }
1728
1729 /*--- ast_extensions_state2: Check state of extension by using hints */
1730 static int ast_extension_state2(struct ast_exten *e)
1731 {
1732         char hint[AST_MAX_EXTENSION] = "";    
1733         char *cur, *rest;
1734         int res = -1;
1735         int allunavailable = 1, allbusy = 1, allfree = 1;
1736         int busy = 0;
1737
1738         if (!e)
1739                 return -1;
1740
1741         strncpy(hint, ast_get_extension_app(e), sizeof(hint)-1);
1742
1743         cur = hint;     /* On or more devices separated with a & character */
1744         do {
1745                 rest = strchr(cur, '&');
1746                 if (rest) {
1747                         *rest = 0;
1748                         rest++;
1749                 }
1750         
1751                 res = ast_device_state(cur);
1752                 switch (res) {
1753                 case AST_DEVICE_NOT_INUSE:
1754                         allunavailable = 0;
1755                         allbusy = 0;
1756                         break;
1757                 case AST_DEVICE_INUSE:
1758                         return AST_EXTENSION_INUSE;
1759                 case AST_DEVICE_BUSY:
1760                         allunavailable = 0;
1761                         allfree = 0;
1762                         busy = 1;
1763                         break;
1764                 case AST_DEVICE_UNAVAILABLE:
1765                 case AST_DEVICE_INVALID:
1766                         allbusy = 0;
1767                         allfree = 0;
1768                         break;
1769                 default:
1770                         allunavailable = 0;
1771                         allbusy = 0;
1772                         allfree = 0;
1773                 }
1774                 cur = rest;
1775         } while (cur);
1776
1777         if (allfree)                    
1778                 return AST_EXTENSION_NOT_INUSE;
1779         if (allbusy)            
1780                 return AST_EXTENSION_BUSY;
1781         if (allunavailable)
1782                 return AST_EXTENSION_UNAVAILABLE;
1783         if (busy) 
1784                 return AST_EXTENSION_INUSE;
1785         
1786         return AST_EXTENSION_NOT_INUSE;
1787 }
1788
1789
1790 /*--- ast_extension_state: Check extension state for an extension by using hint */
1791 int ast_extension_state(struct ast_channel *c, char *context, char *exten)
1792 {
1793         struct ast_exten *e;
1794
1795         e = ast_hint_extension(c, context, exten);      /* Do we have a hint for this extension ? */ 
1796         if (!e) 
1797                 return -1;                              /* No hint, return -1 */
1798
1799         return ast_extension_state2(e);                 /* Check all devices in the hint */
1800 }
1801
1802 /*--- ast_device_state_changed: If device state in cblist is changed  - then notify callback function */
1803 int ast_device_state_changed(const char *fmt, ...) 
1804 {
1805         struct ast_hint *list;
1806         struct ast_state_cb *cblist;
1807         struct ast_devstate_cb *devcb;
1808         char hint[AST_MAX_EXTENSION] = "";
1809         char device[AST_MAX_EXTENSION];
1810
1811         char *cur, *rest;
1812         int state;
1813
1814         va_list ap;
1815
1816         va_start(ap, fmt);
1817         vsnprintf(device, sizeof(device), fmt, ap);
1818         va_end(ap);
1819
1820         rest = strchr(device, '-');
1821         if (rest) {
1822                 *rest = 0;
1823         }
1824
1825
1826         state = ast_device_state(device);
1827         if (option_debug > 2)
1828                 ast_log(LOG_DEBUG, "Changing state for %s - state %d\n", device, state);
1829
1830         ast_mutex_lock(&hintlock);
1831
1832         /* First check device callbacks */
1833         devcb = devcbs;
1834         while(devcb) {
1835                 if (devcb->callback)
1836                         devcb->callback(device, state, devcb->data);
1837                 devcb = devcb->next;
1838         }
1839
1840         /* Then check callbacks in hints */
1841         list = hints;
1842
1843         while (list) {
1844
1845                 strncpy(hint, ast_get_extension_app(list->exten), sizeof(hint) - 1);
1846                 cur = hint;
1847                 do {
1848                         rest = strchr(cur, '&');
1849                         if (rest) {
1850                                 *rest = 0;
1851                                 rest++;
1852                         }
1853                         
1854                         if (!strcmp(cur, device)) {     /* Is this device referred to in this hint? */
1855
1856                                 /* Get device state for this hint */
1857                                 state = ast_extension_state2(list->exten);
1858
1859                                 if ((state != -1) && (state != list->laststate)) {
1860                                         /* Device state changed since last check - notify the watcher */
1861
1862                                         /* For general callbacks */
1863                                         cblist = statecbs;
1864                                         while (cblist) {
1865                                                 cblist->callback(list->exten->parent->name, list->exten->exten, state, cblist->data);
1866                                                 cblist = cblist->next;
1867                                         }
1868
1869                                         /* For extension callbacks */
1870                                         cblist = list->callbacks;
1871                                         while (cblist) {
1872                                                 cblist->callback(list->exten->parent->name, list->exten->exten, state, cblist->data);
1873                                                 cblist = cblist->next;
1874                                         }
1875                         
1876                                         list->laststate = state;
1877                                 }
1878                                 break;
1879                         }
1880                         cur = rest;
1881                 } while (cur);
1882                 list = list->next;
1883         }
1884         ast_mutex_unlock(&hintlock);
1885         return 1;
1886 }
1887                         
1888 /*--- ast_devstate_add: Add device state watcher */
1889 int ast_devstate_add(ast_devstate_cb_type callback, void *data)
1890 {
1891         struct ast_devstate_cb *devcb;
1892         devcb = malloc(sizeof(struct ast_devstate_cb));
1893         if (devcb) {
1894                 memset(devcb, 0, sizeof(struct ast_devstate_cb));
1895                 ast_mutex_lock(&hintlock);
1896                 devcb->data = data;
1897                 devcb->callback = callback;
1898                 devcb->next = devcbs;
1899                 devcbs = devcb;
1900                 ast_mutex_unlock(&hintlock);
1901         }
1902         return 0;
1903 }
1904
1905 /*--- ast_devstate_del: Remove device state watcher */
1906 void ast_devstate_del(ast_devstate_cb_type callback, void *data)
1907 {
1908         struct ast_devstate_cb *devcb, *prev = NULL, *next;
1909         ast_mutex_lock(&hintlock);
1910         devcb = devcbs;
1911         while(devcb) {
1912                 next = devcb->next;
1913                 if ((devcb->data == data) && (devcb->callback == callback)) {
1914                         if (prev)
1915                                 prev->next = next;
1916                         else
1917                                 devcbs = next;
1918                         free(devcb);
1919                 } else
1920                         prev = devcb;
1921                 devcb = next;
1922         }
1923         ast_mutex_unlock(&hintlock);
1924 }
1925
1926 /*--- ast_extension_state_add: Add watcher for extension states */
1927 int ast_extension_state_add(const char *context, const char *exten, 
1928                             ast_state_cb_type callback, void *data)
1929 {
1930         struct ast_hint *list;
1931         struct ast_state_cb *cblist;
1932         struct ast_exten *e;
1933
1934         /* If there's no context and extension:  add callback to statecbs list */
1935         if (!context && !exten) {
1936                 ast_mutex_lock(&hintlock);
1937
1938                 cblist = statecbs;
1939                 while (cblist) {
1940                         if (cblist->callback == callback) {
1941                                 cblist->data = data;
1942                                 ast_mutex_unlock(&hintlock);
1943                                 return 0;
1944                         }
1945                         cblist = cblist->next;
1946                 }
1947         
1948                 /* Now insert the callback */
1949                 cblist = malloc(sizeof(struct ast_state_cb));
1950                 if (!cblist) {
1951                         ast_mutex_unlock(&hintlock);
1952                         return -1;
1953                 }
1954                 memset(cblist, 0, sizeof(struct ast_state_cb));
1955                 cblist->id = 0;
1956                 cblist->callback = callback;
1957                 cblist->data = data;
1958         
1959                 cblist->next = statecbs;
1960                 statecbs = cblist;
1961
1962                 ast_mutex_unlock(&hintlock);
1963                 return 0;
1964         }
1965
1966         if (!context || !exten)
1967                 return -1;
1968
1969         /* This callback type is for only one hint, so get the hint */
1970         e = ast_hint_extension(NULL, context, exten);    
1971         if (!e) {
1972                 return -1;
1973         }
1974
1975         /* Find the hint in the list of hints */
1976         ast_mutex_lock(&hintlock);
1977         list = hints;        
1978
1979         while (list) {
1980                 if (list->exten == e)
1981                         break;      
1982                 list = list->next;    
1983         }
1984
1985         if (!list) {
1986                 /* We have no hint, sorry */
1987                 ast_mutex_unlock(&hintlock);
1988                 return -1;
1989         }
1990
1991         /* Now insert the callback in the callback list  */
1992         cblist = malloc(sizeof(struct ast_state_cb));
1993         if (!cblist) {
1994                 ast_mutex_unlock(&hintlock);
1995                 return -1;
1996         }
1997         memset(cblist, 0, sizeof(struct ast_state_cb));
1998         cblist->id = stateid++;         /* Unique ID for this callback */
1999         cblist->callback = callback;    /* Pointer to callback routine */
2000         cblist->data = data;            /* Data for the callback */
2001
2002         cblist->next = list->callbacks;
2003         list->callbacks = cblist;
2004
2005         ast_mutex_unlock(&hintlock);
2006         return cblist->id;
2007 }
2008
2009 /*--- ast_extension_state_del: Remove a watcher from the callback list */
2010 int ast_extension_state_del(int id, ast_state_cb_type callback)
2011 {
2012         struct ast_hint *list;
2013         struct ast_state_cb *cblist, *cbprev;
2014
2015         if (!id && !callback)
2016                 return -1;
2017
2018         ast_mutex_lock(&hintlock);
2019
2020         /* id is zero is a callback without extension */
2021         if (!id) {
2022                 cbprev = NULL;
2023                 cblist = statecbs;
2024                 while (cblist) {
2025                         if (cblist->callback == callback) {
2026                                 if (!cbprev)
2027                                         statecbs = cblist->next;
2028                                 else
2029                                         cbprev->next = cblist->next;
2030
2031                                 free(cblist);
2032
2033                                 ast_mutex_unlock(&hintlock);
2034                                 return 0;
2035                         }
2036                         cbprev = cblist;
2037                         cblist = cblist->next;
2038                 }
2039
2040                 ast_mutex_lock(&hintlock);
2041                 return -1;
2042         }
2043
2044         /* id greater than zero is a callback with extension */
2045         /* Find the callback based on ID */
2046         list = hints;
2047         while (list) {
2048                 cblist = list->callbacks;
2049                 cbprev = NULL;
2050                 while (cblist) {
2051                         if (cblist->id==id) {
2052                                 if (!cbprev)
2053                                         list->callbacks = cblist->next;         
2054                                 else
2055                                         cbprev->next = cblist->next;
2056                 
2057                                 free(cblist);
2058                 
2059                                 ast_mutex_unlock(&hintlock);
2060                                 return 0;               
2061                         }               
2062                         cbprev = cblist;                                
2063                         cblist = cblist->next;
2064                 }
2065                 list = list->next;
2066         }
2067
2068         ast_mutex_unlock(&hintlock);
2069         return -1;
2070 }
2071
2072 /*--- ast_add_hint: Add hint to hint list, check initial extension state */
2073 static int ast_add_hint(struct ast_exten *e)
2074 {
2075         struct ast_hint *list;
2076
2077         if (!e) 
2078                 return -1;
2079
2080         ast_mutex_lock(&hintlock);
2081         list = hints;        
2082
2083         /* Search if hint exists, do nothing */
2084         while (list) {
2085                 if (list->exten == e) {
2086                         ast_mutex_unlock(&hintlock);
2087                         if (option_debug > 1)
2088                                 ast_log(LOG_DEBUG, "HINTS: Not re-adding existing hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
2089                         return -1;
2090                 }
2091                 list = list->next;    
2092         }
2093
2094         if (option_debug > 1)
2095                 ast_log(LOG_DEBUG, "HINTS: Adding hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
2096
2097         list = malloc(sizeof(struct ast_hint));
2098         if (!list) {
2099                 ast_mutex_unlock(&hintlock);
2100                 if (option_debug > 1)
2101                         ast_log(LOG_DEBUG, "HINTS: Out of memory...\n");
2102                 return -1;
2103         }
2104         /* Initialize and insert new item at the top */
2105         memset(list, 0, sizeof(struct ast_hint));
2106         list->exten = e;
2107         list->laststate = ast_extension_state2(e);
2108         list->next = hints;
2109         hints = list;
2110
2111         ast_mutex_unlock(&hintlock);
2112         return 0;
2113 }
2114
2115 /*--- ast_change_hint: Change hint for an extension */
2116 static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
2117
2118         struct ast_hint *list;
2119
2120         ast_mutex_lock(&hintlock);
2121         list = hints;
2122
2123         while(list) {
2124                 if (list->exten == oe) {
2125                         list->exten = ne;
2126                         ast_mutex_unlock(&hintlock);    
2127                         return 0;
2128                 }
2129                 list = list->next;
2130         }
2131         ast_mutex_unlock(&hintlock);
2132
2133         return -1;
2134 }
2135
2136 /*--- ast_remove_hint: Remove hint from extension */
2137 static int ast_remove_hint(struct ast_exten *e)
2138 {
2139         /* Cleanup the Notifys if hint is removed */
2140         struct ast_hint *list, *prev = NULL;
2141         struct ast_state_cb *cblist, *cbprev;
2142
2143         if (!e) 
2144                 return -1;
2145
2146         ast_mutex_lock(&hintlock);
2147
2148         list = hints;    
2149         while(list) {
2150                 if (list->exten==e) {
2151                         cbprev = NULL;
2152                         cblist = list->callbacks;
2153                         while (cblist) {
2154                                 /* Notify with -1 and remove all callbacks */
2155                                 cbprev = cblist;            
2156                                 cblist = cblist->next;
2157                                 cbprev->callback(list->exten->parent->name, list->exten->exten, -1, cbprev->data);
2158                                 free(cbprev);
2159                         }
2160                         list->callbacks = NULL;
2161
2162                         if (!prev)
2163                                 hints = list->next;
2164                         else
2165                                 prev->next = list->next;
2166                         free(list);
2167             
2168                         ast_mutex_unlock(&hintlock);
2169                         return 0;
2170                 } else {
2171                         prev = list;
2172                         list = list->next;    
2173                 }
2174         }
2175
2176         ast_mutex_unlock(&hintlock);
2177         return -1;
2178 }
2179
2180
2181 /*--- ast_get_hint: Get hint for channel */
2182 int ast_get_hint(char *hint, int hintsize, char *name, int namesize, struct ast_channel *c, const char *context, const char *exten)
2183 {
2184         struct ast_exten *e;
2185         void *tmp;
2186         e = ast_hint_extension(c, context, exten);
2187         if (e) {
2188                 if (hint) 
2189                     strncpy(hint, ast_get_extension_app(e), hintsize - 1);
2190                 if (name) {
2191                         tmp = ast_get_extension_app_data(e);
2192                         if (tmp)
2193                                 strncpy(name, (char *)tmp, namesize - 1);
2194                 }
2195             return -1;
2196         }
2197         return 0;       
2198 }
2199
2200 int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid) 
2201 {
2202         return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_EXISTS);
2203 }
2204
2205 int ast_findlabel_extension(struct ast_channel *c, const char *context, const char *exten, const char *label, const char *callerid) 
2206 {
2207         return pbx_extension_helper(c, NULL, context, exten, 0, label, callerid, HELPER_FINDLABEL);
2208 }
2209
2210 int ast_findlabel_extension2(struct ast_channel *c, struct ast_context *con, const char *exten, const char *label, const char *callerid) 
2211 {
2212         return pbx_extension_helper(c, con, NULL, exten, 0, label, callerid, HELPER_FINDLABEL);
2213 }
2214
2215 int ast_canmatch_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
2216 {
2217         return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_CANMATCH);
2218 }
2219
2220 int ast_matchmore_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
2221 {
2222         return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_MATCHMORE);
2223 }
2224
2225 int ast_spawn_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid) 
2226 {
2227         return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_SPAWN);
2228 }
2229
2230 int ast_exec_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid) 
2231 {
2232         return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_EXEC);
2233 }
2234
2235 int ast_pbx_run(struct ast_channel *c)
2236 {
2237         int firstpass = 1;
2238         char digit;
2239         char exten[256];
2240         int pos;
2241         int waittime;
2242         int res=0;
2243         int autoloopflag;
2244
2245         /* A little initial setup here */
2246         if (c->pbx)
2247                 ast_log(LOG_WARNING, "%s already has PBX structure??\n", c->name);
2248         c->pbx = malloc(sizeof(struct ast_pbx));
2249         if (!c->pbx) {
2250                 ast_log(LOG_ERROR, "Out of memory\n");
2251                 return -1;
2252         }
2253         if (c->amaflags) {
2254                 if (!c->cdr) {
2255                         c->cdr = ast_cdr_alloc();
2256                         if (!c->cdr) {
2257                                 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
2258                                 free(c->pbx);
2259                                 return -1;
2260                         }
2261                         ast_cdr_init(c->cdr, c);
2262                 }
2263         }
2264         memset(c->pbx, 0, sizeof(struct ast_pbx));
2265         /* Set reasonable defaults */
2266         c->pbx->rtimeout = 10;
2267         c->pbx->dtimeout = 5;
2268
2269         autoloopflag = ast_test_flag(c, AST_FLAG_IN_AUTOLOOP);
2270         ast_set_flag(c, AST_FLAG_IN_AUTOLOOP);
2271
2272         /* Start by trying whatever the channel is set to */
2273         if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2274                 /* If not successful fall back to 's' */
2275                 if (option_verbose > 1)
2276                         ast_verbose( VERBOSE_PREFIX_2 "Starting %s at %s,%s,%d failed so falling back to exten 's'\n", c->name, c->context, c->exten, c->priority);
2277                 strncpy(c->exten, "s", sizeof(c->exten)-1);
2278                 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2279                         /* JK02: And finally back to default if everything else failed */
2280                         if (option_verbose > 1)
2281                                 ast_verbose( VERBOSE_PREFIX_2 "Starting %s at %s,%s,%d still failed so falling back to context 'default'\n", c->name, c->context, c->exten, c->priority);
2282                         strncpy(c->context, "default", sizeof(c->context)-1);
2283                 }
2284                 c->priority = 1;
2285         }
2286         if (c->cdr && !c->cdr->start.tv_sec && !c->cdr->start.tv_usec)
2287                 ast_cdr_start(c->cdr);
2288         for(;;) {
2289                 pos = 0;
2290                 digit = 0;
2291                 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2292                         memset(exten, 0, sizeof(exten));
2293                         if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
2294                                 /* Something bad happened, or a hangup has been requested. */
2295                                 if (((res >= '0') && (res <= '9')) || ((res >= 'A') && (res <= 'F')) ||
2296                                         (res == '*') || (res == '#')) {
2297                                         ast_log(LOG_DEBUG, "Oooh, got something to jump out with ('%c')!\n", res);
2298                                         memset(exten, 0, sizeof(exten));
2299                                         pos = 0;
2300                                         exten[pos++] = digit = res;
2301                                         break;
2302                                 }
2303                                 switch(res) {
2304                                 case AST_PBX_KEEPALIVE:
2305                                         if (option_debug)
2306                                                 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
2307                                         else if (option_verbose > 1)
2308                                                 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
2309                                         goto out;
2310                                         break;
2311                                 default:
2312                                         if (option_debug)
2313                                                 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2314                                         else if (option_verbose > 1)
2315                                                 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2316                                         if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
2317                                                 c->_softhangup =0;
2318                                                 break;
2319                                         }
2320                                         /* atimeout */
2321                                         if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
2322                                                 break;
2323                                         }
2324
2325                                         if (c->cdr) {
2326                                                 ast_cdr_update(c);
2327                                         }
2328                                         goto out;
2329                                 }
2330                         }
2331                         if ((c->_softhangup == AST_SOFTHANGUP_TIMEOUT) && (ast_exists_extension(c,c->context,"T",1,c->cid.cid_num))) {
2332                                 strncpy(c->exten,"T",sizeof(c->exten) - 1);
2333                                 /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
2334                                 c->whentohangup = 0;
2335                                 c->priority = 0;
2336                                 c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
2337                         } else if (c->_softhangup) {
2338                                 ast_log(LOG_DEBUG, "Extension %s, priority %d returned normally even though call was hung up\n",
2339                                         c->exten, c->priority);
2340                                 goto out;
2341                         }
2342                         firstpass = 0;
2343                         c->priority++;
2344                 }
2345                 if (!ast_exists_extension(c, c->context, c->exten, 1, c->cid.cid_num)) {
2346                         /* It's not a valid extension anymore */
2347                         if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
2348                                 if (option_verbose > 2)
2349                                         ast_verbose(VERBOSE_PREFIX_3 "Sent into invalid extension '%s' in context '%s' on %s\n", c->exten, c->context, c->name);
2350                                 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", c->exten);
2351                                 strncpy(c->exten, "i", sizeof(c->exten)-1);
2352                                 c->priority = 1;
2353                         } else {
2354                                 ast_log(LOG_WARNING, "Channel '%s' sent into invalid extension '%s' in context '%s', but no invalid handler\n",
2355                                         c->name, c->exten, c->context);
2356                                 goto out;
2357                         }
2358                 } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
2359                         /* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */
2360                         c->_softhangup = 0;
2361                 } else {
2362                         /* Done, wait for an extension */
2363                         waittime = 0;
2364                         if (digit)
2365                                 waittime = c->pbx->dtimeout;
2366                         else if (!autofallthrough)
2367                                 waittime = c->pbx->rtimeout;
2368                         if (waittime) {
2369                                 while (ast_matchmore_extension(c, c->context, exten, 1, c->cid.cid_num)) {
2370                                         /* As long as we're willing to wait, and as long as it's not defined, 
2371                                            keep reading digits until we can't possibly get a right answer anymore.  */
2372                                         digit = ast_waitfordigit(c, waittime * 1000);
2373                                         if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
2374                                                 c->_softhangup = 0;
2375                                         } else {
2376                                                 if (!digit)
2377                                                         /* No entry */
2378                                                         break;
2379                                                 if (digit < 0)
2380                                                         /* Error, maybe a  hangup */
2381                                                         goto out;
2382                                                 exten[pos++] = digit;
2383                                                 waittime = c->pbx->dtimeout;
2384                                         }
2385                                 }
2386                                 if (ast_exists_extension(c, c->context, exten, 1, c->cid.cid_num)) {
2387                                         /* Prepare the next cycle */
2388                                         strncpy(c->exten, exten, sizeof(c->exten)-1);
2389                                         c->priority = 1;
2390                                 } else {
2391                                         /* No such extension */
2392                                         if (!ast_strlen_zero(exten)) {
2393                                                 /* An invalid extension */
2394                                                 if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
2395                                                         if (option_verbose > 2)
2396                                                                 ast_verbose( VERBOSE_PREFIX_3 "Invalid extension '%s' in context '%s' on %s\n", exten, c->context, c->name);
2397                                                         pbx_builtin_setvar_helper(c, "INVALID_EXTEN", exten);
2398                                                         strncpy(c->exten, "i", sizeof(c->exten)-1);
2399                                                         c->priority = 1;
2400                                                 } else {
2401                                                         ast_log(LOG_WARNING, "Invalid extension '%s', but no rule 'i' in context '%s'\n", exten, c->context);
2402                                                         goto out;
2403                                                 }
2404                                         } else {
2405                                                 /* A simple timeout */
2406                                                 if (ast_exists_extension(c, c->context, "t", 1, c->cid.cid_num)) {
2407                                                         if (option_verbose > 2)
2408                                                                 ast_verbose( VERBOSE_PREFIX_3 "Timeout on %s\n", c->name);
2409                                                         strncpy(c->exten, "t", sizeof(c->exten)-1);
2410                                                         c->priority = 1;
2411                                                 } else {
2412                                                         ast_log(LOG_WARNING, "Timeout, but no rule 't' in context '%s'\n", c->context);
2413                                                         goto out;
2414                                                 }
2415                                         }       
2416                                 }
2417                                 if (c->cdr) {
2418                                         if (option_verbose > 2)
2419                                                 ast_verbose(VERBOSE_PREFIX_2 "CDR updated on %s\n",c->name);    
2420                                         ast_cdr_update(c);
2421                             }
2422                         } else {
2423                                 char *status;
2424
2425                                 status = pbx_builtin_getvar_helper(c, "DIALSTATUS");
2426                                 if (!status)
2427                                         status = "UNKNOWN";
2428                                 if (option_verbose > 2)
2429                                         ast_verbose(VERBOSE_PREFIX_2 "Auto fallthrough, channel '%s' status is '%s'\n", c->name, status);
2430                                 if (!strcasecmp(status, "CONGESTION"))
2431                                         res = pbx_builtin_congestion(c, "10");
2432                                 else if (!strcasecmp(status, "CHANUNAVAIL"))
2433                                         res = pbx_builtin_congestion(c, "10");
2434                                 else if (!strcasecmp(status, "BUSY"))
2435                                         res = pbx_builtin_busy(c, "10");
2436                                 goto out;
2437                         }
2438                 }
2439         }
2440         if (firstpass) 
2441                 ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", c->name);
2442 out:
2443         if ((res != AST_PBX_KEEPALIVE) && ast_exists_extension(c, c->context, "h", 1, c->cid.cid_num)) {
2444                 c->exten[0] = 'h';
2445                 c->exten[1] = '\0';
2446                 c->priority = 1;
2447                 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2448                         if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
2449                                 /* Something bad happened, or a hangup has been requested. */
2450                                 if (option_debug)
2451                                         ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2452                                 else if (option_verbose > 1)
2453                                         ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2454                                 break;
2455                         }
2456                         c->priority++;
2457                 }
2458         }
2459         ast_set2_flag(c, autoloopflag, AST_FLAG_IN_AUTOLOOP);
2460
2461         pbx_destroy(c->pbx);
2462         c->pbx = NULL;
2463         if (res != AST_PBX_KEEPALIVE)
2464                 ast_hangup(c);
2465         return 0;
2466 }
2467
2468 static void *pbx_thread(void *data)
2469 {
2470         /* Oh joyeous kernel, we're a new thread, with nothing to do but
2471            answer this channel and get it going.  The setjmp stuff is fairly
2472            confusing, but necessary to get smooth transitions between
2473            the execution of different applications (without the use of
2474            additional threads) */
2475         struct ast_channel *c = data;
2476         ast_pbx_run(c);
2477         pthread_exit(NULL);
2478         return NULL;
2479 }
2480
2481 int ast_pbx_start(struct ast_channel *c)
2482 {
2483         pthread_t t;
2484         pthread_attr_t attr;
2485         if (!c) {
2486                 ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
2487                 return -1;
2488         }
2489            
2490         /* Start a new thread, and get something handling this channel. */
2491         pthread_attr_init(&attr);
2492         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
2493         if (ast_pthread_create(&t, &attr, pbx_thread, c)) {
2494                 ast_log(LOG_WARNING, "Failed to create new channel thread\n");
2495                 return -1;
2496         }
2497         return 0;
2498 }
2499
2500 int pbx_set_autofallthrough(int newval)
2501 {
2502         int oldval;
2503         oldval = autofallthrough;
2504         if (oldval != newval)
2505                 autofallthrough = newval;
2506         return oldval;
2507 }
2508
2509 /*
2510  * This function locks contexts list by &conlist, search for the right context
2511  * structure, leave context list locked and call ast_context_remove_include2
2512  * which removes include, unlock contexts list and return ...
2513  */
2514 int ast_context_remove_include(const char *context, const char *include, const char *registrar)
2515 {
2516         struct ast_context *c;
2517
2518         if (ast_lock_contexts()) return -1;
2519
2520         /* walk contexts and search for the right one ...*/
2521         c = ast_walk_contexts(NULL);
2522         while (c) {
2523                 /* we found one ... */
2524                 if (!strcmp(ast_get_context_name(c), context)) {
2525                         int ret;
2526                         /* remove include from this context ... */      
2527                         ret = ast_context_remove_include2(c, include, registrar);
2528
2529                         ast_unlock_contexts();
2530
2531                         /* ... return results */
2532                         return ret;
2533                 }
2534                 c = ast_walk_contexts(c);
2535         }
2536
2537         /* we can't find the right one context */
2538         ast_unlock_contexts();
2539         return -1;
2540 }
2541
2542 /*
2543  * When we call this function, &conlock lock must be locked, because when
2544  * we giving *con argument, some process can remove/change this context
2545  * and after that there can be segfault.
2546  *
2547  * This function locks given context, removes include, unlock context and
2548  * return.
2549  */
2550 int ast_context_remove_include2(struct ast_context *con, const char *include, const char *registrar)
2551 {
2552         struct ast_include *i, *pi = NULL;
2553
2554         if (ast_mutex_lock(&con->lock)) return -1;
2555
2556         /* walk includes */
2557         i = con->includes;
2558         while (i) {
2559                 /* find our include */
2560                 if (!strcmp(i->name, include) && 
2561                         (!registrar || !strcmp(i->registrar, registrar))) {
2562                         /* remove from list */
2563                         if (pi)
2564                                 pi->next = i->next;
2565                         else
2566                                 con->includes = i->next;
2567                         /* free include and return */
2568                         free(i);
2569                         ast_mutex_unlock(&con->lock);
2570                         return 0;
2571                 }
2572                 pi = i;
2573                 i = i->next;
2574         }
2575
2576         /* we can't find the right include */
2577         ast_mutex_unlock(&con->lock);
2578         return -1;
2579 }
2580
2581 /*
2582  * This function locks contexts list by &conlist, search for the rigt context
2583  * structure, leave context list locked and call ast_context_remove_switch2
2584  * which removes switch, unlock contexts list and return ...
2585  */
2586 int ast_context_remove_switch(const char *context, const char *sw, const char *data, const char *registrar)
2587 {
2588         struct ast_context *c;
2589
2590         if (ast_lock_contexts()) return -1;
2591
2592         /* walk contexts and search for the right one ...*/
2593         c = ast_walk_contexts(NULL);
2594         while (c) {
2595                 /* we found one ... */
2596                 if (!strcmp(ast_get_context_name(c), context)) {
2597                         int ret;
2598                         /* remove switch from this context ... */       
2599                         ret = ast_context_remove_switch2(c, sw, data, registrar);
2600
2601                         ast_unlock_contexts();
2602
2603                         /* ... return results */
2604                         return ret;
2605                 }
2606                 c = ast_walk_contexts(c);
2607         }
2608
2609         /* we can't find the right one context */
2610         ast_unlock_contexts();
2611         return -1;
2612 }
2613
2614 /*
2615  * When we call this function, &conlock lock must be locked, because when
2616  * we giving *con argument, some process can remove/change this context
2617  * and after that there can be segfault.
2618  *
2619  * This function locks given context, removes switch, unlock context and
2620  * return.
2621  */
2622 int ast_context_remove_switch2(struct ast_context *con, const char *sw, const char *data, const char *registrar)
2623 {
2624         struct ast_sw *i, *pi = NULL;
2625
2626         if (ast_mutex_lock(&con->lock)) return -1;
2627
2628         /* walk switchs */
2629         i = con->alts;
2630         while (i) {
2631                 /* find our switch */
2632                 if (!strcmp(i->name, sw) && !strcmp(i->data, data) && 
2633                         (!registrar || !strcmp(i->registrar, registrar))) {
2634                         /* remove from list */
2635                         if (pi)
2636                                 pi->next = i->next;
2637                         else
2638                                 con->alts = i->next;
2639                         /* free switch and return */
2640                         free(i);
2641                         ast_mutex_unlock(&con->lock);
2642                         return 0;
2643                 }
2644                 pi = i;
2645                 i = i->next;
2646         }
2647
2648         /* we can't find the right switch */
2649         ast_mutex_unlock(&con->lock);
2650         return -1;
2651 }
2652
2653 /*
2654  * This functions lock contexts list, search for the right context,
2655  * call ast_context_remove_extension2, unlock contexts list and return.
2656  * In this function we are using
2657  */
2658 int ast_context_remove_extension(const char *context, const char *extension, int priority, const char *registrar)
2659 {
2660         struct ast_context *c;
2661
2662         if (ast_lock_contexts()) return -1;
2663
2664         /* walk contexts ... */
2665         c = ast_walk_contexts(NULL);
2666         while (c) {
2667                 /* ... search for the right one ... */
2668                 if (!strcmp(ast_get_context_name(c), context)) {
2669                         /* ... remove extension ... */
2670                         int ret = ast_context_remove_extension2(c, extension, priority,
2671                                 registrar);
2672                         /* ... unlock contexts list and return */
2673                         ast_unlock_contexts();
2674                         return ret;
2675                 }
2676                 c = ast_walk_contexts(c);
2677         }
2678
2679         /* we can't find the right context */
2680         ast_unlock_contexts();
2681         return -1;
2682 }
2683
2684 /*
2685  * When do you want to call this function, make sure that &conlock is locked,
2686  * because some process can handle with your *con context before you lock
2687  * it.
2688  *
2689  * This functionc locks given context, search for the right extension and
2690  * fires out all peer in this extensions with given priority. If priority
2691  * is set to 0, all peers are removed. After that, unlock context and
2692  * return.
2693  */
2694 int ast_context_remove_extension2(struct ast_context *con, const char *extension, int priority, const char *registrar)
2695 {
2696         struct ast_exten *exten, *prev_exten = NULL;
2697
2698         if (ast_mutex_lock(&con->lock)) return -1;
2699
2700         /* go through all extensions in context and search the right one ... */
2701         exten = con->root;
2702         while (exten) {
2703
2704                 /* look for right extension */
2705                 if (!strcmp(exten->exten, extension) &&
2706                         (!registrar || !strcmp(exten->registrar, registrar))) {
2707                         struct ast_exten *peer;
2708
2709                         /* should we free all peers in this extension? (priority == 0)? */
2710                         if (priority == 0) {
2711                                 /* remove this extension from context list */
2712                                 if (prev_exten)
2713                                         prev_exten->next = exten->next;
2714                                 else
2715                                         con->root = exten->next;
2716
2717                                 /* fire out all peers */
2718                                 peer = exten; 
2719                                 while (peer) {
2720                                         exten = peer->peer;
2721                                         
2722                                         if (!peer->priority==PRIORITY_HINT) 
2723                                             ast_remove_hint(peer);
2724
2725                                         peer->datad(peer->data);
2726                                         free(peer);
2727
2728                                         peer = exten;
2729                                 }
2730
2731                                 ast_mutex_unlock(&con->lock);
2732                                 return 0;
2733                         } else {
2734                                 /* remove only extension with exten->priority == priority */
2735                                 struct ast_exten *previous_peer = NULL;
2736
2737                                 peer = exten;
2738                                 while (peer) {
2739                                         /* is this our extension? */
2740                                         if (peer->priority == priority &&
2741                                                 (!registrar || !strcmp(peer->registrar, registrar) )) {
2742                                                 /* we are first priority extension? */
2743                                                 if (!previous_peer) {
2744                                                         /* exists previous extension here? */
2745                                                         if (prev_exten) {
2746                                                                 /* yes, so we must change next pointer in
2747                                                                  * previous connection to next peer
2748                                                                  */
2749                                                                 if (peer->peer) {
2750                                                                         prev_exten->next = peer->peer;
2751                                                                         peer->peer->next = exten->next;
2752                                                                 } else
2753                                                                         prev_exten->next = exten->next;
2754                                                         } else {
2755                                                                 /* no previous extension, we are first
2756                                                                  * extension, so change con->root ...
2757                                                                  */
2758                                                                 if (peer->peer)
2759                                                                         con->root = peer->peer;
2760                                                                 else
2761                                                                         con->root = exten->next; 
2762                                                         }
2763                                                 } else {
2764                                                         /* we are not first priority in extension */
2765                                                         previous_peer->peer = peer->peer;
2766                                                 }
2767
2768                                                 /* now, free whole priority extension */
2769                                                 if (peer->priority==PRIORITY_HINT)
2770                                                     ast_remove_hint(peer);
2771                                                 peer->datad(peer->data);
2772                                                 free(peer);
2773
2774                                                 ast_mutex_unlock(&con->lock);
2775                                                 return 0;
2776                                         } else {
2777                                                 /* this is not right extension, skip to next peer */
2778                                                 previous_peer = peer;
2779                                                 peer = peer->peer;
2780                                         }
2781                                 }
2782
2783                                 ast_mutex_unlock(&con->lock);
2784                                 return -1;
2785                         }
2786                 }
2787
2788                 prev_exten = exten;
2789                 exten = exten->next;
2790         }
2791
2792         /* we can't find right extension */
2793         ast_mutex_unlock(&con->lock);
2794         return -1;
2795 }
2796
2797
2798 int ast_register_application(const char *app, int (*execute)(struct ast_channel *, void *), const char *synopsis, const char *description)
2799 {
2800         struct ast_app *tmp, *prev, *cur;
2801         char tmps[80];
2802         int length;
2803         length = sizeof(struct ast_app);
2804         length += strlen(app) + 1;
2805         if (ast_mutex_lock(&applock)) {
2806                 ast_log(LOG_ERROR, "Unable to lock application list\n");
2807                 return -1;
2808         }
2809         tmp = apps;
2810         while(tmp) {
2811                 if (!strcasecmp(app, tmp->name)) {
2812                         ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
2813                         ast_mutex_unlock(&applock);
2814                         return -1;
2815                 }
2816                 tmp = tmp->next;
2817         }
2818         tmp = malloc(length);
2819         if (tmp) {
2820                 memset(tmp, 0, length);
2821                 strcpy(tmp->name, app);
2822                 tmp->execute = execute;
2823                 tmp->synopsis = synopsis;
2824                 tmp->description = description;
2825                 /* Store in alphabetical order */
2826                 cur = apps;
2827                 prev = NULL;
2828                 while(cur) {
2829                         if (strcasecmp(tmp->name, cur->name) < 0)
2830                                 break;
2831                         prev = cur;
2832                         cur = cur->next;
2833                 }
2834                 if (prev) {
2835                         tmp->next = prev->next;
2836                         prev->next = tmp;
2837                 } else {
2838                         tmp->next = apps;
2839                         apps = tmp;
2840                 }
2841         } else {
2842                 ast_log(LOG_ERROR, "Out of memory\n");
2843                 ast_mutex_unlock(&applock);
2844                 return -1;
2845         }
2846         if (option_verbose > 1)
2847                 ast_verbose( VERBOSE_PREFIX_2 "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
2848         ast_mutex_unlock(&applock);
2849         return 0;
2850 }
2851
2852 int ast_register_switch(struct ast_switch *sw)
2853 {
2854         struct ast_switch *tmp, *prev=NULL;
2855         if (ast_mutex_lock(&switchlock)) {
2856                 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
2857                 return -1;
2858         }
2859         tmp = switches;
2860         while(tmp) {
2861                 if (!strcasecmp(tmp->name, sw->name))
2862                         break;
2863                 prev = tmp;
2864                 tmp = tmp->next;
2865         }
2866         if (tmp) {      
2867                 ast_mutex_unlock(&switchlock);
2868                 ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name);
2869                 return -1;
2870         }
2871         sw->next = NULL;
2872         if (prev) 
2873                 prev->next = sw;
2874         else
2875                 switches = sw;
2876         ast_mutex_unlock(&switchlock);
2877         return 0;
2878 }
2879
2880 void ast_unregister_switch(struct ast_switch *sw)
2881 {
2882         struct ast_switch *tmp, *prev=NULL;
2883         if (ast_mutex_lock(&switchlock)) {
2884                 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
2885                 return;
2886         }
2887         tmp = switches;
2888         while(tmp) {
2889                 if (tmp == sw) {
2890                         if (prev)
2891                                 prev->next = tmp->next;
2892                         else
2893                                 switches = tmp->next;
2894                         tmp->next = NULL;
2895                         break;                  
2896                 }
2897                 prev = tmp;
2898                 tmp = tmp->next;
2899         }
2900         ast_mutex_unlock(&switchlock);
2901 }
2902
2903 /*
2904  * Help for CLI commands ...
2905  */
2906 static char show_application_help[] = 
2907 "Usage: show application <application> [<application> [<application> [...]]]\n"
2908 "       Describes a particular application.\n";
2909
2910 static char show_functions_help[] =
2911 "Usage: show functions\n"
2912 "       List builtin functions accessable as $(function args)\n";
2913
2914 static char show_function_help[] =
2915 "Usage: show function <function>\n"
2916 "       Describe a particular dialplan function.\n";
2917
2918 static char show_applications_help[] =
2919 "Usage: show applications [{like|describing} <text>]\n"
2920 "       List applications which are currently available.\n"
2921 "       If 'like', <text> will be a substring of the app name\n"
2922 "       If 'describing', <text> will be a substring of the description\n";
2923
2924 static char show_dialplan_help[] =
2925 "Usage: show dialplan [exten@][context]\n"
2926 "       Show dialplan\n";
2927
2928 static char show_switches_help[] = 
2929 "Usage: show switches\n"
2930 "       Show registered switches\n";
2931
2932 static char show_hints_help[] = 
2933 "Usage: show hints\n"
2934 "       Show registered hints\n";
2935
2936
2937 /*
2938  * IMPLEMENTATION OF CLI FUNCTIONS IS IN THE SAME ORDER AS COMMANDS HELPS
2939  *
2940  */
2941
2942 /*
2943  * 'show application' CLI command implementation functions ...
2944  */
2945
2946 /*
2947  * There is a possibility to show informations about more than one
2948  * application at one time. You can type 'show application Dial Echo' and
2949  * you will see informations about these two applications ...
2950  */
2951 static char *complete_show_application(char *line, char *word,
2952         int pos, int state)
2953 {
2954         struct ast_app *a;
2955         int which = 0;
2956
2957         /* try to lock applications list ... */
2958         if (ast_mutex_lock(&applock)) {
2959                 ast_log(LOG_ERROR, "Unable to lock application list\n");
2960                 return NULL;
2961         }
2962
2963         /* ... walk all applications ... */
2964         a = apps; 
2965         while (a) {
2966                 /* ... check if word matches this application ... */
2967                 if (!strncasecmp(word, a->name, strlen(word))) {
2968                         /* ... if this is right app serve it ... */
2969                         if (++which > state) {
2970                                 char *ret = strdup(a->name);
2971                                 ast_mutex_unlock(&applock);
2972                                 return ret;
2973                         }
2974                 }
2975                 a = a->next; 
2976         }
2977
2978         /* no application match */
2979         ast_mutex_unlock(&applock);
2980         return NULL; 
2981 }
2982
2983 static int handle_show_application(int fd, int argc, char *argv[])
2984 {
2985         struct ast_app *a;
2986         int app, no_registered_app = 1;
2987
2988         if (argc < 3) return RESULT_SHOWUSAGE;
2989
2990         /* try to lock applications list ... */
2991         if (ast_mutex_lock(&applock)) {
2992                 ast_log(LOG_ERROR, "Unable to lock application list\n");
2993                 return -1;
2994         }
2995
2996         /* ... go through all applications ... */
2997         a = apps; 
2998         while (a) {
2999                 /* ... compare this application name with all arguments given
3000                  * to 'show application' command ... */
3001                 for (app = 2; app < argc; app++) {
3002                         if (!strcasecmp(a->name, argv[app])) {
3003                                 /* Maximum number of characters added by terminal coloring is 22 */
3004                                 char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
3005                                 char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
3006                                 int synopsis_size, description_size;
3007
3008                                 no_registered_app = 0;
3009
3010                                 if (a->synopsis)
3011                                         synopsis_size = strlen(a->synopsis) + 23;
3012                                 else
3013                                         synopsis_size = strlen("Not available") + 23;
3014                                 synopsis = alloca(synopsis_size);
3015
3016                                 if (a->description)
3017                                         description_size = strlen(a->description) + 23;
3018                                 else
3019                                         description_size = strlen("Not available") + 23;
3020                                 description = alloca(description_size);
3021
3022                                 if (synopsis && description) {
3023                                         snprintf(info, 64 + AST_MAX_APP, "\n  -= Info about application '%s' =- \n\n", a->name);
3024                                         term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
3025                                         term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
3026                                         term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
3027                                         term_color(synopsis,
3028                                                                         a->synopsis ? a->synopsis : "Not available",
3029                                                                         COLOR_CYAN, 0, synopsis_size);
3030                                         term_color(description,
3031                                                                         a->description ? a->description : "Not available",
3032                                                                         COLOR_CYAN, 0, description_size);
3033
3034                                         ast_cli(fd,"%s%s%s\n\n%s%s\n", infotitle, syntitle, synopsis, destitle, description);
3035                                 } else {
3036                                         /* ... one of our applications, show info ...*/
3037                                         ast_cli(fd,"\n  -= Info about application '%s' =- \n\n"
3038                                                 "[Synopsis]\n  %s\n\n"
3039                                                 "[Description]\n%s\n",
3040                                                 a->name,
3041                                                 a->synopsis ? a->synopsis : "Not available",
3042                                                 a->description ? a->description : "Not available");
3043                                 }
3044                         }
3045                 }
3046                 a = a->next; 
3047         }
3048
3049         ast_mutex_unlock(&applock);
3050
3051         /* we found at least one app? no? */
3052         if (no_registered_app) {
3053                 ast_cli(fd, "Your application(s) is (are) not registered\n");
3054                 return RESULT_FAILURE;
3055         }
3056
3057         return RESULT_SUCCESS;
3058 }
3059
3060 /*--- handle_show_hints: CLI support for listing registred dial plan hints */
3061 static int handle_show_hints(int fd, int argc, char *argv[])
3062 {
3063         struct ast_hint *hint;
3064         int num = 0;
3065
3066         if (!hints) {
3067                 ast_cli(fd, "There are no registered dialplan hints\n");
3068                 return RESULT_SUCCESS;
3069         }
3070         /* ... we have hints ... */
3071         ast_cli(fd, "\n    -= Registered Asterisk Dial Plan Hints =-\n");
3072         if (ast_mutex_lock(&hintlock)) {
3073                 ast_log(LOG_ERROR, "Unable to lock hints\n");
3074                 return -1;
3075         }
3076         hint = hints;
3077         while (hint) {
3078                 ast_cli(fd, "   %-20.20s: %-20.20s  State %2d\n", ast_get_extension_name(hint->exten), ast_get_extension_app(hint->exten), hint->laststate );
3079                 num++;
3080                 hint = hint->next;
3081         }
3082         ast_cli(fd, "----------------\n");
3083         ast_cli(fd, "- %d hints registred\n", num);
3084         ast_mutex_unlock(&hintlock);
3085         return RESULT_SUCCESS;
3086 }
3087
3088 /*--- handle_show_switches: CLI support for listing registred dial plan switches */
3089 static int handle_show_switches(int fd, int argc, char *argv[])
3090 {
3091         struct ast_switch *sw;
3092         if (!switches) {
3093                 ast_cli(fd, "There are no registered alternative switches\n");
3094                 return RESULT_SUCCESS;
3095         }
3096         /* ... we have applications ... */
3097         ast_cli(fd, "\n    -= Registered Asterisk Alternative Switches =-\n");
3098         if (ast_mutex_lock(&switchlock)) {
3099                 ast_log(LOG_ERROR, "Unable to lock switches\n");
3100                 return -1;
3101         }
3102         sw = switches;
3103         while (sw) {
3104                 ast_cli(fd, "%s: %s\n", sw->name, sw->description);
3105                 sw = sw->next;
3106         }
3107         ast_mutex_unlock(&switchlock);
3108         return RESULT_SUCCESS;
3109 }
3110
3111 /*
3112  * 'show applications' CLI command implementation functions ...
3113  */
3114 static int handle_show_applications(int fd, int argc, char *argv[])
3115 {
3116         struct ast_app *a;
3117         int like=0, describing=0;
3118         int total_match = 0;    /* Number of matches in like clause */
3119         int total_apps = 0;     /* Number of apps registered */
3120         
3121         /* try to lock applications list ... */
3122         if (ast_mutex_lock(&applock)) {
3123                 ast_log(LOG_ERROR, "Unable to lock application list\n");
3124                 return -1;
3125         }
3126
3127         /* ... have we got at least one application (first)? no? */
3128         if (!apps) {
3129                 ast_cli(fd, "There are no registered applications\n");
3130                 ast_mutex_unlock(&applock);
3131                 return -1;
3132         }
3133
3134         /* show applications like <keyword> */
3135         if ((argc == 4) && (!strcmp(argv[2], "like"))) {
3136                 like = 1;
3137         } else if ((argc > 3) && (!strcmp(argv[2], "describing"))) {
3138                 describing = 1;
3139         }
3140
3141         /* show applications describing <keyword1> [<keyword2>] [...] */
3142         if ((!like) && (!describing)) {
3143                 ast_cli(fd, "    -= Registered Asterisk Applications =-\n");
3144         } else {
3145                 ast_cli(fd, "    -= Matching Asterisk Applications =-\n");
3146         }
3147
3148         /* ... go through all applications ... */
3149         for (a = apps; a; a = a->next) {
3150                 /* ... show informations about applications ... */
3151                 int printapp=0;
3152                 total_apps++;
3153                 if (like) {
3154                         if (ast_strcasestr(a->name, argv[3])) {
3155                                 printapp = 1;
3156                                 total_match++;
3157                         }
3158                 } else if (describing) {
3159                         if (a->description) {
3160                                 /* Match all words on command line */
3161                                 int i;
3162                                 printapp = 1;
3163                                 for (i=3;i<argc;i++) {
3164                                         if (! ast_strcasestr(a->description, argv[i])) {
3165                                                 printapp = 0;
3166                                         } else {
3167                                                 total_match++;
3168                                         }
3169                                 }
3170                         }
3171                 } else {
3172                         printapp = 1;
3173                 }
3174
3175                 if (printapp) {
3176                         ast_cli(fd,"  %20s: %s\n", a->name, a->synopsis ? a->synopsis : "<Synopsis not available>");
3177                 }
3178         }
3179         if ((!like) && (!describing)) {
3180                 ast_cli(fd, "    -= %d Applications Registered =-\n",total_apps);
3181         } else {
3182                 ast_cli(fd, "    -= %d Applications Matching =-\n",total_match);
3183         }
3184         
3185         /* ... unlock and return */
3186         ast_mutex_unlock(&applock);
3187
3188         return RESULT_SUCCESS;
3189 }
3190
3191 static char *complete_show_applications(char *line, char *word, int pos, int state)
3192 {
3193         if (pos == 2) {
3194                 if (ast_strlen_zero(word)) {
3195                         switch (state) {
3196                         case 0:
3197                                 return strdup("like");
3198                         case 1:
3199                                 return strdup("describing");
3200                         default:
3201                                 return NULL;
3202                         }
3203                 } else if (! strncasecmp(word, "like", strlen(word))) {
3204                         if (state == 0) {
3205                                 return strdup("like");
3206                         } else {
3207                                 return NULL;
3208                         }
3209                 } else if (! strncasecmp(word, "describing", strlen(word))) {
3210                         if (state == 0) {
3211                                 return strdup("describing");
3212                         } else {
3213                                 return NULL;
3214                         }
3215                 }
3216         }
3217         return NULL;
3218 }
3219
3220 /*
3221  * 'show dialplan' CLI command implementation functions ...
3222  */
3223 static char *complete_show_dialplan_context(char *line, char *word, int pos,
3224         int state)
3225 {
3226         struct ast_context *c;
3227         int which = 0;
3228
3229         /* we are do completion of [exten@]context on second position only */
3230         if (pos != 2) return NULL;
3231
3232         /* try to lock contexts list ... */
3233         if (ast_lock_contexts()) {
3234                 ast_log(LOG_ERROR, "Unable to lock context list\n");
3235                 return NULL;
3236         }
3237
3238         /* ... walk through all contexts ... */
3239         c = ast_walk_contexts(NULL);
3240         while(c) {
3241                 /* ... word matches context name? yes? ... */
3242                 if (!strncasecmp(word, ast_get_context_name(c), strlen(word))) {
3243                         /* ... for serve? ... */
3244                         if (++which > state) {
3245                                 /* ... yes, serve this context name ... */
3246                                 char *ret = strdup(ast_get_context_name(c));
3247                                 ast_unlock_contexts();
3248                                 return ret;
3249                         }
3250                 }
3251                 c = ast_walk_contexts(c);
3252         }
3253
3254         /* ... unlock and return */
3255         ast_unlock_contexts();
3256         return NULL;
3257 }
3258
3259 struct dialplan_counters {
3260         int total_context;
3261         int total_exten;
3262         int total_prio;
3263         int context_existence;
3264         int extension_existence;
3265 };
3266
3267 static int show_dialplan_helper(int fd, char *context, char *exten, struct dialplan_counters *dpc, struct ast_include *rinclude)
3268 {
3269         struct ast_context *c;
3270         int res=0, old_total_exten = dpc->total_exten;
3271
3272         /* try to lock contexts */
3273         if (ast_lock_contexts()) {
3274                 ast_log(LOG_WARNING, "Failed to lock contexts list\n");
3275                 return -1;
3276         }
3277
3278         /* walk all contexts ... */
3279         for (c = ast_walk_contexts(NULL); c ; c = ast_walk_contexts(c)) {
3280                 /* show this context? */
3281                 if (!context ||
3282                         !strcmp(ast_get_context_name(c), context)) {
3283                         dpc->context_existence = 1;
3284
3285                         /* try to lock context before walking in ... */
3286                         if (!ast_lock_context(c)) {
3287                                 struct ast_exten *e;
3288                                 struct ast_include *i;
3289                                 struct ast_ignorepat *ip;
3290                                 struct ast_sw *sw;
3291                                 char buf[256], buf2[256];
3292                                 int context_info_printed = 0;
3293
3294                                 /* are we looking for exten too? if yes, we print context
3295                                  * if we our extension only
3296                                  */
3297                                 if (!exten) {
3298                                         dpc->total_context++;
3299                                         ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
3300                                                 ast_get_context_name(c), ast_get_context_registrar(c));
3301                                         context_info_printed = 1;
3302                                 }
3303
3304                                 /* walk extensions ... */
3305                                 for (e = ast_walk_context_extensions(c, NULL); e; e = ast_walk_context_extensions(c, e)) {
3306                                         struct ast_exten *p;
3307                                         int prio;
3308
3309                                         /* looking for extension? is this our extension? */
3310                                         if (exten &&
3311                                                 !ast_extension_match(ast_get_extension_name(e), exten))
3312                                         {
3313                                                 /* we are looking for extension and it's not our
3314                                                  * extension, so skip to next extension */
3315                                                 continue;
3316                                         }
3317
3318                                         dpc->extension_existence = 1;
3319
3320                                         /* may we print context info? */        
3321                                         if (!context_info_printed) {
3322                                                 dpc->total_context++;
3323                                                 if (rinclude) {
3324                                                         /* TODO Print more info about rinclude */
3325                                                         ast_cli(fd, "[ Included context '%s' created by '%s' ]\n",
3326                                                                 ast_get_context_name(c),
3327                                                                 ast_get_context_registrar(c));
3328                                                 } else {
3329                                                         ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
3330                                                                 ast_get_context_name(c),
3331                                                                 ast_get_context_registrar(c));
3332                                                 }
3333                                                 context_info_printed = 1;
3334                                         }
3335                                         dpc->total_prio++;
3336
3337                                         /* write extension name and first peer */       
3338                                         bzero(buf, sizeof(buf));                
3339                                         snprintf(buf, sizeof(buf), "'%s' =>",
3340                                                 ast_get_extension_name(e));
3341
3342                                         prio = ast_get_extension_priority(e);
3343                                         if (prio == PRIORITY_HINT) {
3344                                                 snprintf(buf2, sizeof(buf2),
3345                                                         "hint: %s",
3346                                                         ast_get_extension_app(e));
3347                                         } else {
3348                                                 snprintf(buf2, sizeof(buf2),
3349                                                         "%d. %s(%s)",
3350                                                         prio,
3351                                                         ast_get_extension_app(e),
3352                                                         (char *)ast_get_extension_app_data(e));
3353                                         }
3354
3355                                         ast_cli(fd, "  %-17s %-45s [%s]\n", buf, buf2,
3356                                                 ast_get_extension_registrar(e));
3357
3358                                         dpc->total_exten++;
3359                                         /* walk next extension peers */
3360                                         for (p=ast_walk_extension_priorities(e, e); p; p=ast_walk_extension_priorities(e, p)) {
3361                                                 dpc->total_prio++;
3362                                                 bzero((void *)buf2, sizeof(buf2));
3363                                                 bzero((void *)buf, sizeof(buf));
3364                                                 if (ast_get_extension_label(p))
3365                                                         snprintf(buf, sizeof(buf), "   [%s]", ast_get_extension_label(p));
3366                                                 prio = ast_get_extension_priority(p);
3367                                                 if (prio == PRIORITY_HINT) {
3368                                                         snprintf(buf2, sizeof(buf2),
3369                                                                 "hint: %s",
3370                                                                 ast_get_extension_app(p));
3371                                                 } else {
3372                                                         snprintf(buf2, sizeof(buf2),
3373                                                                 "%d. %s(%s)",
3374                                                                 prio,
3375                                                                 ast_get_extension_app(p),
3376                                                                 (char *)ast_get_extension_app_data(p));
3377                                                 }
3378
3379                                                 ast_cli(fd,"  %-17s %-45s [%s]\n",
3380                                                         buf, buf2,
3381                                                         ast_get_extension_registrar(p));
3382                                         }
3383                                 }
3384
3385                                 /* walk included and write info ... */
3386                                 for (i = ast_walk_context_includes(c, NULL); i; i = ast_walk_context_includes(c, i)) {
3387                                         bzero(buf, sizeof(buf));
3388                                         snprintf(buf, sizeof(buf), "'%s'",
3389                                                 ast_get_include_name(i));
3390                                         if (exten) {
3391                                                 /* Check all includes for the requested extension */
3392                                                 show_dialplan_helper(fd, (char *)ast_get_include_name(i), exten, dpc, i);
3393                                         } else {
3394                                                 ast_cli(fd, "  Include =>        %-45s [%s]\n",
3395                                                         buf, ast_get_include_registrar(i));
3396                                         }
3397                                 }
3398
3399                                 /* walk ignore patterns and write info ... */
3400                                 for (ip=ast_walk_context_ignorepats(c, NULL); ip; ip=ast_walk_context_ignorepats(c, ip)) {
3401                                         const char *ipname = ast_get_ignorepat_name(ip);
3402                                         char ignorepat[AST_MAX_EXTENSION];