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