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