formatting fixes (bug #4736)
[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
1128         ast_cli(fd, "Installed Custom Functions:\n--------------------------------------------------------------------------------\n");
1129         for (acf = acf_root ; acf; acf = acf->next) {
1130                 ast_cli(fd, "%-20.20s  %-35.35s  %s\n", acf->name, acf->syntax, acf->synopsis);
1131         }
1132         ast_cli(fd, "\n");
1133         return 0;
1134 }
1135
1136 static int handle_show_function(int fd, int argc, char *argv[])
1137 {
1138         struct ast_custom_function *acf;
1139         /* Maximum number of characters added by terminal coloring is 22 */
1140         char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
1141         char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
1142         char stxtitle[40], *syntax = NULL;
1143         int synopsis_size, description_size, syntax_size;
1144
1145         if (argc < 3) return RESULT_SHOWUSAGE;
1146
1147         if (!(acf = ast_custom_function_find(argv[2]))) {
1148                 ast_cli(fd, "No function by that name registered.\n");
1149                 return RESULT_FAILURE;
1150
1151         }
1152
1153         if (acf->synopsis)
1154                 synopsis_size = strlen(acf->synopsis) + 23;
1155         else
1156                 synopsis_size = strlen("Not available") + 23;
1157         synopsis = alloca(synopsis_size);
1158         
1159         if (acf->desc)
1160                 description_size = strlen(acf->desc) + 23;
1161         else
1162                 description_size = strlen("Not available") + 23;
1163         description = alloca(description_size);
1164
1165         if (acf->syntax)
1166                 syntax_size = strlen(acf->syntax) + 23;
1167         else
1168                 syntax_size = strlen("Not available") + 23;
1169         syntax = alloca(syntax_size);
1170
1171         snprintf(info, 64 + AST_MAX_APP, "\n  -= Info about function '%s' =- \n\n", acf->name);
1172         term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
1173         term_color(stxtitle, "[Syntax]\n", COLOR_MAGENTA, 0, 40);
1174         term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
1175         term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
1176         term_color(syntax,
1177                    acf->syntax ? acf->syntax : "Not available",
1178                    COLOR_CYAN, 0, syntax_size);
1179         term_color(synopsis,
1180                    acf->synopsis ? acf->synopsis : "Not available",
1181                    COLOR_CYAN, 0, synopsis_size);
1182         term_color(description,
1183                    acf->desc ? acf->desc : "Not available",
1184                    COLOR_CYAN, 0, description_size);
1185         
1186         ast_cli(fd,"%s%s%s\n\n%s%s\n\n%s%s\n", infotitle, stxtitle, syntax, syntitle, synopsis, destitle, description);
1187
1188         return RESULT_SUCCESS;
1189 }
1190
1191 static char *complete_show_function(char *line, char *word, int pos, int state)
1192 {
1193         struct ast_custom_function *acf;
1194         int which = 0;
1195
1196         /* try to lock functions list ... */
1197         if (ast_mutex_lock(&acflock)) {
1198                 ast_log(LOG_ERROR, "Unable to lock function list\n");
1199                 return NULL;
1200         }
1201
1202         acf = acf_root;
1203         while (acf) {
1204                 if (!strncasecmp(word, acf->name, strlen(word))) {
1205                         if (++which > state) {
1206                                 char *ret = strdup(acf->name);
1207                                 ast_mutex_unlock(&acflock);
1208                                 return ret;
1209                         }
1210                 }
1211                 acf = acf->next; 
1212         }
1213
1214         ast_mutex_unlock(&acflock);
1215         return NULL; 
1216 }
1217
1218 struct ast_custom_function* ast_custom_function_find(char *name) 
1219 {
1220         struct ast_custom_function *acfptr;
1221
1222         /* try to lock functions list ... */
1223         if (ast_mutex_lock(&acflock)) {
1224                 ast_log(LOG_ERROR, "Unable to lock function list\n");
1225                 return NULL;
1226         }
1227
1228         for (acfptr = acf_root; acfptr; acfptr = acfptr->next) {
1229                 if (!strcmp(name, acfptr->name)) {
1230                         break;
1231                 }
1232         }
1233
1234         ast_mutex_unlock(&acflock);
1235         
1236         return acfptr;
1237 }
1238
1239 int ast_custom_function_unregister(struct ast_custom_function *acf) 
1240 {
1241         struct ast_custom_function *acfptr, *lastacf = NULL;
1242         int res = -1;
1243
1244         if (!acf)
1245                 return -1;
1246
1247         /* try to lock functions list ... */
1248         if (ast_mutex_lock(&acflock)) {
1249                 ast_log(LOG_ERROR, "Unable to lock function list\n");
1250                 return -1;
1251         }
1252
1253         for (acfptr = acf_root; acfptr; acfptr = acfptr->next) {
1254                 if (acfptr == acf) {
1255                         if (lastacf) {
1256                                 lastacf->next = acf->next;
1257                         } else {
1258                                 acf_root = acf->next;
1259                         }
1260                         res = 0;
1261                         break;
1262                 }
1263                 lastacf = acfptr;
1264         }
1265
1266         ast_mutex_unlock(&acflock);
1267
1268         if (!res && (option_verbose > 1))
1269                 ast_verbose(VERBOSE_PREFIX_2 "Unregistered custom function %s\n", acf->name);
1270
1271         return res;
1272 }
1273
1274 int ast_custom_function_register(struct ast_custom_function *acf) 
1275 {
1276         if (!acf)
1277                 return -1;
1278
1279         /* try to lock functions list ... */
1280         if (ast_mutex_lock(&acflock)) {
1281                 ast_log(LOG_ERROR, "Unable to lock function list. Failed registering function %s\n", acf->name);
1282                 return -1;
1283         }
1284
1285         if (ast_custom_function_find(acf->name)) {
1286                 ast_log(LOG_ERROR, "Function %s already registered.\n", acf->name);
1287                 ast_mutex_unlock(&acflock);
1288                 return -1;
1289         }
1290
1291         acf->next = acf_root;
1292         acf_root = acf;
1293
1294         ast_mutex_unlock(&acflock);
1295
1296         if (option_verbose > 1)
1297                 ast_verbose(VERBOSE_PREFIX_2 "Registered custom function %s\n", acf->name);
1298
1299         return 0;
1300 }
1301
1302 char *ast_func_read(struct ast_channel *chan, const char *in, char *workspace, size_t len)
1303 {
1304         char *args = NULL, *function, *p;
1305         char *ret = "0";
1306         struct ast_custom_function *acfptr;
1307
1308         function = ast_strdupa(in);
1309         if (!function) {
1310                 ast_log(LOG_ERROR, "Out of memory\n");
1311                 return ret;
1312         }
1313         if ((args = strchr(function, '('))) {
1314                 *args = '\0';
1315                 args++;
1316                 if ((p = strrchr(args, ')'))) {
1317                         *p = '\0';
1318                 } else {
1319                         ast_log(LOG_WARNING, "Can't find trailing parenthesis?\n");
1320                 }
1321         } else {
1322                 ast_log(LOG_WARNING, "Function doesn't contain parentheses.  Assuming null argument.\n");
1323         }
1324
1325         if ((acfptr = ast_custom_function_find(function))) {
1326                 /* run the custom function */
1327                 if (acfptr->read) {
1328                         return acfptr->read(chan, function, args, workspace, len);
1329                 } else {
1330                         ast_log(LOG_ERROR, "Function %s cannot be read\n", function);
1331                 }
1332         } else {
1333                 ast_log(LOG_ERROR, "Function %s not registered\n", function);
1334         }
1335         return ret;
1336 }
1337
1338 void ast_func_write(struct ast_channel *chan, const char *in, const char *value)
1339 {
1340         char *args = NULL, *function, *p;
1341         struct ast_custom_function *acfptr;
1342
1343         function = ast_strdupa(in);
1344         if (!function) {
1345                 ast_log(LOG_ERROR, "Out of memory\n");
1346                 return;
1347         }
1348         if ((args = strchr(function, '('))) {
1349                 *args = '\0';
1350                 args++;
1351                 if ((p = strrchr(args, ')'))) {
1352                         *p = '\0';
1353                 } else {
1354                         ast_log(LOG_WARNING, "Can't find trailing parenthesis?\n");
1355                 }
1356         } else {
1357                 ast_log(LOG_WARNING, "Function doesn't contain parentheses.  Assuming null argument.\n");
1358         }
1359
1360         if ((acfptr = ast_custom_function_find(function))) {
1361                 /* run the custom function */
1362                 if (acfptr->write) {
1363                         acfptr->write(chan, function, args, value);
1364                 } else {
1365                         ast_log(LOG_ERROR, "Function %s is read-only, it cannot be written to\n", function);
1366                 }
1367         } else {
1368                 ast_log(LOG_ERROR, "Function %s not registered\n", function);
1369         }
1370 }
1371
1372 static void pbx_substitute_variables_helper_full(struct ast_channel *c, const char *cp1, char *cp2, int count, struct varshead *headp)
1373 {
1374         char *cp4;
1375         const char *tmp, *whereweare;
1376         int length;
1377         char workspace[4096];
1378         char ltmp[4096], var[4096];
1379         char *nextvar, *nextexp, *nextthing;
1380         char *vars, *vare;
1381         int pos, brackets, needsub, len;
1382         
1383         /* Substitutes variables into cp2, based on string cp1, and assuming cp2 to be
1384            zero-filled */
1385         whereweare=tmp=cp1;
1386         while(!ast_strlen_zero(whereweare) && count) {
1387                 /* Assume we're copying the whole remaining string */
1388                 pos = strlen(whereweare);
1389                 nextvar = NULL;
1390                 nextexp = NULL;
1391                 nextthing = strchr(whereweare, '$');
1392                 if (nextthing) {
1393                         switch(nextthing[1]) {
1394                         case '{':
1395                                 nextvar = nextthing;
1396                                 break;
1397                         case '[':
1398                                 nextexp = nextthing;
1399                                 break;
1400                         }
1401                 }
1402                 /* If there is one, we only go that far */
1403                 if (nextvar)
1404                         pos = nextvar - whereweare;
1405                 else if (nextexp)
1406                         pos = nextexp - whereweare;
1407
1408                 /* Can't copy more than 'count' bytes */
1409                 if (pos > count)
1410                         pos = count;
1411
1412                 /* Copy that many bytes */
1413                 memcpy(cp2, whereweare, pos);
1414
1415                 count -= pos;
1416                 cp2 += pos;
1417                 whereweare += pos;
1418                 
1419                 if (nextvar) {
1420                         /* We have a variable.  Find the start and end, and determine
1421                            if we are going to have to recursively call ourselves on the
1422                            contents */
1423                         vars = vare = nextvar + 2;
1424                         brackets = 1;
1425                         needsub = 0;
1426
1427                         /* Find the end of it */
1428                         while(brackets && *vare) {
1429                                 if ((vare[0] == '$') && (vare[1] == '{')) {
1430                                         needsub++;
1431                                         brackets++;
1432                                 } else if (vare[0] == '}') {
1433                                         brackets--;
1434                                 } else if ((vare[0] == '$') && (vare[1] == '['))
1435                                         needsub++;
1436                                 vare++;
1437                         }
1438                         if (brackets)
1439                                 ast_log(LOG_NOTICE, "Error in extension logic (missing '}')\n");
1440                         len = vare - vars - 1;
1441
1442                         /* Skip totally over variable name */
1443                         whereweare += (len + 3);
1444
1445                         /* Store variable name (and truncate) */
1446                         memset(var, 0, sizeof(var));
1447                         ast_copy_string(var, vars, sizeof(var));
1448                         var[len] = '\0';
1449
1450                         /* Substitute if necessary */
1451                         if (needsub) {
1452                                 memset(ltmp, 0, sizeof(ltmp));
1453                                 pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1);
1454                                 vars = ltmp;
1455                         } else {
1456                                 vars = var;
1457                         }
1458
1459                         workspace[0] = '\0';
1460
1461                         if (var[len - 1] == ')') {
1462                                 /* Evaluate function */
1463                                 cp4 = ast_func_read(c, vars, workspace, sizeof(workspace));
1464
1465                                 ast_log(LOG_DEBUG, "Function result is '%s'\n", cp4 ? cp4 : "(null)");
1466                         } else {
1467                                 /* Retrieve variable value */
1468                                 pbx_retrieve_variable(c, vars, &cp4, workspace, sizeof(workspace), headp);
1469                         }
1470                         if (cp4) {
1471                                 length = strlen(cp4);
1472                                 if (length > count)
1473                                         length = count;
1474                                 memcpy(cp2, cp4, length);
1475                                 count -= length;
1476                                 cp2 += length;
1477                         }
1478                 } else if (nextexp) {
1479                         /* We have an expression.  Find the start and end, and determine
1480                            if we are going to have to recursively call ourselves on the
1481                            contents */
1482                         vars = vare = nextexp + 2;
1483                         brackets = 1;
1484                         needsub = 0;
1485
1486                         /* Find the end of it */
1487                         while(brackets && *vare) {
1488                                 if ((vare[0] == '$') && (vare[1] == '[')) {
1489                                         needsub++;
1490                                         brackets++;
1491                                         vare++;
1492                                 } else if (vare[0] == '[') {
1493                                         brackets++;
1494                                 } else if (vare[0] == ']') {
1495                                         brackets--;
1496                                 } else if ((vare[0] == '$') && (vare[1] == '{')) {
1497                                         needsub++;
1498                                         vare++;
1499                                 }
1500                                 vare++;
1501                         }
1502                         if (brackets)
1503                                 ast_log(LOG_NOTICE, "Error in extension logic (missing ']')\n");
1504                         len = vare - vars - 1;
1505                         
1506                         /* Skip totally over variable name */
1507                         whereweare += ( len + 3);
1508                         
1509                         /* Store variable name (and truncate) */
1510                         memset(var, 0, sizeof(var));
1511                         ast_copy_string(var, vars, sizeof(var));
1512                         var[len] = '\0';
1513                         
1514                         /* Substitute if necessary */
1515                         if (needsub) {
1516                                 memset(ltmp, 0, sizeof(ltmp));
1517                                 pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1);
1518                                 vars = ltmp;
1519                         } else {
1520                                 vars = var;
1521                         }
1522
1523                         /* Evaluate expression */                       
1524                         cp4 = ast_expr(vars);
1525                         
1526                         ast_log(LOG_DEBUG, "Expression is '%s'\n", cp4);
1527                         
1528                         if (cp4) {
1529                                 length = strlen(cp4);
1530                                 if (length > count)
1531                                         length = count;
1532                                 memcpy(cp2, cp4, length);
1533                                 count -= length;
1534                                 cp2 += length;
1535                                 free(cp4);
1536                         }
1537                 } else
1538                         break;
1539         }
1540 }
1541
1542 void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
1543 {
1544         pbx_substitute_variables_helper_full(c, cp1, cp2, count, NULL);
1545 }
1546
1547 void pbx_substitute_variables_varshead(struct varshead *headp, const char *cp1, char *cp2, int count)
1548 {
1549         pbx_substitute_variables_helper_full(NULL, cp1, cp2, count, headp);
1550 }
1551
1552 static void pbx_substitute_variables(char *passdata, int datalen, struct ast_channel *c, struct ast_exten *e)
1553 {
1554         memset(passdata, 0, datalen);
1555                 
1556         /* No variables or expressions in e->data, so why scan it? */
1557         if (!strstr(e->data,"${") && !strstr(e->data,"$[") && !strstr(e->data,"$(")) {
1558                 ast_copy_string(passdata, e->data, datalen);
1559                 passdata[datalen-1] = '\0';
1560                 return;
1561         }
1562         
1563         pbx_substitute_variables_helper(c, e->data, passdata, datalen - 1);
1564 }                                                               
1565
1566 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) 
1567 {
1568         struct ast_exten *e;
1569         struct ast_app *app;
1570         struct ast_switch *sw;
1571         char *data;
1572         const char *foundcontext=NULL;
1573         int newstack = 0;
1574         int res;
1575         int status = 0;
1576         char *incstack[AST_PBX_MAX_STACK];
1577         char passdata[EXT_DATA_SIZE];
1578         int stacklen = 0;
1579         char tmp[80];
1580         char tmp2[80];
1581         char tmp3[EXT_DATA_SIZE];
1582         char atmp[80];
1583         char atmp2[EXT_DATA_SIZE+100];
1584
1585         if (ast_mutex_lock(&conlock)) {
1586                 ast_log(LOG_WARNING, "Unable to obtain lock\n");
1587                 if ((action == HELPER_EXISTS) || (action == HELPER_CANMATCH) || (action == HELPER_MATCHMORE))
1588                         return 0;
1589                 else
1590                         return -1;
1591         }
1592         e = pbx_find_extension(c, con, context, exten, priority, label, callerid, action, incstack, &stacklen, &status, &sw, &data, &foundcontext);
1593         if (e) {
1594                 switch(action) {
1595                 case HELPER_CANMATCH:
1596                         ast_mutex_unlock(&conlock);
1597                         return -1;
1598                 case HELPER_EXISTS:
1599                         ast_mutex_unlock(&conlock);
1600                         return -1;
1601                 case HELPER_FINDLABEL:
1602                         res = e->priority;
1603                         ast_mutex_unlock(&conlock);
1604                         return res;
1605                 case HELPER_MATCHMORE:
1606                         ast_mutex_unlock(&conlock);
1607                         return -1;
1608                 case HELPER_SPAWN:
1609                         newstack++;
1610                         /* Fall through */
1611                 case HELPER_EXEC:
1612                         app = pbx_findapp(e->app);
1613                         ast_mutex_unlock(&conlock);
1614                         if (app) {
1615                                 if (c->context != context)
1616                                         ast_copy_string(c->context, context, sizeof(c->context));
1617                                 if (c->exten != exten)
1618                                         ast_copy_string(c->exten, exten, sizeof(c->exten));
1619                                 c->priority = priority;
1620                                 pbx_substitute_variables(passdata, sizeof(passdata), c, e);
1621                                 if (option_debug) {
1622                                                 ast_log(LOG_DEBUG, "Launching '%s'\n", app->name);
1623                                                 snprintf(atmp, 80, "STACK-%s-%s-%d", context, exten, priority);
1624                                                 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"));
1625                                                 pbx_builtin_setvar_helper(c, atmp, atmp2);
1626                                 }
1627                                 if (option_verbose > 2)
1628                                                 ast_verbose( VERBOSE_PREFIX_3 "Executing %s(\"%s\", \"%s\") %s\n", 
1629                                                                 term_color(tmp, app->name, COLOR_BRCYAN, 0, sizeof(tmp)),
1630                                                                 term_color(tmp2, c->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
1631                                                                 term_color(tmp3, (!ast_strlen_zero(passdata) ? (char *)passdata : ""), COLOR_BRMAGENTA, 0, sizeof(tmp3)),
1632                                                                 (newstack ? "in new stack" : "in same stack"));
1633                                 manager_event(EVENT_FLAG_CALL, "Newexten", 
1634                                         "Channel: %s\r\n"
1635                                         "Context: %s\r\n"
1636                                         "Extension: %s\r\n"
1637                                         "Priority: %d\r\n"
1638                                         "Application: %s\r\n"
1639                                         "AppData: %s\r\n"
1640                                         "Uniqueid: %s\r\n",
1641                                         c->name, c->context, c->exten, c->priority, app->name, passdata ? passdata : "(NULL)", c->uniqueid);
1642                                 res = pbx_exec(c, app, passdata, newstack);
1643                                 return res;
1644                         } else {
1645                                 ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
1646                                 return -1;
1647                         }
1648                 default:
1649                         ast_log(LOG_WARNING, "Huh (%d)?\n", action);                    return -1;
1650                 }
1651         } else if (sw) {
1652                 switch(action) {
1653                 case HELPER_CANMATCH:
1654                         ast_mutex_unlock(&conlock);
1655                         return -1;
1656                 case HELPER_EXISTS:
1657                         ast_mutex_unlock(&conlock);
1658                         return -1;
1659                 case HELPER_MATCHMORE:
1660                         ast_mutex_unlock(&conlock);
1661                         return -1;
1662                 case HELPER_FINDLABEL:
1663                         ast_mutex_unlock(&conlock);
1664                         return -1;
1665                 case HELPER_SPAWN:
1666                         newstack++;
1667                         /* Fall through */
1668                 case HELPER_EXEC:
1669                         ast_mutex_unlock(&conlock);
1670                         if (sw->exec)
1671                                 res = sw->exec(c, foundcontext ? foundcontext : context, exten, priority, callerid, newstack, data);
1672                         else {
1673                                 ast_log(LOG_WARNING, "No execution engine for switch %s\n", sw->name);
1674                                 res = -1;
1675                         }
1676                         return res;
1677                 default:
1678                         ast_log(LOG_WARNING, "Huh (%d)?\n", action);
1679                         return -1;
1680                 }
1681         } else {
1682                 ast_mutex_unlock(&conlock);
1683                 switch(status) {
1684                 case STATUS_NO_CONTEXT:
1685                         if ((action != HELPER_EXISTS) && (action != HELPER_MATCHMORE))
1686                                 ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", context);
1687                         break;
1688                 case STATUS_NO_EXTENSION:
1689                         if ((action != HELPER_EXISTS) && (action !=  HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1690                                 ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, context);
1691                         break;
1692                 case STATUS_NO_PRIORITY:
1693                         if ((action != HELPER_EXISTS) && (action !=  HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1694                                 ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, context);
1695                         break;
1696                 case STATUS_NO_LABEL:
1697                         if (context)
1698                                 ast_log(LOG_NOTICE, "No such label '%s' in extension '%s' in context '%s'\n", label, exten, context);
1699                         break;
1700                 default:
1701                         ast_log(LOG_DEBUG, "Shouldn't happen!\n");
1702                 }
1703                 
1704                 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1705                         return -1;
1706                 else
1707                         return 0;
1708         }
1709
1710 }
1711
1712 /*--- ast_hint_extension: Find hint for given extension in context */
1713 static struct ast_exten *ast_hint_extension(struct ast_channel *c, const char *context, const char *exten)
1714 {
1715         struct ast_exten *e;
1716         struct ast_switch *sw;
1717         char *data;
1718         const char *foundcontext = NULL;
1719         int status = 0;
1720         char *incstack[AST_PBX_MAX_STACK];
1721         int stacklen = 0;
1722
1723         if (ast_mutex_lock(&conlock)) {
1724                 ast_log(LOG_WARNING, "Unable to obtain lock\n");
1725                 return NULL;
1726         }
1727         e = pbx_find_extension(c, NULL, context, exten, PRIORITY_HINT, NULL, "", HELPER_EXISTS, incstack, &stacklen, &status, &sw, &data, &foundcontext);
1728         ast_mutex_unlock(&conlock);     
1729         return e;
1730 }
1731
1732 /*--- ast_extensions_state2: Check state of extension by using hints */
1733 static int ast_extension_state2(struct ast_exten *e)
1734 {
1735         char hint[AST_MAX_EXTENSION] = "";    
1736         char *cur, *rest;
1737         int res = -1;
1738         int allunavailable = 1, allbusy = 1, allfree = 1;
1739         int busy = 0;
1740
1741         if (!e)
1742                 return -1;
1743
1744         ast_copy_string(hint, ast_get_extension_app(e), sizeof(hint));
1745
1746         cur = hint;     /* On or more devices separated with a & character */
1747         do {
1748                 rest = strchr(cur, '&');
1749                 if (rest) {
1750                         *rest = 0;
1751                         rest++;
1752                 }
1753         
1754                 res = ast_device_state(cur);
1755                 switch (res) {
1756                 case AST_DEVICE_NOT_INUSE:
1757                         allunavailable = 0;
1758                         allbusy = 0;
1759                         break;
1760                 case AST_DEVICE_INUSE:
1761                         return AST_EXTENSION_INUSE;
1762                 case AST_DEVICE_BUSY:
1763                         allunavailable = 0;
1764                         allfree = 0;
1765                         busy = 1;
1766                         break;
1767                 case AST_DEVICE_UNAVAILABLE:
1768                 case AST_DEVICE_INVALID:
1769                         allbusy = 0;
1770                         allfree = 0;
1771                         break;
1772                 default:
1773                         allunavailable = 0;
1774                         allbusy = 0;
1775                         allfree = 0;
1776                 }
1777                 cur = rest;
1778         } while (cur);
1779
1780         if (allfree)                    
1781                 return AST_EXTENSION_NOT_INUSE;
1782         if (allbusy)            
1783                 return AST_EXTENSION_BUSY;
1784         if (allunavailable)
1785                 return AST_EXTENSION_UNAVAILABLE;
1786         if (busy) 
1787                 return AST_EXTENSION_INUSE;
1788         
1789         return AST_EXTENSION_NOT_INUSE;
1790 }
1791
1792
1793 /*--- ast_extension_state: Check extension state for an extension by using hint */
1794 int ast_extension_state(struct ast_channel *c, char *context, char *exten)
1795 {
1796         struct ast_exten *e;
1797
1798         e = ast_hint_extension(c, context, exten);      /* Do we have a hint for this extension ? */ 
1799         if (!e) 
1800                 return -1;                              /* No hint, return -1 */
1801
1802         return ast_extension_state2(e);                 /* Check all devices in the hint */
1803 }
1804
1805 void ast_hint_state_changed(const char *device)
1806 {
1807         struct ast_hint *hint;
1808         struct ast_state_cb *cblist;
1809         char buf[AST_MAX_EXTENSION];
1810         char *parse;
1811         char *cur;
1812         int state;
1813
1814         ast_mutex_lock(&hintlock);
1815
1816         for (hint = hints; hint; hint = hint->next) {
1817                 ast_copy_string(buf, ast_get_extension_app(hint->exten), sizeof(buf));
1818                 parse = buf;
1819                 for (cur = strsep(&parse, "&"); cur; cur = strsep(&parse, "&")) {
1820                         if (strcmp(cur, device))
1821                                 continue;
1822
1823                         /* Get device state for this hint */
1824                         state = ast_extension_state2(hint->exten);
1825                         
1826                         if ((state == -1) || (state == hint->laststate))
1827                                 continue;
1828
1829                         /* Device state changed since last check - notify the watchers */
1830                         
1831                         /* For general callbacks */
1832                         for (cblist = statecbs; cblist; cblist = cblist->next)
1833                                 cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data);
1834                         
1835                         /* For extension callbacks */
1836                         for (cblist = hint->callbacks; cblist; cblist = cblist->next)
1837                                 cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data);
1838                         
1839                         hint->laststate = state;
1840                         break;
1841                 }
1842         }
1843
1844         ast_mutex_unlock(&hintlock);
1845 }
1846                         
1847 /*--- ast_extension_state_add: Add watcher for extension states */
1848 int ast_extension_state_add(const char *context, const char *exten, 
1849                             ast_state_cb_type callback, void *data)
1850 {
1851         struct ast_hint *list;
1852         struct ast_state_cb *cblist;
1853         struct ast_exten *e;
1854
1855         /* If there's no context and extension:  add callback to statecbs list */
1856         if (!context && !exten) {
1857                 ast_mutex_lock(&hintlock);
1858
1859                 cblist = statecbs;
1860                 while (cblist) {
1861                         if (cblist->callback == callback) {
1862                                 cblist->data = data;
1863                                 ast_mutex_unlock(&hintlock);
1864                                 return 0;
1865                         }
1866                         cblist = cblist->next;
1867                 }
1868         
1869                 /* Now insert the callback */
1870                 cblist = malloc(sizeof(struct ast_state_cb));
1871                 if (!cblist) {
1872                         ast_mutex_unlock(&hintlock);
1873                         return -1;
1874                 }
1875                 memset(cblist, 0, sizeof(struct ast_state_cb));
1876                 cblist->id = 0;
1877                 cblist->callback = callback;
1878                 cblist->data = data;
1879         
1880                 cblist->next = statecbs;
1881                 statecbs = cblist;
1882
1883                 ast_mutex_unlock(&hintlock);
1884                 return 0;
1885         }
1886
1887         if (!context || !exten)
1888                 return -1;
1889
1890         /* This callback type is for only one hint, so get the hint */
1891         e = ast_hint_extension(NULL, context, exten);    
1892         if (!e) {
1893                 return -1;
1894         }
1895
1896         /* Find the hint in the list of hints */
1897         ast_mutex_lock(&hintlock);
1898         list = hints;        
1899
1900         while (list) {
1901                 if (list->exten == e)
1902                         break;      
1903                 list = list->next;    
1904         }
1905
1906         if (!list) {
1907                 /* We have no hint, sorry */
1908                 ast_mutex_unlock(&hintlock);
1909                 return -1;
1910         }
1911
1912         /* Now insert the callback in the callback list  */
1913         cblist = malloc(sizeof(struct ast_state_cb));
1914         if (!cblist) {
1915                 ast_mutex_unlock(&hintlock);
1916                 return -1;
1917         }
1918         memset(cblist, 0, sizeof(struct ast_state_cb));
1919         cblist->id = stateid++;         /* Unique ID for this callback */
1920         cblist->callback = callback;    /* Pointer to callback routine */
1921         cblist->data = data;            /* Data for the callback */
1922
1923         cblist->next = list->callbacks;
1924         list->callbacks = cblist;
1925
1926         ast_mutex_unlock(&hintlock);
1927         return cblist->id;
1928 }
1929
1930 /*--- ast_extension_state_del: Remove a watcher from the callback list */
1931 int ast_extension_state_del(int id, ast_state_cb_type callback)
1932 {
1933         struct ast_hint *list;
1934         struct ast_state_cb *cblist, *cbprev;
1935
1936         if (!id && !callback)
1937                 return -1;
1938
1939         ast_mutex_lock(&hintlock);
1940
1941         /* id is zero is a callback without extension */
1942         if (!id) {
1943                 cbprev = NULL;
1944                 cblist = statecbs;
1945                 while (cblist) {
1946                         if (cblist->callback == callback) {
1947                                 if (!cbprev)
1948                                         statecbs = cblist->next;
1949                                 else
1950                                         cbprev->next = cblist->next;
1951
1952                                 free(cblist);
1953
1954                                 ast_mutex_unlock(&hintlock);
1955                                 return 0;
1956                         }
1957                         cbprev = cblist;
1958                         cblist = cblist->next;
1959                 }
1960
1961                 ast_mutex_lock(&hintlock);
1962                 return -1;
1963         }
1964
1965         /* id greater than zero is a callback with extension */
1966         /* Find the callback based on ID */
1967         list = hints;
1968         while (list) {
1969                 cblist = list->callbacks;
1970                 cbprev = NULL;
1971                 while (cblist) {
1972                         if (cblist->id==id) {
1973                                 if (!cbprev)
1974                                         list->callbacks = cblist->next;         
1975                                 else
1976                                         cbprev->next = cblist->next;
1977                 
1978                                 free(cblist);
1979                 
1980                                 ast_mutex_unlock(&hintlock);
1981                                 return 0;               
1982                         }               
1983                         cbprev = cblist;                                
1984                         cblist = cblist->next;
1985                 }
1986                 list = list->next;
1987         }
1988
1989         ast_mutex_unlock(&hintlock);
1990         return -1;
1991 }
1992
1993 /*--- ast_add_hint: Add hint to hint list, check initial extension state */
1994 static int ast_add_hint(struct ast_exten *e)
1995 {
1996         struct ast_hint *list;
1997
1998         if (!e) 
1999                 return -1;
2000
2001         ast_mutex_lock(&hintlock);
2002         list = hints;        
2003
2004         /* Search if hint exists, do nothing */
2005         while (list) {
2006                 if (list->exten == e) {
2007                         ast_mutex_unlock(&hintlock);
2008                         if (option_debug > 1)
2009                                 ast_log(LOG_DEBUG, "HINTS: Not re-adding existing hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
2010                         return -1;
2011                 }
2012                 list = list->next;    
2013         }
2014
2015         if (option_debug > 1)
2016                 ast_log(LOG_DEBUG, "HINTS: Adding hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
2017
2018         list = malloc(sizeof(struct ast_hint));
2019         if (!list) {
2020                 ast_mutex_unlock(&hintlock);
2021                 if (option_debug > 1)
2022                         ast_log(LOG_DEBUG, "HINTS: Out of memory...\n");
2023                 return -1;
2024         }
2025         /* Initialize and insert new item at the top */
2026         memset(list, 0, sizeof(struct ast_hint));
2027         list->exten = e;
2028         list->laststate = ast_extension_state2(e);
2029         list->next = hints;
2030         hints = list;
2031
2032         ast_mutex_unlock(&hintlock);
2033         return 0;
2034 }
2035
2036 /*--- ast_change_hint: Change hint for an extension */
2037 static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
2038
2039         struct ast_hint *list;
2040
2041         ast_mutex_lock(&hintlock);
2042         list = hints;
2043
2044         while(list) {
2045                 if (list->exten == oe) {
2046                         list->exten = ne;
2047                         ast_mutex_unlock(&hintlock);    
2048                         return 0;
2049                 }
2050                 list = list->next;
2051         }
2052         ast_mutex_unlock(&hintlock);
2053
2054         return -1;
2055 }
2056
2057 /*--- ast_remove_hint: Remove hint from extension */
2058 static int ast_remove_hint(struct ast_exten *e)
2059 {
2060         /* Cleanup the Notifys if hint is removed */
2061         struct ast_hint *list, *prev = NULL;
2062         struct ast_state_cb *cblist, *cbprev;
2063
2064         if (!e) 
2065                 return -1;
2066
2067         ast_mutex_lock(&hintlock);
2068
2069         list = hints;    
2070         while(list) {
2071                 if (list->exten==e) {
2072                         cbprev = NULL;
2073                         cblist = list->callbacks;
2074                         while (cblist) {
2075                                 /* Notify with -1 and remove all callbacks */
2076                                 cbprev = cblist;            
2077                                 cblist = cblist->next;
2078                                 cbprev->callback(list->exten->parent->name, list->exten->exten, -1, cbprev->data);
2079                                 free(cbprev);
2080                         }
2081                         list->callbacks = NULL;
2082
2083                         if (!prev)
2084                                 hints = list->next;
2085                         else
2086                                 prev->next = list->next;
2087                         free(list);
2088             
2089                         ast_mutex_unlock(&hintlock);
2090                         return 0;
2091                 } else {
2092                         prev = list;
2093                         list = list->next;    
2094                 }
2095         }
2096
2097         ast_mutex_unlock(&hintlock);
2098         return -1;
2099 }
2100
2101
2102 /*--- ast_get_hint: Get hint for channel */
2103 int ast_get_hint(char *hint, int hintsize, char *name, int namesize, struct ast_channel *c, const char *context, const char *exten)
2104 {
2105         struct ast_exten *e;
2106         void *tmp;
2107
2108         e = ast_hint_extension(c, context, exten);
2109         if (e) {
2110                 if (hint) 
2111                     ast_copy_string(hint, ast_get_extension_app(e), hintsize);
2112                 if (name) {
2113                         tmp = ast_get_extension_app_data(e);
2114                         if (tmp)
2115                                 ast_copy_string(name, (char *) tmp, namesize);
2116                 }
2117             return -1;
2118         }
2119         return 0;       
2120 }
2121
2122 int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid) 
2123 {
2124         return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_EXISTS);
2125 }
2126
2127 int ast_findlabel_extension(struct ast_channel *c, const char *context, const char *exten, const char *label, const char *callerid) 
2128 {
2129         return pbx_extension_helper(c, NULL, context, exten, 0, label, callerid, HELPER_FINDLABEL);
2130 }
2131
2132 int ast_findlabel_extension2(struct ast_channel *c, struct ast_context *con, const char *exten, const char *label, const char *callerid) 
2133 {
2134         return pbx_extension_helper(c, con, NULL, exten, 0, label, callerid, HELPER_FINDLABEL);
2135 }
2136
2137 int ast_canmatch_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
2138 {
2139         return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_CANMATCH);
2140 }
2141
2142 int ast_matchmore_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
2143 {
2144         return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_MATCHMORE);
2145 }
2146
2147 int ast_spawn_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid) 
2148 {
2149         return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_SPAWN);
2150 }
2151
2152 int ast_exec_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid) 
2153 {
2154         return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_EXEC);
2155 }
2156
2157 static int __ast_pbx_run(struct ast_channel *c)
2158 {
2159         int firstpass = 1;
2160         int digit;
2161         char exten[256];
2162         int pos;
2163         int waittime;
2164         int res=0;
2165         int autoloopflag;
2166
2167         /* A little initial setup here */
2168         if (c->pbx)
2169                 ast_log(LOG_WARNING, "%s already has PBX structure??\n", c->name);
2170         c->pbx = malloc(sizeof(struct ast_pbx));
2171         if (!c->pbx) {
2172                 ast_log(LOG_ERROR, "Out of memory\n");
2173                 return -1;
2174         }
2175         if (c->amaflags) {
2176                 if (!c->cdr) {
2177                         c->cdr = ast_cdr_alloc();
2178                         if (!c->cdr) {
2179                                 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
2180                                 free(c->pbx);
2181                                 return -1;
2182                         }
2183                         ast_cdr_init(c->cdr, c);
2184                 }
2185         }
2186         memset(c->pbx, 0, sizeof(struct ast_pbx));
2187         /* Set reasonable defaults */
2188         c->pbx->rtimeout = 10;
2189         c->pbx->dtimeout = 5;
2190
2191         autoloopflag = ast_test_flag(c, AST_FLAG_IN_AUTOLOOP);
2192         ast_set_flag(c, AST_FLAG_IN_AUTOLOOP);
2193
2194         /* Start by trying whatever the channel is set to */
2195         if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2196                 /* If not successful fall back to 's' */
2197                 if (option_verbose > 1)
2198                         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);
2199                 ast_copy_string(c->exten, "s", sizeof(c->exten));
2200                 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2201                         /* JK02: And finally back to default if everything else failed */
2202                         if (option_verbose > 1)
2203                                 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);
2204                         ast_copy_string(c->context, "default", sizeof(c->context));
2205                 }
2206                 c->priority = 1;
2207         }
2208         if (c->cdr && !c->cdr->start.tv_sec && !c->cdr->start.tv_usec)
2209                 ast_cdr_start(c->cdr);
2210         for(;;) {
2211                 pos = 0;
2212                 digit = 0;
2213                 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2214                         memset(exten, 0, sizeof(exten));
2215                         if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
2216                                 /* Something bad happened, or a hangup has been requested. */
2217                                 if (((res >= '0') && (res <= '9')) || ((res >= 'A') && (res <= 'F')) ||
2218                                         (res == '*') || (res == '#')) {
2219                                         ast_log(LOG_DEBUG, "Oooh, got something to jump out with ('%c')!\n", res);
2220                                         memset(exten, 0, sizeof(exten));
2221                                         pos = 0;
2222                                         exten[pos++] = digit = res;
2223                                         break;
2224                                 }
2225                                 switch(res) {
2226                                 case AST_PBX_KEEPALIVE:
2227                                         if (option_debug)
2228                                                 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
2229                                         else if (option_verbose > 1)
2230                                                 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
2231                                         goto out;
2232                                         break;
2233                                 default:
2234                                         if (option_debug)
2235                                                 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2236                                         else if (option_verbose > 1)
2237                                                 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2238                                         if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
2239                                                 c->_softhangup =0;
2240                                                 break;
2241                                         }
2242                                         /* atimeout */
2243                                         if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
2244                                                 break;
2245                                         }
2246
2247                                         if (c->cdr) {
2248                                                 ast_cdr_update(c);
2249                                         }
2250                                         goto out;
2251                                 }
2252                         }
2253                         if ((c->_softhangup == AST_SOFTHANGUP_TIMEOUT) && (ast_exists_extension(c,c->context,"T",1,c->cid.cid_num))) {
2254                                 ast_copy_string(c->exten, "T", sizeof(c->exten));
2255                                 /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
2256                                 c->whentohangup = 0;
2257                                 c->priority = 0;
2258                                 c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
2259                         } else if (c->_softhangup) {
2260                                 ast_log(LOG_DEBUG, "Extension %s, priority %d returned normally even though call was hung up\n",
2261                                         c->exten, c->priority);
2262                                 goto out;
2263                         }
2264                         firstpass = 0;
2265                         c->priority++;
2266                 }
2267                 if (!ast_exists_extension(c, c->context, c->exten, 1, c->cid.cid_num)) {
2268                         /* It's not a valid extension anymore */
2269                         if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
2270                                 if (option_verbose > 2)
2271                                         ast_verbose(VERBOSE_PREFIX_3 "Sent into invalid extension '%s' in context '%s' on %s\n", c->exten, c->context, c->name);
2272                                 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", c->exten);
2273                                 ast_copy_string(c->exten, "i", sizeof(c->exten));
2274                                 c->priority = 1;
2275                         } else {
2276                                 ast_log(LOG_WARNING, "Channel '%s' sent into invalid extension '%s' in context '%s', but no invalid handler\n",
2277                                         c->name, c->exten, c->context);
2278                                 goto out;
2279                         }
2280                 } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
2281                         /* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */
2282                         c->_softhangup = 0;
2283                 } else {
2284                         /* Done, wait for an extension */
2285                         waittime = 0;
2286                         if (digit)
2287                                 waittime = c->pbx->dtimeout;
2288                         else if (!autofallthrough)
2289                                 waittime = c->pbx->rtimeout;
2290                         if (waittime) {
2291                                 while (ast_matchmore_extension(c, c->context, exten, 1, c->cid.cid_num)) {
2292                                         /* As long as we're willing to wait, and as long as it's not defined, 
2293                                            keep reading digits until we can't possibly get a right answer anymore.  */
2294                                         digit = ast_waitfordigit(c, waittime * 1000);
2295                                         if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
2296                                                 c->_softhangup = 0;
2297                                         } else {
2298                                                 if (!digit)
2299                                                         /* No entry */
2300                                                         break;
2301                                                 if (digit < 0)
2302                                                         /* Error, maybe a  hangup */
2303                                                         goto out;
2304                                                 exten[pos++] = digit;
2305                                                 waittime = c->pbx->dtimeout;
2306                                         }
2307                                 }
2308                                 if (ast_exists_extension(c, c->context, exten, 1, c->cid.cid_num)) {
2309                                         /* Prepare the next cycle */
2310                                         ast_copy_string(c->exten, exten, sizeof(c->exten));
2311                                         c->priority = 1;
2312                                 } else {
2313                                         /* No such extension */
2314                                         if (!ast_strlen_zero(exten)) {
2315                                                 /* An invalid extension */
2316                                                 if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
2317                                                         if (option_verbose > 2)
2318                                                                 ast_verbose( VERBOSE_PREFIX_3 "Invalid extension '%s' in context '%s' on %s\n", exten, c->context, c->name);
2319                                                         pbx_builtin_setvar_helper(c, "INVALID_EXTEN", exten);
2320                                                         ast_copy_string(c->exten, "i", sizeof(c->exten));
2321                                                         c->priority = 1;
2322                                                 } else {
2323                                                         ast_log(LOG_WARNING, "Invalid extension '%s', but no rule 'i' in context '%s'\n", exten, c->context);
2324                                                         goto out;
2325                                                 }
2326                                         } else {
2327                                                 /* A simple timeout */
2328                                                 if (ast_exists_extension(c, c->context, "t", 1, c->cid.cid_num)) {
2329                                                         if (option_verbose > 2)
2330                                                                 ast_verbose( VERBOSE_PREFIX_3 "Timeout on %s\n", c->name);
2331                                                         ast_copy_string(c->exten, "t", sizeof(c->exten));
2332                                                         c->priority = 1;
2333                                                 } else {
2334                                                         ast_log(LOG_WARNING, "Timeout, but no rule 't' in context '%s'\n", c->context);
2335                                                         goto out;
2336                                                 }
2337                                         }       
2338                                 }
2339                                 if (c->cdr) {
2340                                         if (option_verbose > 2)
2341                                                 ast_verbose(VERBOSE_PREFIX_2 "CDR updated on %s\n",c->name);    
2342                                         ast_cdr_update(c);
2343                             }
2344                         } else {
2345                                 char *status;
2346
2347                                 status = pbx_builtin_getvar_helper(c, "DIALSTATUS");
2348                                 if (!status)
2349                                         status = "UNKNOWN";
2350                                 if (option_verbose > 2)
2351                                         ast_verbose(VERBOSE_PREFIX_2 "Auto fallthrough, channel '%s' status is '%s'\n", c->name, status);
2352                                 if (!strcasecmp(status, "CONGESTION"))
2353                                         res = pbx_builtin_congestion(c, "10");
2354                                 else if (!strcasecmp(status, "CHANUNAVAIL"))
2355                                         res = pbx_builtin_congestion(c, "10");
2356                                 else if (!strcasecmp(status, "BUSY"))
2357                                         res = pbx_builtin_busy(c, "10");
2358                                 goto out;
2359                         }
2360                 }
2361         }
2362         if (firstpass) 
2363                 ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", c->name);
2364 out:
2365         if ((res != AST_PBX_KEEPALIVE) && ast_exists_extension(c, c->context, "h", 1, c->cid.cid_num)) {
2366                 c->exten[0] = 'h';
2367                 c->exten[1] = '\0';
2368                 c->priority = 1;
2369                 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2370                         if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
2371                                 /* Something bad happened, or a hangup has been requested. */
2372                                 if (option_debug)
2373                                         ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2374                                 else if (option_verbose > 1)
2375                                         ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2376                                 break;
2377                         }
2378                         c->priority++;
2379                 }
2380         }
2381         ast_set2_flag(c, autoloopflag, AST_FLAG_IN_AUTOLOOP);
2382
2383         pbx_destroy(c->pbx);
2384         c->pbx = NULL;
2385         if (res != AST_PBX_KEEPALIVE)
2386                 ast_hangup(c);
2387         return 0;
2388 }
2389
2390 static void *pbx_thread(void *data)
2391 {
2392         /* Oh joyeous kernel, we're a new thread, with nothing to do but
2393            answer this channel and get it going.  The setjmp stuff is fairly
2394            confusing, but necessary to get smooth transitions between
2395            the execution of different applications (without the use of
2396            additional threads) */
2397         struct ast_channel *c = data;
2398         ast_pbx_run(c);
2399         pthread_exit(NULL);
2400         return NULL;
2401 }
2402
2403 int ast_pbx_start(struct ast_channel *c)
2404 {
2405         pthread_t t;
2406         pthread_attr_t attr;
2407         if (!c) {
2408                 ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
2409                 return -1;
2410         }
2411            
2412         /* Start a new thread, and get something handling this channel. */
2413         pthread_attr_init(&attr);
2414         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
2415         if (ast_pthread_create(&t, &attr, pbx_thread, c)) {
2416                 ast_log(LOG_WARNING, "Failed to create new channel thread\n");
2417                 return -1;
2418         }
2419         return 0;
2420 }
2421
2422 int ast_pbx_run(struct ast_channel *c)
2423 {
2424         int res = 0;
2425         ast_mutex_lock(&maxcalllock);
2426         if (option_maxcalls) {
2427                 if (countcalls >= option_maxcalls) {
2428                         ast_log(LOG_NOTICE, "Maximum call limit of %d calls exceeded by '%s'!\n", option_maxcalls, c->name);
2429                         res = -1;
2430                 }
2431         }
2432         if (!res)
2433                 countcalls++;   
2434         ast_mutex_unlock(&maxcalllock);
2435         if (!res) {
2436                 res = __ast_pbx_run(c);
2437                 ast_mutex_lock(&maxcalllock);
2438                 if (countcalls > 0)
2439                         countcalls--;
2440                 ast_mutex_unlock(&maxcalllock);
2441         }
2442         return res;
2443 }
2444
2445 int ast_active_calls(void)
2446 {
2447         return countcalls;
2448 }
2449
2450 int pbx_set_autofallthrough(int newval)
2451 {
2452         int oldval;
2453         oldval = autofallthrough;
2454         if (oldval != newval)
2455                 autofallthrough = newval;
2456         return oldval;
2457 }
2458
2459 /*
2460  * This function locks contexts list by &conlist, search for the right context
2461  * structure, leave context list locked and call ast_context_remove_include2
2462  * which removes include, unlock contexts list and return ...
2463  */
2464 int ast_context_remove_include(const char *context, const char *include, const char *registrar)
2465 {
2466         struct ast_context *c;
2467
2468         if (ast_lock_contexts()) return -1;
2469
2470         /* walk contexts and search for the right one ...*/
2471         c = ast_walk_contexts(NULL);
2472         while (c) {
2473                 /* we found one ... */
2474                 if (!strcmp(ast_get_context_name(c), context)) {
2475                         int ret;
2476                         /* remove include from this context ... */      
2477                         ret = ast_context_remove_include2(c, include, registrar);
2478
2479                         ast_unlock_contexts();
2480
2481                         /* ... return results */
2482                         return ret;
2483                 }
2484                 c = ast_walk_contexts(c);
2485         }
2486
2487         /* we can't find the right one context */
2488         ast_unlock_contexts();
2489         return -1;
2490 }
2491
2492 /*
2493  * When we call this function, &conlock lock must be locked, because when
2494  * we giving *con argument, some process can remove/change this context
2495  * and after that there can be segfault.
2496  *
2497  * This function locks given context, removes include, unlock context and
2498  * return.
2499  */
2500 int ast_context_remove_include2(struct ast_context *con, const char *include, const char *registrar)
2501 {
2502         struct ast_include *i, *pi = NULL;
2503
2504         if (ast_mutex_lock(&con->lock)) return -1;
2505
2506         /* walk includes */
2507         i = con->includes;
2508         while (i) {
2509                 /* find our include */
2510                 if (!strcmp(i->name, include) && 
2511                         (!registrar || !strcmp(i->registrar, registrar))) {
2512                         /* remove from list */
2513                         if (pi)
2514                                 pi->next = i->next;
2515                         else
2516                                 con->includes = i->next;
2517                         /* free include and return */
2518                         free(i);
2519                         ast_mutex_unlock(&con->lock);
2520                         return 0;
2521                 }
2522                 pi = i;
2523                 i = i->next;
2524         }
2525
2526         /* we can't find the right include */
2527         ast_mutex_unlock(&con->lock);
2528         return -1;
2529 }
2530
2531 /*
2532  * This function locks contexts list by &conlist, search for the rigt context
2533  * structure, leave context list locked and call ast_context_remove_switch2
2534  * which removes switch, unlock contexts list and return ...
2535  */
2536 int ast_context_remove_switch(const char *context, const char *sw, const char *data, const char *registrar)
2537 {
2538         struct ast_context *c;
2539
2540         if (ast_lock_contexts()) return -1;
2541
2542         /* walk contexts and search for the right one ...*/
2543         c = ast_walk_contexts(NULL);
2544         while (c) {
2545                 /* we found one ... */
2546                 if (!strcmp(ast_get_context_name(c), context)) {
2547                         int ret;
2548                         /* remove switch from this context ... */       
2549                         ret = ast_context_remove_switch2(c, sw, data, registrar);
2550
2551                         ast_unlock_contexts();
2552
2553                         /* ... return results */
2554                         return ret;
2555                 }
2556                 c = ast_walk_contexts(c);
2557         }
2558
2559         /* we can't find the right one context */
2560         ast_unlock_contexts();
2561         return -1;
2562 }
2563
2564 /*
2565  * When we call this function, &conlock lock must be locked, because when
2566  * we giving *con argument, some process can remove/change this context
2567  * and after that there can be segfault.
2568  *
2569  * This function locks given context, removes switch, unlock context and
2570  * return.
2571  */
2572 int ast_context_remove_switch2(struct ast_context *con, const char *sw, const char *data, const char *registrar)
2573 {
2574         struct ast_sw *i, *pi = NULL;
2575
2576         if (ast_mutex_lock(&con->lock)) return -1;
2577
2578         /* walk switchs */
2579         i = con->alts;
2580         while (i) {
2581                 /* find our switch */
2582                 if (!strcmp(i->name, sw) && !strcmp(i->data, data) && 
2583                         (!registrar || !strcmp(i->registrar, registrar))) {
2584                         /* remove from list */
2585                         if (pi)
2586                                 pi->next = i->next;
2587                         else
2588                                 con->alts = i->next;
2589                         /* free switch and return */
2590                         free(i);
2591                         ast_mutex_unlock(&con->lock);
2592                         return 0;
2593                 }
2594                 pi = i;
2595                 i = i->next;
2596         }
2597
2598         /* we can't find the right switch */
2599         ast_mutex_unlock(&con->lock);
2600         return -1;
2601 }
2602
2603 /*
2604  * This functions lock contexts list, search for the right context,
2605  * call ast_context_remove_extension2, unlock contexts list and return.
2606  * In this function we are using
2607  */
2608 int ast_context_remove_extension(const char *context, const char *extension, int priority, const char *registrar)
2609 {
2610         struct ast_context *c;
2611
2612         if (ast_lock_contexts()) return -1;
2613
2614         /* walk contexts ... */
2615         c = ast_walk_contexts(NULL);
2616         while (c) {
2617                 /* ... search for the right one ... */
2618                 if (!strcmp(ast_get_context_name(c), context)) {
2619                         /* ... remove extension ... */
2620                         int ret = ast_context_remove_extension2(c, extension, priority,
2621                                 registrar);
2622                         /* ... unlock contexts list and return */
2623                         ast_unlock_contexts();
2624                         return ret;
2625                 }
2626                 c = ast_walk_contexts(c);
2627         }
2628
2629         /* we can't find the right context */
2630         ast_unlock_contexts();
2631         return -1;
2632 }
2633
2634 /*
2635  * When do you want to call this function, make sure that &conlock is locked,
2636  * because some process can handle with your *con context before you lock
2637  * it.
2638  *
2639  * This functionc locks given context, search for the right extension and
2640  * fires out all peer in this extensions with given priority. If priority
2641  * is set to 0, all peers are removed. After that, unlock context and
2642  * return.
2643  */
2644 int ast_context_remove_extension2(struct ast_context *con, const char *extension, int priority, const char *registrar)
2645 {
2646         struct ast_exten *exten, *prev_exten = NULL;
2647
2648         if (ast_mutex_lock(&con->lock)) return -1;
2649
2650         /* go through all extensions in context and search the right one ... */
2651         exten = con->root;
2652         while (exten) {
2653
2654                 /* look for right extension */
2655                 if (!strcmp(exten->exten, extension) &&
2656                         (!registrar || !strcmp(exten->registrar, registrar))) {
2657                         struct ast_exten *peer;
2658
2659                         /* should we free all peers in this extension? (priority == 0)? */
2660                         if (priority == 0) {
2661                                 /* remove this extension from context list */
2662                                 if (prev_exten)
2663                                         prev_exten->next = exten->next;
2664                                 else
2665                                         con->root = exten->next;
2666
2667                                 /* fire out all peers */
2668                                 peer = exten; 
2669                                 while (peer) {
2670                                         exten = peer->peer;
2671                                         
2672                                         if (!peer->priority==PRIORITY_HINT) 
2673                                             ast_remove_hint(peer);
2674
2675                                         peer->datad(peer->data);
2676                                         free(peer);
2677
2678                                         peer = exten;
2679                                 }
2680
2681                                 ast_mutex_unlock(&con->lock);
2682                                 return 0;
2683                         } else {
2684                                 /* remove only extension with exten->priority == priority */
2685                                 struct ast_exten *previous_peer = NULL;
2686
2687                                 peer = exten;
2688                                 while (peer) {
2689                                         /* is this our extension? */
2690                                         if (peer->priority == priority &&
2691                                                 (!registrar || !strcmp(peer->registrar, registrar) )) {
2692                                                 /* we are first priority extension? */
2693                                                 if (!previous_peer) {
2694                                                         /* exists previous extension here? */
2695                                                         if (prev_exten) {
2696                                                                 /* yes, so we must change next pointer in
2697                                                                  * previous connection to next peer
2698                                                                  */
2699                                                                 if (peer->peer) {
2700                                                                         prev_exten->next = peer->peer;
2701                                                                         peer->peer->next = exten->next;
2702                                                                 } else
2703                                                                         prev_exten->next = exten->next;
2704                                                         } else {
2705                                                                 /* no previous extension, we are first
2706                                                                  * extension, so change con->root ...
2707                                                                  */
2708                                                                 if (peer->peer)
2709                                                                         con->root = peer->peer;
2710                                                                 else
2711                                                                         con->root = exten->next; 
2712                                                         }
2713                                                 } else {
2714                                                         /* we are not first priority in extension */
2715                                                         previous_peer->peer = peer->peer;
2716                                                 }
2717
2718                                                 /* now, free whole priority extension */
2719                                                 if (peer->priority==PRIORITY_HINT)
2720                                                     ast_remove_hint(peer);
2721                                                 peer->datad(peer->data);
2722                                                 free(peer);
2723
2724                                                 ast_mutex_unlock(&con->lock);
2725                                                 return 0;
2726                                         } else {
2727                                                 /* this is not right extension, skip to next peer */
2728                                                 previous_peer = peer;
2729                                                 peer = peer->peer;
2730                                         }
2731                                 }
2732
2733                                 ast_mutex_unlock(&con->lock);
2734                                 return -1;
2735                         }
2736                 }
2737
2738                 prev_exten = exten;
2739                 exten = exten->next;
2740         }
2741
2742         /* we can't find right extension */
2743         ast_mutex_unlock(&con->lock);
2744         return -1;
2745 }
2746
2747
2748 int ast_register_application(const char *app, int (*execute)(struct ast_channel *, void *), const char *synopsis, const char *description)
2749 {
2750         struct ast_app *tmp, *prev, *cur;
2751         char tmps[80];
2752         int length;
2753         length = sizeof(struct ast_app);
2754         length += strlen(app) + 1;
2755         if (ast_mutex_lock(&applock)) {
2756                 ast_log(LOG_ERROR, "Unable to lock application list\n");
2757                 return -1;
2758         }
2759         tmp = apps;
2760         while(tmp) {
2761                 if (!strcasecmp(app, tmp->name)) {
2762                         ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
2763                         ast_mutex_unlock(&applock);
2764                         return -1;
2765                 }
2766                 tmp = tmp->next;
2767         }
2768         tmp = malloc(length);
2769         if (tmp) {
2770                 memset(tmp, 0, length);
2771                 strcpy(tmp->name, app);
2772                 tmp->execute = execute;
2773                 tmp->synopsis = synopsis;
2774                 tmp->description = description;
2775                 /* Store in alphabetical order */
2776                 cur = apps;
2777                 prev = NULL;
2778                 while(cur) {
2779                         if (strcasecmp(tmp->name, cur->name) < 0)
2780                                 break;
2781                         prev = cur;
2782                         cur = cur->next;
2783                 }
2784                 if (prev) {
2785                         tmp->next = prev->next;
2786                         prev->next = tmp;
2787                 } else {
2788                         tmp->next = apps;
2789                         apps = tmp;
2790                 }
2791         } else {
2792                 ast_log(LOG_ERROR, "Out of memory\n");
2793                 ast_mutex_unlock(&applock);
2794                 return -1;
2795         }
2796         if (option_verbose > 1)
2797                 ast_verbose( VERBOSE_PREFIX_2 "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
2798         ast_mutex_unlock(&applock);
2799         return 0;
2800 }
2801
2802 int ast_register_switch(struct ast_switch *sw)
2803 {
2804         struct ast_switch *tmp, *prev=NULL;
2805         if (ast_mutex_lock(&switchlock)) {
2806                 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
2807                 return -1;
2808         }
2809         tmp = switches;
2810         while(tmp) {
2811                 if (!strcasecmp(tmp->name, sw->name))
2812                         break;
2813                 prev = tmp;
2814                 tmp = tmp->next;
2815         }
2816         if (tmp) {      
2817                 ast_mutex_unlock(&switchlock);
2818                 ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name);
2819                 return -1;
2820         }
2821         sw->next = NULL;
2822         if (prev) 
2823                 prev->next = sw;
2824         else
2825                 switches = sw;
2826         ast_mutex_unlock(&switchlock);
2827         return 0;
2828 }
2829
2830 void ast_unregister_switch(struct ast_switch *sw)
2831 {
2832         struct ast_switch *tmp, *prev=NULL;
2833         if (ast_mutex_lock(&switchlock)) {
2834                 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
2835                 return;
2836         }
2837         tmp = switches;
2838         while(tmp) {
2839                 if (tmp == sw) {
2840                         if (prev)
2841                                 prev->next = tmp->next;
2842                         else
2843                                 switches = tmp->next;
2844                         tmp->next = NULL;
2845                         break;                  
2846                 }
2847                 prev = tmp;
2848                 tmp = tmp->next;
2849         }
2850         ast_mutex_unlock(&switchlock);
2851 }
2852
2853 /*
2854  * Help for CLI commands ...
2855  */
2856 static char show_application_help[] = 
2857 "Usage: show application <application> [<application> [<application> [...]]]\n"
2858 "       Describes a particular application.\n";
2859
2860 static char show_functions_help[] =
2861 "Usage: show functions\n"
2862 "       List builtin functions accessable as $(function args)\n";
2863
2864 static char show_function_help[] =
2865 "Usage: show function <function>\n"
2866 "       Describe a particular dialplan function.\n";
2867
2868 static char show_applications_help[] =
2869 "Usage: show applications [{like|describing} <text>]\n"
2870 "       List applications which are currently available.\n"
2871 "       If 'like', <text> will be a substring of the app name\n"
2872 "       If 'describing', <text> will be a substring of the description\n";
2873
2874 static char show_dialplan_help[] =
2875 "Usage: show dialplan [exten@][context]\n"
2876 "       Show dialplan\n";
2877
2878 static char show_switches_help[] = 
2879 "Usage: show switches\n"
2880 "       Show registered switches\n";
2881
2882 static char show_hints_help[] = 
2883 "Usage: show hints\n"
2884 "       Show registered hints\n";
2885
2886
2887 /*
2888  * IMPLEMENTATION OF CLI FUNCTIONS IS IN THE SAME ORDER AS COMMANDS HELPS
2889  *
2890  */
2891
2892 /*
2893  * 'show application' CLI command implementation functions ...
2894  */
2895
2896 /*
2897  * There is a possibility to show informations about more than one
2898  * application at one time. You can type 'show application Dial Echo' and
2899  * you will see informations about these two applications ...
2900  */
2901 static char *complete_show_application(char *line, char *word,
2902         int pos, int state)
2903 {
2904         struct ast_app *a;
2905         int which = 0;
2906
2907         /* try to lock applications list ... */
2908         if (ast_mutex_lock(&applock)) {
2909                 ast_log(LOG_ERROR, "Unable to lock application list\n");
2910                 return NULL;
2911         }
2912
2913         /* ... walk all applications ... */
2914         a = apps; 
2915         while (a) {
2916                 /* ... check if word matches this application ... */
2917                 if (!strncasecmp(word, a->name, strlen(word))) {
2918                         /* ... if this is right app serve it ... */
2919                         if (++which > state) {
2920                                 char *ret = strdup(a->name);
2921                                 ast_mutex_unlock(&applock);
2922                                 return ret;
2923                         }
2924                 }
2925                 a = a->next; 
2926         }
2927
2928         /* no application match */
2929         ast_mutex_unlock(&applock);
2930         return NULL; 
2931 }
2932
2933 static int handle_show_application(int fd, int argc, char *argv[])
2934 {
2935         struct ast_app *a;
2936         int app, no_registered_app = 1;
2937
2938         if (argc < 3) return RESULT_SHOWUSAGE;
2939
2940         /* try to lock applications list ... */
2941         if (ast_mutex_lock(&applock)) {
2942                 ast_log(LOG_ERROR, "Unable to lock application list\n");
2943                 return -1;
2944         }
2945
2946         /* ... go through all applications ... */
2947         a = apps; 
2948         while (a) {
2949                 /* ... compare this application name with all arguments given
2950                  * to 'show application' command ... */
2951                 for (app = 2; app < argc; app++) {
2952                         if (!strcasecmp(a->name, argv[app])) {
2953                                 /* Maximum number of characters added by terminal coloring is 22 */
2954                                 char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
2955                                 char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
2956                                 int synopsis_size, description_size;
2957
2958                                 no_registered_app = 0;
2959
2960                                 if (a->synopsis)
2961                                         synopsis_size = strlen(a->synopsis) + 23;
2962                                 else
2963                                         synopsis_size = strlen("Not available") + 23;
2964                                 synopsis = alloca(synopsis_size);
2965
2966                                 if (a->description)
2967                                         description_size = strlen(a->description) + 23;
2968                                 else
2969                                         description_size = strlen("Not available") + 23;
2970                                 description = alloca(description_size);
2971
2972                                 if (synopsis && description) {
2973                                         snprintf(info, 64 + AST_MAX_APP, "\n  -= Info about application '%s' =- \n\n", a->name);
2974                                         term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
2975                                         term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
2976                                         term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
2977                                         term_color(synopsis,
2978                                                                         a->synopsis ? a->synopsis : "Not available",
2979                                                                         COLOR_CYAN, 0, synopsis_size);
2980                                         term_color(description,
2981                                                                         a->description ? a->description : "Not available",
2982                                                                         COLOR_CYAN, 0, description_size);
2983
2984                                         ast_cli(fd,"%s%s%s\n\n%s%s\n", infotitle, syntitle, synopsis, destitle, description);
2985                                 } else {
2986                                         /* ... one of our applications, show info ...*/
2987                                         ast_cli(fd,"\n  -= Info about application '%s' =- \n\n"
2988                                                 "[Synopsis]\n  %s\n\n"
2989                                                 "[Description]\n%s\n",
2990                                                 a->name,
2991                                                 a->synopsis ? a->synopsis : "Not available",
2992                                                 a->description ? a->description : "Not available");
2993                                 }
2994                         }
2995                 }
2996                 a = a->next; 
2997         }
2998
2999         ast_mutex_unlock(&applock);
3000
3001         /* we found at least one app? no? */
3002         if (no_registered_app) {
3003                 ast_cli(fd, "Your application(s) is (are) not registered\n");
3004                 return RESULT_FAILURE;
3005         }
3006
3007         return RESULT_SUCCESS;
3008 }
3009
3010 /*--- handle_show_hints: CLI support for listing registred dial plan hints */
3011 static int handle_show_hints(int fd, int argc, char *argv[])
3012 {
3013         struct ast_hint *hint;
3014         int num = 0;
3015
3016         if (!hints) {
3017                 ast_cli(fd, "There are no registered dialplan hints\n");
3018                 return RESULT_SUCCESS;
3019         }
3020         /* ... we have hints ... */
3021         ast_cli(fd, "\n    -= Registered Asterisk Dial Plan Hints =-\n");
3022         if (ast_mutex_lock(&hintlock)) {
3023                 ast_log(LOG_ERROR, "Unable to lock hints\n");
3024                 return -1;
3025         }
3026         hint = hints;
3027         while (hint) {
3028                 ast_cli(fd, "   %-20.20s: %-20.20s  State %2d\n", ast_get_extension_name(hint->exten), ast_get_extension_app(hint->exten), hint->laststate );
3029                 num++;
3030                 hint = hint->next;
3031         }
3032         ast_cli(fd, "----------------\n");
3033         ast_cli(fd, "- %d hints registred\n", num);
3034         ast_mutex_unlock(&hintlock);
3035         return RESULT_SUCCESS;
3036 }
3037
3038 /*--- handle_show_switches: CLI support for listing registred dial plan switches */
3039 static int handle_show_switches(int fd, int argc, char *argv[])
3040 {
3041         struct ast_switch *sw;
3042         if (!switches) {
3043                 ast_cli(fd, "There are no registered alternative switches\n");
3044                 return RESULT_SUCCESS;
3045         }
3046         /* ... we have applications ... */
3047         ast_cli(fd, "\n    -= Registered Asterisk Alternative Switches =-\n");
3048         if (ast_mutex_lock(&switchlock)) {
3049                 ast_log(LOG_ERROR, "Unable to lock switches\n");
3050                 return -1;
3051         }
3052         sw = switches;
3053         while (sw) {
3054                 ast_cli(fd, "%s: %s\n", sw->name, sw->description);
3055                 sw = sw->next;
3056         }
3057         ast_mutex_unlock(&switchlock);
3058         return RESULT_SUCCESS;
3059 }
3060
3061 /*
3062  * 'show applications' CLI command implementation functions ...
3063  */
3064 static int handle_show_applications(int fd, int argc, char *argv[])
3065 {
3066         struct ast_app *a;
3067         int like=0, describing=0;
3068         int total_match = 0;    /* Number of matches in like clause */
3069         int total_apps = 0;     /* Number of apps registered */
3070         
3071         /* try to lock applications list ... */
3072         if (ast_mutex_lock(&applock)) {
3073                 ast_log(LOG_ERROR, "Unable to lock application list\n");
3074                 return -1;
3075         }
3076
3077         /* ... have we got at least one application (first)? no? */
3078         if (!apps) {
3079                 ast_cli(fd, "There are no registered applications\n");
3080                 ast_mutex_unlock(&applock);
3081                 return -1;
3082         }
3083
3084         /* show applications like <keyword> */
3085         if ((argc == 4) && (!strcmp(argv[2], "like"))) {
3086                 like = 1;
3087         } else if ((argc > 3) && (!strcmp(argv[2], "describing"))) {
3088                 describing = 1;
3089         }
3090
3091         /* show applications describing <keyword1> [<keyword2>] [...] */
3092         if ((!like) && (!describing)) {
3093                 ast_cli(fd, "    -= Registered Asterisk Applications =-\n");
3094         } else {
3095                 ast_cli(fd, "    -= Matching Asterisk Applications =-\n");
3096         }
3097
3098         /* ... go through all applications ... */
3099         for (a = apps; a; a = a->next) {
3100                 /* ... show informations about applications ... */
3101                 int printapp=0;
3102                 total_apps++;
3103                 if (like) {
3104                         if (strcasestr(a->name, argv[3])) {
3105                                 printapp = 1;
3106                                 total_match++;
3107                         }
3108                 } else if (describing) {
3109                         if (a->description) {
3110                                 /* Match all words on command line */
3111                                 int i;
3112                                 printapp = 1;
3113                                 for (i=3; i<argc; i++) {
3114                                         if (!strcasestr(a->description, argv[i])) {
3115                                                 printapp = 0;
3116                                         } else {
3117                                                 total_match++;
3118                                         }
3119                                 }
3120                         }
3121                 } else {
3122                         printapp = 1;
3123                 }
3124
3125                 if (printapp) {
3126                         ast_cli(fd,"  %20s: %s\n", a->name, a->synopsis ? a->synopsis : "<Synopsis not available>");
3127                 }
3128         }
3129         if ((!like) && (!describing)) {
3130                 ast_cli(fd, "    -= %d Applications Registered =-\n",total_apps);
3131         } else {
3132                 ast_cli(fd, "    -= %d Applications Matching =-\n",total_match);
3133         }
3134         
3135         /* ... unlock and return */
3136         ast_mutex_unlock(&applock);
3137
3138         return RESULT_SUCCESS;
3139 }
3140
3141 static char *complete_show_applications(char *line, char *word, int pos, int state)
3142 {
3143         if (pos == 2) {
3144                 if (ast_strlen_zero(word)) {
3145                         switch (state) {
3146                         case 0:
3147                                 return strdup("like");
3148                         case 1:
3149                                 return strdup("describing");
3150                         default:
3151                                 return NULL;
3152                         }
3153                 } else if (! strncasecmp(word, "like", strlen(word))) {
3154                         if (state == 0) {
3155                                 return strdup("like");
3156                         } else {
3157                                 return NULL;
3158                         }
3159                 } else if (! strncasecmp(word, "describing", strlen(word))) {
3160                         if (state == 0) {
3161                                 return strdup("describing");
3162                         } else {
3163                                 return NULL;
3164                         }
3165                 }
3166         }
3167         return NULL;
3168 }
3169
3170 /*
3171  * 'show dialplan' CLI command implementation functions ...
3172  */
3173 static char *complete_show_dialplan_context(char *line, char *word, int pos,
3174         int state)
3175 {
3176         struct ast_context *c;
3177         int which = 0;
3178
3179         /* we are do completion of [exten@]context on second position only */
3180         if (pos != 2) return NULL;
3181
3182         /* try to lock contexts list ... */
3183         if (ast_lock_contexts()) {
3184                 ast_log(LOG_ERROR, "Unable to lock context list\n");
3185                 return NULL;
3186         }
3187
3188         /* ... walk through all contexts ... */
3189         c = ast_walk_contexts(NULL);
3190         while(c) {
3191                 /* ... word matches context name? yes? ... */
3192                 if (!strncasecmp(word, ast_get_context_name(c), strlen(word))) {
3193                         /* ... for serve? ... */
3194                         if (++which > state) {
3195                                 /* ... yes, serve this context name ... */
3196                                 char *ret = strdup(ast_get_context_name(c));
3197                                 ast_unlock_contexts();
3198                                 return ret;
3199                         }
3200                 }
3201                 c = ast_walk_contexts(c);
3202         }
3203
3204         /* ... unlock and return */
3205         ast_unlock_contexts();
3206         return NULL;
3207 }
3208
3209 struct dialplan_counters {
3210         int total_context;
3211         int total_exten;
3212         int total_prio;
3213         int context_existence;
3214         int extension_existence;
3215 };
3216
3217 static int show_dialplan_helper(int fd, char *context, char *exten, struct dialplan_counters *dpc, struct ast_include *rinclude)
3218 {
3219         struct ast_context *c;
3220         int res=0, old_total_exten = dpc->total_exten;
3221
3222         /* try to lock contexts */
3223         if (ast_lock_contexts()) {
3224                 ast_log(LOG_WARNING, "Failed to lock contexts list\n");
3225                 return -1;
3226         }
3227
3228         /* walk all contexts ... */
3229         for (c = ast_walk_contexts(NULL); c ; c = ast_walk_contexts(c)) {
3230                 /* show this context? */
3231                 if (!context ||
3232                         !strcmp(ast_get_context_name(c), context)) {
3233                         dpc->context_existence = 1;
3234
3235                         /* try to lock context before walking in ... */
3236                         if (!ast_lock_context(c)) {
3237                                 struct ast_exten *e;
3238                                 struct ast_include *i;
3239                                 struct ast_ignorepat *ip;
3240                                 struct ast_sw *sw;
3241                                 char buf[256], buf2[256];
3242                                 int context_info_printed = 0;
3243
3244                                 /* are we looking for exten too? if yes, we print context
3245                                  * if we our extension only
3246                                  */
3247                                 if (!exten) {
3248                                         dpc->total_context++;
3249                                         ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
3250                                                 ast_get_context_name(c), ast_get_context_registrar(c));
3251                                         context_info_printed = 1;
3252                                 }
3253
3254                                 /* walk extensions ... */
3255                                 for (e = ast_walk_context_extensions(c, NULL); e; e = ast_walk_context_extensions(c, e)) {
3256                                         struct ast_exten *p;
3257                                         int prio;
3258
3259                                         /* looking for extension? is this our extension? */
3260                                         if (exten &&
3261                                                 !ast_extension_match(ast_get_extension_name(e), exten))
3262                                         {
3263                                                 /* we are looking for extension and it's not our
3264                                                  * extension, so skip to next extension */
3265                                                 continue;
3266                                         }
3267
3268                                         dpc->extension_existence = 1;
3269
3270                                         /* may we print context info? */        
3271                                         if (!context_info_printed) {
3272                                                 dpc->total_context++;
3273                                                 if (rinclude) {
3274                                                         /* TODO Print more info about rinclude */
3275                                                         ast_cli(fd, "[ Included context '%s' created by '%s' ]\n",
3276                                                                 ast_get_context_name(c),
3277                                                                 ast_get_context_registrar(c));
3278                                                 } else {
3279                                                         ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
3280                                                                 ast_get_context_name(c),
3281                                                                 ast_get_context_registrar(c));
3282                                                 }
3283                                                 context_info_printed = 1;
3284                                         }
3285                                         dpc->total_prio++;
3286
3287                                         /* write extension name and first peer */       
3288                                         bzero(buf, sizeof(buf));                
3289                                         snprintf(buf, sizeof(buf), "'%s' =>",
3290                                                 ast_get_extension_name(e));
3291
3292                                         prio = ast_get_extension_priority(e);
3293                                         if (prio == PRIORITY_HINT) {
3294                                                 snprintf(buf2, sizeof(buf2),
3295                                                         "hint: %s",
3296                                                         ast_get_extension_app(e));
3297                                         } else {
3298                                                 snprintf(buf2, sizeof(buf2),
3299                                                         "%d. %s(%s)",
3300                                                         prio,
3301                                                         ast_get_extension_app(e),
3302                                                         (char *)ast_get_extension_app_data(e));
3303                                         }
3304
3305                                         ast_cli(fd, "  %-17s %-45s [%s]\n", buf, buf2,
3306                                                 ast_get_extension_registrar(e));
3307
3308                                         dpc->total_exten++;
3309                                         /* walk next extension peers */
3310                                         for (p=ast_walk_extension_priorities(e, e); p; p=ast_walk_extension_priorities(e, p)) {
3311                                                 dpc->total_prio++;
3312                                                 bzero((void *)buf2, sizeof(buf2));
3313                                                 bzero((void *)buf, sizeof(buf));
3314                                                 if (ast_get_extension_label(p))
3315                                                         snprintf(buf, sizeof(buf), "   [%s]", ast_get_extension_label(p));
3316                                                 prio = ast_get_extension_priority(p);
3317                                                 if (prio == PRIORITY_HINT) {
3318                                                         snprintf(buf2, sizeof(buf2),
3319                                                                 "hint: %s",
3320                                                                 ast_get_extension_app(p));
3321                                                 } else {
3322                                                         snprintf(buf2, sizeof(buf2),
3323                                                                 "%d. %s(%s)",
3324                                                                 prio,
3325                                                                 ast_get_extension_app(p),
3326                                                                 (char *)ast_get_extension_app_data(p));
3327                                                 }
3328
3329                                                 ast_cli(fd,"  %-17s %-45s [%s]\n",
3330                                                         buf, buf2,
3331                                                         ast_get_extension_registrar(p));
3332                                         }
3333                                 }
3334
3335                                 /* walk included and write info ... */
3336                                 for (i = ast_walk_context_includes(c, NULL); i; i = ast_walk_context_includes(c, i)) {
3337                                         bzero(buf, sizeof(buf));
3338                                         snprintf(buf, sizeof(buf), "'%s'",
3339                                                 ast_get_include_name(i));
3340                                         if (exten) {
3341                                                 /* Check all includes for the requested extension */
3342                                                 show_dialplan_helper(fd, (char *)ast_get_include_name(i), exten, dpc, i);
3343                                         } else {
3344                                                 ast_cli(fd, "  Include =>        %-45s [%s]\n",
3345                                                         buf, ast_get_include_registrar(i));
3346                                         }
3347                                 }
3348
3349                                 /* walk ignore patterns and write info ... */
3350                                 for (ip=ast_walk_context_ignorepats(c, NULL); ip; ip=ast_walk_context_ignorepats(c, ip)) {
3351                                         const char *ipname = ast_get_ignorepat_name(ip);
3352                                         char ignorepat[AST_MAX_EXTENSION];
3353                                         snprintf(buf, sizeof(buf), "'%s'", ipname);
3354                                         snprintf(ignorepat, sizeof(ignorepat), "_%s.", ipname);
3355                                         if ((!exten) || ast_extension_match(ignorepat, exten)) {
3356                                                 ast_cli(fd, "  Ignore pattern => %-45s [%s]\n",
3357                                                         buf, ast_get_ignorepat_registrar(ip));
3358                                         }
3359                                 }
3360                                 if (!rinclude) {
3361                                         for (sw = ast_walk_context_switches(c, NULL); sw; sw = ast_walk_context_switches(c, sw)) {
3362                                                 snprintf(buf, sizeof(buf), "'%s/%s'",
3363                                                         ast_get_switch_name(sw),
3364                                                         ast_get_switch_data(sw));
3365                                                 ast_cli(fd, "  Alt. Switch =>    %-45s [%s]\n",
3366                                                         buf, ast_get_switch_registrar(sw));     
3367                                         }
3368                                 }
3369         
3370                                 ast_unlock_context(c);
3371
3372                                 /* if we print something in context, make an empty line */
3373                                 if (context_info_printed) ast_cli(fd, "\r\n");
3374                         }
3375                 }
3376         }
3377         ast_unlock_contexts();
3378
3379         if (dpc->total_exten == old_total_exten) {
3380                 /* Nothing new under the sun */
3381                 return -1;
3382         } else {
3383                 return res;
3384         }
3385 }
3386
3387 static int handle_show_dialplan(int fd, int argc, char *argv[])
3388 {
3389         char *exten = NULL, *context = NULL;
3390         /* Variables used for different counters */
3391         struct dialplan_counters counters;
3392
3393         memset(&counters, 0, sizeof(counters));
3394
3395         if (argc != 2 && argc != 3) 
3396                 return RESULT_SHOWUSAGE;
3397
3398         /* we obtain [exten@]context? if yes, split them ... */
3399         if (argc == 3) {
3400                 char *splitter = ast_strdupa(argv[2]);
3401                 /* is there a '@' character? */
3402                 if (splitter &&