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