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