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