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