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