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