Update chanelog
[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, 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         tmp = contexts;
748         while(tmp) {
749                 /* Match context */
750                 if (!strcmp(tmp->name, context)) {
751                         if (*status < STATUS_NO_EXTENSION)
752                                 *status = STATUS_NO_EXTENSION;
753                         eroot = tmp->root;
754                         while(eroot) {
755                                 /* Match extension */
756                                 if ((((action != HELPER_MATCHMORE) && ast_extension_match(eroot->exten, exten)) ||
757                                                 ((action == HELPER_CANMATCH) && (extension_close(eroot->exten, exten, 0))) ||
758                                                 ((action == HELPER_MATCHMORE) && (extension_close(eroot->exten, exten, 1)))) &&
759                                                 (!eroot->matchcid || matchcid(eroot->cidmatch, callerid))) {
760                                                 e = eroot;
761                                                 if (*status < STATUS_NO_PRIORITY)
762                                                         *status = STATUS_NO_PRIORITY;
763                                                 while(e) {
764                                                         /* Match priority */
765                                                         if (action == HELPER_FINDLABEL) {
766                                                                 if (*status < STATUS_NO_LABEL)
767                                                                         *status = STATUS_NO_LABEL;
768                                                                 if (label && e->label && !strcmp(label, e->label)) {
769                                                                         *status = STATUS_SUCCESS;
770                                                                         return e;
771                                                                 }
772                                                         } else if (e->priority == priority) {
773                                                                 *status = STATUS_SUCCESS;
774                                                                 return e;
775                                                         }
776                                                         e = e->peer;
777                                                 }
778                                 }
779                                 eroot = eroot->next;
780                         }
781                         /* Check alternative switches */
782                         sw = tmp->alts;
783                         while(sw) {
784                                 if ((asw = pbx_findswitch(sw->name))) {
785                                         if (action == HELPER_CANMATCH)
786                                                 res = asw->canmatch ? asw->canmatch(chan, context, exten, priority, callerid, sw->data) : 0;
787                                         else if (action == HELPER_MATCHMORE)
788                                                 res = asw->matchmore ? asw->matchmore(chan, context, exten, priority, callerid, sw->data) : 0;
789                                         else
790                                                 res = asw->exists ? asw->exists(chan, context, exten, priority, callerid, sw->data) : 0;
791                                         if (res) {
792                                                 /* Got a match */
793                                                 *swo = asw;
794                                                 *data = sw->data;
795                                                 return NULL;
796                                         }
797                                 } else {
798                                         ast_log(LOG_WARNING, "No such switch '%s'\n", sw->name);
799                                 }
800                                 sw = sw->next;
801                         }
802                         /* Setup the stack */
803                         incstack[*stacklen] = tmp->name;
804                         (*stacklen)++;
805                         /* Now try any includes we have in this context */
806                         i = tmp->includes;
807                         while(i) {
808                                 if (include_valid(i)) {
809                                         if ((e = pbx_find_extension(chan, i->rname, exten, priority, label, callerid, action, incstack, stacklen, status, swo, data))) 
810                                                 return e;
811                                         if (*swo) 
812                                                 return NULL;
813                                 }
814                                 i = i->next;
815                         }
816                 }
817                 tmp = tmp->next;
818         }
819         return NULL;
820 }
821
822 static void pbx_substitute_variables_temp(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen)
823 {
824         char *first,*second;
825         char tmpvar[80] = "";
826         time_t thistime;
827         struct tm brokentime;
828         int offset,offset2;
829         struct ast_var_t *variables;
830         struct varshead *headp=NULL;
831
832         if (c) 
833                 headp=&c->varshead;
834         *ret=NULL;
835         /* Now we have the variable name on cp3 */
836         if (!strncasecmp(var,"LEN(",4)) {
837                 int len=strlen(var);
838                 int len_len=4;
839                 if (strrchr(var,')')) {
840                         char cp3[80];
841                         strncpy(cp3, var, sizeof(cp3) - 1);
842                         cp3[len-len_len-1]='\0';
843                         sprintf(workspace,"%d",(int)strlen(cp3));
844                         *ret = workspace;
845                 } else {
846                         /* length is zero */
847                         *ret = "0";
848                 }
849         } else if ((first=strchr(var,':'))) {
850                 strncpy(tmpvar, var, sizeof(tmpvar) - 1);
851                 first = strchr(tmpvar, ':');
852                 if (!first)
853                         first = tmpvar + strlen(tmpvar);
854                 *first='\0';
855                 pbx_substitute_variables_temp(c,tmpvar,ret,workspace,workspacelen - 1);
856                 if (!(*ret)) return;
857                 offset=atoi(first+1);
858                 if ((second=strchr(first+1,':'))) {
859                         *second='\0';
860                         offset2=atoi(second+1);
861                 } else
862                         offset2=strlen(*ret)-offset;
863                 if (abs(offset)>strlen(*ret)) {
864                         if (offset>=0) 
865                                 offset=strlen(*ret);
866                         else 
867                                 offset=-strlen(*ret);
868                 }
869                 if ((offset<0 && offset2>-offset) || (offset>=0 && offset+offset2>strlen(*ret))) {
870                         if (offset>=0) 
871                                 offset2=strlen(*ret)-offset;
872                         else 
873                                 offset2=strlen(*ret)+offset;
874                 }
875                 if (offset>=0)
876                         *ret+=offset;
877                 else
878                         *ret+=strlen(*ret)+offset;
879                 (*ret)[offset2] = '\0';
880         } else if (c && !strcmp(var, "CALLERIDNUM")) {
881                 if (c->cid.cid_num) {
882                         strncpy(workspace, c->cid.cid_num, workspacelen - 1);
883                         *ret = workspace;
884                 } else
885                         *ret = NULL;
886         } else if (c && !strcmp(var, "CALLERANI")) {
887                 if (c->cid.cid_ani) {
888                         strncpy(workspace, c->cid.cid_ani, workspacelen - 1);
889                         *ret = workspace;
890                 } else
891                         *ret = NULL;
892         } else if (c && !strcmp(var, "CALLERIDNAME")) {
893                 if (c->cid.cid_name) {
894                         strncpy(workspace, c->cid.cid_name, workspacelen - 1);
895                         *ret = workspace;
896                 } else
897                         *ret = NULL;
898         } else if (c && !strcmp(var, "CALLERID")) {
899                 if (c->cid.cid_num) {
900                         if (c->cid.cid_name) {
901                                 snprintf(workspace, workspacelen, "\"%s\" <%s>", c->cid.cid_name, c->cid.cid_num);
902                         } else {
903                                 strncpy(workspace, c->cid.cid_num, workspacelen - 1);
904                         }
905                         *ret = workspace;
906                 } else if (c->cid.cid_name) {
907                         strncpy(workspace, c->cid.cid_name, workspacelen - 1);
908                         *ret = workspace;
909                 } else
910                         *ret = NULL;
911         } else if (c && !strcmp(var, "DNID")) {
912                 if (c->cid.cid_dnid) {
913                         strncpy(workspace, c->cid.cid_dnid, workspacelen - 1);
914                         *ret = workspace;
915                 } else
916                         *ret = NULL;
917         } else if (c && !strcmp(var, "HINT")) {
918                 if (!ast_get_hint(workspace, workspacelen, c, c->context, c->exten))
919                         *ret = NULL;
920                 else
921                         *ret = workspace;
922         } else if (c && !strcmp(var, "EXTEN")) {
923                 strncpy(workspace, c->exten, workspacelen - 1);
924                 *ret = workspace;
925         } else if (c && !strncmp(var, "EXTEN-", strlen("EXTEN-")) && 
926                 /* XXX Remove me eventually */
927                 (sscanf(var + strlen("EXTEN-"), "%d", &offset) == 1)) {
928                 if (offset < 0)
929                         offset=0;
930                 if (offset > strlen(c->exten))
931                         offset = strlen(c->exten);
932                 strncpy(workspace, c->exten + offset, workspacelen - 1);
933                 *ret = workspace;
934                 ast_log(LOG_WARNING, "The use of 'EXTEN-foo' has been deprecated in favor of 'EXTEN:foo'\n");
935         } else if (c && !strcmp(var, "RDNIS")) {
936                 if (c->cid.cid_rdnis) {
937                         strncpy(workspace, c->cid.cid_rdnis, workspacelen - 1);
938                         *ret = workspace;
939                 } else
940                         *ret = NULL;
941         } else if (c && !strcmp(var, "CONTEXT")) {
942                 strncpy(workspace, c->context, workspacelen - 1);
943                 *ret = workspace;
944         } else if (c && !strcmp(var, "PRIORITY")) {
945                 snprintf(workspace, workspacelen, "%d", c->priority);
946                 *ret = workspace;
947         } else if (c && !strcmp(var, "CALLINGPRES")) {
948                 snprintf(workspace, workspacelen, "%d", c->cid.cid_pres);
949                 *ret = workspace;
950         } else if (c && !strcmp(var, "CALLINGANI2")) {
951                 snprintf(workspace, workspacelen, "%d", c->cid.cid_ani2);
952                 *ret = workspace;
953         } else if (c && !strcmp(var, "CALLINGTON")) {
954                 snprintf(workspace, workspacelen, "%d", c->cid.cid_ton);
955                 *ret = workspace;
956         } else if (c && !strcmp(var, "CALLINGTNS")) {
957                 snprintf(workspace, workspacelen, "%d", c->cid.cid_tns);
958                 *ret = workspace;
959         } else if (c && !strcmp(var, "CHANNEL")) {
960                 strncpy(workspace, c->name, workspacelen - 1);
961                 *ret = workspace;
962         } else if (c && !strcmp(var, "EPOCH")) {
963                 snprintf(workspace, workspacelen, "%u",(int)time(NULL));
964                 *ret = workspace;
965         } else if (c && !strcmp(var, "DATETIME")) {
966                 thistime=time(NULL);
967                 localtime_r(&thistime, &brokentime);
968                 snprintf(workspace, workspacelen, "%02d%02d%04d-%02d:%02d:%02d",
969                         brokentime.tm_mday,
970                         brokentime.tm_mon+1,
971                         brokentime.tm_year+1900,
972                         brokentime.tm_hour,
973                         brokentime.tm_min,
974                         brokentime.tm_sec
975                 );
976                 *ret = workspace;
977         } else if (c && !strcmp(var, "TIMESTAMP")) {
978                 thistime=time(NULL);
979                 localtime_r(&thistime, &brokentime);
980                 /* 20031130-150612 */
981                 snprintf(workspace, workspacelen, "%04d%02d%02d-%02d%02d%02d",
982                         brokentime.tm_year+1900,
983                         brokentime.tm_mon+1,
984                         brokentime.tm_mday,
985                         brokentime.tm_hour,
986                         brokentime.tm_min,
987                         brokentime.tm_sec
988                 );
989                 *ret = workspace;
990         } else if (c && !strcmp(var, "UNIQUEID")) {
991                 snprintf(workspace, workspacelen, "%s", c->uniqueid);
992                 *ret = workspace;
993         } else if (c && !strcmp(var, "HANGUPCAUSE")) {
994                 snprintf(workspace, workspacelen, "%i", c->hangupcause);
995                 *ret = workspace;
996         } else if (c && !strcmp(var, "ACCOUNTCODE")) {
997                 strncpy(workspace, c->accountcode, workspacelen - 1);
998                 *ret = workspace;
999         } else if (c && !strcmp(var, "LANGUAGE")) {
1000                 strncpy(workspace, c->language, workspacelen - 1);
1001                 *ret = workspace;
1002         } else {
1003                 if (c) {
1004                         AST_LIST_TRAVERSE(headp,variables,entries) {
1005 #if 0
1006                                 ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",var,ast_var_name(variables));
1007 #endif
1008                                 if (strcasecmp(ast_var_name(variables),var)==0) {
1009                                         *ret=ast_var_value(variables);
1010                                         if (*ret) {
1011                                                 strncpy(workspace, *ret, workspacelen - 1);
1012                                                 *ret = workspace;
1013                                         }
1014                                         break;
1015                                 }
1016                         }
1017                 }
1018                 if (!(*ret)) {
1019                         /* Try globals */
1020                         AST_LIST_TRAVERSE(&globals,variables,entries) {
1021 #if 0
1022                                 ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",var,ast_var_name(variables));
1023 #endif
1024                                 if (strcasecmp(ast_var_name(variables),var)==0) {
1025                                         *ret=ast_var_value(variables);
1026                                         if (*ret) {
1027                                                 strncpy(workspace, *ret, workspacelen - 1);
1028                                                 *ret = workspace;
1029                                         }
1030                                 }
1031                         }
1032                 }
1033                 if (!(*ret)) {
1034                         int len=strlen(var);
1035                         int len_env=strlen("ENV(");
1036                         if (len > (len_env+1) && !strncasecmp(var,"ENV(",len_env) && !strcmp(var+len-1,")")) {
1037                                 char cp3[80] = "";
1038                                 strncpy(cp3, var, sizeof(cp3) - 1);
1039                                 cp3[len-1]='\0';
1040                                 *ret=getenv(cp3+len_env);
1041                                 if (*ret) {
1042                                         strncpy(workspace, *ret, workspacelen - 1);
1043                                         *ret = workspace;
1044                                 }
1045                         }
1046                 }
1047         }
1048 }
1049
1050 void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
1051 {
1052         char *cp4;
1053         const char *tmp, *whereweare;
1054         int length;
1055         char workspace[4096];
1056         char ltmp[4096], var[4096];
1057         char *nextvar, *nextexp;
1058         char *vars, *vare;
1059         int pos, brackets, needsub, len;
1060         
1061         /* Substitutes variables into cp2, based on string cp1, and assuming cp2 to be
1062            zero-filled */
1063         whereweare=tmp=cp1;
1064         while(!ast_strlen_zero(whereweare) && count) {
1065                 /* Assume we're copying the whole remaining string */
1066                 pos = strlen(whereweare);
1067
1068                 /* Look for a variable */
1069                 nextvar = strstr(whereweare, "${");
1070                 
1071                 /* Look for an expression */
1072                 nextexp = strstr(whereweare, "$[");
1073                 
1074                 /* Pick the first one only */
1075                 if (nextvar && nextexp) {
1076                         if (nextvar < nextexp)
1077                                 nextexp = NULL;
1078                         else
1079                                 nextvar = NULL;
1080                 }
1081                 
1082                 /* If there is one, we only go that far */
1083                 if (nextvar)
1084                         pos = nextvar - whereweare;
1085                 else if (nextexp)
1086                         pos = nextexp - whereweare;
1087                 
1088                 /* Can't copy more than 'count' bytes */
1089                 if (pos > count)
1090                         pos = count;
1091                 
1092                 /* Copy that many bytes */
1093                 memcpy(cp2, whereweare, pos);
1094                 
1095                 count -= pos;
1096                 cp2 += pos;
1097                 whereweare += pos;
1098                 
1099                 if (nextvar) {
1100                         /* We have a variable.  Find the start and end, and determine
1101                            if we are going to have to recursively call ourselves on the
1102                            contents */
1103                         vars = vare = nextvar + 2;
1104                         brackets = 1;
1105                         needsub = 0;
1106                         
1107                         /* Find the end of it */
1108                         while(brackets && *vare) {
1109                                 if ((vare[0] == '$') && (vare[1] == '{')) {
1110                                         needsub++;
1111                                         brackets++;
1112                                 } else if (vare[0] == '}') {
1113                                         brackets--;
1114                                 } else if ((vare[0] == '$') && (vare[1] == '['))
1115                                         needsub++;
1116                                 vare++;
1117                         }
1118                         if (brackets)
1119                                 ast_log(LOG_NOTICE, "Error in extension logic (missing '}')\n");
1120                         len = vare - vars - 1;
1121                         
1122                         /* Skip totally over variable name */
1123                         whereweare += ( len + 3);
1124                         
1125                         /* Store variable name (and truncate) */
1126                         memset(var, 0, sizeof(var));
1127                         strncpy(var, vars, sizeof(var) - 1);
1128                         var[len] = '\0';
1129                         
1130                         /* Substitute if necessary */
1131                         if (needsub) {
1132                                 memset(ltmp, 0, sizeof(ltmp));
1133                                 pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1);
1134                                 vars = ltmp;
1135                         } else {
1136                                 vars = var;
1137                         }
1138                         
1139                         /* Retrieve variable value */
1140                         workspace[0] = '\0';
1141                         pbx_substitute_variables_temp(c,vars,&cp4, workspace, sizeof(workspace));
1142                         if (cp4) {
1143                                 length = strlen(cp4);
1144                                 if (length > count)
1145                                         length = count;
1146                                 memcpy(cp2, cp4, length);
1147                                 count -= length;
1148                                 cp2 += length;
1149                         }
1150                         
1151                 } else if (nextexp) {
1152                         /* We have an expression.  Find the start and end, and determine
1153                            if we are going to have to recursively call ourselves on the
1154                            contents */
1155                         vars = vare = nextexp + 2;
1156                         brackets = 1;
1157                         needsub = 0;
1158                         
1159                         /* Find the end of it */
1160                         while(brackets && *vare) {
1161                                 if ((vare[0] == '$') && (vare[1] == '[')) {
1162                                         needsub++;
1163                                         brackets++;
1164                                         vare++;
1165                                 } else if (vare[0] == '[') {
1166                                         brackets++;
1167                                 } else if (vare[0] == ']') {
1168                                         brackets--;
1169                                 } else if ((vare[0] == '$') && (vare[1] == '{')) {
1170                                         needsub++;
1171                                         vare++;
1172                                 }
1173                                 vare++;
1174                         }
1175                         if (brackets)
1176                                 ast_log(LOG_NOTICE, "Error in extension logic (missing ']')\n");
1177                         len = vare - vars - 1;
1178                         
1179                         /* Skip totally over variable name */
1180                         whereweare += ( len + 3);
1181                         
1182                         /* Store variable name (and truncate) */
1183                         memset(var, 0, sizeof(var));
1184                         strncpy(var, vars, sizeof(var) - 1);
1185                         var[len] = '\0';
1186                         
1187                         /* Substitute if necessary */
1188                         if (needsub) {
1189                                 memset(ltmp, 0, sizeof(ltmp));
1190                                 pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1);
1191                                 vars = ltmp;
1192                         } else {
1193                                 vars = var;
1194                         }
1195
1196                         /* Evaluate expression */                       
1197                         cp4 = ast_expr(vars);
1198                         
1199                         ast_log(LOG_DEBUG, "Expression is '%s'\n", cp4);
1200                         
1201                         if (cp4) {
1202                                 length = strlen(cp4);
1203                                 if (length > count)
1204                                         length = count;
1205                                 memcpy(cp2, cp4, length);
1206                                 count -= length;
1207                                 cp2 += length;
1208                                 free(cp4);
1209                         }
1210                         
1211                 } else
1212                         break;
1213         }
1214 }
1215
1216 static void pbx_substitute_variables(char *passdata, int datalen, struct ast_channel *c, struct ast_exten *e) {
1217         
1218         memset(passdata, 0, datalen);
1219                 
1220         /* No variables or expressions in e->data, so why scan it? */
1221         if (!strstr(e->data,"${") && !strstr(e->data,"$[")) {
1222                 strncpy(passdata, e->data, datalen - 1);
1223                 passdata[datalen-1] = '\0';
1224                 return;
1225         }
1226         
1227         pbx_substitute_variables_helper(c, e->data, passdata, datalen - 1);
1228 }                                                               
1229
1230 static int pbx_extension_helper(struct ast_channel *c, const char *context, const char *exten, int priority, const char *label, const char *callerid, int action) 
1231 {
1232         struct ast_exten *e;
1233         struct ast_app *app;
1234         struct ast_switch *sw;
1235         char *data;
1236         int newstack = 0;
1237         int res;
1238         int status = 0;
1239         char *incstack[AST_PBX_MAX_STACK];
1240         char passdata[EXT_DATA_SIZE];
1241         int stacklen = 0;
1242         char tmp[80];
1243         char tmp2[80];
1244         char tmp3[EXT_DATA_SIZE];
1245
1246         if (ast_mutex_lock(&conlock)) {
1247                 ast_log(LOG_WARNING, "Unable to obtain lock\n");
1248                 if ((action == HELPER_EXISTS) || (action == HELPER_CANMATCH) || (action == HELPER_MATCHMORE))
1249                         return 0;
1250                 else
1251                         return -1;
1252         }
1253         e = pbx_find_extension(c, context, exten, priority, label, callerid, action, incstack, &stacklen, &status, &sw, &data);
1254         if (e) {
1255                 switch(action) {
1256                 case HELPER_CANMATCH:
1257                         ast_mutex_unlock(&conlock);
1258                         return -1;
1259                 case HELPER_EXISTS:
1260                         ast_mutex_unlock(&conlock);
1261                         return -1;
1262                 case HELPER_FINDLABEL:
1263                         res = e->priority;
1264                         ast_mutex_unlock(&conlock);
1265                         return res;
1266                 case HELPER_MATCHMORE:
1267                         ast_mutex_unlock(&conlock);
1268                         return -1;
1269                 case HELPER_SPAWN:
1270                         newstack++;
1271                         /* Fall through */
1272                 case HELPER_EXEC:
1273                         app = pbx_findapp(e->app);
1274                         ast_mutex_unlock(&conlock);
1275                         if (app) {
1276                                 if (c->context != context)
1277                                         strncpy(c->context, context, sizeof(c->context)-1);
1278                                 if (c->exten != exten)
1279                                         strncpy(c->exten, exten, sizeof(c->exten)-1);
1280                                 c->priority = priority;
1281                                 pbx_substitute_variables(passdata, sizeof(passdata), c, e);
1282                                 if (option_debug)
1283                                                 ast_log(LOG_DEBUG, "Launching '%s'\n", app->name);
1284                                 else if (option_verbose > 2)
1285                                                 ast_verbose( VERBOSE_PREFIX_3 "Executing %s(\"%s\", \"%s\") %s\n", 
1286                                                                 term_color(tmp, app->name, COLOR_BRCYAN, 0, sizeof(tmp)),
1287                                                                 term_color(tmp2, c->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
1288                                                                 term_color(tmp3, (!ast_strlen_zero(passdata) ? (char *)passdata : ""), COLOR_BRMAGENTA, 0, sizeof(tmp3)),
1289                                                                 (newstack ? "in new stack" : "in same stack"));
1290                                 manager_event(EVENT_FLAG_CALL, "Newexten", 
1291                                         "Channel: %s\r\n"
1292                                         "Context: %s\r\n"
1293                                         "Extension: %s\r\n"
1294                                         "Priority: %d\r\n"
1295                                         "Application: %s\r\n"
1296                                         "AppData: %s\r\n"
1297                                         "Uniqueid: %s\r\n",
1298                                         c->name, c->context, c->exten, c->priority, app->name, passdata ? passdata : "(NULL)", c->uniqueid);
1299                                 res = pbx_exec(c, app, passdata, newstack);
1300                                 return res;
1301                         } else {
1302                                 ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
1303                                 return -1;
1304                         }
1305                 default:
1306                         ast_log(LOG_WARNING, "Huh (%d)?\n", action);                    return -1;
1307                 }
1308         } else if (sw) {
1309                 switch(action) {
1310                 case HELPER_CANMATCH:
1311                         ast_mutex_unlock(&conlock);
1312                         return -1;
1313                 case HELPER_EXISTS:
1314                         ast_mutex_unlock(&conlock);
1315                         return -1;
1316                 case HELPER_MATCHMORE:
1317                         ast_mutex_unlock(&conlock);
1318                         return -1;
1319                 case HELPER_FINDLABEL:
1320                         ast_mutex_unlock(&conlock);
1321                         return -1;
1322                 case HELPER_SPAWN:
1323                         newstack++;
1324                         /* Fall through */
1325                 case HELPER_EXEC:
1326                         ast_mutex_unlock(&conlock);
1327                         if (sw->exec)
1328                                 res = sw->exec(c, context, exten, priority, callerid, newstack, data);
1329                         else {
1330                                 ast_log(LOG_WARNING, "No execution engine for switch %s\n", sw->name);
1331                                 res = -1;
1332                         }
1333                         return res;
1334                 default:
1335                         ast_log(LOG_WARNING, "Huh (%d)?\n", action);
1336                         return -1;
1337                 }
1338         } else {
1339                 ast_mutex_unlock(&conlock);
1340                 switch(status) {
1341                 case STATUS_NO_CONTEXT:
1342                         if ((action != HELPER_EXISTS) && (action != HELPER_MATCHMORE))
1343                                 ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", context);
1344                         break;
1345                 case STATUS_NO_EXTENSION:
1346                         if ((action != HELPER_EXISTS) && (action !=  HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1347                                 ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, context);
1348                         break;
1349                 case STATUS_NO_PRIORITY:
1350                         if ((action != HELPER_EXISTS) && (action !=  HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1351                                 ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, context);
1352                         break;
1353                 case STATUS_NO_LABEL:
1354                         ast_log(LOG_NOTICE, "No such label '%s' in extension '%s' in context '%s'\n", label, exten, context);
1355                         break;
1356                 default:
1357                         ast_log(LOG_DEBUG, "Shouldn't happen!\n");
1358                 }
1359                 
1360                 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1361                         return -1;
1362                 else
1363                         return 0;
1364         }
1365
1366 }
1367
1368 static struct ast_exten *ast_hint_extension(struct ast_channel *c, const char *context, const char *exten)
1369 {
1370         struct ast_exten *e;
1371         struct ast_switch *sw;
1372         char *data;
1373         int status = 0;
1374         char *incstack[AST_PBX_MAX_STACK];
1375         int stacklen = 0;
1376
1377         if (ast_mutex_lock(&conlock)) {
1378                 ast_log(LOG_WARNING, "Unable to obtain lock\n");
1379                 return NULL;
1380         }
1381         e = pbx_find_extension(c, context, exten, PRIORITY_HINT, NULL, "", HELPER_EXISTS, incstack, &stacklen, &status, &sw, &data);
1382         ast_mutex_unlock(&conlock);     
1383         return e;
1384 }
1385
1386 static int ast_extension_state2(struct ast_exten *e)
1387 {
1388         char hint[AST_MAX_EXTENSION] = "";    
1389         char *cur, *rest;
1390         int res = -1;
1391         int allunavailable = 1, allbusy = 1, allfree = 1;
1392         int busy = 0;
1393
1394         strncpy(hint, ast_get_extension_app(e), sizeof(hint)-1);
1395     
1396         cur = hint;    
1397         do {
1398                 rest = strchr(cur, '&');
1399                 if (rest) {
1400                         *rest = 0;
1401                         rest++;
1402                 }
1403         
1404                 res = ast_device_state(cur);
1405                 switch (res) {
1406                 case AST_DEVICE_NOT_INUSE:
1407                         allunavailable = 0;
1408                         allbusy = 0;
1409                         break;
1410                 case AST_DEVICE_INUSE:
1411                         return AST_EXTENSION_INUSE;
1412                 case AST_DEVICE_BUSY:
1413                         allunavailable = 0;
1414                         allfree = 0;
1415                         busy = 1;
1416                         break;
1417                 case AST_DEVICE_UNAVAILABLE:
1418                 case AST_DEVICE_INVALID:
1419                         allbusy = 0;
1420                         allfree = 0;
1421                         break;
1422                 default:
1423                         allunavailable = 0;
1424                         allbusy = 0;
1425                         allfree = 0;
1426                 }
1427                 cur = rest;
1428         } while (cur);
1429
1430         if (allfree)
1431                 return AST_EXTENSION_NOT_INUSE;
1432         if (allbusy)
1433                 return AST_EXTENSION_BUSY;
1434         if (allunavailable)
1435                 return AST_EXTENSION_UNAVAILABLE;
1436         if (busy) 
1437                 return AST_EXTENSION_INUSE;
1438         
1439         return AST_EXTENSION_NOT_INUSE;
1440 }
1441
1442
1443 int ast_extension_state(struct ast_channel *c, char *context, char *exten)
1444 {
1445         struct ast_exten *e;
1446
1447         e = ast_hint_extension(c, context, exten);    
1448         if (!e) 
1449                 return -1;
1450
1451         return ast_extension_state2(e);    
1452 }
1453
1454 int ast_device_state_changed(const char *fmt, ...) 
1455 {
1456         struct ast_hint *list;
1457         struct ast_state_cb *cblist;
1458         char hint[AST_MAX_EXTENSION] = "";
1459         char device[AST_MAX_EXTENSION];
1460         char *cur, *rest;
1461         int state;
1462
1463         va_list ap;
1464
1465         va_start(ap, fmt);
1466         vsnprintf(device, sizeof(device), fmt, ap);
1467         va_end(ap);
1468
1469         rest = strchr(device, '-');
1470         if (rest) {
1471                 *rest = 0;
1472         }
1473
1474         ast_mutex_lock(&hintlock);
1475
1476         list = hints;
1477
1478         while (list) {
1479
1480                 strncpy(hint, ast_get_extension_app(list->exten), sizeof(hint) - 1);
1481                 cur = hint;
1482                 do {
1483                         rest = strchr(cur, '&');
1484                         if (rest) {
1485                                 *rest = 0;
1486                                 rest++;
1487                         }
1488                         
1489                         if (!strcmp(cur, device)) {
1490                                 /* Found extension execute callbacks  */
1491                                 state = ast_extension_state2(list->exten);
1492                                 if ((state != -1) && (state != list->laststate)) {
1493                                         /* For general callbacks */
1494                                         cblist = statecbs;
1495                                         while (cblist) {
1496                                                 cblist->callback(list->exten->parent->name, list->exten->exten, state, cblist->data);
1497                                                 cblist = cblist->next;
1498                                         }
1499
1500                                         /* For extension callbacks */
1501                                         cblist = list->callbacks;
1502                                         while (cblist) {
1503                                                 cblist->callback(list->exten->parent->name, list->exten->exten, state, cblist->data);
1504                                                 cblist = cblist->next;
1505                                         }
1506                         
1507                                         list->laststate = state;
1508                                 }
1509                                 break;
1510                         }
1511                         cur = rest;
1512                 } while (cur);
1513                 list = list->next;
1514         }
1515         ast_mutex_unlock(&hintlock);
1516         return 1;
1517 }
1518                         
1519 int ast_extension_state_add(const char *context, const char *exten, 
1520                             ast_state_cb_type callback, void *data)
1521 {
1522         struct ast_hint *list;
1523         struct ast_state_cb *cblist;
1524         struct ast_exten *e;
1525
1526         /* No context and extension add callback to statecbs list */
1527         if (!context && !exten) {
1528                 ast_mutex_lock(&hintlock);
1529
1530                 cblist = statecbs;
1531                 while (cblist) {
1532                         if (cblist->callback == callback) {
1533                                 cblist->data = data;
1534                                 ast_mutex_unlock(&hintlock);
1535                         }
1536                         cblist = cblist->next;
1537                 }
1538         
1539                 /* Now inserts the callback */
1540                 cblist = malloc(sizeof(struct ast_state_cb));
1541                 if (!cblist) {
1542                         ast_mutex_unlock(&hintlock);
1543                         return -1;
1544                 }
1545                 memset(cblist, 0, sizeof(struct ast_state_cb));
1546                 cblist->id = 0;
1547                 cblist->callback = callback;
1548                 cblist->data = data;
1549         
1550                 cblist->next = statecbs;
1551                 statecbs = cblist;
1552
1553                 ast_mutex_unlock(&hintlock);
1554                 return 0;
1555         }
1556
1557         if (!context || !exten)
1558                 return -1;
1559
1560         /* This callback type is for only one hint */
1561         e = ast_hint_extension(NULL, context, exten);    
1562         if (!e) {
1563                 return -1;
1564         }
1565     
1566         ast_mutex_lock(&hintlock);
1567         list = hints;        
1568     
1569         while (list) {
1570                 if (list->exten == e)
1571                         break;      
1572                 list = list->next;    
1573         }
1574
1575         if (!list) {
1576                 ast_mutex_unlock(&hintlock);
1577                 return -1;
1578         }
1579
1580         /* Now inserts the callback */
1581         cblist = malloc(sizeof(struct ast_state_cb));
1582         if (!cblist) {
1583                 ast_mutex_unlock(&hintlock);
1584                 return -1;
1585         }
1586         memset(cblist, 0, sizeof(struct ast_state_cb));
1587         cblist->id = stateid++;
1588         cblist->callback = callback;
1589         cblist->data = data;
1590
1591         cblist->next = list->callbacks;
1592         list->callbacks = cblist;
1593
1594         ast_mutex_unlock(&hintlock);
1595         return cblist->id;
1596 }
1597
1598 int ast_extension_state_del(int id, ast_state_cb_type callback)
1599 {
1600         struct ast_hint *list;
1601         struct ast_state_cb *cblist, *cbprev;
1602     
1603         if (!id && !callback)
1604                 return -1;
1605             
1606         ast_mutex_lock(&hintlock);
1607
1608         /* id is zero is a callback without extension */
1609         if (!id) {
1610                 cbprev = NULL;
1611                 cblist = statecbs;
1612                 while (cblist) {
1613                         if (cblist->callback == callback) {
1614                                 if (!cbprev)
1615                                         statecbs = cblist->next;
1616                                 else
1617                                         cbprev->next = cblist->next;
1618
1619                                 free(cblist);
1620
1621                                 ast_mutex_unlock(&hintlock);
1622                                 return 0;
1623                         }
1624                         cbprev = cblist;
1625                         cblist = cblist->next;
1626                 }
1627
1628                 ast_mutex_lock(&hintlock);
1629                 return -1;
1630         }
1631
1632         /* id greater than zero is a callback with extension */
1633         list = hints;
1634         while (list) {
1635                 cblist = list->callbacks;
1636                 cbprev = NULL;
1637                 while (cblist) {
1638                         if (cblist->id==id) {
1639                                 if (!cbprev)
1640                                         list->callbacks = cblist->next;         
1641                                 else
1642                                         cbprev->next = cblist->next;
1643                 
1644                                 free(cblist);
1645                 
1646                                 ast_mutex_unlock(&hintlock);
1647                                 return 0;               
1648                         }               
1649                         cbprev = cblist;                                
1650                         cblist = cblist->next;
1651                 }
1652                 list = list->next;
1653         }
1654     
1655         ast_mutex_unlock(&hintlock);
1656         return -1;
1657 }
1658
1659 static int ast_add_hint(struct ast_exten *e)
1660 {
1661         struct ast_hint *list;
1662
1663         if (!e) 
1664                 return -1;
1665     
1666         ast_mutex_lock(&hintlock);
1667         list = hints;        
1668     
1669         /* Search if hint exists, do nothing */
1670         while (list) {
1671                 if (list->exten == e) {
1672                         ast_mutex_unlock(&hintlock);
1673                         return -1;
1674                 }
1675                 list = list->next;    
1676         }
1677
1678         list = malloc(sizeof(struct ast_hint));
1679         if (!list) {
1680                 ast_mutex_unlock(&hintlock);
1681                 return -1;
1682         }
1683         /* Initialize and insert new item */
1684         memset(list, 0, sizeof(struct ast_hint));
1685         list->exten = e;
1686         list->laststate = ast_extension_state2(e);
1687         list->next = hints;
1688         hints = list;
1689
1690         ast_mutex_unlock(&hintlock);
1691         return 0;
1692 }
1693
1694 static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
1695
1696         struct ast_hint *list;
1697
1698         ast_mutex_lock(&hintlock);
1699         list = hints;
1700     
1701         while(list) {
1702                 if (list->exten == oe) {
1703                         list->exten = ne;
1704                         ast_mutex_unlock(&hintlock);    
1705                         return 0;
1706                 }
1707                 list = list->next;
1708         }
1709         ast_mutex_unlock(&hintlock);
1710
1711         return -1;
1712 }
1713
1714 static int ast_remove_hint(struct ast_exten *e)
1715 {
1716         /* Cleanup the Notifys if hint is removed */
1717         struct ast_hint *list, *prev = NULL;
1718         struct ast_state_cb *cblist, *cbprev;
1719
1720         if (!e) 
1721                 return -1;
1722
1723         ast_mutex_lock(&hintlock);
1724
1725         list = hints;    
1726         while(list) {
1727                 if (list->exten==e) {
1728                         cbprev = NULL;
1729                         cblist = list->callbacks;
1730                         while (cblist) {
1731                                 /* Notify with -1 and remove all callbacks */
1732                                 cbprev = cblist;            
1733                                 cblist = cblist->next;
1734                                 cbprev->callback(list->exten->parent->name, list->exten->exten, -1, cbprev->data);
1735                                 free(cbprev);
1736                         }
1737                         list->callbacks = NULL;
1738
1739                         if (!prev)
1740                                 hints = list->next;
1741                         else
1742                                 prev->next = list->next;
1743                         free(list);
1744             
1745                         ast_mutex_unlock(&hintlock);
1746                         return 0;
1747                 } else {
1748                         prev = list;
1749                         list = list->next;    
1750                 }
1751         }
1752
1753         ast_mutex_unlock(&hintlock);
1754         return -1;
1755 }
1756
1757
1758 int ast_get_hint(char *hint, int hintsize, struct ast_channel *c, const char *context, const char *exten)
1759 {
1760         struct ast_exten *e;
1761         e = ast_hint_extension(c, context, exten);
1762         if (e) {        
1763             strncpy(hint, ast_get_extension_app(e), hintsize - 1);
1764             return -1;
1765         }
1766         return 0;       
1767 }
1768
1769 int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid) 
1770 {
1771         return pbx_extension_helper(c, context, exten, priority, NULL, callerid, HELPER_EXISTS);
1772 }
1773
1774 int ast_findlabel_extension(struct ast_channel *c, const char *context, const char *exten, const char *label, const char *callerid) 
1775 {
1776         return pbx_extension_helper(c, context, exten, 0, label, callerid, HELPER_FINDLABEL);
1777 }
1778
1779 int ast_canmatch_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
1780 {
1781         return pbx_extension_helper(c, context, exten, priority, NULL, callerid, HELPER_CANMATCH);
1782 }
1783
1784 int ast_matchmore_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
1785 {
1786         return pbx_extension_helper(c, context, exten, priority, NULL, callerid, HELPER_MATCHMORE);
1787 }
1788
1789 int ast_spawn_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid) 
1790 {
1791         return pbx_extension_helper(c, context, exten, priority, NULL, callerid, HELPER_SPAWN);
1792 }
1793
1794 int ast_pbx_run(struct ast_channel *c)
1795 {
1796         int firstpass = 1;
1797         char digit;
1798         char exten[256];
1799         int pos;
1800         int waittime;
1801         int res=0;
1802
1803         /* A little initial setup here */
1804         if (c->pbx)
1805                 ast_log(LOG_WARNING, "%s already has PBX structure??\n", c->name);
1806         c->pbx = malloc(sizeof(struct ast_pbx));
1807         if (!c->pbx) {
1808                 ast_log(LOG_ERROR, "Out of memory\n");
1809                 return -1;
1810         }
1811         if (c->amaflags) {
1812                 if (c->cdr) {
1813                         ast_log(LOG_WARNING, "%s already has a call record??\n", c->name);
1814                 } else {
1815                         c->cdr = ast_cdr_alloc();
1816                         if (!c->cdr) {
1817                                 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
1818                                 free(c->pbx);
1819                                 return -1;
1820                         }
1821                         ast_cdr_init(c->cdr, c);
1822                 }
1823         }
1824         memset(c->pbx, 0, sizeof(struct ast_pbx));
1825         /* Set reasonable defaults */
1826         c->pbx->rtimeout = 10;
1827         c->pbx->dtimeout = 5;
1828
1829         /* Start by trying whatever the channel is set to */
1830         if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
1831                 /* JK02: If not successfull fall back to 's' */
1832                 if (option_verbose > 1)
1833                         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);
1834                 strncpy(c->exten, "s", sizeof(c->exten)-1);
1835                 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
1836                         /* JK02: And finally back to default if everything else failed */
1837                         if (option_verbose > 1)
1838                                 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);
1839                         strncpy(c->context, "default", sizeof(c->context)-1);
1840                 }
1841                 c->priority = 1;
1842         }
1843         if (c->cdr)
1844                 ast_cdr_start(c->cdr);
1845         for(;;) {
1846                 pos = 0;
1847                 digit = 0;
1848                 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
1849                         memset(exten, 0, sizeof(exten));
1850                         if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
1851                                 /* Something bad happened, or a hangup has been requested. */
1852                                 if (((res >= '0') && (res <= '9')) || ((res >= 'A') && (res <= 'F')) ||
1853                                         (res == '*') || (res == '#')) {
1854                                         ast_log(LOG_DEBUG, "Oooh, got something to jump out with ('%c')!\n", res);
1855                                         memset(exten, 0, sizeof(exten));
1856                                         pos = 0;
1857                                         exten[pos++] = digit = res;
1858                                         break;
1859                                 }
1860                                 switch(res) {
1861                                 case AST_PBX_KEEPALIVE:
1862                                         if (option_debug)
1863                                                 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
1864                                         else if (option_verbose > 1)
1865                                                 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
1866                                         goto out;
1867                                         break;
1868                                 default:
1869                                         if (option_debug)
1870                                                 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
1871                                         else if (option_verbose > 1)
1872                                                 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
1873                                         if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
1874                                                 c->_softhangup =0;
1875                                                 break;
1876                                         }
1877                                         /* atimeout */
1878                                         if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
1879                                                 break;
1880                                         }
1881
1882                                         if (c->cdr) {
1883                                                 ast_cdr_update(c);
1884                                         }
1885                                         goto out;
1886                                 }
1887                         }
1888                         if ((c->_softhangup == AST_SOFTHANGUP_TIMEOUT) && (ast_exists_extension(c,c->context,"T",1,c->cid.cid_num))) {
1889                                 strncpy(c->exten,"T",sizeof(c->exten) - 1);
1890                                 /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
1891                                 c->whentohangup = 0;
1892                                 c->priority = 0;
1893                                 c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
1894                         } else if (c->_softhangup) {
1895                                 ast_log(LOG_DEBUG, "Extension %s, priority %d returned normally even though call was hung up\n",
1896                                         c->exten, c->priority);
1897                                 goto out;
1898                         }
1899                         firstpass = 0;
1900                         c->priority++;
1901                 }
1902                 if (!ast_exists_extension(c, c->context, c->exten, 1, c->cid.cid_num)) {
1903                         /* It's not a valid extension anymore */
1904                         if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
1905                                 if (option_verbose > 2)
1906                                         ast_verbose(VERBOSE_PREFIX_3 "Sent into invalid extension '%s' in context '%s' on %s\n", c->exten, c->context, c->name);
1907                                 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", c->exten);
1908                                 strncpy(c->exten, "i", sizeof(c->exten)-1);
1909                                 c->priority = 1;
1910                         } else {
1911                                 ast_log(LOG_WARNING, "Channel '%s' sent into invalid extension '%s' in context '%s', but no invalid handler\n",
1912                                         c->name, c->exten, c->context);
1913                                 goto out;
1914                         }
1915                 } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
1916                         /* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */
1917                         c->_softhangup = 0;
1918                 } else {
1919                         /* Done, wait for an extension */
1920                         if (digit)
1921                                 waittime = c->pbx->dtimeout;
1922                         else
1923                                 waittime = c->pbx->rtimeout;
1924                         while (ast_matchmore_extension(c, c->context, exten, 1, c->cid.cid_num)) {
1925                                 /* As long as we're willing to wait, and as long as it's not defined, 
1926                                    keep reading digits until we can't possibly get a right answer anymore.  */
1927                                 digit = ast_waitfordigit(c, waittime * 1000);
1928                                 if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
1929                                         c->_softhangup = 0;
1930                                 } else {
1931                                         if (!digit)
1932                                                 /* No entry */
1933                                                 break;
1934                                         if (digit < 0)
1935                                                 /* Error, maybe a  hangup */
1936                                                 goto out;
1937                                         exten[pos++] = digit;
1938                                         waittime = c->pbx->dtimeout;
1939                                 }
1940                         }
1941                         if (ast_exists_extension(c, c->context, exten, 1, c->cid.cid_num)) {
1942                                 /* Prepare the next cycle */
1943                                 strncpy(c->exten, exten, sizeof(c->exten)-1);
1944                                 c->priority = 1;
1945                         } else {
1946                                 /* No such extension */
1947                                 if (!ast_strlen_zero(exten)) {
1948                                         /* An invalid extension */
1949                                         if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
1950                                                 if (option_verbose > 2)
1951                                                         ast_verbose( VERBOSE_PREFIX_3 "Invalid extension '%s' in context '%s' on %s\n", exten, c->context, c->name);
1952                                                 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", exten);
1953                                                 strncpy(c->exten, "i", sizeof(c->exten)-1);
1954                                                 c->priority = 1;
1955                                         } else {
1956                                                 ast_log(LOG_WARNING, "Invalid extension '%s', but no rule 'i' in context '%s'\n", exten, c->context);
1957                                                 goto out;
1958                                         }
1959                                 } else {
1960                                         /* A simple timeout */
1961                                         if (ast_exists_extension(c, c->context, "t", 1, c->cid.cid_num)) {
1962                                                 if (option_verbose > 2)
1963                                                         ast_verbose( VERBOSE_PREFIX_3 "Timeout on %s\n", c->name);
1964                                                 strncpy(c->exten, "t", sizeof(c->exten)-1);
1965                                                 c->priority = 1;
1966                                         } else {
1967                                                 ast_log(LOG_WARNING, "Timeout, but no rule 't' in context '%s'\n", c->context);
1968                                                 goto out;
1969                                         }
1970                                 }       
1971                         }
1972                         if (c->cdr) {
1973                                 if (option_verbose > 2)
1974                                         ast_verbose(VERBOSE_PREFIX_2 "CDR updated on %s\n",c->name);    
1975                                 ast_cdr_update(c);
1976                     }
1977                 }
1978         }
1979         if (firstpass) 
1980                 ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", c->name);
1981 out:
1982         if ((res != AST_PBX_KEEPALIVE) && ast_exists_extension(c, c->context, "h", 1, c->cid.cid_num)) {
1983                 c->exten[0] = 'h';
1984                 c->exten[1] = '\0';
1985                 c->priority = 1;
1986                 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
1987                         if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
1988                                 /* Something bad happened, or a hangup has been requested. */
1989                                 if (option_debug)
1990                                         ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
1991                                 else if (option_verbose > 1)
1992                                         ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
1993                                 break;
1994                         }
1995                         c->priority++;
1996                 }
1997         }
1998
1999         pbx_destroy(c->pbx);
2000         c->pbx = NULL;
2001         if (res != AST_PBX_KEEPALIVE)
2002                 ast_hangup(c);
2003         return 0;
2004 }
2005
2006 static void *pbx_thread(void *data)
2007 {
2008         /* Oh joyeous kernel, we're a new thread, with nothing to do but
2009            answer this channel and get it going.  The setjmp stuff is fairly
2010            confusing, but necessary to get smooth transitions between
2011            the execution of different applications (without the use of
2012            additional threads) */
2013         struct ast_channel *c = data;
2014         ast_pbx_run(c);
2015         pthread_exit(NULL);
2016         return NULL;
2017 }
2018
2019 int ast_pbx_start(struct ast_channel *c)
2020 {
2021         pthread_t t;
2022         pthread_attr_t attr;
2023         if (!c) {
2024                 ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
2025                 return -1;
2026         }
2027            
2028         /* Start a new thread, and get something handling this channel. */
2029         pthread_attr_init(&attr);
2030         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
2031         if (ast_pthread_create(&t, &attr, pbx_thread, c)) {
2032                 ast_log(LOG_WARNING, "Failed to create new channel thread\n");
2033                 return -1;
2034         }
2035         return 0;
2036 }
2037
2038 /*
2039  * This function locks contexts list by &conlist, search for the right context
2040  * structure, leave context list locked and call ast_context_remove_include2
2041  * which removes include, unlock contexts list and return ...
2042  */
2043 int ast_context_remove_include(const char *context, const char *include, const char *registrar)
2044 {
2045         struct ast_context *c;
2046
2047         if (ast_lock_contexts()) return -1;
2048
2049         /* walk contexts and search for the right one ...*/
2050         c = ast_walk_contexts(NULL);
2051         while (c) {
2052                 /* we found one ... */
2053                 if (!strcmp(ast_get_context_name(c), context)) {
2054                         int ret;
2055                         /* remove include from this context ... */      
2056                         ret = ast_context_remove_include2(c, include, registrar);
2057
2058                         ast_unlock_contexts();
2059
2060                         /* ... return results */
2061                         return ret;
2062                 }
2063                 c = ast_walk_contexts(c);
2064         }
2065
2066         /* we can't find the right one context */
2067         ast_unlock_contexts();
2068         return -1;
2069 }
2070
2071 /*
2072  * When we call this function, &conlock lock must be locked, because when
2073  * we giving *con argument, some process can remove/change this context
2074  * and after that there can be segfault.
2075  *
2076  * This function locks given context, removes include, unlock context and
2077  * return.
2078  */
2079 int ast_context_remove_include2(struct ast_context *con, const char *include, const char *registrar)
2080 {
2081         struct ast_include *i, *pi = NULL;
2082
2083         if (ast_mutex_lock(&con->lock)) return -1;
2084
2085         /* walk includes */
2086         i = con->includes;
2087         while (i) {
2088                 /* find our include */
2089                 if (!strcmp(i->name, include) && 
2090                         (!registrar || !strcmp(i->registrar, registrar))) {
2091                         /* remove from list */
2092                         if (pi)
2093                                 pi->next = i->next;
2094                         else
2095                                 con->includes = i->next;
2096                         /* free include and return */
2097                         free(i);
2098                         ast_mutex_unlock(&con->lock);
2099                         return 0;
2100                 }
2101                 pi = i;
2102                 i = i->next;
2103         }
2104
2105         /* we can't find the right include */
2106         ast_mutex_unlock(&con->lock);
2107         return -1;
2108 }
2109
2110 /*
2111  * This function locks contexts list by &conlist, search for the rigt context
2112  * structure, leave context list locked and call ast_context_remove_switch2
2113  * which removes switch, unlock contexts list and return ...
2114  */
2115 int ast_context_remove_switch(const char *context, const char *sw, const char *data, const char *registrar)
2116 {
2117         struct ast_context *c;
2118
2119         if (ast_lock_contexts()) return -1;
2120
2121         /* walk contexts and search for the right one ...*/
2122         c = ast_walk_contexts(NULL);
2123         while (c) {
2124                 /* we found one ... */
2125                 if (!strcmp(ast_get_context_name(c), context)) {
2126                         int ret;
2127                         /* remove switch from this context ... */       
2128                         ret = ast_context_remove_switch2(c, sw, data, registrar);
2129
2130                         ast_unlock_contexts();
2131
2132                         /* ... return results */
2133                         return ret;
2134                 }
2135                 c = ast_walk_contexts(c);
2136         }
2137
2138         /* we can't find the right one context */
2139         ast_unlock_contexts();
2140         return -1;
2141 }
2142
2143 /*
2144  * When we call this function, &conlock lock must be locked, because when
2145  * we giving *con argument, some process can remove/change this context
2146  * and after that there can be segfault.
2147  *
2148  * This function locks given context, removes switch, unlock context and
2149  * return.
2150  */
2151 int ast_context_remove_switch2(struct ast_context *con, const char *sw, const char *data, const char *registrar)
2152 {
2153         struct ast_sw *i, *pi = NULL;
2154
2155         if (ast_mutex_lock(&con->lock)) return -1;
2156
2157         /* walk switchs */
2158         i = con->alts;
2159         while (i) {
2160                 /* find our switch */
2161                 if (!strcmp(i->name, sw) && !strcmp(i->data, data) && 
2162                         (!registrar || !strcmp(i->registrar, registrar))) {
2163                         /* remove from list */
2164                         if (pi)
2165                                 pi->next = i->next;
2166                         else
2167                                 con->alts = i->next;
2168                         /* free switch and return */
2169                         free(i);
2170                         ast_mutex_unlock(&con->lock);
2171                         return 0;
2172                 }
2173                 pi = i;
2174                 i = i->next;
2175         }
2176
2177         /* we can't find the right switch */
2178         ast_mutex_unlock(&con->lock);
2179         return -1;
2180 }
2181
2182 /*
2183  * This functions lock contexts list, search for the right context,
2184  * call ast_context_remove_extension2, unlock contexts list and return.
2185  * In this function we are using
2186  */
2187 int ast_context_remove_extension(const char *context, const char *extension, int priority, const char *registrar)
2188 {
2189         struct ast_context *c;
2190
2191         if (ast_lock_contexts()) return -1;
2192
2193         /* walk contexts ... */
2194         c = ast_walk_contexts(NULL);
2195         while (c) {
2196                 /* ... search for the right one ... */
2197                 if (!strcmp(ast_get_context_name(c), context)) {
2198                         /* ... remove extension ... */
2199                         int ret = ast_context_remove_extension2(c, extension, priority,
2200                                 registrar);
2201                         /* ... unlock contexts list and return */
2202                         ast_unlock_contexts();
2203                         return ret;
2204                 }
2205                 c = ast_walk_contexts(c);
2206         }
2207
2208         /* we can't find the right context */
2209         ast_unlock_contexts();
2210         return -1;
2211 }
2212
2213 /*
2214  * When do you want to call this function, make sure that &conlock is locked,
2215  * because some process can handle with your *con context before you lock
2216  * it.
2217  *
2218  * This functionc locks given context, search for the right extension and
2219  * fires out all peer in this extensions with given priority. If priority
2220  * is set to 0, all peers are removed. After that, unlock context and
2221  * return.
2222  */
2223 int ast_context_remove_extension2(struct ast_context *con, const char *extension, int priority, const char *registrar)
2224 {
2225         struct ast_exten *exten, *prev_exten = NULL;
2226
2227         if (ast_mutex_lock(&con->lock)) return -1;
2228
2229         /* go through all extensions in context and search the right one ... */
2230         exten = con->root;
2231         while (exten) {
2232
2233                 /* look for right extension */
2234                 if (!strcmp(exten->exten, extension) &&
2235                         (!registrar || !strcmp(exten->registrar, registrar))) {
2236                         struct ast_exten *peer;
2237
2238                         /* should we free all peers in this extension? (priority == 0)? */
2239                         if (priority == 0) {
2240                                 /* remove this extension from context list */
2241                                 if (prev_exten)
2242                                         prev_exten->next = exten->next;
2243                                 else
2244                                         con->root = exten->next;
2245
2246                                 /* fire out all peers */
2247                                 peer = exten; 
2248                                 while (peer) {
2249                                         exten = peer->peer;
2250                                         
2251                                         if (!peer->priority==PRIORITY_HINT) 
2252                                             ast_remove_hint(peer);
2253
2254                                         peer->datad(peer->data);
2255                                         free(peer);
2256
2257                                         peer = exten;
2258                                 }
2259
2260                                 ast_mutex_unlock(&con->lock);
2261                                 return 0;
2262                         } else {
2263                                 /* remove only extension with exten->priority == priority */
2264                                 struct ast_exten *previous_peer = NULL;
2265
2266                                 peer = exten;
2267                                 while (peer) {
2268                                         /* is this our extension? */
2269                                         if (peer->priority == priority &&
2270                                                 (!registrar || !strcmp(peer->registrar, registrar) )) {
2271                                                 /* we are first priority extension? */
2272                                                 if (!previous_peer) {
2273                                                         /* exists previous extension here? */
2274                                                         if (prev_exten) {
2275                                                                 /* yes, so we must change next pointer in
2276                                                                  * previous connection to next peer
2277                                                                  */
2278                                                                 if (peer->peer) {
2279                                                                         prev_exten->next = peer->peer;
2280                                                                         peer->peer->next = exten->next;
2281                                                                 } else
2282                                                                         prev_exten->next = exten->next;
2283                                                         } else {
2284                                                                 /* no previous extension, we are first
2285                                                                  * extension, so change con->root ...
2286                                                                  */
2287                                                                 if (peer->peer)
2288                                                                         con->root = peer->peer;
2289                                                                 else
2290                                                                         con->root = exten->next; 
2291                                                         }
2292                                                 } else {
2293                                                         /* we are not first priority in extension */
2294                                                         previous_peer->peer = peer->peer;
2295                                                 }
2296
2297                                                 /* now, free whole priority extension */
2298                                                 if (peer->priority==PRIORITY_HINT)
2299                                                     ast_remove_hint(peer);
2300                                                 peer->datad(peer->data);
2301                                                 free(peer);
2302
2303                                                 ast_mutex_unlock(&con->lock);
2304                                                 return 0;
2305                                         } else {
2306                                                 /* this is not right extension, skip to next peer */
2307                                                 previous_peer = peer;
2308                                                 peer = peer->peer;
2309                                         }
2310                                 }
2311
2312                                 ast_mutex_unlock(&con->lock);
2313                                 return -1;
2314                         }
2315                 }
2316
2317                 prev_exten = exten;
2318                 exten = exten->next;
2319         }
2320
2321         /* we can't find right extension */
2322         ast_mutex_unlock(&con->lock);
2323         return -1;
2324 }
2325
2326
2327 int ast_register_application(const char *app, int (*execute)(struct ast_channel *, void *), const char *synopsis, const char *description)
2328 {
2329         struct ast_app *tmp, *prev, *cur;
2330         char tmps[80];
2331         int length;
2332         length = sizeof(struct ast_app);
2333         length += strlen(app) + 1;
2334         if (ast_mutex_lock(&applock)) {
2335                 ast_log(LOG_ERROR, "Unable to lock application list\n");
2336                 return -1;
2337         }
2338         tmp = apps;
2339         while(tmp) {
2340                 if (!strcasecmp(app, tmp->name)) {
2341                         ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
2342                         ast_mutex_unlock(&applock);
2343                         return -1;
2344                 }
2345                 tmp = tmp->next;
2346         }
2347         tmp = malloc(length);
2348         if (tmp) {
2349                 memset(tmp, 0, length);
2350                 strcpy(tmp->name, app);
2351                 tmp->execute = execute;
2352                 tmp->synopsis = synopsis;
2353                 tmp->description = description;
2354                 /* Store in alphabetical order */
2355                 cur = apps;
2356                 prev = NULL;
2357                 while(cur) {
2358                         if (strcasecmp(tmp->name, cur->name) < 0)
2359                                 break;
2360                         prev = cur;
2361                         cur = cur->next;
2362                 }
2363                 if (prev) {
2364                         tmp->next = prev->next;
2365                         prev->next = tmp;
2366                 } else {
2367                         tmp->next = apps;
2368                         apps = tmp;
2369                 }
2370         } else {
2371                 ast_log(LOG_ERROR, "Out of memory\n");
2372                 ast_mutex_unlock(&applock);
2373                 return -1;
2374         }
2375         if (option_verbose > 1)
2376                 ast_verbose( VERBOSE_PREFIX_2 "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
2377         ast_mutex_unlock(&applock);
2378         return 0;
2379 }
2380
2381 int ast_register_switch(struct ast_switch *sw)
2382 {
2383         struct ast_switch *tmp, *prev=NULL;
2384         if (ast_mutex_lock(&switchlock)) {
2385                 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
2386                 return -1;
2387         }
2388         tmp = switches;
2389         while(tmp) {
2390                 if (!strcasecmp(tmp->name, sw->name))
2391                         break;
2392                 prev = tmp;
2393                 tmp = tmp->next;
2394         }
2395         if (tmp) {      
2396                 ast_mutex_unlock(&switchlock);
2397                 ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name);
2398                 return -1;
2399         }
2400         sw->next = NULL;
2401         if (prev) 
2402                 prev->next = sw;
2403         else
2404                 switches = sw;
2405         ast_mutex_unlock(&switchlock);
2406         return 0;
2407 }
2408
2409 void ast_unregister_switch(struct ast_switch *sw)
2410 {
2411         struct ast_switch *tmp, *prev=NULL;
2412         if (ast_mutex_lock(&switchlock)) {
2413                 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
2414                 return;
2415         }
2416         tmp = switches;
2417         while(tmp) {
2418                 if (tmp == sw) {
2419                         if (prev)
2420                                 prev->next = tmp->next;
2421                         else
2422                                 switches = tmp->next;
2423                         tmp->next = NULL;
2424                         break;                  
2425                 }
2426                 prev = tmp;
2427                 tmp = tmp->next;
2428         }
2429         ast_mutex_unlock(&switchlock);
2430 }
2431
2432 /*
2433  * Help for CLI commands ...
2434  */
2435 static char show_application_help[] = 
2436 "Usage: show application <application> [<application> [<application> [...]]]\n"
2437 "       Describes a particular application.\n";
2438
2439 static char show_applications_help[] =
2440 "Usage: show applications [{like|describing} <text>]\n"
2441 "       List applications which are currently available.\n"
2442 "       If 'like', <text> will be a substring of the app name\n"
2443 "       If 'describing', <text> will be a substring of the description\n";
2444
2445 static char show_dialplan_help[] =
2446 "Usage: show dialplan [exten@][context]\n"
2447 "       Show dialplan\n";
2448
2449 static char show_switches_help[] = 
2450 "Usage: show switches\n"
2451 "       Show registered switches\n";
2452
2453 /*
2454  * IMPLEMENTATION OF CLI FUNCTIONS IS IN THE SAME ORDER AS COMMANDS HELPS
2455  *
2456  */
2457
2458 /*
2459  * 'show application' CLI command implementation functions ...
2460  */
2461
2462 /*
2463  * There is a possibility to show informations about more than one
2464  * application at one time. You can type 'show application Dial Echo' and
2465  * you will see informations about these two applications ...
2466  */
2467 static char *complete_show_application(char *line, char *word,
2468         int pos, int state)
2469 {
2470         struct ast_app *a;
2471         int which = 0;
2472
2473         /* try to lock applications list ... */
2474         if (ast_mutex_lock(&applock)) {
2475                 ast_log(LOG_ERROR, "Unable to lock application list\n");
2476                 return NULL;
2477         }
2478
2479         /* ... walk all applications ... */
2480         a = apps; 
2481         while (a) {
2482                 /* ... check if word matches this application ... */
2483                 if (!strncasecmp(word, a->name, strlen(word))) {
2484                         /* ... if this is right app serve it ... */
2485                         if (++which > state) {
2486                                 char *ret = strdup(a->name);
2487                                 ast_mutex_unlock(&applock);
2488                                 return ret;
2489                         }
2490                 }
2491                 a = a->next; 
2492         }
2493
2494         /* no application match */
2495         ast_mutex_unlock(&applock);
2496         return NULL; 
2497 }
2498
2499 static int handle_show_application(int fd, int argc, char *argv[])
2500 {
2501         struct ast_app *a;
2502         int app, no_registered_app = 1;
2503
2504         if (argc < 3) return RESULT_SHOWUSAGE;
2505
2506         /* try to lock applications list ... */
2507         if (ast_mutex_lock(&applock)) {
2508                 ast_log(LOG_ERROR, "Unable to lock application list\n");
2509                 return -1;
2510         }
2511
2512         /* ... go through all applications ... */
2513         a = apps; 
2514         while (a) {
2515                 /* ... compare this application name with all arguments given
2516                  * to 'show application' command ... */
2517                 for (app = 2; app < argc; app++) {
2518                         if (!strcasecmp(a->name, argv[app])) {
2519                                 /* Maximum number of characters added by terminal coloring is 22 */
2520                                 char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
2521                                 char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
2522                                 int synopsis_size, description_size;
2523
2524                                 no_registered_app = 0;
2525
2526                                 if (a->synopsis)
2527                                         synopsis_size = strlen(a->synopsis) + 23;
2528                                 else
2529                                         synopsis_size = strlen("Not available") + 23;
2530                                 synopsis = alloca(synopsis_size);
2531
2532                                 if (a->description)
2533                                         description_size = strlen(a->description) + 23;
2534                                 else
2535                                         description_size = strlen("Not available") + 23;
2536                                 description = alloca(description_size);
2537
2538                                 if (synopsis && description) {
2539                                         snprintf(info, 64 + AST_MAX_APP, "\n  -= Info about application '%s' =- \n\n", a->name);
2540                                         term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
2541                                         term_color(syntitle, "[Synopsis]:\n", COLOR_MAGENTA, 0, 40);
2542                                         term_color(destitle, "[Description]:\n", COLOR_MAGENTA, 0, 40);
2543                                         term_color(synopsis,
2544                                                                         a->synopsis ? a->synopsis : "Not available",
2545                                                                         COLOR_CYAN, 0, synopsis_size);
2546                                         term_color(description,
2547                                                                         a->description ? a->description : "Not available",
2548                                                                         COLOR_CYAN, 0, description_size);
2549
2550                                         ast_cli(fd,"%s%s%s\n\n%s%s\n", infotitle, syntitle, synopsis, destitle, description);
2551                                 } else {
2552                                         /* ... one of our applications, show info ...*/
2553                                         ast_cli(fd,"\n  -= Info about application '%s' =- \n\n"
2554                                                 "[Synopsis]:\n  %s\n\n"
2555                                                 "[Description]:\n%s\n",
2556                                                 a->name,
2557                                                 a->synopsis ? a->synopsis : "Not available",
2558                                                 a->description ? a->description : "Not available");
2559                                 }
2560                         }
2561                 }
2562                 a = a->next; 
2563         }
2564
2565         ast_mutex_unlock(&applock);
2566
2567         /* we found at least one app? no? */
2568         if (no_registered_app) {
2569                 ast_cli(fd, "Your application(s) is (are) not registered\n");
2570                 return RESULT_FAILURE;
2571         }
2572
2573         return RESULT_SUCCESS;
2574 }
2575
2576 static int handle_show_switches(int fd, int argc, char *argv[])
2577 {
2578         struct ast_switch *sw;
2579         if (!switches) {
2580                 ast_cli(fd, "There are no registered alternative switches\n");
2581                 return RESULT_SUCCESS;
2582         }
2583         /* ... we have applications ... */
2584         ast_cli(fd, "\n    -= Registered Asterisk Alternative Switches =-\n");
2585         if (ast_mutex_lock(&switchlock)) {
2586                 ast_log(LOG_ERROR, "Unable to lock switches\n");
2587                 return -1;
2588         }
2589         sw = switches;
2590         while (sw) {
2591                 ast_cli(fd, "%s: %s\n", sw->name, sw->description);
2592                 sw = sw->next;
2593         }
2594         ast_mutex_unlock(&switchlock);
2595         return RESULT_SUCCESS;
2596 }
2597
2598 /*
2599  * 'show applications' CLI command implementation functions ...
2600  */
2601 static int handle_show_applications(int fd, int argc, char *argv[])
2602 {
2603         struct ast_app *a;
2604         int like=0, describing=0;
2605
2606         /* try to lock applications list ... */
2607         if (ast_mutex_lock(&applock)) {
2608                 ast_log(LOG_ERROR, "Unable to lock application list\n");
2609                 return -1;
2610         }
2611
2612         /* ... have we got at least one application (first)? no? */
2613         if (!apps) {
2614                 ast_cli(fd, "There are no registered applications\n");
2615                 ast_mutex_unlock(&applock);
2616                 return -1;
2617         }
2618
2619         /* show applications like <keyword> */
2620         if ((argc == 4) && (!strcmp(argv[2], "like"))) {
2621                 like = 1;
2622         } else if ((argc > 3) && (!strcmp(argv[2], "describing"))) {
2623                 describing = 1;
2624         }
2625
2626         /* show applications describing <keyword1> [<keyword2>] [...] */
2627         if ((!like) && (!describing)) {
2628                 ast_cli(fd, "    -= Registered Asterisk Applications =-\n");
2629         } else {
2630                 ast_cli(fd, "    -= Matching Asterisk Applications =-\n");
2631         }
2632
2633         /* ... go through all applications ... */
2634         for (a = apps; a; a = a->next) {
2635                 /* ... show informations about applications ... */
2636                 int printapp=0;
2637
2638                 if (like) {
2639                         if (ast_strcasestr(a->name, argv[3])) {
2640                                 printapp = 1;
2641                         }
2642                 } else if (describing) {
2643                         if (a->description) {
2644                                 /* Match all words on command line */
2645                                 int i;
2646                                 printapp = 1;
2647                                 for (i=3;i<argc;i++) {
2648                                         if (! ast_strcasestr(a->description, argv[i])) {
2649                                                 printapp = 0;
2650                                         }
2651                                 }
2652                         }
2653                 } else {
2654                         printapp = 1;
2655                 }
2656
2657                 if (printapp) {
2658                         ast_cli(fd,"  %20s: %s\n", a->name, a->synopsis ? a->synopsis : "<Synopsis not available>");
2659                 }
2660         }
2661
2662         /* ... unlock and return */
2663         ast_mutex_unlock(&applock);
2664
2665         return RESULT_SUCCESS;
2666 }
2667
2668 static char *complete_show_applications(char *line, char *word, int pos, int state)
2669 {
2670         if (pos == 2) {
2671                 if (ast_strlen_zero(word)) {
2672                         switch (state) {
2673                         case 0:
2674                                 return strdup("like");
2675                         case 1:
2676                                 return strdup("describing");
2677                         default:
2678                                 return NULL;
2679                         }
2680                 } else if (! strncasecmp(word, "like", strlen(word))) {
2681                         if (state == 0) {
2682                                 return strdup("like");
2683                         } else {
2684                                 return NULL;
2685                         }
2686                 } else if (! strncasecmp(word, "describing", strlen(word))) {
2687                         if (state == 0) {
2688                                 return strdup("describing");
2689                         } else {
2690                                 return NULL;
2691                         }
2692                 }
2693         }
2694         return NULL;
2695 }
2696
2697 /*
2698  * 'show dialplan' CLI command implementation functions ...
2699  */
2700 static char *complete_show_dialplan_context(char *line, char *word, int pos,
2701         int state)
2702 {
2703         struct ast_context *c;
2704         int which = 0;
2705
2706         /* we are do completion of [exten@]context on second position only */
2707         if (pos != 2) return NULL;
2708
2709         /* try to lock contexts list ... */
2710         if (ast_lock_contexts()) {
2711                 ast_log(LOG_ERROR, "Unable to lock context list\n");
2712                 return NULL;
2713         }
2714
2715         /* ... walk through all contexts ... */
2716         c = ast_walk_contexts(NULL);
2717         while(c) {
2718                 /* ... word matches context name? yes? ... */
2719                 if (!strncasecmp(word, ast_get_context_name(c), strlen(word))) {
2720                         /* ... for serve? ... */
2721                         if (++which > state) {
2722                                 /* ... yes, serve this context name ... */
2723                                 char *ret = strdup(ast_get_context_name(c));
2724                                 ast_unlock_contexts();
2725                                 return ret;
2726                         }
2727                 }
2728                 c = ast_walk_contexts(c);
2729         }
2730
2731         /* ... unlock and return */
2732         ast_unlock_contexts();
2733         return NULL;
2734 }
2735
2736 static int handle_show_dialplan(int fd, int argc, char *argv[])
2737 {
2738         struct ast_context *c;
2739         char *exten = NULL, *context = NULL;
2740         int context_existence = 0, extension_existence = 0;
2741
2742         if (argc != 3 && argc != 2) return -1;
2743
2744         /* we obtain [exten@]context? if yes, split them ... */
2745         if (argc == 3) {
2746                 char *splitter = argv[2];
2747                 /* is there a '@' character? */
2748                 if (strchr(argv[2], '@')) {
2749                         /* yes, split into exten & context ... */
2750                         exten   = strsep(&splitter, "@");
2751                         context = splitter;
2752
2753                         /* check for length and change to NULL if ast_strlen_zero() */
2754                         if (ast_strlen_zero(exten))   exten = NULL;
2755                         if (ast_strlen_zero(context)) context = NULL;
2756                 } else
2757                 {
2758                         /* no '@' char, only context given */
2759                         context = argv[2];
2760                         if (ast_strlen_zero(context)) context = NULL;
2761                 }
2762         }
2763
2764         /* try to lock contexts */
2765         if (ast_lock_contexts()) {
2766                 ast_log(LOG_WARNING, "Failed to lock contexts list\n");
2767                 return RESULT_FAILURE;
2768         }
2769
2770         /* walk all contexts ... */
2771         c = ast_walk_contexts(NULL);
2772         while (c) {
2773                 /* show this context? */
2774                 if (!context ||
2775                         !strcmp(ast_get_context_name(c), context)) {
2776                         context_existence = 1;
2777
2778                         /* try to lock context before walking in ... */
2779                         if (!ast_lock_context(c)) {
2780                                 struct ast_exten *e;
2781                                 struct ast_include *i;
2782                                 struct ast_ignorepat *ip;
2783                                 struct ast_sw *sw;
2784                                 char buf[256], buf2[256];
2785                                 int context_info_printed = 0;
2786
2787                                 /* are we looking for exten too? if yes, we print context
2788                                  * if we our extension only
2789                                  */
2790                                 if (!exten) {
2791                                         ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
2792                                                 ast_get_context_name(c), ast_get_context_registrar(c));
2793                                         context_info_printed = 1;
2794                                 }
2795
2796                                 /* walk extensions ... */
2797                                 e = ast_walk_context_extensions(c, NULL);
2798                                 while (e) {
2799                                         struct ast_exten *p;
2800
2801                                         /* looking for extension? is this our extension? */
2802                                         if (exten &&
2803                                                 strcmp(ast_get_extension_name(e), exten))
2804                                         {
2805                                                 /* we are looking for extension and it's not our
2806                                                  * extension, so skip to next extension */
2807                                                 e = ast_walk_context_extensions(c, e);
2808                                                 continue;
2809                                         }
2810
2811                                         extension_existence = 1;
2812
2813                                         /* may we print context info? */        
2814                                         if (!context_info_printed) {
2815                                                 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
2816                                                         ast_get_context_name(c),
2817                                                         ast_get_context_registrar(c));
2818                                                 context_info_printed = 1;
2819                                         }
2820
2821                                         /* write extension name and first peer */       
2822                                         bzero(buf, sizeof(buf));                
2823                                         snprintf(buf, sizeof(buf), "'%s' =>",
2824                                                 ast_get_extension_name(e));
2825
2826                                         snprintf(buf2, sizeof(buf2),
2827                                                 "%d. %s(%s)",
2828                                                 ast_get_extension_priority(e),
2829                                                 ast_get_extension_app(e),
2830                                                 (char *)ast_get_extension_app_data(e));
2831
2832                                         ast_cli(fd, "  %-17s %-45s [%s]\n", buf, buf2,
2833                                                 ast_get_extension_registrar(e));
2834
2835                                         /* walk next extension peers */
2836                                         p = ast_walk_extension_priorities(e, e);
2837                                         while (p) {
2838                                                 bzero((void *)buf2, sizeof(buf2));
2839                                                 bzero((void *)buf, sizeof(buf));
2840                                                 if (ast_get_extension_label(p))
2841                                                         snprintf(buf, sizeof(buf), "   [%s]", ast_get_extension_label(p));
2842                                                 snprintf(buf2, sizeof(buf2),
2843                                                         "%d. %s(%s)",
2844                                                         ast_get_extension_priority(p),
2845                                                         ast_get_extension_app(p),
2846                                                         (char *)ast_get_extension_app_data(p));
2847
2848                                                 ast_cli(fd,"  %-17s %-45s [%s]\n",
2849                                                         buf, buf2,
2850                                                         ast_get_extension_registrar(p));        
2851
2852                                                 p = ast_walk_extension_priorities(e, p);
2853                                         }
2854                                         e = ast_walk_context_extensions(c, e);
2855                                 }
2856
2857                                 /* include & ignorepat we all printing if we are not
2858                                  * looking for exact extension
2859                                  */
2860                                 if (!exten) {
2861                                         if (ast_walk_context_extensions(c, NULL))
2862                                                 ast_cli(fd, "\n");
2863
2864                                         /* walk included and write info ... */
2865                                         i = ast_walk_context_includes(c, NULL);
2866                                         while (i) {
2867                                                 bzero(buf, sizeof(buf));
2868                                                 snprintf(buf, sizeof(buf), "'%s'",
2869                                                         ast_get_include_name(i));
2870                                                 ast_cli(fd, "  Include =>        %-45s [%s]\n",
2871                                                         buf, ast_get_include_registrar(i));
2872                                                 i = ast_walk_context_includes(c, i);
2873                                         }
2874
2875                                         /* walk ignore patterns and write info ... */
2876                                         ip = ast_walk_context_ignorepats(c, NULL);
2877                                         while (ip) {
2878                                                 bzero(buf, sizeof(buf));
2879                                                 snprintf(buf, sizeof(buf), "'%s'",
2880                                                         ast_get_ignorepat_name(ip));
2881                                                 ast_cli(fd, "  Ignore pattern => %-45s [%s]\n",
2882                                                         buf, ast_get_ignorepat_registrar(ip));  
2883                                                 ip = ast_walk_context_ignorepats(c, ip);
2884                                         }
2885                                         sw = ast_walk_context_switches(c, NULL);
2886                                         while(sw) {
2887                                                 bzero(buf, sizeof(buf));
2888                                                 snprintf(buf, sizeof(buf), "'%s/%s'",
2889                                                         ast_get_switch_name(sw),
2890                                                         ast_get_switch_data(sw));
2891                                                 ast_cli(fd, "  Alt. Switch =>    %-45s [%s]\n",
2892                                                         buf, ast_get_switch_registrar(sw));     
2893                                                 sw = ast_walk_context_switches(c, sw);
2894                                         }
2895                                 }
2896         
2897                                 ast_unlock_context(c);
2898
2899                                 /* if we print something in context, make an empty line */
2900                                 if (context_info_printed) ast_cli(fd, "\n");
2901                         }
2902                 }
2903                 c = ast_walk_contexts(c);
2904         }
2905         ast_unlock_contexts();
2906
2907         /* check for input failure and throw some error messages */
2908         if (context && !context_existence) {
2909                 ast_cli(fd, "There is no existence of '%s' context\n",
2910                         context);
2911                 return RESULT_FAILURE;
2912         }
2913
2914         if (exten && !extension_existence) {
2915                 if (context)
2916                         ast_cli(fd, "There is no existence of %s@%s extension\n",
2917                                 exten, context);
2918                 else
2919                         ast_cli(fd,
2920                                 "There is no existence of '%s' extension in all contexts\n",
2921                                 exten);
2922                 return RESULT_FAILURE;
2923         }
2924
2925         /* everything ok */
2926         return RESULT_SUCCESS;
2927 }
2928
2929 /*
2930  * CLI entries for upper commands ...
2931  */
2932 static struct ast_cli_entry show_applications_cli = 
2933         { { "show", "applications", NULL }, 
2934         handle_show_applications, "Shows registered applications",
2935         show_applications_help, complete_show_applications };
2936
2937 static struct ast_cli_entry show_application_cli =
2938         { { "show", "application", NULL }, 
2939         handle_show_application, "Describe a specific application",
2940         show_application_help, complete_show_application };
2941
2942 static struct ast_cli_entry show_dialplan_cli =
2943         { { "show", "dialplan", NULL },
2944                 handle_show_dialplan, "Show dialplan",
2945                 show_dialplan_help, complete_show_dialplan_context };
2946
2947 static struct ast_cli_entry show_switches_cli =
2948         { { "show", "switches", NULL },
2949                 handle_show_switches, "Show alternative switches",
2950                 show_switches_help, NULL };
2951
2952 int ast_unregister_application(const char *app) {
2953         struct ast_app *tmp, *tmpl = NULL;
2954         if (ast_mutex_lock(&applock)) {
2955                 ast_log(LOG_ERROR, "Unable to lock application list\n");
2956                 return -1;
2957         }
2958         tmp = apps;
2959         while(tmp) {
2960                 if (!strcasecmp(app, tmp->name)) {
2961                         if (tmpl)
2962                                 tmpl->next = tmp->next;
2963                         else
2964                                 apps = tmp->next;
2965                         if (option_verbose > 1)
2966                                 ast_verbose( VERBOSE_PREFIX_2 "Unregistered application '%s'\n", tmp->name);
2967                         free(tmp);
2968                         ast_mutex_unlock(&applock);
2969                         return 0;
2970                 }
2971                 tmpl = tmp;
2972                 tmp = tmp->next;
2973         }
2974         ast_mutex_unlock(&applock);
2975         return -1;
2976 }
2977
2978 struct ast_context *ast_context_create(struct ast_context **extcontexts, const char *name, const char *registrar)
2979 {
2980         struct ast_context *tmp, **local_contexts;
2981         int length;
2982         length = sizeof(struct ast_context);
2983         length += strlen(name) + 1;
2984         if (!extcontexts) {
2985                 local_contexts = &contexts;