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