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