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