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