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