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