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