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