Fix serious typo (code segment was only enabled with verbose!)
[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_regex(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len) 
1187 {
1188         char *ret_true = "1", *ret_false = "0", *ret;
1189         char *arg, *tmp;
1190         regex_t regexbuf;
1191
1192         ret = ret_false; /* convince me otherwise */
1193         if ((tmp = ast_strdupa(data)) && (arg = strchr(tmp, '"')) && (data = strchr(arg+1, '"'))) {
1194                 arg++;
1195                 *data = '\0';
1196                 data++;
1197                 
1198                 if(data[0] == ' ') {
1199                         data++;
1200                 } else {
1201                         ast_log(LOG_WARNING, "Malformed input missing space in %s\n", cmd);
1202                         ret = ret_false;
1203                 }
1204                 
1205                 if (regcomp(&regexbuf, arg, REG_EXTENDED | REG_NOSUB)) {
1206                         ast_log(LOG_WARNING, "Malformed regex input %s\n", cmd);
1207                         ret = NULL;
1208                 }
1209                 ret = regexec(&regexbuf, data, 0, NULL, 0) ? ret_false : ret_true;
1210                 regfree(&regexbuf);
1211                 
1212                                 
1213         } else {
1214                 ast_log(LOG_WARNING, "Malformed input %s\n", cmd);
1215         }
1216
1217         return ret;
1218 }
1219
1220 static void pbx_substitute_variables_helper_full(struct ast_channel *c, const char *cp1, char *cp2, int count, struct varshead *headp)
1221 {
1222         char *cp4;
1223         const char *tmp, *whereweare;
1224         int length;
1225         char workspace[4096];
1226         char ltmp[4096], var[4096];
1227         char *nextvar, *nextexp, *nextfunc, *nextthing;
1228         char *vars, *vare;
1229         int pos, brackets, needsub, len, needfunc;
1230         
1231         /* Substitutes variables into cp2, based on string cp1, and assuming cp2 to be
1232            zero-filled */
1233         whereweare=tmp=cp1;
1234         while(!ast_strlen_zero(whereweare) && count) {
1235                 /* Assume we're copying the whole remaining string */
1236                 pos = strlen(whereweare);
1237                 nextvar = NULL;
1238                 nextexp = NULL;
1239                 nextfunc = NULL;
1240                 nextthing = strchr(whereweare, '$');
1241                 if (nextthing) {
1242                         switch(nextthing[1]) {
1243                         case '{':
1244                                 nextvar = nextthing;
1245                                 break;
1246                         case '[':
1247                                 nextexp = nextthing;
1248                                 break;
1249                         case '(':
1250                                 nextfunc = nextthing;
1251                                 break;
1252                         }
1253                 }
1254                 /* If there is one, we only go that far */
1255                 if (nextvar)
1256                         pos = nextvar - whereweare;
1257                 else if (nextexp)
1258                         pos = nextexp - whereweare;
1259                 else if (nextfunc) {
1260                         pos = nextfunc - whereweare;
1261                 }
1262                 /* Can't copy more than 'count' bytes */
1263                 if (pos > count)
1264                         pos = count;
1265                 
1266                 /* Copy that many bytes */
1267                 memcpy(cp2, whereweare, pos);
1268                 
1269                 count -= pos;
1270                 cp2 += pos;
1271                 whereweare += pos;
1272                 
1273                 if (nextvar) {
1274                         /* We have a variable.  Find the start and end, and determine
1275                            if we are going to have to recursively call ourselves on the
1276                            contents */
1277                         vars = vare = nextvar + 2;
1278                         brackets = 1;
1279                         needsub = 0;
1280                         
1281                         /* Find the end of it */
1282                         while(brackets && *vare) {
1283                                 if ((vare[0] == '$') && (vare[1] == '{')) {
1284                                         needsub++;
1285                                         brackets++;
1286                                 } else if (vare[0] == '}') {
1287                                         brackets--;
1288                                 } else if ((vare[0] == '$') && (vare[1] == '['))
1289                                         needsub++;
1290                                 vare++;
1291                         }
1292                         if (brackets)
1293                                 ast_log(LOG_NOTICE, "Error in extension logic (missing '}')\n");
1294                         len = vare - vars - 1;
1295                         
1296                         /* Skip totally over variable name */
1297                         whereweare += ( len + 3);
1298                         
1299                         /* Store variable name (and truncate) */
1300                         memset(var, 0, sizeof(var));
1301                         strncpy(var, vars, sizeof(var) - 1);
1302                         var[len] = '\0';
1303                         
1304                         /* Substitute if necessary */
1305                         if (needsub) {
1306                                 memset(ltmp, 0, sizeof(ltmp));
1307                                 pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1);
1308                                 vars = ltmp;
1309                         } else {
1310                                 vars = var;
1311                         }
1312                         
1313                         /* Retrieve variable value */
1314                         workspace[0] = '\0';
1315                         pbx_retrieve_variable(c,vars,&cp4, workspace, sizeof(workspace), headp);
1316                         if (cp4) {
1317                                 length = strlen(cp4);
1318                                 if (length > count)
1319                                         length = count;
1320                                 memcpy(cp2, cp4, length);
1321                                 count -= length;
1322                                 cp2 += length;
1323                         }
1324                         
1325                 } else if (nextexp) {
1326                         /* We have an expression.  Find the start and end, and determine
1327                            if we are going to have to recursively call ourselves on the
1328                            contents */
1329                         vars = vare = nextexp + 2;
1330                         brackets = 1;
1331                         needsub = 0;
1332                         needfunc = 0;
1333
1334                         /* Find the end of it */
1335                         while(brackets && *vare) {
1336                                 if ((vare[0] == '$') && (vare[1] == '[')) {
1337                                         needsub++;
1338                                         brackets++;
1339                                         vare++;
1340                                 } else if (vare[0] == '[') {
1341                                         brackets++;
1342                                 } else if (vare[0] == ']') {
1343                                         brackets--;
1344                                 } else if ((vare[0] == '$') && (vare[1] == '{')) {
1345                                         needsub++;
1346                                         vare++;
1347                                 } else if ((vare[0] == '$') && (vare[1] == '(')) {
1348                                         needfunc++;
1349                                         vare++;
1350                                 }
1351                                 vare++;
1352                         }
1353                         if (brackets)
1354                                 ast_log(LOG_NOTICE, "Error in extension logic (missing ']')\n");
1355                         len = vare - vars - 1;
1356                         
1357                         /* Skip totally over variable name */
1358                         whereweare += ( len + 3);
1359                         
1360                         /* Store variable name (and truncate) */
1361                         memset(var, 0, sizeof(var));
1362                         strncpy(var, vars, sizeof(var) - 1);
1363                         var[len] = '\0';
1364                         
1365                         /* Substitute if necessary */
1366                         if (needsub || needfunc) {
1367                                 memset(ltmp, 0, sizeof(ltmp));
1368                                 pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1);
1369                                 vars = ltmp;
1370                         } else {
1371                                 vars = var;
1372                         }
1373
1374                         /* Evaluate expression */                       
1375                         cp4 = ast_expr(vars);
1376                         
1377                         ast_log(LOG_DEBUG, "Expression is '%s'\n", cp4);
1378                         
1379                         if (cp4) {
1380                                 length = strlen(cp4);
1381                                 if (length > count)
1382                                         length = count;
1383                                 memcpy(cp2, cp4, length);
1384                                 count -= length;
1385                                 cp2 += length;
1386                                 free(cp4);
1387                         }
1388                 } else if (nextfunc) {
1389                         /* We have a function.  Find the start and end */
1390                         vars = vare = nextfunc + 2;
1391                         brackets = 1;
1392                         needsub = 0;
1393                         
1394                         /* Find the end of it */
1395                         while(brackets && *vare) {
1396                                 if ((vare[0] == '$') && (vare[1] == '(')) {
1397                                         needsub++;
1398                                         brackets++;
1399                                         vare++;
1400                                 } else if (vare[0] == '(') {
1401                                         brackets++;
1402                                 } else if (vare[0] == ')') {
1403                                         brackets--;
1404                                 } else if ((vare[0] == '$') && (vare[1] == '{')) {
1405                                         needsub++;
1406                                         vare++;
1407                                 }
1408                                 vare++;
1409                         }
1410                         if (brackets)
1411                                 ast_log(LOG_NOTICE, "Error in extension logic (missing ')')\n");
1412                         len = vare - vars - 1;
1413                         
1414                         /* Skip totally over variable name */
1415                         whereweare += ( len + 3);
1416                         
1417                         /* Store variable name (and truncate) */
1418                         memset(var, 0, sizeof(var));
1419                         strncpy(var, vars, sizeof(var) - 1);
1420                         var[len] = '\0';
1421                         
1422                         /* Substitute if necessary */
1423                         if (needsub) {
1424                                 memset(ltmp, 0, sizeof(ltmp));
1425                                 pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1);
1426                                 vars = ltmp;
1427                         } else {
1428                                 vars = var;
1429                         }
1430                         
1431                         /* Evaluate expression */                       
1432                         cp4 = ast_func(c, vars, workspace, sizeof(workspace));
1433                         
1434                         ast_log(LOG_DEBUG, "Expression is '%s'\n", cp4);
1435                         
1436                         if (cp4) {
1437                                 length = strlen(cp4);
1438                                 if (length > count)
1439                                         length = count;
1440                                 memcpy(cp2, cp4, length);
1441                                 count -= length;
1442                                 cp2 += length;
1443                                 free(cp4);
1444                         }
1445                         
1446                 } else
1447                         break;
1448         }
1449 }
1450
1451 void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
1452 {
1453         pbx_substitute_variables_helper_full(c, cp1, cp2, count, NULL);
1454 }
1455
1456 void pbx_substitute_variables_varshead(struct varshead *headp, const char *cp1, char *cp2, int count)
1457 {
1458         pbx_substitute_variables_helper_full(NULL, cp1, cp2, count, headp);
1459 }
1460
1461 static void pbx_substitute_variables(char *passdata, int datalen, struct ast_channel *c, struct ast_exten *e) {
1462         
1463         memset(passdata, 0, datalen);
1464                 
1465         /* No variables or expressions in e->data, so why scan it? */
1466         if (!strstr(e->data,"${") && !strstr(e->data,"$[") && !strstr(e->data,"$(")) {
1467                 strncpy(passdata, e->data, datalen - 1);
1468                 passdata[datalen-1] = '\0';
1469                 return;
1470         }
1471         
1472         pbx_substitute_variables_helper(c, e->data, passdata, datalen - 1);
1473 }                                                               
1474
1475 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) 
1476 {
1477         struct ast_exten *e;
1478         struct ast_app *app;
1479         struct ast_switch *sw;
1480         char *data;
1481         const char *foundcontext=NULL;
1482         int newstack = 0;
1483         int res;
1484         int status = 0;
1485         char *incstack[AST_PBX_MAX_STACK];
1486         char passdata[EXT_DATA_SIZE];
1487         int stacklen = 0;
1488         char tmp[80];
1489         char tmp2[80];
1490         char tmp3[EXT_DATA_SIZE];
1491         char atmp[80];
1492         char atmp2[EXT_DATA_SIZE+100];
1493
1494         if (ast_mutex_lock(&conlock)) {
1495                 ast_log(LOG_WARNING, "Unable to obtain lock\n");
1496                 if ((action == HELPER_EXISTS) || (action == HELPER_CANMATCH) || (action == HELPER_MATCHMORE))
1497                         return 0;
1498                 else
1499                         return -1;
1500         }
1501         e = pbx_find_extension(c, con, context, exten, priority, label, callerid, action, incstack, &stacklen, &status, &sw, &data, &foundcontext);
1502         if (e) {
1503                 switch(action) {
1504                 case HELPER_CANMATCH:
1505                         ast_mutex_unlock(&conlock);
1506                         return -1;
1507                 case HELPER_EXISTS:
1508                         ast_mutex_unlock(&conlock);
1509                         return -1;
1510                 case HELPER_FINDLABEL:
1511                         res = e->priority;
1512                         ast_mutex_unlock(&conlock);
1513                         return res;
1514                 case HELPER_MATCHMORE:
1515                         ast_mutex_unlock(&conlock);
1516                         return -1;
1517                 case HELPER_SPAWN:
1518                         newstack++;
1519                         /* Fall through */
1520                 case HELPER_EXEC:
1521                         app = pbx_findapp(e->app);
1522                         ast_mutex_unlock(&conlock);
1523                         if (app) {
1524                                 if (c->context != context)
1525                                         strncpy(c->context, context, sizeof(c->context)-1);
1526                                 if (c->exten != exten)
1527                                         strncpy(c->exten, exten, sizeof(c->exten)-1);
1528                                 c->priority = priority;
1529                                 pbx_substitute_variables(passdata, sizeof(passdata), c, e);
1530                                 if (option_debug) {
1531                                                 ast_log(LOG_DEBUG, "Launching '%s'\n", app->name);
1532                                                 snprintf(atmp, 80, "STACK-%s-%s-%d", context, exten, priority);
1533                                                 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"));
1534                                                 pbx_builtin_setvar_helper(c, atmp, atmp2);
1535                                 }
1536                                 if (option_verbose > 2)
1537                                                 ast_verbose( VERBOSE_PREFIX_3 "Executing %s(\"%s\", \"%s\") %s\n", 
1538                                                                 term_color(tmp, app->name, COLOR_BRCYAN, 0, sizeof(tmp)),
1539                                                                 term_color(tmp2, c->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
1540                                                                 term_color(tmp3, (!ast_strlen_zero(passdata) ? (char *)passdata : ""), COLOR_BRMAGENTA, 0, sizeof(tmp3)),
1541                                                                 (newstack ? "in new stack" : "in same stack"));
1542                                 manager_event(EVENT_FLAG_CALL, "Newexten", 
1543                                         "Channel: %s\r\n"
1544                                         "Context: %s\r\n"
1545                                         "Extension: %s\r\n"
1546                                         "Priority: %d\r\n"
1547                                         "Application: %s\r\n"
1548                                         "AppData: %s\r\n"
1549                                         "Uniqueid: %s\r\n",
1550                                         c->name, c->context, c->exten, c->priority, app->name, passdata ? passdata : "(NULL)", c->uniqueid);
1551                                 res = pbx_exec(c, app, passdata, newstack);
1552                                 return res;
1553                         } else {
1554                                 ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
1555                                 return -1;
1556                         }
1557                 default:
1558                         ast_log(LOG_WARNING, "Huh (%d)?\n", action);                    return -1;
1559                 }
1560         } else if (sw) {
1561                 switch(action) {
1562                 case HELPER_CANMATCH:
1563                         ast_mutex_unlock(&conlock);
1564                         return -1;
1565                 case HELPER_EXISTS:
1566                         ast_mutex_unlock(&conlock);
1567                         return -1;
1568                 case HELPER_MATCHMORE:
1569                         ast_mutex_unlock(&conlock);
1570                         return -1;
1571                 case HELPER_FINDLABEL:
1572                         ast_mutex_unlock(&conlock);
1573                         return -1;
1574                 case HELPER_SPAWN:
1575                         newstack++;
1576                         /* Fall through */
1577                 case HELPER_EXEC:
1578                         ast_mutex_unlock(&conlock);
1579                         if (sw->exec)
1580                                 res = sw->exec(c, foundcontext ? foundcontext : context, exten, priority, callerid, newstack, data);
1581                         else {
1582                                 ast_log(LOG_WARNING, "No execution engine for switch %s\n", sw->name);
1583                                 res = -1;
1584                         }
1585                         return res;
1586                 default:
1587                         ast_log(LOG_WARNING, "Huh (%d)?\n", action);
1588                         return -1;
1589                 }
1590         } else {
1591                 ast_mutex_unlock(&conlock);
1592                 switch(status) {
1593                 case STATUS_NO_CONTEXT:
1594                         if ((action != HELPER_EXISTS) && (action != HELPER_MATCHMORE))
1595                                 ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", context);
1596                         break;
1597                 case STATUS_NO_EXTENSION:
1598                         if ((action != HELPER_EXISTS) && (action !=  HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1599                                 ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, context);
1600                         break;
1601                 case STATUS_NO_PRIORITY:
1602                         if ((action != HELPER_EXISTS) && (action !=  HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1603                                 ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, context);
1604                         break;
1605                 case STATUS_NO_LABEL:
1606                         if (context)
1607                                 ast_log(LOG_NOTICE, "No such label '%s' in extension '%s' in context '%s'\n", label, exten, context);
1608                         break;
1609                 default:
1610                         ast_log(LOG_DEBUG, "Shouldn't happen!\n");
1611                 }
1612                 
1613                 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1614                         return -1;
1615                 else
1616                         return 0;
1617         }
1618
1619 }
1620
1621 /*--- ast_hint_extension: Find hint for given extension in context */
1622 static struct ast_exten *ast_hint_extension(struct ast_channel *c, const char *context, const char *exten)
1623 {
1624         struct ast_exten *e;
1625         struct ast_switch *sw;
1626         char *data;
1627         const char *foundcontext = NULL;
1628         int status = 0;
1629         char *incstack[AST_PBX_MAX_STACK];
1630         int stacklen = 0;
1631
1632         if (ast_mutex_lock(&conlock)) {
1633                 ast_log(LOG_WARNING, "Unable to obtain lock\n");
1634                 return NULL;
1635         }
1636         e = pbx_find_extension(c, NULL, context, exten, PRIORITY_HINT, NULL, "", HELPER_EXISTS, incstack, &stacklen, &status, &sw, &data, &foundcontext);
1637         ast_mutex_unlock(&conlock);     
1638         return e;
1639 }
1640
1641 static int ast_extension_state2(struct ast_exten *e)
1642 {
1643         char hint[AST_MAX_EXTENSION] = "";    
1644         char *cur, *rest;
1645         int res = -1;
1646         int allunavailable = 1, allbusy = 1, allfree = 1;
1647         int busy = 0;
1648
1649         strncpy(hint, ast_get_extension_app(e), sizeof(hint)-1);
1650     
1651         cur = hint;    
1652         do {
1653                 rest = strchr(cur, '&');
1654                 if (rest) {
1655                         *rest = 0;
1656                         rest++;
1657                 }
1658         
1659                 res = ast_device_state(cur);
1660                 switch (res) {
1661                 case AST_DEVICE_NOT_INUSE:
1662                         allunavailable = 0;
1663                         allbusy = 0;
1664                         break;
1665                 case AST_DEVICE_INUSE:
1666                         return AST_EXTENSION_INUSE;
1667                 case AST_DEVICE_BUSY:
1668                         allunavailable = 0;
1669                         allfree = 0;
1670                         busy = 1;
1671                         break;
1672                 case AST_DEVICE_UNAVAILABLE:
1673                 case AST_DEVICE_INVALID:
1674                         allbusy = 0;
1675                         allfree = 0;
1676                         break;
1677                 default:
1678                         allunavailable = 0;
1679                         allbusy = 0;
1680                         allfree = 0;
1681                 }
1682                 cur = rest;
1683         } while (cur);
1684
1685         if (allfree)
1686                 return AST_EXTENSION_NOT_INUSE;
1687         if (allbusy)
1688                 return AST_EXTENSION_BUSY;
1689         if (allunavailable)
1690                 return AST_EXTENSION_UNAVAILABLE;
1691         if (busy) 
1692                 return AST_EXTENSION_INUSE;
1693         
1694         return AST_EXTENSION_NOT_INUSE;
1695 }
1696
1697
1698 int ast_extension_state(struct ast_channel *c, char *context, char *exten)
1699 {
1700         struct ast_exten *e;
1701
1702         e = ast_hint_extension(c, context, exten);    
1703         if (!e) 
1704                 return -1;
1705
1706         return ast_extension_state2(e);    
1707 }
1708
1709 int ast_device_state_changed(const char *fmt, ...) 
1710 {
1711         struct ast_hint *list;
1712         struct ast_state_cb *cblist;
1713         struct ast_devstate_cb *devcb;
1714         char hint[AST_MAX_EXTENSION] = "";
1715         char device[AST_MAX_EXTENSION];
1716         char *cur, *rest;
1717         int state;
1718
1719         va_list ap;
1720
1721         va_start(ap, fmt);
1722         vsnprintf(device, sizeof(device), fmt, ap);
1723         va_end(ap);
1724
1725         rest = strchr(device, '-');
1726         if (rest) {
1727                 *rest = 0;
1728         }
1729
1730         state = ast_device_state(device);
1731
1732         ast_mutex_lock(&hintlock);
1733
1734         devcb = devcbs;
1735         while(devcb) {
1736                 if (devcb->callback)
1737                         devcb->callback(device, state, devcb->data);
1738                 devcb = devcb->next;
1739         }
1740         list = hints;
1741
1742         while (list) {
1743
1744                 strncpy(hint, ast_get_extension_app(list->exten), sizeof(hint) - 1);
1745                 cur = hint;
1746                 do {
1747                         rest = strchr(cur, '&');
1748                         if (rest) {
1749                                 *rest = 0;
1750                                 rest++;
1751                         }
1752                         
1753                         if (!strcmp(cur, device)) {
1754                                 /* Found extension execute callbacks  */
1755                                 state = ast_extension_state2(list->exten);
1756                                 if ((state != -1) && (state != list->laststate)) {
1757                                         /* For general callbacks */
1758                                         cblist = statecbs;
1759                                         while (cblist) {
1760                                                 cblist->callback(list->exten->parent->name, list->exten->exten, state, cblist->data);
1761                                                 cblist = cblist->next;
1762                                         }
1763
1764                                         /* For extension callbacks */
1765                                         cblist = list->callbacks;
1766                                         while (cblist) {
1767                                                 cblist->callback(list->exten->parent->name, list->exten->exten, state, cblist->data);
1768                                                 cblist = cblist->next;
1769                                         }
1770                         
1771                                         list->laststate = state;
1772                                 }
1773                                 break;
1774                         }
1775                         cur = rest;
1776                 } while (cur);
1777                 list = list->next;
1778         }
1779         ast_mutex_unlock(&hintlock);
1780         return 1;
1781 }
1782                         
1783 int ast_devstate_add(ast_devstate_cb_type callback, void *data)
1784 {
1785         struct ast_devstate_cb *devcb;
1786         devcb = malloc(sizeof(struct ast_devstate_cb));
1787         if (devcb) {
1788                 memset(devcb, 0, sizeof(struct ast_devstate_cb));
1789                 ast_mutex_lock(&hintlock);
1790                 devcb->data = data;
1791                 devcb->callback = callback;
1792                 devcb->next = devcbs;
1793                 devcbs = devcb;
1794                 ast_mutex_unlock(&hintlock);
1795         }
1796         return 0;
1797 }
1798
1799 void ast_devstate_del(ast_devstate_cb_type callback, void *data)
1800 {
1801         struct ast_devstate_cb *devcb, *prev = NULL, *next;
1802         ast_mutex_lock(&hintlock);
1803         devcb = devcbs;
1804         while(devcb) {
1805                 next = devcb->next;
1806                 if ((devcb->data == data) && (devcb->callback == callback)) {
1807                         if (prev)
1808                                 prev->next = next;
1809                         else
1810                                 devcbs = next;
1811                         free(devcb);
1812                 } else
1813                         prev = devcb;
1814                 devcb = next;
1815         }
1816         ast_mutex_unlock(&hintlock);
1817 }
1818
1819 int ast_extension_state_add(const char *context, const char *exten, 
1820                             ast_state_cb_type callback, void *data)
1821 {
1822         struct ast_hint *list;
1823         struct ast_state_cb *cblist;
1824         struct ast_exten *e;
1825
1826         /* No context and extension add callback to statecbs list */
1827         if (!context && !exten) {
1828                 ast_mutex_lock(&hintlock);
1829
1830                 cblist = statecbs;
1831                 while (cblist) {
1832                         if (cblist->callback == callback) {
1833                                 cblist->data = data;
1834                                 ast_mutex_unlock(&hintlock);
1835                         }
1836                         cblist = cblist->next;
1837                 }
1838         
1839                 /* Now inserts the callback */
1840                 cblist = malloc(sizeof(struct ast_state_cb));
1841                 if (!cblist) {
1842                         ast_mutex_unlock(&hintlock);
1843                         return -1;
1844                 }
1845                 memset(cblist, 0, sizeof(struct ast_state_cb));
1846                 cblist->id = 0;
1847                 cblist->callback = callback;
1848                 cblist->data = data;
1849         
1850                 cblist->next = statecbs;
1851                 statecbs = cblist;
1852
1853                 ast_mutex_unlock(&hintlock);
1854                 return 0;
1855         }
1856
1857         if (!context || !exten)
1858                 return -1;
1859
1860         /* This callback type is for only one hint */
1861         e = ast_hint_extension(NULL, context, exten);    
1862         if (!e) {
1863                 return -1;
1864         }
1865     
1866         ast_mutex_lock(&hintlock);
1867         list = hints;        
1868     
1869         while (list) {
1870                 if (list->exten == e)
1871                         break;      
1872                 list = list->next;    
1873         }
1874
1875         if (!list) {
1876                 ast_mutex_unlock(&hintlock);
1877                 return -1;
1878         }
1879
1880         /* Now inserts the callback */
1881         cblist = malloc(sizeof(struct ast_state_cb));
1882         if (!cblist) {
1883                 ast_mutex_unlock(&hintlock);
1884                 return -1;
1885         }
1886         memset(cblist, 0, sizeof(struct ast_state_cb));
1887         cblist->id = stateid++;
1888         cblist->callback = callback;
1889         cblist->data = data;
1890
1891         cblist->next = list->callbacks;
1892         list->callbacks = cblist;
1893
1894         ast_mutex_unlock(&hintlock);
1895         return cblist->id;
1896 }
1897
1898 int ast_extension_state_del(int id, ast_state_cb_type callback)
1899 {
1900         struct ast_hint *list;
1901         struct ast_state_cb *cblist, *cbprev;
1902     
1903         if (!id && !callback)
1904                 return -1;
1905             
1906         ast_mutex_lock(&hintlock);
1907
1908         /* id is zero is a callback without extension */
1909         if (!id) {
1910                 cbprev = NULL;
1911                 cblist = statecbs;
1912                 while (cblist) {
1913                         if (cblist->callback == callback) {
1914                                 if (!cbprev)
1915                                         statecbs = cblist->next;
1916                                 else
1917                                         cbprev->next = cblist->next;
1918
1919                                 free(cblist);
1920
1921                                 ast_mutex_unlock(&hintlock);
1922                                 return 0;
1923                         }
1924                         cbprev = cblist;
1925                         cblist = cblist->next;
1926                 }
1927
1928                 ast_mutex_lock(&hintlock);
1929                 return -1;
1930         }
1931
1932         /* id greater than zero is a callback with extension */
1933         list = hints;
1934         while (list) {
1935                 cblist = list->callbacks;
1936                 cbprev = NULL;
1937                 while (cblist) {
1938                         if (cblist->id==id) {
1939                                 if (!cbprev)
1940                                         list->callbacks = cblist->next;         
1941                                 else
1942                                         cbprev->next = cblist->next;
1943                 
1944                                 free(cblist);
1945                 
1946                                 ast_mutex_unlock(&hintlock);
1947                                 return 0;               
1948                         }               
1949                         cbprev = cblist;                                
1950                         cblist = cblist->next;
1951                 }
1952                 list = list->next;
1953         }
1954     
1955         ast_mutex_unlock(&hintlock);
1956         return -1;
1957 }
1958
1959 /*--- ast_add_hint: Add hint to hint list, check initial extension state */
1960 static int ast_add_hint(struct ast_exten *e)
1961 {
1962         struct ast_hint *list;
1963
1964         if (!e) 
1965                 return -1;
1966     
1967         ast_mutex_lock(&hintlock);
1968         list = hints;        
1969     
1970         /* Search if hint exists, do nothing */
1971         while (list) {
1972                 if (list->exten == e) {
1973                         ast_mutex_unlock(&hintlock);
1974                         if (option_debug > 1)
1975                                 ast_log(LOG_DEBUG, "HINTS: Not re-adding existing hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
1976                         return -1;
1977                 }
1978                 list = list->next;    
1979         }
1980
1981         if (option_debug > 1)
1982                 ast_log(LOG_DEBUG, "HINTS: Adding hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
1983
1984         list = malloc(sizeof(struct ast_hint));
1985         if (!list) {
1986                 ast_mutex_unlock(&hintlock);
1987                 if (option_debug > 1)
1988                         ast_log(LOG_DEBUG, "HINTS: Out of memory...\n");
1989                 return -1;
1990         }
1991         /* Initialize and insert new item at the top */
1992         memset(list, 0, sizeof(struct ast_hint));
1993         list->exten = e;
1994         list->laststate = ast_extension_state2(e);
1995         list->next = hints;
1996         hints = list;
1997
1998         ast_mutex_unlock(&hintlock);
1999         return 0;
2000 }
2001
2002 /*--- ast_change_hint: Change hint for an extension */
2003 static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
2004
2005         struct ast_hint *list;
2006
2007         ast_mutex_lock(&hintlock);
2008         list = hints;
2009     
2010         while(list) {
2011                 if (list->exten == oe) {
2012                         list->exten = ne;
2013                         ast_mutex_unlock(&hintlock);    
2014                         return 0;
2015                 }
2016                 list = list->next;
2017         }
2018         ast_mutex_unlock(&hintlock);
2019
2020         return -1;
2021 }
2022
2023 /*--- ast_remove_hint: Remove hint from extension */
2024 static int ast_remove_hint(struct ast_exten *e)
2025 {
2026         /* Cleanup the Notifys if hint is removed */
2027         struct ast_hint *list, *prev = NULL;
2028         struct ast_state_cb *cblist, *cbprev;
2029
2030         if (!e) 
2031                 return -1;
2032
2033         ast_mutex_lock(&hintlock);
2034
2035         list = hints;    
2036         while(list) {
2037                 if (list->exten==e) {
2038                         cbprev = NULL;
2039                         cblist = list->callbacks;
2040                         while (cblist) {
2041                                 /* Notify with -1 and remove all callbacks */
2042                                 cbprev = cblist;            
2043                                 cblist = cblist->next;
2044                                 cbprev->callback(list->exten->parent->name, list->exten->exten, -1, cbprev->data);
2045                                 free(cbprev);
2046                         }
2047                         list->callbacks = NULL;
2048
2049                         if (!prev)
2050                                 hints = list->next;
2051                         else
2052                                 prev->next = list->next;
2053                         free(list);
2054             
2055                         ast_mutex_unlock(&hintlock);
2056                         return 0;
2057                 } else {
2058                         prev = list;
2059                         list = list->next;    
2060                 }
2061         }
2062
2063         ast_mutex_unlock(&hintlock);
2064         return -1;
2065 }
2066
2067
2068 /*--- ast_get_hint: Get hint for channel */
2069 int ast_get_hint(char *hint, int hintsize, char *name, int namesize, struct ast_channel *c, const char *context, const char *exten)
2070 {
2071         struct ast_exten *e;
2072         void *tmp;
2073         e = ast_hint_extension(c, context, exten);
2074         if (e) {
2075                 if (hint) 
2076                     strncpy(hint, ast_get_extension_app(e), hintsize - 1);
2077                 if (name) {
2078                         tmp = ast_get_extension_app_data(e);
2079                         if (tmp)
2080                                 strncpy(name, (char *)tmp, namesize - 1);
2081                 }
2082             return -1;
2083         }
2084         return 0;       
2085 }
2086
2087 int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid) 
2088 {
2089         return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_EXISTS);
2090 }
2091
2092 int ast_findlabel_extension(struct ast_channel *c, const char *context, const char *exten, const char *label, const char *callerid) 
2093 {
2094         return pbx_extension_helper(c, NULL, context, exten, 0, label, callerid, HELPER_FINDLABEL);
2095 }
2096
2097 int ast_findlabel_extension2(struct ast_channel *c, struct ast_context *con, const char *exten, const char *label, const char *callerid) 
2098 {
2099         return pbx_extension_helper(c, con, NULL, exten, 0, label, callerid, HELPER_FINDLABEL);
2100 }
2101
2102 int ast_canmatch_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
2103 {
2104         return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_CANMATCH);
2105 }
2106
2107 int ast_matchmore_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
2108 {
2109         return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_MATCHMORE);
2110 }
2111
2112 int ast_spawn_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid) 
2113 {
2114         return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_SPAWN);
2115 }
2116
2117 int ast_exec_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid) 
2118 {
2119         return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_EXEC);
2120 }
2121
2122 int ast_pbx_run(struct ast_channel *c)
2123 {
2124         int firstpass = 1;
2125         char digit;
2126         char exten[256];
2127         int pos;
2128         int waittime;
2129         int res=0;
2130
2131         /* A little initial setup here */
2132         if (c->pbx)
2133                 ast_log(LOG_WARNING, "%s already has PBX structure??\n", c->name);
2134         c->pbx = malloc(sizeof(struct ast_pbx));
2135         if (!c->pbx) {
2136                 ast_log(LOG_ERROR, "Out of memory\n");
2137                 return -1;
2138         }
2139         if (c->amaflags) {
2140                 if (!c->cdr) {
2141                         c->cdr = ast_cdr_alloc();
2142                         if (!c->cdr) {
2143                                 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
2144                                 free(c->pbx);
2145                                 return -1;
2146                         }
2147                         ast_cdr_init(c->cdr, c);
2148                 }
2149         }
2150         memset(c->pbx, 0, sizeof(struct ast_pbx));
2151         /* Set reasonable defaults */
2152         c->pbx->rtimeout = 10;
2153         c->pbx->dtimeout = 5;
2154
2155         /* Start by trying whatever the channel is set to */
2156         if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2157                 /* JK02: If not successfull fall back to 's' */
2158                 if (option_verbose > 1)
2159                         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);
2160                 strncpy(c->exten, "s", sizeof(c->exten)-1);
2161                 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2162                         /* JK02: And finally back to default if everything else failed */
2163                         if (option_verbose > 1)
2164                                 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);
2165                         strncpy(c->context, "default", sizeof(c->context)-1);
2166                 }
2167                 c->priority = 1;
2168         }
2169         if (c->cdr && !c->cdr->start.tv_sec && !c->cdr->start.tv_usec)
2170                 ast_cdr_start(c->cdr);
2171         for(;;) {
2172                 pos = 0;
2173                 digit = 0;
2174                 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2175                         memset(exten, 0, sizeof(exten));
2176                         if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
2177                                 /* Something bad happened, or a hangup has been requested. */
2178                                 if (((res >= '0') && (res <= '9')) || ((res >= 'A') && (res <= 'F')) ||
2179                                         (res == '*') || (res == '#')) {
2180                                         ast_log(LOG_DEBUG, "Oooh, got something to jump out with ('%c')!\n", res);
2181                                         memset(exten, 0, sizeof(exten));
2182                                         pos = 0;
2183                                         exten[pos++] = digit = res;
2184                                         break;
2185                                 }
2186                                 switch(res) {
2187                                 case AST_PBX_KEEPALIVE:
2188                                         if (option_debug)
2189                                                 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
2190                                         else if (option_verbose > 1)
2191                                                 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
2192                                         goto out;
2193                                         break;
2194                                 default:
2195                                         if (option_debug)
2196                                                 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2197                                         else if (option_verbose > 1)
2198                                                 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2199                                         if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
2200                                                 c->_softhangup =0;
2201                                                 break;
2202                                         }
2203                                         /* atimeout */
2204                                         if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
2205                                                 break;
2206                                         }
2207
2208                                         if (c->cdr) {
2209                                                 ast_cdr_update(c);
2210                                         }
2211                                         goto out;
2212                                 }
2213                         }
2214                         if ((c->_softhangup == AST_SOFTHANGUP_TIMEOUT) && (ast_exists_extension(c,c->context,"T",1,c->cid.cid_num))) {
2215                                 strncpy(c->exten,"T",sizeof(c->exten) - 1);
2216                                 /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
2217                                 c->whentohangup = 0;
2218                                 c->priority = 0;
2219                                 c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
2220                         } else if (c->_softhangup) {
2221                                 ast_log(LOG_DEBUG, "Extension %s, priority %d returned normally even though call was hung up\n",
2222                                         c->exten, c->priority);
2223                                 goto out;
2224                         }
2225                         firstpass = 0;
2226                         c->priority++;
2227                 }
2228                 if (!ast_exists_extension(c, c->context, c->exten, 1, c->cid.cid_num)) {
2229                         /* It's not a valid extension anymore */
2230                         if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
2231                                 if (option_verbose > 2)
2232                                         ast_verbose(VERBOSE_PREFIX_3 "Sent into invalid extension '%s' in context '%s' on %s\n", c->exten, c->context, c->name);
2233                                 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", c->exten);
2234                                 strncpy(c->exten, "i", sizeof(c->exten)-1);
2235                                 c->priority = 1;
2236                         } else {
2237                                 ast_log(LOG_WARNING, "Channel '%s' sent into invalid extension '%s' in context '%s', but no invalid handler\n",
2238                                         c->name, c->exten, c->context);
2239                                 goto out;
2240                         }
2241                 } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
2242                         /* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */
2243                         c->_softhangup = 0;
2244                 } else {
2245                         /* Done, wait for an extension */
2246                         waittime = 0;
2247                         if (digit)
2248                                 waittime = c->pbx->dtimeout;
2249                         else if (!autofallthrough)
2250                                 waittime = c->pbx->rtimeout;
2251                         if (waittime) {
2252                                 while (ast_matchmore_extension(c, c->context, exten, 1, c->cid.cid_num)) {
2253                                         /* As long as we're willing to wait, and as long as it's not defined, 
2254                                            keep reading digits until we can't possibly get a right answer anymore.  */
2255                                         digit = ast_waitfordigit(c, waittime * 1000);
2256                                         if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
2257                                                 c->_softhangup = 0;
2258                                         } else {
2259                                                 if (!digit)
2260                                                         /* No entry */
2261                                                         break;
2262                                                 if (digit < 0)
2263                                                         /* Error, maybe a  hangup */
2264                                                         goto out;
2265                                                 exten[pos++] = digit;
2266                                                 waittime = c->pbx->dtimeout;
2267                                         }
2268                                 }
2269                                 if (ast_exists_extension(c, c->context, exten, 1, c->cid.cid_num)) {
2270                                         /* Prepare the next cycle */
2271                                         strncpy(c->exten, exten, sizeof(c->exten)-1);
2272                                         c->priority = 1;
2273                                 } else {
2274                                         /* No such extension */
2275                                         if (!ast_strlen_zero(exten)) {
2276                                                 /* An invalid extension */
2277                                                 if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
2278                                                         if (option_verbose > 2)
2279                                                                 ast_verbose( VERBOSE_PREFIX_3 "Invalid extension '%s' in context '%s' on %s\n", exten, c->context, c->name);
2280                                                         pbx_builtin_setvar_helper(c, "INVALID_EXTEN", exten);
2281                                                         strncpy(c->exten, "i", sizeof(c->exten)-1);
2282                                                         c->priority = 1;
2283                                                 } else {
2284                                                         ast_log(LOG_WARNING, "Invalid extension '%s', but no rule 'i' in context '%s'\n", exten, c->context);
2285                                                         goto out;
2286                                                 }
2287                                         } else {
2288                                                 /* A simple timeout */
2289                                                 if (ast_exists_extension(c, c->context, "t", 1, c->cid.cid_num)) {
2290                                                         if (option_verbose > 2)
2291                                                                 ast_verbose( VERBOSE_PREFIX_3 "Timeout on %s\n", c->name);
2292                                                         strncpy(c->exten, "t", sizeof(c->exten)-1);
2293                                                         c->priority = 1;
2294                                                 } else {
2295                                                         ast_log(LOG_WARNING, "Timeout, but no rule 't' in context '%s'\n", c->context);
2296                                                         goto out;
2297                                                 }
2298                                         }       
2299                                 }
2300                                 if (c->cdr) {
2301                                         if (option_verbose > 2)
2302                                                 ast_verbose(VERBOSE_PREFIX_2 "CDR updated on %s\n",c->name);    
2303                                         ast_cdr_update(c);
2304                             }
2305                         } else {
2306                                 char *status;
2307                                 status = pbx_builtin_getvar_helper(c, "DIALSTATUS");
2308                                 if (!status)
2309                                         status = "UNKNOWN";
2310                                 if (option_verbose > 2)
2311                                         ast_verbose(VERBOSE_PREFIX_2 "Auto fallthrough, channel '%s' status is '%s'\n", c->name, status);
2312                                 if (!strcasecmp(status, "CONGESTION"))
2313                                         res = pbx_builtin_congestion(c, "10");
2314                                 else if (!strcasecmp(status, "CHANUNAVAIL"))
2315                                         res = pbx_builtin_congestion(c, "10");
2316                                 else if (!strcasecmp(status, "BUSY"))
2317                                         res = pbx_builtin_busy(c, "10");
2318                                 goto out;
2319                         }
2320                 }
2321         }
2322         if (firstpass) 
2323                 ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", c->name);
2324 out:
2325         if ((res != AST_PBX_KEEPALIVE) && ast_exists_extension(c, c->context, "h", 1, c->cid.cid_num)) {
2326                 c->exten[0] = 'h';
2327                 c->exten[1] = '\0';
2328                 c->priority = 1;
2329                 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2330                         if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
2331                                 /* Something bad happened, or a hangup has been requested. */
2332                                 if (option_debug)
2333                                         ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2334                                 else if (option_verbose > 1)
2335                                         ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2336                                 break;
2337                         }
2338                         c->priority++;
2339                 }
2340         }
2341
2342         pbx_destroy(c->pbx);
2343         c->pbx = NULL;
2344         if (res != AST_PBX_KEEPALIVE)
2345                 ast_hangup(c);
2346         return 0;
2347 }
2348
2349 static void *pbx_thread(void *data)
2350 {
2351         /* Oh joyeous kernel, we're a new thread, with nothing to do but
2352            answer this channel and get it going.  The setjmp stuff is fairly
2353            confusing, but necessary to get smooth transitions between
2354            the execution of different applications (without the use of
2355            additional threads) */
2356         struct ast_channel *c = data;
2357         ast_pbx_run(c);
2358         pthread_exit(NULL);
2359         return NULL;
2360 }
2361
2362 int ast_pbx_start(struct ast_channel *c)
2363 {
2364         pthread_t t;
2365         pthread_attr_t attr;
2366         if (!c) {
2367                 ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
2368                 return -1;
2369         }
2370            
2371         /* Start a new thread, and get something handling this channel. */
2372         pthread_attr_init(&attr);
2373         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
2374         if (ast_pthread_create(&t, &attr, pbx_thread, c)) {
2375                 ast_log(LOG_WARNING, "Failed to create new channel thread\n");
2376                 return -1;
2377         }
2378         return 0;
2379 }
2380
2381 int pbx_set_autofallthrough(int newval)
2382 {
2383         int oldval;
2384         oldval = autofallthrough;
2385         if (oldval != newval)
2386                 autofallthrough = newval;
2387         return oldval;
2388 }
2389
2390 /*
2391  * This function locks contexts list by &conlist, search for the right context
2392  * structure, leave context list locked and call ast_context_remove_include2
2393  * which removes include, unlock contexts list and return ...
2394  */
2395 int ast_context_remove_include(const char *context, const char *include, const char *registrar)
2396 {
2397         struct ast_context *c;
2398
2399         if (ast_lock_contexts()) return -1;
2400
2401         /* walk contexts and search for the right one ...*/
2402         c = ast_walk_contexts(NULL);
2403         while (c) {
2404                 /* we found one ... */
2405                 if (!strcmp(ast_get_context_name(c), context)) {
2406                         int ret;
2407                         /* remove include from this context ... */      
2408                         ret = ast_context_remove_include2(c, include, registrar);
2409
2410                         ast_unlock_contexts();
2411
2412                         /* ... return results */
2413                         return ret;
2414                 }
2415                 c = ast_walk_contexts(c);
2416         }
2417
2418         /* we can't find the right one context */
2419         ast_unlock_contexts();
2420         return -1;
2421 }
2422
2423 /*
2424  * When we call this function, &conlock lock must be locked, because when
2425  * we giving *con argument, some process can remove/change this context
2426  * and after that there can be segfault.
2427  *
2428  * This function locks given context, removes include, unlock context and
2429  * return.
2430  */
2431 int ast_context_remove_include2(struct ast_context *con, const char *include, const char *registrar)
2432 {
2433         struct ast_include *i, *pi = NULL;
2434
2435         if (ast_mutex_lock(&con->lock)) return -1;
2436
2437         /* walk includes */
2438         i = con->includes;
2439         while (i) {
2440                 /* find our include */
2441                 if (!strcmp(i->name, include) && 
2442                         (!registrar || !strcmp(i->registrar, registrar))) {
2443                         /* remove from list */
2444                         if (pi)
2445                                 pi->next = i->next;
2446                         else
2447                                 con->includes = i->next;
2448                         /* free include and return */
2449                         free(i);
2450                         ast_mutex_unlock(&con->lock);
2451                         return 0;
2452                 }
2453                 pi = i;
2454                 i = i->next;
2455         }
2456
2457         /* we can't find the right include */
2458         ast_mutex_unlock(&con->lock);
2459         return -1;
2460 }
2461
2462 /*
2463  * This function locks contexts list by &conlist, search for the rigt context
2464  * structure, leave context list locked and call ast_context_remove_switch2
2465  * which removes switch, unlock contexts list and return ...
2466  */
2467 int ast_context_remove_switch(const char *context, const char *sw, const char *data, const char *registrar)
2468 {
2469         struct ast_context *c;
2470
2471         if (ast_lock_contexts()) return -1;
2472
2473         /* walk contexts and search for the right one ...*/
2474         c = ast_walk_contexts(NULL);
2475         while (c) {
2476                 /* we found one ... */
2477                 if (!strcmp(ast_get_context_name(c), context)) {
2478                         int ret;
2479                         /* remove switch from this context ... */       
2480                         ret = ast_context_remove_switch2(c, sw, data, registrar);
2481
2482                         ast_unlock_contexts();
2483
2484                         /* ... return results */
2485                         return ret;
2486                 }
2487                 c = ast_walk_contexts(c);
2488         }
2489
2490         /* we can't find the right one context */
2491         ast_unlock_contexts();
2492         return -1;
2493 }
2494
2495 /*
2496  * When we call this function, &conlock lock must be locked, because when
2497  * we giving *con argument, some process can remove/change this context
2498  * and after that there can be segfault.
2499  *
2500  * This function locks given context, removes switch, unlock context and
2501  * return.
2502  */
2503 int ast_context_remove_switch2(struct ast_context *con, const char *sw, const char *data, const char *registrar)
2504 {
2505         struct ast_sw *i, *pi = NULL;
2506
2507         if (ast_mutex_lock(&con->lock)) return -1;
2508
2509         /* walk switchs */
2510         i = con->alts;
2511         while (i) {
2512                 /* find our switch */
2513                 if (!strcmp(i->name, sw) && !strcmp(i->data, data) && 
2514                         (!registrar || !strcmp(i->registrar, registrar))) {
2515                         /* remove from list */
2516                         if (pi)
2517                                 pi->next = i->next;
2518                         else
2519                                 con->alts = i->next;
2520                         /* free switch and return */
2521                         free(i);
2522                         ast_mutex_unlock(&con->lock);
2523                         return 0;
2524                 }
2525                 pi = i;
2526                 i = i->next;
2527         }
2528
2529         /* we can't find the right switch */
2530         ast_mutex_unlock(&con->lock);
2531         return -1;
2532 }
2533
2534 /*
2535  * This functions lock contexts list, search for the right context,
2536  * call ast_context_remove_extension2, unlock contexts list and return.
2537  * In this function we are using
2538  */
2539 int ast_context_remove_extension(const char *context, const char *extension, int priority, const char *registrar)
2540 {
2541         struct ast_context *c;
2542
2543         if (ast_lock_contexts()) return -1;
2544
2545         /* walk contexts ... */
2546         c = ast_walk_contexts(NULL);
2547         while (c) {
2548                 /* ... search for the right one ... */
2549                 if (!strcmp(ast_get_context_name(c), context)) {
2550                         /* ... remove extension ... */
2551                         int ret = ast_context_remove_extension2(c, extension, priority,
2552                                 registrar);
2553                         /* ... unlock contexts list and return */
2554                         ast_unlock_contexts();
2555                         return ret;
2556                 }
2557                 c = ast_walk_contexts(c);
2558         }
2559
2560         /* we can't find the right context */
2561         ast_unlock_contexts();
2562         return -1;
2563 }
2564
2565 /*
2566  * When do you want to call this function, make sure that &conlock is locked,
2567  * because some process can handle with your *con context before you lock
2568  * it.
2569  *
2570  * This functionc locks given context, search for the right extension and
2571  * fires out all peer in this extensions with given priority. If priority
2572  * is set to 0, all peers are removed. After that, unlock context and
2573  * return.
2574  */
2575 int ast_context_remove_extension2(struct ast_context *con, const char *extension, int priority, const char *registrar)
2576 {
2577         struct ast_exten *exten, *prev_exten = NULL;
2578
2579         if (ast_mutex_lock(&con->lock)) return -1;
2580
2581         /* go through all extensions in context and search the right one ... */
2582         exten = con->root;
2583         while (exten) {
2584
2585                 /* look for right extension */
2586                 if (!strcmp(exten->exten, extension) &&
2587                         (!registrar || !strcmp(exten->registrar, registrar))) {
2588                         struct ast_exten *peer;
2589
2590                         /* should we free all peers in this extension? (priority == 0)? */
2591                         if (priority == 0) {
2592                                 /* remove this extension from context list */
2593                                 if (prev_exten)
2594                                         prev_exten->next = exten->next;
2595                                 else
2596                                         con->root = exten->next;
2597
2598                                 /* fire out all peers */
2599                                 peer = exten; 
2600                                 while (peer) {
2601                                         exten = peer->peer;
2602                                         
2603                                         if (!peer->priority==PRIORITY_HINT) 
2604                                             ast_remove_hint(peer);
2605
2606                                         peer->datad(peer->data);
2607                                         free(peer);
2608
2609                                         peer = exten;
2610                                 }
2611
2612                                 ast_mutex_unlock(&con->lock);
2613                                 return 0;
2614                         } else {
2615                                 /* remove only extension with exten->priority == priority */
2616                                 struct ast_exten *previous_peer = NULL;
2617
2618                                 peer = exten;
2619                                 while (peer) {
2620                                         /* is this our extension? */
2621                                         if (peer->priority == priority &&
2622                                                 (!registrar || !strcmp(peer->registrar, registrar) )) {
2623                                                 /* we are first priority extension? */
2624                                                 if (!previous_peer) {
2625                                                         /* exists previous extension here? */
2626                                                         if (prev_exten) {
2627                                                                 /* yes, so we must change next pointer in
2628                                                                  * previous connection to next peer
2629                                                                  */
2630                                                                 if (peer->peer) {
2631                                                                         prev_exten->next = peer->peer;
2632                                                                         peer->peer->next = exten->next;
2633                                                                 } else
2634                                                                         prev_exten->next = exten->next;
2635                                                         } else {
2636                                                                 /* no previous extension, we are first
2637                                                                  * extension, so change con->root ...
2638                                                                  */
2639                                                                 if (peer->peer)
2640                                                                         con->root = peer->peer;
2641                                                                 else
2642                                                                         con->root = exten->next; 
2643                                                         }
2644                                                 } else {
2645                                                         /* we are not first priority in extension */
2646                                                         previous_peer->peer = peer->peer;
2647                                                 }
2648
2649                                                 /* now, free whole priority extension */
2650                                                 if (peer->priority==PRIORITY_HINT)
2651                                                     ast_remove_hint(peer);
2652                                                 peer->datad(peer->data);
2653                                                 free(peer);
2654
2655                                                 ast_mutex_unlock(&con->lock);
2656                                                 return 0;
2657                                         } else {
2658                                                 /* this is not right extension, skip to next peer */
2659                                                 previous_peer = peer;
2660                                                 peer = peer->peer;
2661                                         }
2662                                 }
2663
2664                                 ast_mutex_unlock(&con->lock);
2665                                 return -1;
2666                         }
2667                 }
2668
2669                 prev_exten = exten;
2670                 exten = exten->next;
2671         }
2672
2673         /* we can't find right extension */
2674         ast_mutex_unlock(&con->lock);
2675         return -1;
2676 }
2677
2678
2679 int ast_register_application(const char *app, int (*execute)(struct ast_channel *, void *), const char *synopsis, const char *description)
2680 {
2681         struct ast_app *tmp, *prev, *cur;
2682         char tmps[80];
2683         int length;
2684         length = sizeof(struct ast_app);
2685         length += strlen(app) + 1;
2686         if (ast_mutex_lock(&applock)) {
2687                 ast_log(LOG_ERROR, "Unable to lock application list\n");
2688                 return -1;
2689         }
2690         tmp = apps;
2691         while(tmp) {
2692                 if (!strcasecmp(app, tmp->name)) {
2693                         ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
2694                         ast_mutex_unlock(&applock);
2695                         return -1;
2696                 }
2697                 tmp = tmp->next;
2698         }
2699         tmp = malloc(length);
2700         if (tmp) {
2701                 memset(tmp, 0, length);
2702                 strcpy(tmp->name, app);
2703                 tmp->execute = execute;
2704                 tmp->synopsis = synopsis;
2705                 tmp->description = description;
2706                 /* Store in alphabetical order */
2707                 cur = apps;
2708                 prev = NULL;
2709                 while(cur) {
2710                         if (strcasecmp(tmp->name, cur->name) < 0)
2711                                 break;
2712                         prev = cur;
2713                         cur = cur->next;
2714                 }
2715                 if (prev) {
2716                         tmp->next = prev->next;
2717                         prev->next = tmp;
2718                 } else {
2719                         tmp->next = apps;
2720                         apps = tmp;
2721                 }
2722         } else {
2723                 ast_log(LOG_ERROR, "Out of memory\n");
2724                 ast_mutex_unlock(&applock);
2725                 return -1;
2726         }
2727         if (option_verbose > 1)
2728                 ast_verbose( VERBOSE_PREFIX_2 "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
2729         ast_mutex_unlock(&applock);
2730         return 0;
2731 }
2732
2733 int ast_register_switch(struct ast_switch *sw)
2734 {
2735         struct ast_switch *tmp, *prev=NULL;
2736         if (ast_mutex_lock(&switchlock)) {
2737                 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
2738                 return -1;
2739         }
2740         tmp = switches;
2741         while(tmp) {
2742                 if (!strcasecmp(tmp->name, sw->name))
2743                         break;
2744                 prev = tmp;
2745                 tmp = tmp->next;
2746         }
2747         if (tmp) {      
2748                 ast_mutex_unlock(&switchlock);
2749                 ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name);
2750                 return -1;
2751         }
2752         sw->next = NULL;
2753         if (prev) 
2754                 prev->next = sw;
2755         else
2756                 switches = sw;
2757         ast_mutex_unlock(&switchlock);
2758         return 0;
2759 }
2760
2761 void ast_unregister_switch(struct ast_switch *sw)
2762 {
2763         struct ast_switch *tmp, *prev=NULL;
2764         if (ast_mutex_lock(&switchlock)) {
2765                 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
2766                 return;
2767         }
2768         tmp = switches;
2769         while(tmp) {
2770                 if (tmp == sw) {
2771                         if (prev)
2772                                 prev->next = tmp->next;
2773                         else
2774                                 switches = tmp->next;
2775                         tmp->next = NULL;
2776                         break;                  
2777                 }
2778                 prev = tmp;
2779                 tmp = tmp->next;
2780         }
2781         ast_mutex_unlock(&switchlock);
2782 }
2783
2784 /*
2785  * Help for CLI commands ...
2786  */
2787 static char show_application_help[] = 
2788 "Usage: show application <application> [<application> [<application> [...]]]\n"
2789 "       Describes a particular application.\n";
2790
2791 static char show_functions_help[] =
2792 "Usage: show functions\n"
2793 "       List builtin functions accessable as $(function args)";
2794
2795 static char show_applications_help[] =
2796 "Usage: show applications [{like|describing} <text>]\n"
2797 "       List applications which are currently available.\n"
2798 "       If 'like', <text> will be a substring of the app name\n"
2799 "       If 'describing', <text> will be a substring of the description\n";
2800
2801 static char show_dialplan_help[] =
2802 "Usage: show dialplan [exten@][context]\n"
2803 "       Show dialplan\n";
2804
2805 static char show_switches_help[] = 
2806 "Usage: show switches\n"
2807 "       Show registered switches\n";
2808
2809 static char show_hints_help[] = 
2810 "Usage: show hints\n"
2811 "       Show registered hints\n";
2812
2813
2814 /*
2815  * IMPLEMENTATION OF CLI FUNCTIONS IS IN THE SAME ORDER AS COMMANDS HELPS
2816  *
2817  */
2818
2819 /*
2820  * 'show application' CLI command implementation functions ...
2821  */
2822
2823 /*
2824  * There is a possibility to show informations about more than one
2825  * application at one time. You can type 'show application Dial Echo' and
2826  * you will see informations about these two applications ...
2827  */
2828 static char *complete_show_application(char *line, char *word,
2829         int pos, int state)
2830 {
2831         struct ast_app *a;
2832         int which = 0;
2833
2834         /* try to lock applications list ... */
2835         if (ast_mutex_lock(&applock)) {
2836                 ast_log(LOG_ERROR, "Unable to lock application list\n");
2837                 return NULL;
2838         }
2839
2840         /* ... walk all applications ... */
2841         a = apps; 
2842         while (a) {
2843                 /* ... check if word matches this application ... */
2844                 if (!strncasecmp(word, a->name, strlen(word))) {
2845                         /* ... if this is right app serve it ... */
2846                         if (++which > state) {
2847                                 char *ret = strdup(a->name);
2848                                 ast_mutex_unlock(&applock);
2849                                 return ret;
2850                         }
2851                 }
2852                 a = a->next; 
2853         }
2854
2855         /* no application match */
2856         ast_mutex_unlock(&applock);
2857         return NULL; 
2858 }
2859
2860 static int handle_show_application(int fd, int argc, char *argv[])
2861 {
2862         struct ast_app *a;
2863         int app, no_registered_app = 1;
2864
2865         if (argc < 3) return RESULT_SHOWUSAGE;
2866
2867         /* try to lock applications list ... */
2868         if (ast_mutex_lock(&applock)) {
2869                 ast_log(LOG_ERROR, "Unable to lock application list\n");
2870                 return -1;
2871         }
2872
2873         /* ... go through all applications ... */
2874         a = apps; 
2875         while (a) {
2876                 /* ... compare this application name with all arguments given
2877                  * to 'show application' command ... */
2878                 for (app = 2; app < argc; app++) {
2879                         if (!strcasecmp(a->name, argv[app])) {
2880                                 /* Maximum number of characters added by terminal coloring is 22 */
2881                                 char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
2882                                 char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
2883                                 int synopsis_size, description_size;
2884
2885                                 no_registered_app = 0;
2886
2887                                 if (a->synopsis)
2888                                         synopsis_size = strlen(a->synopsis) + 23;
2889                                 else
2890                                         synopsis_size = strlen("Not available") + 23;
2891                                 synopsis = alloca(synopsis_size);
2892
2893                                 if (a->description)
2894                                         description_size = strlen(a->description) + 23;
2895                                 else
2896                                         description_size = strlen("Not available") + 23;
2897                                 description = alloca(description_size);
2898
2899                                 if (synopsis && description) {
2900                                         snprintf(info, 64 + AST_MAX_APP, "\n  -= Info about application '%s' =- \n\n", a->name);
2901                                         term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
2902                                         term_color(syntitle, "[Synopsis]:\n", COLOR_MAGENTA, 0, 40);
2903                                         term_color(destitle, "[Description]:\n", COLOR_MAGENTA, 0, 40);
2904                                         term_color(synopsis,
2905                                                                         a->synopsis ? a->synopsis : "Not available",
2906                                                                         COLOR_CYAN, 0, synopsis_size);
2907                                         term_color(description,
2908                                                                         a->description ? a->description : "Not available",
2909                                                                         COLOR_CYAN, 0, description_size);
2910
2911                                         ast_cli(fd,"%s%s%s\n\n%s%s\n", infotitle, syntitle, synopsis, destitle, description);
2912                                 } else {
2913                                         /* ... one of our applications, show info ...*/
2914                                         ast_cli(fd,"\n  -= Info about application '%s' =- \n\n"
2915                                                 "[Synopsis]:\n  %s\n\n"
2916                                                 "[Description]:\n%s\n",
2917                                                 a->name,
2918                                                 a->synopsis ? a->synopsis : "Not available",
2919                                                 a->description ? a->description : "Not available");
2920                                 }
2921                         }
2922                 }
2923                 a = a->next; 
2924         }
2925
2926         ast_mutex_unlock(&applock);
2927
2928         /* we found at least one app? no? */
2929         if (no_registered_app) {
2930                 ast_cli(fd, "Your application(s) is (are) not registered\n");
2931                 return RESULT_FAILURE;
2932         }
2933
2934         return RESULT_SUCCESS;
2935 }
2936
2937 /*--- handle_show_hints: CLI support for listing registred dial plan hints */
2938 static int handle_show_hints(int fd, int argc, char *argv[])
2939 {
2940         struct ast_hint *hint;
2941         int num = 0;
2942
2943         if (!hints) {
2944                 ast_cli(fd, "There are no registered dialplan hints\n");
2945                 return RESULT_SUCCESS;
2946         }
2947         /* ... we have hints ... */
2948         ast_cli(fd, "\n    -= Registered Asterisk Dial Plan Hints =-\n");
2949         if (ast_mutex_lock(&hintlock)) {
2950                 ast_log(LOG_ERROR, "Unable to lock hints\n");
2951                 return -1;
2952         }
2953         hint = hints;
2954         while (hint) {
2955                 ast_cli(fd, "   %-20.20s: %-20.20s  State %2d\n", ast_get_extension_name(hint->exten), ast_get_extension_app(hint->exten), hint->laststate );
2956                 num++;
2957                 hint = hint->next;
2958         }
2959         ast_cli(fd, "----------------\n");
2960         ast_cli(fd, "- %d hints registred\n", num);
2961         ast_mutex_unlock(&hintlock);
2962         return RESULT_SUCCESS;
2963 }
2964
2965 /*--- handle_show_switches: CLI support for listing registred dial plan switches */
2966 static int handle_show_switches(int fd, int argc, char *argv[])
2967 {
2968         struct ast_switch *sw;
2969         if (!switches) {
2970                 ast_cli(fd, "There are no registered alternative switches\n");
2971                 return RESULT_SUCCESS;
2972         }
2973         /* ... we have applications ... */
2974         ast_cli(fd, "\n    -= Registered Asterisk Alternative Switches =-\n");
2975         if (ast_mutex_lock(&switchlock)) {
2976                 ast_log(LOG_ERROR, "Unable to lock switches\n");
2977                 return -1;
2978         }
2979         sw = switches;
2980         while (sw) {
2981                 ast_cli(fd, "%s: %s\n", sw->name, sw->description);
2982                 sw = sw->next;
2983         }
2984         ast_mutex_unlock(&switchlock);
2985         return RESULT_SUCCESS;
2986 }
2987
2988 /*
2989  * 'show applications' CLI command implementation functions ...
2990  */
2991 static