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