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