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