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