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