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