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