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