0b61d66cd3e372f03d975c84138ea0e6ed0dc64c
[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 (if 'w' option is specifed).\n"
325         "record WILL be stored.\nAlways returns 0.\n"  
326         },
327
328         { "ResponseTimeout", pbx_builtin_rtimeout,
329         "Set maximum timeout awaiting response",
330         "  ResponseTimeout(seconds): Set the maximum amount of time permitted after\n"
331         "falling through a series of priorities for a channel in which the user may\n"
332         "begin typing an extension. If the user does not type an extension in this\n"
333         "amount of time, control will pass to the 't' extension if it exists, and\n"
334         "if not the call would be terminated.\nAlways returns 0.\n"  
335         },
336
337         { "Ringing", pbx_builtin_ringing,
338         "Indicate ringing tone",
339         "  Ringing(): Request that the channel indicate ringing tone to the user.\n"
340         "Always returns 0.\n" 
341         },
342
343         { "SayNumber", pbx_builtin_saynumber,
344         "Say Number",
345         "  SayNumber(digits[,gender]): Says the passed number. SayNumber is using\n" 
346         "the current language setting for the channel. (See app SetLanguage).\n"
347         },
348
349         { "SayDigits", pbx_builtin_saydigits,
350         "Say Digits",
351         "  SayDigits(digits): Says the passed digits. SayDigits is using the\n" 
352         "current language setting for the channel. (See app setLanguage)\n"
353         },
354
355         { "SayAlpha", pbx_builtin_saycharacters,
356         "Say Alpha",
357         "  SayAlpha(string): Spells the passed string\n" 
358         },
359
360         { "SayPhonetic", pbx_builtin_sayphonetic,
361         "Say Phonetic",
362         "  SayPhonetic(string): Spells the passed string with phonetic alphabet\n" 
363         },
364
365         { "SetAccount", pbx_builtin_setaccount,
366         "Sets account code",
367         "  SetAccount([account]):  Set  the  channel account code for billing\n"
368         "purposes. Always returns 0.\n"  
369         },
370
371         { "SetAMAFlags", pbx_builtin_setamaflags,
372         "Sets AMA Flags",
373         "  SetAMAFlags([flag]):  Set  the  channel AMA Flags for billing\n"
374         "purposes. Always returns 0.\n"  
375         },
376
377         { "SetGlobalVar", pbx_builtin_setglobalvar,
378         "Set global variable to value",
379         "  SetGlobalVar(#n=value): Sets global variable n to value. Global\n" 
380         "variable are available across channels.\n"
381         },
382
383         { "SetLanguage", pbx_builtin_setlanguage,
384         "Sets user language",
385         "  SetLanguage(language):  Set  the  channel  language to 'language'.  This\n"
386         "information is used for the syntax in generation of numbers, and to choose\n"
387         "a natural language file when available.\n"
388         "  For example, if language is set to 'fr' and the file 'demo-congrats' is \n"
389         "requested  to  be  played,  if the file 'fr/demo-congrats' exists, then\n"
390         "it will play that file, and if not will play the normal 'demo-congrats'.\n"
391         "Always returns 0.\n"  
392         },
393
394         { "SetVar", pbx_builtin_setvar,
395         "Set variable to value",
396         "  SetVar(#n=value): Sets variable n to value.  If prefixed with _, single\n"
397         "inheritance assumed.  If prefixed with __, infinite inheritance is assumed.\n" },
398
399         { "ImportVar", pbx_builtin_importvar,
400         "Set variable to value",
401         "  ImportVar(#n=channel|variable): Sets variable n to variable as evaluated on\n"
402         "the specified channel (instead of current).  If prefixed with _, single\n"
403         "inheritance assumed.  If prefixed with __, infinite inheritance is assumed.\n" },
404
405         { "StripMSD", pbx_builtin_stripmsd,
406         "Strip leading digits",
407         "  StripMSD(count): Strips the leading 'count' digits from the channel's\n"
408         "associated extension. For example, the number 5551212 when stripped with a\n"
409         "count of 3 would be changed to 1212. This app always returns 0, and the PBX\n"
410         "will continue processing at the next priority for the *new* extension.\n"
411         "  So, for example, if priority 3 of 5551212 is StripMSD 3, the next step\n"
412         "executed will be priority 4 of 1212. If you switch into an extension which\n"
413         "has no first step, the PBX will treat it as though the user dialed an\n"
414         "invalid extension.\n" 
415         },
416
417         { "Suffix", pbx_builtin_suffix, 
418         "Append trailing digits",
419         "  Suffix(digits): Appends the  digit  string  specified  by  digits to the\n"
420         "channel's associated extension. For example, the number 555 when  suffixed\n"
421         "with '1212' will become 5551212. This app always returns 0, and the PBX will\n"
422         "continue processing at the next priority for the *new* extension.\n"
423         "  So, for example, if priority  3  of  555 is Suffix 1212, the  next  step\n"
424         "executed will be priority 4 of 5551212. If  you  switch  into an  extension\n"
425         "which has no first step, the PBX will treat it as though the user dialed an\n"
426         "invalid extension.\n" 
427         },
428
429         { "Wait", pbx_builtin_wait, 
430         "Waits for some time", 
431         "  Wait(seconds): Waits for a specified number of seconds, then returns 0.\n"
432         "seconds can be passed with fractions of a second. (eg: 1.5 = 1.5 seconds)\n" 
433         },
434
435         { "WaitExten", pbx_builtin_waitexten, 
436         "Waits for an extension to be entered", 
437         "  WaitExten([seconds]): Waits for the user to enter a new extension for the \n"
438         "specified number of seconds, then returns 0.  Seconds can be passed with\n"
439         "fractions of a seconds (eg: 1.5 = 1.5 seconds) or if unspecified the\n"
440         "default extension timeout will be used.\n" 
441         },
442
443 };
444
445 AST_MUTEX_DEFINE_STATIC(applock);               /* Lock for the application list */
446 static struct ast_context *contexts = NULL;
447 AST_MUTEX_DEFINE_STATIC(conlock);               /* Lock for the ast_context list */
448 static struct ast_app *apps = NULL;
449
450 AST_MUTEX_DEFINE_STATIC(switchlock);            /* Lock for switches */
451 struct ast_switch *switches = NULL;
452
453 AST_MUTEX_DEFINE_STATIC(hintlock);              /* Lock for extension state notifys */
454 static int stateid = 1;
455 struct ast_hint *hints = NULL;
456 struct ast_state_cb *statecbs = NULL;
457
458 int pbx_exec(struct ast_channel *c,             /* Channel */
459                 struct ast_app *app,            /* Application */
460                 void *data,                     /* Data for execution */
461                 int newstack)                   /* Force stack increment */
462 {
463         /* This function is special.  It saves the stack so that no matter
464            how many times it is called, it returns to the same place */
465         int res;
466         
467         char *saved_c_appl;
468         char *saved_c_data;
469         
470         int (*execute)(struct ast_channel *chan, void *data) = app->execute; 
471
472         if (newstack) {
473                 if (c->cdr)
474                         ast_cdr_setapp(c->cdr, app->name, data);
475
476                 /* save channel values */
477                 saved_c_appl= c->appl;
478                 saved_c_data= c->data;
479
480                 c->appl = app->name;
481                 c->data = data;         
482                 res = execute(c, data);
483                 /* restore channel values */
484                 c->appl= saved_c_appl;
485                 c->data= saved_c_data;
486                 return res;
487         } else
488                 ast_log(LOG_WARNING, "You really didn't want to call this function with newstack set to 0\n");
489         return -1;
490 }
491
492
493 /* Go no deeper than this through includes (not counting loops) */
494 #define AST_PBX_MAX_STACK       128
495
496 #define HELPER_EXISTS 0
497 #define HELPER_SPAWN 1
498 #define HELPER_EXEC 2
499 #define HELPER_CANMATCH 3
500 #define HELPER_MATCHMORE 4
501 #define HELPER_FINDLABEL 5
502
503 struct ast_app *pbx_findapp(const char *app) 
504 {
505         struct ast_app *tmp;
506
507         if (ast_mutex_lock(&applock)) {
508                 ast_log(LOG_WARNING, "Unable to obtain application lock\n");
509                 return NULL;
510         }
511         tmp = apps;
512         while(tmp) {
513                 if (!strcasecmp(tmp->name, app))
514                         break;
515                 tmp = tmp->next;
516         }
517         ast_mutex_unlock(&applock);
518         return tmp;
519 }
520
521 static struct ast_switch *pbx_findswitch(const char *sw)
522 {
523         struct ast_switch *asw;
524
525         if (ast_mutex_lock(&switchlock)) {
526                 ast_log(LOG_WARNING, "Unable to obtain application lock\n");
527                 return NULL;
528         }
529         asw = switches;
530         while(asw) {
531                 if (!strcasecmp(asw->name, sw))
532                         break;
533                 asw = asw->next;
534         }
535         ast_mutex_unlock(&switchlock);
536         return asw;
537 }
538
539 static inline int include_valid(struct ast_include *i)
540 {
541         if (!i->hastime)
542                 return 1;
543
544         return ast_check_timing(&(i->timing));
545 }
546
547 static void pbx_destroy(struct ast_pbx *p)
548 {
549         free(p);
550 }
551
552 #define EXTENSION_MATCH_CORE(data,pattern,match) {\
553         /* All patterns begin with _ */\
554         if (pattern[0] != '_') \
555                 return 0;\
556         /* Start optimistic */\
557         match=1;\
558         pattern++;\
559         while(match && *data && *pattern && (*pattern != '/')) {\
560                 while (*data == '-' && (*(data+1) != '\0')) data++;\
561                 switch(toupper(*pattern)) {\
562                 case '[': \
563                 {\
564                         int i,border=0;\
565                         char *where;\
566                         match=0;\
567                         pattern++;\
568                         where=strchr(pattern,']');\
569                         if (where)\
570                                 border=(int)(where-pattern);\
571                         if (!where || border > strlen(pattern)) {\
572                                 ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");\
573                                 return match;\
574                         }\
575                         for (i=0; i<border; i++) {\
576                                 int res=0;\
577                                 if (i+2<border)\
578                                         if (pattern[i+1]=='-') {\
579                                                 if (*data >= pattern[i] && *data <= pattern[i+2]) {\
580                                                         res=1;\
581                                                 } else {\
582                                                         i+=2;\
583                                                         continue;\
584                                                 }\
585                                         }\
586                                 if (res==1 || *data==pattern[i]) {\
587                                         match = 1;\
588                                         break;\
589                                 }\
590                         }\
591                         pattern+=border;\
592                         break;\
593                 }\
594                 case 'N':\
595                         if ((*data < '2') || (*data > '9'))\
596                                 match=0;\
597                         break;\
598                 case 'X':\
599                         if ((*data < '0') || (*data > '9'))\
600                                 match = 0;\
601                         break;\
602                 case 'Z':\
603                         if ((*data < '1') || (*data > '9'))\
604                                 match = 0;\
605                         break;\
606                 case '.':\
607                         /* Must match */\
608                         return 1;\
609                 case ' ':\
610                 case '-':\
611                         /* Ignore these characters */\
612                         data--;\
613                         break;\
614                 default:\
615                         if (*data != *pattern)\
616                                 match =0;\
617                 }\
618                 data++;\
619                 pattern++;\
620         }\
621 }
622
623 int ast_extension_match(const char *pattern, const char *data)
624 {
625         int match;
626         /* If they're the same return */
627         if (!strcmp(pattern, data))
628                 return 1;
629         EXTENSION_MATCH_CORE(data,pattern,match);
630         /* Must be at the end of both */
631         if (*data || (*pattern && (*pattern != '/')))
632                 match = 0;
633         return match;
634 }
635
636 int ast_extension_close(const char *pattern, const char *data, int needmore)
637 {
638         int match;
639         /* If "data" is longer, it can'be a subset of pattern unless
640            pattern is a pattern match */
641         if ((strlen(pattern) < strlen(data)) && (pattern[0] != '_'))
642                 return 0;
643         
644         if ((ast_strlen_zero((char *)data) || !strncasecmp(pattern, data, strlen(data))) && 
645                 (!needmore || (strlen(pattern) > strlen(data)))) {
646                 return 1;
647         }
648         EXTENSION_MATCH_CORE(data,pattern,match);
649         /* If there's more or we don't care about more, return non-zero, otlherwise it's a miss */
650         if (!needmore || *pattern) {
651                 return match;
652         } else
653                 return 0;
654 }
655
656 struct ast_context *ast_context_find(const char *name)
657 {
658         struct ast_context *tmp;
659         ast_mutex_lock(&conlock);
660         if (name) {
661                 tmp = contexts;
662                 while(tmp) {
663                         if (!strcasecmp(name, tmp->name))
664                                 break;
665                         tmp = tmp->next;
666                 }
667         } else
668                 tmp = contexts;
669         ast_mutex_unlock(&conlock);
670         return tmp;
671 }
672
673 #define STATUS_NO_CONTEXT   1
674 #define STATUS_NO_EXTENSION 2
675 #define STATUS_NO_PRIORITY  3
676 #define STATUS_NO_LABEL         4
677 #define STATUS_SUCCESS      5
678
679 static int matchcid(const char *cidpattern, const char *callerid)
680 {
681         int failresult;
682         
683         /* If the Caller*ID pattern is empty, then we're matching NO Caller*ID, so
684            failing to get a number should count as a match, otherwise not */
685
686
687         if (!ast_strlen_zero(cidpattern))
688                 failresult = 0;
689         else
690                 failresult = 1;
691
692         if (!callerid)
693                 return failresult;
694
695         return ast_extension_match(cidpattern, callerid);
696 }
697
698 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)
699 {
700         int x, res;
701         struct ast_context *tmp;
702         struct ast_exten *e, *eroot;
703         struct ast_include *i;
704         struct ast_sw *sw;
705         struct ast_switch *asw;
706
707         /* Initialize status if appropriate */
708         if (!*stacklen) {
709                 *status = STATUS_NO_CONTEXT;
710                 *swo = NULL;
711                 *data = NULL;
712         }
713         /* Check for stack overflow */
714         if (*stacklen >= AST_PBX_MAX_STACK) {
715                 ast_log(LOG_WARNING, "Maximum PBX stack exceeded\n");
716                 return NULL;
717         }
718         /* Check first to see if we've already been checked */
719         for (x=0;x<*stacklen;x++) {
720                 if (!strcasecmp(incstack[x], context))
721                         return NULL;
722         }
723         if (bypass)
724                 tmp = bypass;
725         else
726                 tmp = contexts;
727         while(tmp) {
728                 /* Match context */
729                 if (bypass || !strcmp(tmp->name, context)) {
730                         if (*status < STATUS_NO_EXTENSION)
731                                 *status = STATUS_NO_EXTENSION;
732                         eroot = tmp->root;
733                         while(eroot) {
734                                 /* Match extension */
735                                 if ((((action != HELPER_MATCHMORE) && ast_extension_match(eroot->exten, exten)) ||
736                                                 ((action == HELPER_CANMATCH) && (ast_extension_close(eroot->exten, exten, 0))) ||
737                                                 ((action == HELPER_MATCHMORE) && (ast_extension_close(eroot->exten, exten, 1)))) &&
738                                                 (!eroot->matchcid || matchcid(eroot->cidmatch, callerid))) {
739                                                 e = eroot;
740                                                 if (*status < STATUS_NO_PRIORITY)
741                                                         *status = STATUS_NO_PRIORITY;
742                                                 while(e) {
743                                                         /* Match priority */
744                                                         if (action == HELPER_FINDLABEL) {
745                                                                 if (*status < STATUS_NO_LABEL)
746                                                                         *status = STATUS_NO_LABEL;
747                                                                 if (label && e->label && !strcmp(label, e->label)) {
748                                                                         *status = STATUS_SUCCESS;
749                                                                         *foundcontext = context;
750                                                                         return e;
751                                                                 }
752                                                         } else if (e->priority == priority) {
753                                                                 *status = STATUS_SUCCESS;
754                                                                 *foundcontext = context;
755                                                                 return e;
756                                                         }
757                                                         e = e->peer;
758                                                 }
759                                 }
760                                 eroot = eroot->next;
761                         }
762                         /* Check alternative switches */
763                         sw = tmp->alts;
764                         while(sw) {
765                                 if ((asw = pbx_findswitch(sw->name))) {
766                                         /* Substitute variables now */
767                                         if (sw->eval) 
768                                                 pbx_substitute_variables_helper(chan, sw->data, sw->tmpdata, SWITCH_DATA_LENGTH - 1);
769                                         if (action == HELPER_CANMATCH)
770                                                 res = asw->canmatch ? asw->canmatch(chan, context, exten, priority, callerid, sw->eval ? sw->tmpdata : sw->data) : 0;
771                                         else if (action == HELPER_MATCHMORE)
772                                                 res = asw->matchmore ? asw->matchmore(chan, context, exten, priority, callerid, sw->eval ? sw->tmpdata : sw->data) : 0;
773                                         else
774                                                 res = asw->exists ? asw->exists(chan, context, exten, priority, callerid, sw->eval ? sw->tmpdata : sw->data) : 0;
775                                         if (res) {
776                                                 /* Got a match */
777                                                 *swo = asw;
778                                                 *data = sw->eval ? sw->tmpdata : sw->data;
779                                                 *foundcontext = context;
780                                                 return NULL;
781                                         }
782                                 } else {
783                                         ast_log(LOG_WARNING, "No such switch '%s'\n", sw->name);
784                                 }
785                                 sw = sw->next;
786                         }
787                         /* Setup the stack */
788                         incstack[*stacklen] = tmp->name;
789                         (*stacklen)++;
790                         /* Now try any includes we have in this context */
791                         i = tmp->includes;
792                         while(i) {
793                                 if (include_valid(i)) {
794                                         if ((e = pbx_find_extension(chan, bypass, i->rname, exten, priority, label, callerid, action, incstack, stacklen, status, swo, data, foundcontext))) 
795                                                 return e;
796                                         if (*swo) 
797                                                 return NULL;
798                                 }
799                                 i = i->next;
800                         }
801                         break;
802                 }
803                 tmp = tmp->next;
804         }
805         return NULL;
806 }
807
808 void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp)
809 {
810         char *first,*second;
811         char tmpvar[80] = "";
812         time_t thistime;
813         struct tm brokentime;
814         int offset,offset2;
815         struct ast_var_t *variables;
816
817         if (c) 
818                 headp=&c->varshead;
819         *ret=NULL;
820         /* Now we have the variable name on cp3 */
821         if (!strncasecmp(var,"LEN(",4)) {
822                 int len=strlen(var);
823                 int len_len=4;
824                 if (strrchr(var,')')) {
825                         char cp3[80];
826                         strncpy(cp3, var, sizeof(cp3) - 1);
827                         cp3[len-len_len-1]='\0';
828                         sprintf(workspace,"%d",(int)strlen(cp3));
829                         *ret = workspace;
830                 } else {
831                         /* length is zero */
832                         *ret = "0";
833                 }
834         } else if ((first=strchr(var,':'))) {
835                 strncpy(tmpvar, var, sizeof(tmpvar) - 1);
836                 first = strchr(tmpvar, ':');
837                 if (!first)
838                         first = tmpvar + strlen(tmpvar);
839                 *first='\0';
840                 pbx_retrieve_variable(c,tmpvar,ret,workspace,workspacelen - 1, headp);
841                 if (!(*ret)) return;
842                 offset=atoi(first+1);
843                 if ((second=strchr(first+1,':'))) {
844                         *second='\0';
845                         offset2=atoi(second+1);
846                 } else
847                         offset2=strlen(*ret)-offset;
848                 if (abs(offset)>strlen(*ret)) {
849                         if (offset>=0) 
850                                 offset=strlen(*ret);
851                         else 
852                                 offset=-strlen(*ret);
853                 }
854                 if ((offset<0 && offset2>-offset) || (offset>=0 && offset+offset2>strlen(*ret))) {
855                         if (offset>=0) 
856                                 offset2=strlen(*ret)-offset;
857                         else 
858                                 offset2=strlen(*ret)+offset;
859                 }
860                 if (offset>=0)
861                         *ret+=offset;
862                 else
863                         *ret+=strlen(*ret)+offset;
864                 (*ret)[offset2] = '\0';
865         } else if (c && !strcmp(var, "CALLERIDNUM")) {
866                 if (c->cid.cid_num) {
867                         strncpy(workspace, c->cid.cid_num, workspacelen - 1);
868                         *ret = workspace;
869                 } else
870                         *ret = NULL;
871         } else if (c && !strcmp(var, "CALLERANI")) {
872                 if (c->cid.cid_ani) {
873                         strncpy(workspace, c->cid.cid_ani, workspacelen - 1);
874                         *ret = workspace;
875                 } else
876                         *ret = NULL;
877         } else if (c && !strcmp(var, "CALLERIDNAME")) {
878                 if (c->cid.cid_name) {
879                         strncpy(workspace, c->cid.cid_name, workspacelen - 1);
880                         *ret = workspace;
881                 } else
882                         *ret = NULL;
883         } else if (c && !strcmp(var, "CALLERID")) {
884                 if (c->cid.cid_num) {
885                         if (c->cid.cid_name) {
886                                 snprintf(workspace, workspacelen, "\"%s\" <%s>", c->cid.cid_name, c->cid.cid_num);
887                         } else {
888                                 strncpy(workspace, c->cid.cid_num, workspacelen - 1);
889                         }
890                         *ret = workspace;
891                 } else if (c->cid.cid_name) {
892                         strncpy(workspace, c->cid.cid_name, workspacelen - 1);
893                         *ret = workspace;
894                 } else
895                         *ret = NULL;
896         } else if (c && !strcmp(var, "DNID")) {
897                 if (c->cid.cid_dnid) {
898                         strncpy(workspace, c->cid.cid_dnid, workspacelen - 1);
899                         *ret = workspace;
900                 } else
901                         *ret = NULL;
902         } else if (c && !strcmp(var, "HINT")) {
903                 if (!ast_get_hint(workspace, workspacelen, NULL, 0, c, c->context, c->exten))
904                         *ret = NULL;
905                 else
906                         *ret = workspace;
907         } else if (c && !strcmp(var, "HINTNAME")) {
908                 if (!ast_get_hint(NULL, 0, workspace, workspacelen, c, c->context, c->exten))
909                         *ret = NULL;
910                 else
911                         *ret = workspace;
912         } else if (c && !strcmp(var, "EXTEN")) {
913                 strncpy(workspace, c->exten, workspacelen - 1);
914                 *ret = workspace;
915         } else if (c && !strcmp(var, "RDNIS")) {
916                 if (c->cid.cid_rdnis) {
917                         strncpy(workspace, c->cid.cid_rdnis, workspacelen - 1);
918                         *ret = workspace;
919                 } else
920                         *ret = NULL;
921         } else if (c && !strcmp(var, "CONTEXT")) {
922                 strncpy(workspace, c->context, workspacelen - 1);
923                 *ret = workspace;
924         } else if (c && !strcmp(var, "PRIORITY")) {
925                 snprintf(workspace, workspacelen, "%d", c->priority);
926                 *ret = workspace;
927         } else if (c && !strcmp(var, "CALLINGPRES")) {
928                 snprintf(workspace, workspacelen, "%d", c->cid.cid_pres);
929                 *ret = workspace;
930         } else if (c && !strcmp(var, "CALLINGANI2")) {
931                 snprintf(workspace, workspacelen, "%d", c->cid.cid_ani2);
932                 *ret = workspace;
933         } else if (c && !strcmp(var, "CALLINGTON")) {
934                 snprintf(workspace, workspacelen, "%d", c->cid.cid_ton);
935                 *ret = workspace;
936         } else if (c && !strcmp(var, "CALLINGTNS")) {
937                 snprintf(workspace, workspacelen, "%d", c->cid.cid_tns);
938                 *ret = workspace;
939         } else if (c && !strcmp(var, "CHANNEL")) {
940                 strncpy(workspace, c->name, workspacelen - 1);
941                 *ret = workspace;
942         } else if (c && !strcmp(var, "EPOCH")) {
943                 snprintf(workspace, workspacelen, "%u",(int)time(NULL));
944                 *ret = workspace;
945         } else if (c && !strcmp(var, "DATETIME")) {
946                 thistime=time(NULL);
947                 localtime_r(&thistime, &brokentime);
948                 snprintf(workspace, workspacelen, "%02d%02d%04d-%02d:%02d:%02d",
949                         brokentime.tm_mday,
950                         brokentime.tm_mon+1,
951                         brokentime.tm_year+1900,
952                         brokentime.tm_hour,
953                         brokentime.tm_min,
954                         brokentime.tm_sec
955                 );
956                 *ret = workspace;
957         } else if (c && !strcmp(var, "TIMESTAMP")) {
958                 thistime=time(NULL);
959                 localtime_r(&thistime, &brokentime);
960                 /* 20031130-150612 */
961                 snprintf(workspace, workspacelen, "%04d%02d%02d-%02d%02d%02d",
962                         brokentime.tm_year+1900,
963                         brokentime.tm_mon+1,
964                         brokentime.tm_mday,
965                         brokentime.tm_hour,
966                         brokentime.tm_min,
967                         brokentime.tm_sec
968                 );
969                 *ret = workspace;
970         } else if (c && !strcmp(var, "UNIQUEID")) {
971                 snprintf(workspace, workspacelen, "%s", c->uniqueid);
972                 *ret = workspace;
973         } else if (c && !strcmp(var, "HANGUPCAUSE")) {
974                 snprintf(workspace, workspacelen, "%i", c->hangupcause);
975                 *ret = workspace;
976         } else if (c && !strcmp(var, "ACCOUNTCODE")) {
977                 strncpy(workspace, c->accountcode, workspacelen - 1);
978                 *ret = workspace;
979         } else if (c && !strcmp(var, "LANGUAGE")) {
980                 strncpy(workspace, c->language, workspacelen - 1);
981                 *ret = workspace;
982         } else {
983                 if (headp) {
984                         AST_LIST_TRAVERSE(headp,variables,entries) {
985 #if 0
986                                 ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",var,ast_var_name(variables));
987 #endif
988                                 if (strcasecmp(ast_var_name(variables),var)==0) {
989                                         *ret=ast_var_value(variables);
990                                         if (*ret) {
991                                                 strncpy(workspace, *ret, workspacelen - 1);
992                                                 *ret = workspace;
993                                         }
994                                         break;
995                                 }
996                         }
997                 }
998                 if (!(*ret)) {
999                         /* Try globals */
1000                         AST_LIST_TRAVERSE(&globals,variables,entries) {
1001 #if 0
1002                                 ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",var,ast_var_name(variables));
1003 #endif
1004                                 if (strcasecmp(ast_var_name(variables),var)==0) {
1005                                         *ret=ast_var_value(variables);
1006                                         if (*ret) {
1007                                                 strncpy(workspace, *ret, workspacelen - 1);
1008                                                 *ret = workspace;
1009                                         }
1010                                 }
1011                         }
1012                 }
1013                 if (!(*ret)) {
1014                         int len=strlen(var);
1015                         int len_env=strlen("ENV(");
1016                         if (len > (len_env+1) && !strncasecmp(var,"ENV(",len_env) && !strcmp(var+len-1,")")) {
1017                                 char cp3[80] = "";
1018                                 strncpy(cp3, var, sizeof(cp3) - 1);
1019                                 cp3[len-1]='\0';
1020                                 *ret=getenv(cp3+len_env);
1021                                 if (*ret) {
1022                                         strncpy(workspace, *ret, workspacelen - 1);
1023                                         *ret = workspace;
1024                                 }
1025                         }
1026                 }
1027         }
1028 }
1029
1030 static void pbx_substitute_variables_helper_full(struct ast_channel *c, const char *cp1, char *cp2, int count, struct varshead *headp)
1031 {
1032         char *cp4;
1033         const char *tmp, *whereweare;
1034         int length;
1035         char workspace[4096];
1036         char ltmp[4096], var[4096];
1037         char *nextvar, *nextexp;
1038         char *vars, *vare;
1039         int pos, brackets, needsub, len;
1040         
1041         /* Substitutes variables into cp2, based on string cp1, and assuming cp2 to be
1042            zero-filled */
1043         whereweare=tmp=cp1;
1044         while(!ast_strlen_zero(whereweare) && count) {
1045                 /* Assume we're copying the whole remaining string */
1046                 pos = strlen(whereweare);
1047
1048                 /* Look for a variable */
1049                 nextvar = strstr(whereweare, "${");
1050                 
1051                 /* Look for an expression */
1052                 nextexp = strstr(whereweare, "$[");
1053                 
1054                 /* Pick the first one only */
1055                 if (nextvar && nextexp) {
1056                         if (nextvar < nextexp)
1057                                 nextexp = NULL;
1058                         else
1059                                 nextvar = NULL;
1060                 }
1061                 
1062                 /* If there is one, we only go that far */
1063                 if (nextvar)
1064                         pos = nextvar - whereweare;
1065                 else if (nextexp)
1066                         pos = nextexp - whereweare;
1067                 
1068                 /* Can't copy more than 'count' bytes */
1069                 if (pos > count)
1070                         pos = count;
1071                 
1072                 /* Copy that many bytes */
1073                 memcpy(cp2, whereweare, pos);
1074                 
1075                 count -= pos;
1076                 cp2 += pos;
1077                 whereweare += pos;
1078                 
1079                 if (nextvar) {
1080                         /* We have a variable.  Find the start and end, and determine
1081                            if we are going to have to recursively call ourselves on the
1082                            contents */
1083                         vars = vare = nextvar + 2;
1084                         brackets = 1;
1085                         needsub = 0;
1086                         
1087                         /* Find the end of it */
1088                         while(brackets && *vare) {
1089                                 if ((vare[0] == '$') && (vare[1] == '{')) {
1090                                         needsub++;
1091                                         brackets++;
1092                                 } else if (vare[0] == '}') {
1093                                         brackets--;
1094                                 } else if ((vare[0] == '$') && (vare[1] == '['))
1095                                         needsub++;
1096                                 vare++;
1097                         }
1098                         if (brackets)
1099                                 ast_log(LOG_NOTICE, "Error in extension logic (missing '}')\n");
1100                         len = vare - vars - 1;
1101                         
1102                         /* Skip totally over variable name */
1103                         whereweare += ( len + 3);
1104                         
1105                         /* Store variable name (and truncate) */
1106                         memset(var, 0, sizeof(var));
1107                         strncpy(var, vars, sizeof(var) - 1);
1108                         var[len] = '\0';
1109                         
1110                         /* Substitute if necessary */
1111                         if (needsub) {
1112                                 memset(ltmp, 0, sizeof(ltmp));
1113                                 pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1);
1114                                 vars = ltmp;
1115                         } else {
1116                                 vars = var;
1117                         }
1118                         
1119                         /* Retrieve variable value */
1120                         workspace[0] = '\0';
1121                         pbx_retrieve_variable(c,vars,&cp4, workspace, sizeof(workspace), headp);
1122                         if (cp4) {
1123                                 length = strlen(cp4);
1124                                 if (length > count)
1125                                         length = count;
1126                                 memcpy(cp2, cp4, length);
1127                                 count -= length;
1128                                 cp2 += length;
1129                         }
1130                         
1131                 } else if (nextexp) {
1132                         /* We have an expression.  Find the start and end, and determine
1133                            if we are going to have to recursively call ourselves on the
1134                            contents */
1135                         vars = vare = nextexp + 2;
1136                         brackets = 1;
1137                         needsub = 0;
1138                         
1139                         /* Find the end of it */
1140                         while(brackets && *vare) {
1141                                 if ((vare[0] == '$') && (vare[1] == '[')) {
1142                                         needsub++;
1143                                         brackets++;
1144                                         vare++;
1145                                 } else if (vare[0] == '[') {
1146                                         brackets++;
1147                                 } else if (vare[0] == ']') {
1148                                         brackets--;
1149                                 } else if ((vare[0] == '$') && (vare[1] == '{')) {
1150                                         needsub++;
1151                                         vare++;
1152                                 }
1153                                 vare++;
1154                         }
1155                         if (brackets)
1156                                 ast_log(LOG_NOTICE, "Error in extension logic (missing ']')\n");
1157                         len = vare - vars - 1;
1158                         
1159                         /* Skip totally over variable name */
1160                         whereweare += ( len + 3);
1161                         
1162                         /* Store variable name (and truncate) */
1163                         memset(var, 0, sizeof(var));
1164                         strncpy(var, vars, sizeof(var) - 1);
1165                         var[len] = '\0';
1166                         
1167                         /* Substitute if necessary */
1168                         if (needsub) {
1169                                 memset(ltmp, 0, sizeof(ltmp));
1170                                 pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1);
1171                                 vars = ltmp;
1172                         } else {
1173                                 vars = var;
1174                         }
1175
1176                         /* Evaluate expression */                       
1177                         cp4 = ast_expr(vars);
1178                         
1179                         ast_log(LOG_DEBUG, "Expression is '%s'\n", cp4);
1180                         
1181                         if (cp4) {
1182                                 length = strlen(cp4);
1183                                 if (length > count)
1184                                         length = count;
1185                                 memcpy(cp2, cp4, length);
1186                                 count -= length;
1187                                 cp2 += length;
1188                                 free(cp4);
1189                         }
1190                         
1191                 } else
1192                         break;
1193         }
1194 }
1195
1196 void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
1197 {
1198         pbx_substitute_variables_helper_full(c, cp1, cp2, count, NULL);
1199 }
1200
1201 void pbx_substitute_variables_varshead(struct varshead *headp, const char *cp1, char *cp2, int count)
1202 {
1203         pbx_substitute_variables_helper_full(NULL, cp1, cp2, count, headp);
1204 }
1205
1206 static void pbx_substitute_variables(char *passdata, int datalen, struct ast_channel *c, struct ast_exten *e) {
1207         
1208         memset(passdata, 0, datalen);
1209                 
1210         /* No variables or expressions in e->data, so why scan it? */
1211         if (!strstr(e->data,"${") && !strstr(e->data,"$[")) {
1212                 strncpy(passdata, e->data, datalen - 1);
1213                 passdata[datalen-1] = '\0';
1214                 return;
1215         }
1216         
1217         pbx_substitute_variables_helper(c, e->data, passdata, datalen - 1);
1218 }                                                               
1219
1220 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) 
1221 {
1222         struct ast_exten *e;
1223         struct ast_app *app;
1224         struct ast_switch *sw;
1225         char *data;
1226         const char *foundcontext=NULL;
1227         int newstack = 0;
1228         int res;
1229         int status = 0;
1230         char *incstack[AST_PBX_MAX_STACK];
1231         char passdata[EXT_DATA_SIZE];
1232         int stacklen = 0;
1233         char tmp[80];
1234         char tmp2[80];
1235         char tmp3[EXT_DATA_SIZE];
1236         char atmp[80];
1237         char atmp2[EXT_DATA_SIZE+100];
1238
1239         if (ast_mutex_lock(&conlock)) {
1240                 ast_log(LOG_WARNING, "Unable to obtain lock\n");
1241                 if ((action == HELPER_EXISTS) || (action == HELPER_CANMATCH) || (action == HELPER_MATCHMORE))
1242                         return 0;
1243                 else
1244                         return -1;
1245         }
1246         e = pbx_find_extension(c, con, context, exten, priority, label, callerid, action, incstack, &stacklen, &status, &sw, &data, &foundcontext);
1247         if (e) {
1248                 switch(action) {
1249                 case HELPER_CANMATCH:
1250                         ast_mutex_unlock(&conlock);
1251                         return -1;
1252                 case HELPER_EXISTS:
1253                         ast_mutex_unlock(&conlock);
1254                         return -1;
1255                 case HELPER_FINDLABEL:
1256                         res = e->priority;
1257                         ast_mutex_unlock(&conlock);
1258                         return res;
1259                 case HELPER_MATCHMORE:
1260                         ast_mutex_unlock(&conlock);
1261                         return -1;
1262                 case HELPER_SPAWN:
1263                         newstack++;
1264                         /* Fall through */
1265                 case HELPER_EXEC:
1266                         app = pbx_findapp(e->app);
1267                         ast_mutex_unlock(&conlock);
1268                         if (app) {
1269                                 if (c->context != context)
1270                                         strncpy(c->context, context, sizeof(c->context)-1);
1271                                 if (c->exten != exten)
1272                                         strncpy(c->exten, exten, sizeof(c->exten)-1);
1273                                 c->priority = priority;
1274                                 pbx_substitute_variables(passdata, sizeof(passdata), c, e);
1275                                 if (option_debug) {
1276                                                 ast_log(LOG_DEBUG, "Launching '%s'\n", app->name);
1277                                                 snprintf(atmp, 80, "STACK-%s-%s-%d", context, exten, priority);
1278                                                 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"));
1279                                                 pbx_builtin_setvar_helper(c, atmp, atmp2);
1280                                 }
1281                                 if (option_verbose > 2)
1282                                                 ast_verbose( VERBOSE_PREFIX_3 "Executing %s(\"%s\", \"%s\") %s\n", 
1283                                                                 term_color(tmp, app->name, COLOR_BRCYAN, 0, sizeof(tmp)),
1284                                                                 term_color(tmp2, c->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
1285                                                                 term_color(tmp3, (!ast_strlen_zero(passdata) ? (char *)passdata : ""), COLOR_BRMAGENTA, 0, sizeof(tmp3)),
1286                                                                 (newstack ? "in new stack" : "in same stack"));
1287                                 manager_event(EVENT_FLAG_CALL, "Newexten", 
1288                                         "Channel: %s\r\n"
1289                                         "Context: %s\r\n"
1290                                         "Extension: %s\r\n"
1291                                         "Priority: %d\r\n"
1292                                         "Application: %s\r\n"
1293                                         "AppData: %s\r\n"
1294                                         "Uniqueid: %s\r\n",
1295                                         c->name, c->context, c->exten, c->priority, app->name, passdata ? passdata : "(NULL)", c->uniqueid);
1296                                 res = pbx_exec(c, app, passdata, newstack);
1297                                 return res;
1298                         } else {
1299                                 ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
1300                                 return -1;
1301                         }
1302                 default:
1303                         ast_log(LOG_WARNING, "Huh (%d)?\n", action);                    return -1;
1304                 }
1305         } else if (sw) {
1306                 switch(action) {
1307                 case HELPER_CANMATCH:
1308                         ast_mutex_unlock(&conlock);
1309                         return -1;
1310                 case HELPER_EXISTS:
1311                         ast_mutex_unlock(&conlock);
1312                         return -1;
1313                 case HELPER_MATCHMORE:
1314                         ast_mutex_unlock(&conlock);
1315                         return -1;
1316                 case HELPER_FINDLABEL:
1317                         ast_mutex_unlock(&conlock);
1318                         return -1;
1319                 case HELPER_SPAWN:
1320                         newstack++;
1321                         /* Fall through */
1322                 case HELPER_EXEC:
1323                         ast_mutex_unlock(&conlock);
1324                         if (sw->exec)
1325                                 res = sw->exec(c, foundcontext ? foundcontext : context, exten, priority, callerid, newstack, data);
1326                         else {
1327                                 ast_log(LOG_WARNING, "No execution engine for switch %s\n", sw->name);
1328                                 res = -1;
1329                         }
1330                         return res;
1331                 default:
1332                         ast_log(LOG_WARNING, "Huh (%d)?\n", action);
1333                         return -1;
1334                 }
1335         } else {
1336                 ast_mutex_unlock(&conlock);
1337                 switch(status) {
1338                 case STATUS_NO_CONTEXT:
1339                         if ((action != HELPER_EXISTS) && (action != HELPER_MATCHMORE))
1340                                 ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", context);
1341                         break;
1342                 case STATUS_NO_EXTENSION:
1343                         if ((action != HELPER_EXISTS) && (action !=  HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1344                                 ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, context);
1345                         break;
1346                 case STATUS_NO_PRIORITY:
1347                         if ((action != HELPER_EXISTS) && (action !=  HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1348                                 ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, context);
1349                         break;
1350                 case STATUS_NO_LABEL:
1351                         if (context)
1352                                 ast_log(LOG_NOTICE, "No such label '%s' in extension '%s' in context '%s'\n", label, exten, context);
1353                         break;
1354                 default:
1355                         ast_log(LOG_DEBUG, "Shouldn't happen!\n");
1356                 }
1357                 
1358                 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1359                         return -1;
1360                 else
1361                         return 0;
1362         }
1363
1364 }
1365
1366 static struct ast_exten *ast_hint_extension(struct ast_channel *c, const char *context, const char *exten)
1367 {
1368         struct ast_exten *e;
1369         struct ast_switch *sw;
1370         char *data;
1371         const char *foundcontext = NULL;
1372         int status = 0;
1373         char *incstack[AST_PBX_MAX_STACK];
1374         int stacklen = 0;
1375
1376         if (ast_mutex_lock(&conlock)) {
1377                 ast_log(LOG_WARNING, "Unable to obtain lock\n");
1378                 return NULL;
1379         }
1380         e = pbx_find_extension(c, NULL, context, exten, PRIORITY_HINT, NULL, "", HELPER_EXISTS, incstack, &stacklen, &status, &sw, &data, &foundcontext);
1381         ast_mutex_unlock(&conlock);     
1382         return e;
1383 }
1384
1385 static int ast_extension_state2(struct ast_exten *e)
1386 {
1387         char hint[AST_MAX_EXTENSION] = "";    
1388         char *cur, *rest;
1389         int res = -1;
1390         int allunavailable = 1, allbusy = 1, allfree = 1;
1391         int busy = 0;
1392
1393         strncpy(hint, ast_get_extension_app(e), sizeof(hint)-1);
1394     
1395         cur = hint;    
1396         do {
1397                 rest = strchr(cur, '&');
1398                 if (rest) {
1399                         *rest = 0;
1400                         rest++;
1401                 }
1402         
1403                 res = ast_device_state(cur);
1404                 switch (res) {
1405                 case AST_DEVICE_NOT_INUSE:
1406                         allunavailable = 0;
1407                         allbusy = 0;
1408                         break;
1409                 case AST_DEVICE_INUSE:
1410                         return AST_EXTENSION_INUSE;
1411                 case AST_DEVICE_BUSY:
1412                         allunavailable = 0;
1413                         allfree = 0;
1414                         busy = 1;
1415                         break;
1416                 case AST_DEVICE_UNAVAILABLE:
1417                 case AST_DEVICE_INVALID:
1418                         allbusy = 0;
1419                         allfree = 0;
1420                         break;
1421                 default:
1422                         allunavailable = 0;
1423                         allbusy = 0;
1424                         allfree = 0;
1425                 }
1426                 cur = rest;
1427         } while (cur);
1428
1429         if (allfree)
1430                 return AST_EXTENSION_NOT_INUSE;
1431         if (allbusy)
1432                 return AST_EXTENSION_BUSY;
1433         if (allunavailable)
1434                 return AST_EXTENSION_UNAVAILABLE;
1435         if (busy) 
1436                 return AST_EXTENSION_INUSE;
1437         
1438         return AST_EXTENSION_NOT_INUSE;
1439 }
1440
1441
1442 int ast_extension_state(struct ast_channel *c, char *context, char *exten)
1443 {
1444         struct ast_exten *e;
1445
1446         e = ast_hint_extension(c, context, exten);    
1447         if (!e) 
1448                 return -1;
1449
1450         return ast_extension_state2(e);    
1451 }
1452
1453 int ast_device_state_changed(const char *fmt, ...) 
1454 {
1455         struct ast_hint *list;
1456         struct ast_state_cb *cblist;
1457         struct ast_devstate_cb *devcb;
1458         char hint[AST_MAX_EXTENSION] = "";
1459         char device[AST_MAX_EXTENSION];
1460         char *cur, *rest;
1461         int state;
1462
1463         va_list ap;
1464
1465         va_start(ap, fmt);
1466         vsnprintf(device, sizeof(device), fmt, ap);
1467         va_end(ap);
1468
1469         rest = strchr(device, '-');
1470         if (rest) {
1471                 *rest = 0;
1472         }
1473
1474         state = ast_device_state(device);
1475
1476         ast_mutex_lock(&hintlock);
1477
1478         devcb = devcbs;
1479         while(devcb) {
1480                 if (devcb->callback)
1481                         devcb->callback(device, state, devcb->data);
1482                 devcb = devcb->next;
1483         }
1484         list = hints;
1485
1486         while (list) {
1487
1488                 strncpy(hint, ast_get_extension_app(list->exten), sizeof(hint) - 1);
1489                 cur = hint;
1490                 do {
1491                         rest = strchr(cur, '&');
1492                         if (rest) {
1493                                 *rest = 0;
1494                                 rest++;
1495                         }
1496                         
1497                         if (!strcmp(cur, device)) {
1498                                 /* Found extension execute callbacks  */
1499                                 state = ast_extension_state2(list->exten);
1500                                 if ((state != -1) && (state != list->laststate)) {
1501                                         /* For general callbacks */
1502                                         cblist = statecbs;
1503                                         while (cblist) {
1504                                                 cblist->callback(list->exten->parent->name, list->exten->exten, state, cblist->data);
1505                                                 cblist = cblist->next;
1506                                         }
1507
1508                                         /* For extension callbacks */
1509                                         cblist = list->callbacks;
1510                                         while (cblist) {
1511                                                 cblist->callback(list->exten->parent->name, list->exten->exten, state, cblist->data);
1512                                                 cblist = cblist->next;
1513                                         }
1514                         
1515                                         list->laststate = state;
1516                                 }
1517                                 break;
1518                         }
1519                         cur = rest;
1520                 } while (cur);
1521                 list = list->next;
1522         }
1523         ast_mutex_unlock(&hintlock);
1524         return 1;
1525 }
1526                         
1527 int ast_devstate_add(ast_devstate_cb_type callback, void *data)
1528 {
1529         struct ast_devstate_cb *devcb;
1530         devcb = malloc(sizeof(struct ast_devstate_cb));
1531         if (devcb) {
1532                 memset(devcb, 0, sizeof(struct ast_devstate_cb));
1533                 ast_mutex_lock(&hintlock);
1534                 devcb->data = data;
1535                 devcb->callback = callback;
1536                 devcb->next = devcbs;
1537                 devcbs = devcb;
1538                 ast_mutex_unlock(&hintlock);
1539         }
1540         return 0;
1541 }
1542
1543 void ast_devstate_del(ast_devstate_cb_type callback, void *data)
1544 {
1545         struct ast_devstate_cb *devcb, *prev = NULL, *next;
1546         ast_mutex_lock(&hintlock);
1547         devcb = devcbs;
1548         while(devcb) {
1549                 next = devcb->next;
1550                 if ((devcb->data == data) && (devcb->callback == callback)) {
1551                         if (prev)
1552                                 prev->next = next;
1553                         else
1554                                 devcbs = next;
1555                         free(devcb);
1556                 } else
1557                         prev = devcb;
1558                 devcb = next;
1559         }
1560         ast_mutex_unlock(&hintlock);
1561 }
1562
1563 int ast_extension_state_add(const char *context, const char *exten, 
1564                             ast_state_cb_type callback, void *data)
1565 {
1566         struct ast_hint *list;
1567         struct ast_state_cb *cblist;
1568         struct ast_exten *e;
1569
1570         /* No context and extension add callback to statecbs list */
1571         if (!context && !exten) {
1572                 ast_mutex_lock(&hintlock);
1573
1574                 cblist = statecbs;
1575                 while (cblist) {
1576                         if (cblist->callback == callback) {
1577                                 cblist->data = data;
1578                                 ast_mutex_unlock(&hintlock);
1579                         }
1580                         cblist = cblist->next;
1581                 }
1582         
1583                 /* Now inserts the callback */
1584                 cblist = malloc(sizeof(struct ast_state_cb));
1585                 if (!cblist) {
1586                         ast_mutex_unlock(&hintlock);
1587                         return -1;
1588                 }
1589                 memset(cblist, 0, sizeof(struct ast_state_cb));
1590                 cblist->id = 0;
1591                 cblist->callback = callback;
1592                 cblist->data = data;
1593         
1594                 cblist->next = statecbs;
1595                 statecbs = cblist;
1596
1597                 ast_mutex_unlock(&hintlock);
1598                 return 0;
1599         }
1600
1601         if (!context || !exten)
1602                 return -1;
1603
1604         /* This callback type is for only one hint */
1605         e = ast_hint_extension(NULL, context, exten);    
1606         if (!e) {
1607                 return -1;
1608         }
1609     
1610         ast_mutex_lock(&hintlock);
1611         list = hints;        
1612     
1613         while (list) {
1614                 if (list->exten == e)
1615                         break;      
1616                 list = list->next;    
1617         }
1618
1619         if (!list) {
1620                 ast_mutex_unlock(&hintlock);
1621                 return -1;
1622         }
1623
1624         /* Now inserts the callback */
1625         cblist = malloc(sizeof(struct ast_state_cb));
1626         if (!cblist) {
1627                 ast_mutex_unlock(&hintlock);
1628                 return -1;
1629         }
1630         memset(cblist, 0, sizeof(struct ast_state_cb));
1631         cblist->id = stateid++;
1632         cblist->callback = callback;
1633         cblist->data = data;
1634
1635         cblist->next = list->callbacks;
1636         list->callbacks = cblist;
1637
1638         ast_mutex_unlock(&hintlock);
1639         return cblist->id;
1640 }
1641
1642 int ast_extension_state_del(int id, ast_state_cb_type callback)
1643 {
1644         struct ast_hint *list;
1645         struct ast_state_cb *cblist, *cbprev;
1646     
1647         if (!id && !callback)
1648                 return -1;
1649             
1650         ast_mutex_lock(&hintlock);
1651
1652         /* id is zero is a callback without extension */
1653         if (!id) {
1654                 cbprev = NULL;
1655                 cblist = statecbs;
1656                 while (cblist) {
1657                         if (cblist->callback == callback) {
1658                                 if (!cbprev)
1659                                         statecbs = cblist->next;
1660                                 else
1661                                         cbprev->next = cblist->next;
1662
1663                                 free(cblist);
1664
1665                                 ast_mutex_unlock(&hintlock);
1666                                 return 0;
1667                         }
1668                         cbprev = cblist;
1669                         cblist = cblist->next;
1670                 }
1671
1672                 ast_mutex_lock(&hintlock);
1673                 return -1;
1674         }
1675
1676         /* id greater than zero is a callback with extension */
1677         list = hints;
1678         while (list) {
1679                 cblist = list->callbacks;
1680                 cbprev = NULL;
1681                 while (cblist) {
1682                         if (cblist->id==id) {
1683                                 if (!cbprev)
1684                                         list->callbacks = cblist->next;         
1685                                 else
1686                                         cbprev->next = cblist->next;
1687                 
1688                                 free(cblist);
1689                 
1690                                 ast_mutex_unlock(&hintlock);
1691                                 return 0;               
1692                         }               
1693                         cbprev = cblist;                                
1694                         cblist = cblist->next;
1695                 }
1696                 list = list->next;
1697         }
1698     
1699         ast_mutex_unlock(&hintlock);
1700         return -1;
1701 }
1702
1703 static int ast_add_hint(struct ast_exten *e)
1704 {
1705         struct ast_hint *list;
1706
1707         if (!e) 
1708                 return -1;
1709     
1710         ast_mutex_lock(&hintlock);
1711         list = hints;        
1712     
1713         /* Search if hint exists, do nothing */
1714         while (list) {
1715                 if (list->exten == e) {
1716                         ast_mutex_unlock(&hintlock);
1717                         return -1;
1718                 }
1719                 list = list->next;    
1720         }
1721
1722         list = malloc(sizeof(struct ast_hint));
1723         if (!list) {
1724                 ast_mutex_unlock(&hintlock);
1725                 return -1;
1726         }
1727         /* Initialize and insert new item */
1728         memset(list, 0, sizeof(struct ast_hint));
1729         list->exten = e;
1730         list->laststate = ast_extension_state2(e);
1731         list->next = hints;
1732         hints = list;
1733
1734         ast_mutex_unlock(&hintlock);
1735         return 0;
1736 }
1737
1738 static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
1739
1740         struct ast_hint *list;
1741
1742         ast_mutex_lock(&hintlock);
1743         list = hints;
1744     
1745         while(list) {
1746                 if (list->exten == oe) {
1747                         list->exten = ne;
1748                         ast_mutex_unlock(&hintlock);    
1749                         return 0;
1750                 }
1751                 list = list->next;
1752         }
1753         ast_mutex_unlock(&hintlock);
1754
1755         return -1;
1756 }
1757
1758 static int ast_remove_hint(struct ast_exten *e)
1759 {
1760         /* Cleanup the Notifys if hint is removed */
1761         struct ast_hint *list, *prev = NULL;
1762         struct ast_state_cb *cblist, *cbprev;
1763
1764         if (!e) 
1765                 return -1;
1766
1767         ast_mutex_lock(&hintlock);
1768
1769         list = hints;    
1770         while(list) {
1771                 if (list->exten==e) {
1772                         cbprev = NULL;
1773                         cblist = list->callbacks;
1774                         while (cblist) {
1775                                 /* Notify with -1 and remove all callbacks */
1776                                 cbprev = cblist;            
1777                                 cblist = cblist->next;
1778                                 cbprev->callback(list->exten->parent->name, list->exten->exten, -1, cbprev->data);
1779                                 free(cbprev);
1780                         }
1781                         list->callbacks = NULL;
1782
1783                         if (!prev)
1784                                 hints = list->next;
1785                         else
1786                                 prev->next = list->next;
1787                         free(list);
1788             
1789                         ast_mutex_unlock(&hintlock);
1790                         return 0;
1791                 } else {
1792                         prev = list;
1793                         list = list->next;    
1794                 }
1795         }
1796
1797         ast_mutex_unlock(&hintlock);
1798         return -1;
1799 }
1800
1801
1802 int ast_get_hint(char *hint, int hintsize, char *name, int namesize, struct ast_channel *c, const char *context, const char *exten)
1803 {
1804         struct ast_exten *e;
1805         void *tmp;
1806         e = ast_hint_extension(c, context, exten);
1807         if (e) {
1808                 if (hint) 
1809                     strncpy(hint, ast_get_extension_app(e), hintsize - 1);
1810                 if (name) {
1811                         tmp = ast_get_extension_app_data(e);
1812                         if (tmp)
1813                                 strncpy(name, (char *)tmp, namesize - 1);
1814                 }
1815             return -1;
1816         }
1817         return 0;       
1818 }
1819
1820 int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid) 
1821 {
1822         return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_EXISTS);
1823 }
1824
1825 int ast_findlabel_extension(struct ast_channel *c, const char *context, const char *exten, const char *label, const char *callerid) 
1826 {
1827         return pbx_extension_helper(c, NULL, context, exten, 0, label, callerid, HELPER_FINDLABEL);
1828 }
1829
1830 int ast_findlabel_extension2(struct ast_channel *c, struct ast_context *con, const char *exten, const char *label, const char *callerid) 
1831 {
1832         return pbx_extension_helper(c, con, NULL, exten, 0, label, callerid, HELPER_FINDLABEL);
1833 }
1834
1835 int ast_canmatch_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
1836 {
1837         return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_CANMATCH);
1838 }
1839
1840 int ast_matchmore_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
1841 {
1842         return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_MATCHMORE);
1843 }
1844
1845 int ast_spawn_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid) 
1846 {
1847         return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_SPAWN);
1848 }
1849
1850 int ast_exec_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid) 
1851 {
1852         return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_EXEC);
1853 }
1854
1855 int ast_pbx_run(struct ast_channel *c)
1856 {
1857         int firstpass = 1;
1858         char digit;
1859         char exten[256];
1860         int pos;
1861         int waittime;
1862         int res=0;
1863
1864         /* A little initial setup here */
1865         if (c->pbx)
1866                 ast_log(LOG_WARNING, "%s already has PBX structure??\n", c->name);
1867         c->pbx = malloc(sizeof(struct ast_pbx));
1868         if (!c->pbx) {
1869                 ast_log(LOG_ERROR, "Out of memory\n");
1870                 return -1;
1871         }
1872         if (c->amaflags) {
1873                 if (!c->cdr) {
1874                         c->cdr = ast_cdr_alloc();
1875                         if (!c->cdr) {
1876                                 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
1877                                 free(c->pbx);
1878                                 return -1;
1879                         }
1880                         ast_cdr_init(c->cdr, c);
1881                 }
1882         }
1883         memset(c->pbx, 0, sizeof(struct ast_pbx));
1884         /* Set reasonable defaults */
1885         c->pbx->rtimeout = 10;
1886         c->pbx->dtimeout = 5;
1887
1888         /* Start by trying whatever the channel is set to */
1889         if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
1890                 /* JK02: If not successfull fall back to 's' */
1891                 if (option_verbose > 1)
1892                         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);
1893                 strncpy(c->exten, "s", sizeof(c->exten)-1);
1894                 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
1895                         /* JK02: And finally back to default if everything else failed */
1896                         if (option_verbose > 1)
1897                                 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);
1898                         strncpy(c->context, "default", sizeof(c->context)-1);
1899                 }
1900                 c->priority = 1;
1901         }
1902         if (c->cdr && !c->cdr->start.tv_sec && !c->cdr->start.tv_usec)
1903                 ast_cdr_start(c->cdr);
1904         for(;;) {
1905                 pos = 0;
1906                 digit = 0;
1907                 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
1908                         memset(exten, 0, sizeof(exten));
1909                         if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
1910                                 /* Something bad happened, or a hangup has been requested. */
1911                                 if (((res >= '0') && (res <= '9')) || ((res >= 'A') && (res <= 'F')) ||
1912                                         (res == '*') || (res == '#')) {
1913                                         ast_log(LOG_DEBUG, "Oooh, got something to jump out with ('%c')!\n", res);
1914                                         memset(exten, 0, sizeof(exten));
1915                                         pos = 0;
1916                                         exten[pos++] = digit = res;
1917                                         break;
1918                                 }
1919                                 switch(res) {
1920                                 case AST_PBX_KEEPALIVE:
1921                                         if (option_debug)
1922                                                 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
1923                                         else if (option_verbose > 1)
1924                                                 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
1925                                         goto out;
1926                                         break;
1927                                 default:
1928                                         if (option_debug)
1929                                                 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
1930                                         else if (option_verbose > 1)
1931                                                 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
1932                                         if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
1933                                                 c->_softhangup =0;
1934                                                 break;
1935                                         }
1936                                         /* atimeout */
1937                                         if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
1938                                                 break;
1939                                         }
1940
1941                                         if (c->cdr) {
1942                                                 ast_cdr_update(c);
1943                                         }
1944                                         goto out;
1945                                 }
1946                         }
1947                         if ((c->_softhangup == AST_SOFTHANGUP_TIMEOUT) && (ast_exists_extension(c,c->context,"T",1,c->cid.cid_num))) {
1948                                 strncpy(c->exten,"T",sizeof(c->exten) - 1);
1949                                 /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
1950                                 c->whentohangup = 0;
1951                                 c->priority = 0;
1952                                 c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
1953                         } else if (c->_softhangup) {
1954                                 ast_log(LOG_DEBUG, "Extension %s, priority %d returned normally even though call was hung up\n",
1955                                         c->exten, c->priority);
1956                                 goto out;
1957                         }
1958                         firstpass = 0;
1959                         c->priority++;
1960                 }
1961                 if (!ast_exists_extension(c, c->context, c->exten, 1, c->cid.cid_num)) {
1962                         /* It's not a valid extension anymore */
1963                         if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
1964                                 if (option_verbose > 2)
1965                                         ast_verbose(VERBOSE_PREFIX_3 "Sent into invalid extension '%s' in context '%s' on %s\n", c->exten, c->context, c->name);
1966                                 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", c->exten);
1967                                 strncpy(c->exten, "i", sizeof(c->exten)-1);
1968                                 c->priority = 1;
1969                         } else {
1970                                 ast_log(LOG_WARNING, "Channel '%s' sent into invalid extension '%s' in context '%s', but no invalid handler\n",
1971                                         c->name, c->exten, c->context);
1972                                 goto out;
1973                         }
1974                 } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
1975                         /* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */
1976                         c->_softhangup = 0;
1977                 } else {
1978                         /* Done, wait for an extension */
1979                         waittime = 0;
1980                         if (digit)
1981                                 waittime = c->pbx->dtimeout;
1982                         else if (!autofallthrough)
1983                                 waittime = c->pbx->rtimeout;
1984                         if (waittime) {
1985                                 while (ast_matchmore_extension(c, c->context, exten, 1, c->cid.cid_num)) {
1986                                         /* As long as we're willing to wait, and as long as it's not defined, 
1987                                            keep reading digits until we can't possibly get a right answer anymore.  */
1988                                         digit = ast_waitfordigit(c, waittime * 1000);
1989                                         if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
1990                                                 c->_softhangup = 0;
1991                                         } else {
1992                                                 if (!digit)
1993                                                         /* No entry */
1994                                                         break;
1995                                                 if (digit < 0)
1996                                                         /* Error, maybe a  hangup */
1997                                                         goto out;
1998                                                 exten[pos++] = digit;
1999                                                 waittime = c->pbx->dtimeout;
2000                                         }
2001                                 }
2002                                 if (ast_exists_extension(c, c->context, exten, 1, c->cid.cid_num)) {
2003                                         /* Prepare the next cycle */
2004                                         strncpy(c->exten, exten, sizeof(c->exten)-1);
2005                                         c->priority = 1;
2006                                 } else {
2007                                         /* No such extension */
2008                                         if (!ast_strlen_zero(exten)) {
2009                                                 /* An invalid extension */
2010                                                 if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
2011                                                         if (option_verbose > 2)
2012                                                                 ast_verbose( VERBOSE_PREFIX_3 "Invalid extension '%s' in context '%s' on %s\n", exten, c->context, c->name);
2013                                                         pbx_builtin_setvar_helper(c, "INVALID_EXTEN", exten);
2014                                                         strncpy(c->exten, "i", sizeof(c->exten)-1);
2015                                                         c->priority = 1;
2016                                                 } else {
2017                                                         ast_log(LOG_WARNING, "Invalid extension '%s', but no rule 'i' in context '%s'\n", exten, c->context);
2018                                                         goto out;
2019                                                 }
2020                                         } else {
2021                                                 /* A simple timeout */
2022                                                 if (ast_exists_extension(c, c->context, "t", 1, c->cid.cid_num)) {
2023                                                         if (option_verbose > 2)
2024                                                                 ast_verbose( VERBOSE_PREFIX_3 "Timeout on %s\n", c->name);
2025                                                         strncpy(c->exten, "t", sizeof(c->exten)-1);
2026                                                         c->priority = 1;
2027                                                 } else {
2028                                                         ast_log(LOG_WARNING, "Timeout, but no rule 't' in context '%s'\n", c->context);
2029                                                         goto out;
2030                                                 }
2031                                         }       
2032                                 }
2033                                 if (c->cdr) {
2034                                         if (option_verbose > 2)
2035                                                 ast_verbose(VERBOSE_PREFIX_2 "CDR updated on %s\n",c->name);    
2036                                         ast_cdr_update(c);
2037                             }
2038                         } else {
2039                                 if (option_verbose > 0) {
2040                                         char *status;
2041                                         status = pbx_builtin_getvar_helper(c, "DIALSTATUS");
2042                                         if (!status)
2043                                                 status = "UNKNOWN";
2044                                         if (option_verbose > 2)
2045                                                 ast_verbose(VERBOSE_PREFIX_2 "Auto fallthrough, channel '%s' status is '%s'\n", c->name, status);
2046                                         if (!strcasecmp(status, "CONGESTION"))
2047                                                 res = pbx_builtin_congestion(c, "10");
2048                                         else if (!strcasecmp(status, "CHANUNAVAIL"))
2049                                                 res = pbx_builtin_congestion(c, "10");
2050                                         else if (!strcasecmp(status, "BUSY"))
2051                                                 res = pbx_builtin_busy(c, "10");
2052                                         goto out;
2053                                 }
2054                         }
2055                 }
2056         }
2057         if (firstpass) 
2058                 ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", c->name);
2059 out:
2060         if ((res != AST_PBX_KEEPALIVE) && ast_exists_extension(c, c->context, "h", 1, c->cid.cid_num)) {
2061                 c->exten[0] = 'h';
2062                 c->exten[1] = '\0';
2063                 c->priority = 1;
2064                 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2065                         if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
2066                                 /* Something bad happened, or a hangup has been requested. */
2067                                 if (option_debug)
2068                                         ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2069                                 else if (option_verbose > 1)
2070                                         ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2071                                 break;
2072                         }
2073                         c->priority++;
2074                 }
2075         }
2076
2077         pbx_destroy(c->pbx);
2078         c->pbx = NULL;
2079         if (res != AST_PBX_KEEPALIVE)
2080                 ast_hangup(c);
2081         return 0;
2082 }
2083
2084 static void *pbx_thread(void *data)
2085 {
2086         /* Oh joyeous kernel, we're a new thread, with nothing to do but
2087            answer this channel and get it going.  The setjmp stuff is fairly
2088            confusing, but necessary to get smooth transitions between
2089            the execution of different applications (without the use of
2090            additional threads) */
2091         struct ast_channel *c = data;
2092         ast_pbx_run(c);
2093         pthread_exit(NULL);
2094         return NULL;
2095 }
2096
2097 int ast_pbx_start(struct ast_channel *c)
2098 {
2099         pthread_t t;
2100         pthread_attr_t attr;
2101         if (!c) {
2102                 ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
2103                 return -1;
2104         }
2105            
2106         /* Start a new thread, and get something handling this channel. */
2107         pthread_attr_init(&attr);
2108         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
2109         if (ast_pthread_create(&t, &attr, pbx_thread, c)) {
2110                 ast_log(LOG_WARNING, "Failed to create new channel thread\n");
2111                 return -1;
2112         }
2113         return 0;
2114 }
2115
2116 int pbx_set_autofallthrough(int newval)
2117 {
2118         int oldval;
2119         oldval = autofallthrough;
2120         if (oldval != newval)
2121                 autofallthrough = newval;
2122         return oldval;
2123 }
2124
2125 /*
2126  * This function locks contexts list by &conlist, search for the right context
2127  * structure, leave context list locked and call ast_context_remove_include2
2128  * which removes include, unlock contexts list and return ...
2129  */
2130 int ast_context_remove_include(const char *context, const char *include, const char *registrar)
2131 {
2132         struct ast_context *c;
2133
2134         if (ast_lock_contexts()) return -1;
2135
2136         /* walk contexts and search for the right one ...*/
2137         c = ast_walk_contexts(NULL);
2138         while (c) {
2139                 /* we found one ... */
2140                 if (!strcmp(ast_get_context_name(c), context)) {
2141                         int ret;
2142                         /* remove include from this context ... */      
2143                         ret = ast_context_remove_include2(c, include, registrar);
2144
2145                         ast_unlock_contexts();
2146
2147                         /* ... return results */
2148                         return ret;
2149                 }
2150                 c = ast_walk_contexts(c);
2151         }
2152
2153         /* we can't find the right one context */
2154         ast_unlock_contexts();
2155         return -1;
2156 }
2157
2158 /*
2159  * When we call this function, &conlock lock must be locked, because when
2160  * we giving *con argument, some process can remove/change this context
2161  * and after that there can be segfault.
2162  *
2163  * This function locks given context, removes include, unlock context and
2164  * return.
2165  */
2166 int ast_context_remove_include2(struct ast_context *con, const char *include, const char *registrar)
2167 {
2168         struct ast_include *i, *pi = NULL;
2169
2170         if (ast_mutex_lock(&con->lock)) return -1;
2171
2172         /* walk includes */
2173         i = con->includes;
2174         while (i) {
2175                 /* find our include */
2176                 if (!strcmp(i->name, include) && 
2177                         (!registrar || !strcmp(i->registrar, registrar))) {
2178                         /* remove from list */
2179                         if (pi)
2180                                 pi->next = i->next;
2181                         else
2182                                 con->includes = i->next;
2183                         /* free include and return */
2184                         free(i);
2185                         ast_mutex_unlock(&con->lock);
2186                         return 0;
2187                 }
2188                 pi = i;
2189                 i = i->next;
2190         }
2191
2192         /* we can't find the right include */
2193         ast_mutex_unlock(&con->lock);
2194         return -1;
2195 }
2196
2197 /*
2198  * This function locks contexts list by &conlist, search for the rigt context
2199  * structure, leave context list locked and call ast_context_remove_switch2
2200  * which removes switch, unlock contexts list and return ...
2201  */
2202 int ast_context_remove_switch(const char *context, const char *sw, const char *data, const char *registrar)
2203 {
2204         struct ast_context *c;
2205
2206         if (ast_lock_contexts()) return -1;
2207
2208         /* walk contexts and search for the right one ...*/
2209         c = ast_walk_contexts(NULL);
2210         while (c) {
2211                 /* we found one ... */
2212                 if (!strcmp(ast_get_context_name(c), context)) {
2213                         int ret;
2214                         /* remove switch from this context ... */       
2215                         ret = ast_context_remove_switch2(c, sw, data, registrar);
2216
2217                         ast_unlock_contexts();
2218
2219                         /* ... return results */
2220                         return ret;
2221                 }
2222                 c = ast_walk_contexts(c);
2223         }
2224
2225         /* we can't find the right one context */
2226         ast_unlock_contexts();
2227         return -1;
2228 }
2229
2230 /*
2231  * When we call this function, &conlock lock must be locked, because when
2232  * we giving *con argument, some process can remove/change this context
2233  * and after that there can be segfault.
2234  *
2235  * This function locks given context, removes switch, unlock context and
2236  * return.
2237  */
2238 int ast_context_remove_switch2(struct ast_context *con, const char *sw, const char *data, const char *registrar)
2239 {
2240         struct ast_sw *i, *pi = NULL;
2241
2242         if (ast_mutex_lock(&con->lock)) return -1;
2243
2244         /* walk switchs */
2245         i = con->alts;
2246         while (i) {
2247                 /* find our switch */
2248                 if (!strcmp(i->name, sw) && !strcmp(i->data, data) && 
2249                         (!registrar || !strcmp(i->registrar, registrar))) {
2250                         /* remove from list */
2251                         if (pi)
2252                                 pi->next = i->next;
2253                         else
2254                                 con->alts = i->next;
2255                         /* free switch and return */
2256                         free(i);
2257                         ast_mutex_unlock(&con->lock);
2258                         return 0;
2259                 }
2260                 pi = i;
2261                 i = i->next;
2262         }
2263
2264         /* we can't find the right switch */
2265         ast_mutex_unlock(&con->lock);
2266         return -1;
2267 }
2268
2269 /*
2270  * This functions lock contexts list, search for the right context,
2271  * call ast_context_remove_extension2, unlock contexts list and return.
2272  * In this function we are using
2273  */
2274 int ast_context_remove_extension(const char *context, const char *extension, int priority, const char *registrar)
2275 {
2276         struct ast_context *c;
2277
2278         if (ast_lock_contexts()) return -1;
2279
2280         /* walk contexts ... */
2281         c = ast_walk_contexts(NULL);
2282         while (c) {
2283                 /* ... search for the right one ... */
2284                 if (!strcmp(ast_get_context_name(c), context)) {
2285                         /* ... remove extension ... */
2286                         int ret = ast_context_remove_extension2(c, extension, priority,
2287                                 registrar);
2288                         /* ... unlock contexts list and return */
2289                         ast_unlock_contexts();
2290                         return ret;
2291                 }
2292                 c = ast_walk_contexts(c);
2293         }
2294
2295         /* we can't find the right context */
2296         ast_unlock_contexts();
2297         return -1;
2298 }
2299
2300 /*
2301  * When do you want to call this function, make sure that &conlock is locked,
2302  * because some process can handle with your *con context before you lock
2303  * it.
2304  *
2305  * This functionc locks given context, search for the right extension and
2306  * fires out all peer in this extensions with given priority. If priority
2307  * is set to 0, all peers are removed. After that, unlock context and
2308  * return.
2309  */
2310 int ast_context_remove_extension2(struct ast_context *con, const char *extension, int priority, const char *registrar)
2311 {
2312         struct ast_exten *exten, *prev_exten = NULL;
2313
2314         if (ast_mutex_lock(&con->lock)) return -1;
2315
2316         /* go through all extensions in context and search the right one ... */
2317         exten = con->root;
2318         while (exten) {
2319
2320                 /* look for right extension */
2321                 if (!strcmp(exten->exten, extension) &&
2322                         (!registrar || !strcmp(exten->registrar, registrar))) {
2323                         struct ast_exten *peer;
2324
2325                         /* should we free all peers in this extension? (priority == 0)? */
2326                         if (priority == 0) {
2327                                 /* remove this extension from context list */
2328                                 if (prev_exten)
2329                                         prev_exten->next = exten->next;
2330                                 else
2331                                         con->root = exten->next;
2332
2333                                 /* fire out all peers */
2334                                 peer = exten; 
2335                                 while (peer) {
2336                                         exten = peer->peer;
2337                                         
2338                                         if (!peer->priority==PRIORITY_HINT) 
2339                                             ast_remove_hint(peer);
2340
2341                                         peer->datad(peer->data);
2342                                         free(peer);
2343
2344                                         peer = exten;
2345                                 }
2346
2347                                 ast_mutex_unlock(&con->lock);
2348                                 return 0;
2349                         } else {
2350                                 /* remove only extension with exten->priority == priority */
2351                                 struct ast_exten *previous_peer = NULL;
2352
2353                                 peer = exten;
2354                                 while (peer) {
2355                                         /* is this our extension? */
2356                                         if (peer->priority == priority &&
2357                                                 (!registrar || !strcmp(peer->registrar, registrar) )) {
2358                                                 /* we are first priority extension? */
2359                                                 if (!previous_peer) {
2360                                                         /* exists previous extension here? */
2361                                                         if (prev_exten) {
2362                                                                 /* yes, so we must change next pointer in
2363                                                                  * previous connection to next peer
2364                                                                  */
2365                                                                 if (peer->peer) {
2366                                                                         prev_exten->next = peer->peer;
2367                                                                         peer->peer->next = exten->next;
2368                                                                 } else
2369                                                                         prev_exten->next = exten->next;
2370                                                         } else {
2371                                                                 /* no previous extension, we are first
2372                                                                  * extension, so change con->root ...
2373                                                                  */
2374                                                                 if (peer->peer)
2375                                                                         con->root = peer->peer;
2376                                                                 else
2377                                                                         con->root = exten->next; 
2378                                                         }
2379                                                 } else {
2380                                                         /* we are not first priority in extension */
2381                                                         previous_peer->peer = peer->peer;
2382                                                 }
2383
2384                                                 /* now, free whole priority extension */
2385                                                 if (peer->priority==PRIORITY_HINT)
2386                                                     ast_remove_hint(peer);
2387                                                 peer->datad(peer->data);
2388                                                 free(peer);
2389
2390                                                 ast_mutex_unlock(&con->lock);
2391                                                 return 0;
2392                                         } else {
2393                                                 /* this is not right extension, skip to next peer */
2394                                                 previous_peer = peer;
2395                                                 peer = peer->peer;
2396                                         }
2397                                 }
2398
2399                                 ast_mutex_unlock(&con->lock);
2400                                 return -1;
2401                         }
2402                 }
2403
2404                 prev_exten = exten;
2405                 exten = exten->next;
2406         }
2407
2408         /* we can't find right extension */
2409         ast_mutex_unlock(&con->lock);
2410         return -1;
2411 }
2412
2413
2414 int ast_register_application(const char *app, int (*execute)(struct ast_channel *, void *), const char *synopsis, const char *description)
2415 {
2416         struct ast_app *tmp, *prev, *cur;
2417         char tmps[80];
2418         int length;
2419         length = sizeof(struct ast_app);
2420         length += strlen(app) + 1;
2421         if (ast_mutex_lock(&applock)) {
2422                 ast_log(LOG_ERROR, "Unable to lock application list\n");
2423                 return -1;
2424         }
2425         tmp = apps;
2426         while(tmp) {
2427                 if (!strcasecmp(app, tmp->name)) {
2428                         ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
2429                         ast_mutex_unlock(&applock);
2430                         return -1;
2431                 }
2432                 tmp = tmp->next;
2433         }
2434         tmp = malloc(length);
2435         if (tmp) {
2436                 memset(tmp, 0, length);
2437                 strcpy(tmp->name, app);
2438                 tmp->execute = execute;
2439                 tmp->synopsis = synopsis;
2440                 tmp->description = description;
2441                 /* Store in alphabetical order */
2442                 cur = apps;
2443                 prev = NULL;
2444                 while(cur) {
2445                         if (strcasecmp(tmp->name, cur->name) < 0)
2446                                 break;
2447                         prev = cur;
2448                         cur = cur->next;
2449                 }
2450                 if (prev) {
2451                         tmp->next = prev->next;
2452                         prev->next = tmp;
2453                 } else {
2454                         tmp->next = apps;
2455                         apps = tmp;
2456                 }
2457         } else {
2458                 ast_log(LOG_ERROR, "Out of memory\n");
2459                 ast_mutex_unlock(&applock);
2460                 return -1;
2461         }
2462         if (option_verbose > 1)
2463                 ast_verbose( VERBOSE_PREFIX_2 "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
2464         ast_mutex_unlock(&applock);
2465         return 0;
2466 }
2467
2468 int ast_register_switch(struct ast_switch *sw)
2469 {
2470         struct ast_switch *tmp, *prev=NULL;
2471         if (ast_mutex_lock(&switchlock)) {
2472                 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
2473                 return -1;
2474         }
2475         tmp = switches;
2476         while(tmp) {
2477                 if (!strcasecmp(tmp->name, sw->name))
2478                         break;
2479                 prev = tmp;
2480                 tmp = tmp->next;
2481         }
2482         if (tmp) {      
2483                 ast_mutex_unlock(&switchlock);
2484                 ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name);
2485                 return -1;
2486         }
2487         sw->next = NULL;
2488         if (prev) 
2489                 prev->next = sw;
2490         else
2491                 switches = sw;
2492         ast_mutex_unlock(&switchlock);
2493         return 0;
2494 }
2495
2496 void ast_unregister_switch(struct ast_switch *sw)
2497 {
2498         struct ast_switch *tmp, *prev=NULL;
2499         if (ast_mutex_lock(&switchlock)) {
2500                 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
2501                 return;
2502         }
2503         tmp = switches;
2504         while(tmp) {
2505                 if (tmp == sw) {
2506                         if (prev)
2507                                 prev->next = tmp->next;
2508                         else
2509                                 switches = tmp->next;
2510                         tmp->next = NULL;
2511                         break;                  
2512                 }
2513                 prev = tmp;
2514                 tmp = tmp->next;
2515         }
2516         ast_mutex_unlock(&switchlock);
2517 }
2518
2519 /*
2520  * Help for CLI commands ...
2521  */
2522 static char show_application_help[] = 
2523 "Usage: show application <application> [<application> [<application> [...]]]\n"
2524 "       Describes a particular application.\n";
2525
2526 static char show_applications_help[] =
2527 "Usage: show applications [{like|describing} <text>]\n"
2528 "       List applications which are currently available.\n"
2529 "       If 'like', <text> will be a substring of the app name\n"
2530 "       If 'describing', <text> will be a substring of the description\n";
2531
2532 static char show_dialplan_help[] =
2533 "Usage: show dialplan [exten@][context]\n"
2534 "       Show dialplan\n";
2535
2536 static char show_switches_help[] = 
2537 "Usage: show switches\n"
2538 "       Show registered switches\n";
2539
2540 /*
2541  * IMPLEMENTATION OF CLI FUNCTIONS IS IN THE SAME ORDER AS COMMANDS HELPS
2542  *
2543  */
2544
2545 /*
2546  * 'show application' CLI command implementation functions ...
2547  */
2548
2549 /*
2550  * There is a possibility to show informations about more than one
2551  * application at one time. You can type 'show application Dial Echo' and
2552  * you will see informations about these two applications ...
2553  */
2554 static char *complete_show_application(char *line, char *word,
2555         int pos, int state)
2556 {
2557         struct ast_app *a;
2558         int which = 0;
2559
2560         /* try to lock applications list ... */
2561         if (ast_mutex_lock(&applock)) {
2562                 ast_log(LOG_ERROR, "Unable to lock application list\n");
2563                 return NULL;
2564         }
2565
2566         /* ... walk all applications ... */
2567         a = apps; 
2568         while (a) {
2569                 /* ... check if word matches this application ... */
2570                 if (!strncasecmp(word, a->name, strlen(word))) {
2571                         /* ... if this is right app serve it ... */
2572                         if (++which > state) {
2573                                 char *ret = strdup(a->name);
2574                                 ast_mutex_unlock(&applock);
2575                                 return ret;
2576                         }
2577                 }
2578                 a = a->next; 
2579         }
2580
2581         /* no application match */
2582         ast_mutex_unlock(&applock);
2583         return NULL; 
2584 }
2585
2586 static int handle_show_application(int fd, int argc, char *argv[])
2587 {
2588         struct ast_app *a;
2589         int app, no_registered_app = 1;
2590
2591         if (argc < 3) return RESULT_SHOWUSAGE;
2592
2593         /* try to lock applications list ... */
2594         if (ast_mutex_lock(&applock)) {
2595                 ast_log(LOG_ERROR, "Unable to lock application list\n");
2596                 return -1;
2597         }
2598
2599         /* ... go through all applications ... */
2600         a = apps; 
2601         while (a) {
2602                 /* ... compare this application name with all arguments given
2603                  * to 'show application' command ... */
2604                 for (app = 2; app < argc; app++) {
2605                         if (!strcasecmp(a->name, argv[app])) {
2606                                 /* Maximum number of characters added by terminal coloring is 22 */
2607                                 char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
2608                                 char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
2609                                 int synopsis_size, description_size;
2610
2611                                 no_registered_app = 0;
2612
2613                                 if (a->synopsis)
2614                                         synopsis_size = strlen(a->synopsis) + 23;
2615                                 else
2616                                         synopsis_size = strlen("Not available") + 23;
2617                                 synopsis = alloca(synopsis_size);
2618
2619                                 if (a->description)
2620                                         description_size = strlen(a->description) + 23;
2621                                 else
2622                                         description_size = strlen("Not available") + 23;
2623                                 description = alloca(description_size);
2624
2625                                 if (synopsis && description) {
2626                                         snprintf(info, 64 + AST_MAX_APP, "\n  -= Info about application '%s' =- \n\n", a->name);
2627                                         term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
2628                                         term_color(syntitle, "[Synopsis]:\n", COLOR_MAGENTA, 0, 40);
2629                                         term_color(destitle, "[Description]:\n", COLOR_MAGENTA, 0, 40);
2630                                         term_color(synopsis,
2631                                                                         a->synopsis ? a->synopsis : "Not available",
2632                                                                         COLOR_CYAN, 0, synopsis_size);
2633                                         term_color(description,
2634                                                                         a->description ? a->description : "Not available",
2635                                                                         COLOR_CYAN, 0, description_size);
2636
2637                                         ast_cli(fd,"%s%s%s\n\n%s%s\n", infotitle, syntitle, synopsis, destitle, description);
2638                                 } else {
2639                                         /* ... one of our applications, show info ...*/
2640                                         ast_cli(fd,"\n  -= Info about application '%s' =- \n\n"
2641                                                 "[Synopsis]:\n  %s\n\n"
2642                                                 "[Description]:\n%s\n",
2643                                                 a->name,
2644                                                 a->synopsis ? a->synopsis : "Not available",
2645                                                 a->description ? a->description : "Not available");
2646                                 }
2647                         }
2648                 }
2649                 a = a->next; 
2650         }
2651
2652         ast_mutex_unlock(&applock);
2653
2654         /* we found at least one app? no? */
2655         if (no_registered_app) {
2656                 ast_cli(fd, "Your application(s) is (are) not registered\n");
2657                 return RESULT_FAILURE;
2658         }
2659
2660         return RESULT_SUCCESS;
2661 }
2662
2663 static int handle_show_switches(int fd, int argc, char *argv[])
2664 {
2665         struct ast_switch *sw;
2666         if (!switches) {
2667                 ast_cli(fd, "There are no registered alternative switches\n");
2668                 return RESULT_SUCCESS;
2669         }
2670         /* ... we have applications ... */
2671         ast_cli(fd, "\n    -= Registered Asterisk Alternative Switches =-\n");
2672         if (ast_mutex_lock(&switchlock)) {
2673                 ast_log(LOG_ERROR, "Unable to lock switches\n");
2674                 return -1;
2675         }
2676         sw = switches;
2677         while (sw) {
2678                 ast_cli(fd, "%s: %s\n", sw->name, sw->description);
2679                 sw = sw->next;
2680         }
2681         ast_mutex_unlock(&switchlock);
2682         return RESULT_SUCCESS;
2683 }
2684
2685 /*
2686  * 'show applications' CLI command implementation functions ...
2687  */
2688 static int handle_show_applications(int fd, int argc, char *argv[])
2689 {
2690         struct ast_app *a;
2691         int like=0, describing=0;
2692         int total_match = 0;    /* Number of matches in like clause */
2693         int total_apps = 0;     /* Number of apps registered */
2694         
2695         /* try to lock applications list ... */
2696         if (ast_mutex_lock(&applock)) {
2697                 ast_log(LOG_ERROR, "Unable to lock application list\n");
2698                 return -1;
2699         }
2700
2701         /* ... have we got at least one application (first)? no? */
2702         if (!apps) {
2703                 ast_cli(fd, "There are no registered applications\n");
2704                 ast_mutex_unlock(&applock);
2705                 return -1;
2706         }
2707
2708         /* show applications like <keyword> */
2709         if ((argc == 4) && (!strcmp(argv[2], "like"))) {
2710                 like = 1;
2711         } else if ((argc > 3) && (!strcmp(argv[2], "describing"))) {
2712                 describing = 1;
2713         }
2714
2715         /* show applications describing <keyword1> [<keyword2>] [...] */
2716         if ((!like) && (!describing)) {
2717                 ast_cli(fd, "    -= Registered Asterisk Applications =-\n");
2718         } else {
2719                 ast_cli(fd, "    -= Matching Asterisk Applications =-\n");
2720         }
2721
2722         /* ... go through all applications ... */
2723         for (a = apps; a; a = a->next) {
2724                 /* ... show informations about applications ... */
2725                 int printapp=0;
2726                 total_apps++;
2727                 if (like) {
2728                         if (ast_strcasestr(a->name, argv[3])) {
2729                                 printapp = 1;
2730                                 total_match++;
2731                         }
2732                 } else if (describing) {
2733                         if (a->description) {
2734                                 /* Match all words on command line */
2735                                 int i;
2736                                 printapp = 1;
2737                                 for (i=3;i<argc;i++) {
2738                                         if (! ast_strcasestr(a->description, argv[i])) {
2739                                                 printapp = 0;
2740                                         } else {
2741                                                 total_match++;
2742                                         }
2743                                 }
2744                         }
2745                 } else {
2746                         printapp = 1;
2747                 }
2748
2749                 if (printapp) {
2750                         ast_cli(fd,"  %20s: %s\n", a->name, a->synopsis ? a->synopsis : "<Synopsis not available>");
2751                 }
2752         }
2753         if ((!like) && (!describing)) {
2754                 ast_cli(fd, "    -= %d Applications Registered =-\n",total_apps);
2755         } else {
2756                 ast_cli(fd, "    -= %d Applications Matching =-\n",total_match);
2757         }
2758         
2759         /* ... unlock and return */
2760         ast_mutex_unlock(&applock);
2761
2762         return RESULT_SUCCESS;
2763 }
2764
2765 static char *complete_show_applications(char *line, char *word, int pos, int state)
2766 {
2767         if (pos == 2) {
2768                 if (ast_strlen_zero(word)) {
2769                         switch (state) {
2770                         case 0:
2771                                 return strdup("like");
2772                         case 1:
2773                                 return strdup("describing");
2774                         default:
2775                                 return NULL;
2776                         }
2777                 } else if (! strncasecmp(word, "like", strlen(word))) {
2778                         if (state == 0) {
2779                                 return strdup("like");
2780                         } else {
2781                                 return NULL;
2782                         }
2783                 } else if (! strncasecmp(word, "describing", strlen(word))) {
2784                         if (state == 0) {
2785                                 return strdup("describing");
2786                         } else {
2787                                 return NULL;
2788                         }
2789                 }
2790         }
2791         return NULL;
2792 }
2793
2794 /*
2795  * 'show dialplan' CLI command implementation functions ...
2796  */
2797 static char *complete_show_dialplan_context(char *line, char *word, int pos,
2798         int state)
2799 {
2800         struct ast_context *c;
2801         int which = 0;
2802
2803         /* we are do completion of [exten@]context on second position only */
2804         if (pos != 2) return NULL;
2805
2806         /* try to lock contexts list ... */
2807         if (ast_lock_contexts()) {
2808                 ast_log(LOG_ERROR, "Unable to lock context list\n");
2809                 return NULL;
2810         }
2811
2812         /* ... walk through all contexts ... */
2813         c = ast_walk_contexts(NULL);
2814         while(c) {
2815                 /* ... word matches context name? yes? ... */
2816                 if (!strncasecmp(word, ast_get_context_name(c), strlen(word))) {
2817                         /* ... for serve? ... */
2818                         if (++which > state) {
2819                                 /* ... yes, serve this context name ... */
2820                                 char *ret = strdup(ast_get_context_name(c));
2821                                 ast_unlock_contexts();
2822                                 return ret;
2823                         }
2824                 }
2825                 c = ast_walk_contexts(c);
2826         }
2827
2828         /* ... unlock and return */
2829         ast_unlock_contexts();
2830         return NULL;
2831 }
2832
2833 struct dialplan_counters {
2834         int total_context;
2835         int total_exten;
2836         int total_prio;
2837         int context_existence;
2838         int extension_existence;
2839 };
2840
2841 static int show_dialplan_helper(int fd, char *context, char *exten, struct dialplan_counters *dpc, struct ast_include *rinclude)
2842 {
2843         struct ast_context *c;
2844         int res=0, old_total_exten = dpc->total_exten;
2845
2846         /* try to lock contexts */
2847         if (ast_lock_contexts()) {
2848                 ast_log(LOG_WARNING, "Failed to lock contexts list\n");
2849                 return -1;
2850         }
2851
2852         /* walk all contexts ... */
2853         for (c = ast_walk_contexts(NULL); c ; c = ast_walk_contexts(c)) {
2854                 /* show this context? */
2855                 if (!context ||
2856                         !strcmp(ast_get_context_name(c), context)) {
2857                         dpc->context_existence = 1;
2858
2859                         /* try to lock context before walking in ... */
2860                         if (!ast_lock_context(c)) {
2861                                 struct ast_exten *e;
2862                                 struct ast_include *i;
2863                                 struct ast_ignorepat *ip;
2864                                 struct ast_sw *sw;
2865                                 char buf[256], buf2[256];
2866                                 int context_info_printed = 0;
2867
2868                                 /* are we looking for exten too? if yes, we print context
2869                                  * if we our extension only
2870                                  */
2871                                 if (!exten) {
2872                                         dpc->total_context++;
2873                                         ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
2874                                                 ast_get_context_name(c), ast_get_context_registrar(c));
2875                                         context_info_printed = 1;
2876                                 }
2877
2878                                 /* walk extensions ... */
2879                                 for (e = ast_walk_context_extensions(c, NULL); e; e = ast_walk_context_extensions(c, e)) {
2880                                         struct ast_exten *p;
2881                                         int prio;
2882
2883                                         /* looking for extension? is this our extension? */
2884                                         if (exten &&
2885                                                 !ast_extension_match(ast_get_extension_name(e), exten))
2886                                         {
2887                                                 /* we are looking for extension and it's not our
2888                                                  * extension, so skip to next extension */
2889                                                 continue;
2890                                         }
2891
2892                                         dpc->extension_existence = 1;
2893
2894                                         /* may we print context info? */        
2895                                         if (!context_info_printed) {
2896                                                 dpc->total_context++;
2897                                                 if (rinclude) {
2898                                                         /* TODO Print more info about rinclude */
2899                                                         ast_cli(fd, "[ Included context '%s' created by '%s' ]\n",
2900                                                                 ast_get_context_name(c),
2901                                                                 ast_get_context_registrar(c));
2902                                                 } else {
2903                                                         ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
2904                                                                 ast_get_context_name(c),
2905                                                                 ast_get_context_registrar(c));
2906                                                 }
2907                                                 context_info_printed = 1;
2908                                         }
2909                                         dpc->total_prio++;
2910
2911                                         /* write extension name and first peer */       
2912                                         bzero(buf, sizeof(buf));                
2913                                         snprintf(buf, sizeof(buf), "'%s' =>",
2914                                                 ast_get_extension_name(e));
2915
2916                                         prio = ast_get_extension_priority(e);
2917                                         if (prio == PRIORITY_HINT) {
2918                                                 snprintf(buf2, sizeof(buf2),
2919                                                         "hint: %s",
2920                                                         ast_get_extension_app(e));
2921                                         } else {
2922                                                 snprintf(buf2, sizeof(buf2),
2923                                                         "%d. %s(%s)",
2924                                                         prio,
2925                                                         ast_get_extension_app(e),
2926                                                         (char *)ast_get_extension_app_data(e));
2927                                         }
2928
2929                                         ast_cli(fd, "  %-17s %-45s [%s]\n", buf, buf2,
2930                                                 ast_get_extension_registrar(e));
2931
2932                                         dpc->total_exten++;
2933                                         /* walk next extension peers */
2934                                         for (p=ast_walk_extension_priorities(e, e); p; p=ast_walk_extension_priorities(e, p)) {
2935                                                 dpc->total_prio++;
2936                                                 bzero((void *)buf2, sizeof(buf2));
2937                                                 bzero((void *)buf, sizeof(buf));
2938                                                 if (ast_get_extension_label(p))
2939                                                         snprintf(buf, sizeof(buf), "   [%s]", ast_get_extension_label(p));
2940                                                 prio = ast_get_extension_priority(p);
2941                                                 if (prio == PRIORITY_HINT) {
2942                                                         snprintf(buf2, sizeof(buf2),
2943                                                                 "hint: %s",
2944                                                                 ast_get_extension_app(p));
2945                                                 } else {
2946                                                         snprintf(buf2, sizeof(buf2),
2947                                                                 "%d. %s(%s)",
2948                                                                 prio,
2949                                                                 ast_get_extension_app(p),
2950                                                                 (char *)ast_get_extension_app_data(p));
2951                                                 }
2952
2953                                                 ast_cli(fd,"  %-17s %-45s [%s]\n",
2954                                                         buf, buf2,
2955                                                         ast_get_extension_registrar(p));
2956                                         }
2957                                 }
2958
2959                                 /* walk included and write info ... */
2960                                 for (i = ast_walk_context_includes(c, NULL); i; i = ast_walk_context_includes(c, i)) {
2961                                         bzero(buf, sizeof(buf));
2962                                         snprintf(buf, sizeof(buf), "'%s'",
2963                                                 ast_get_include_name(i));
2964                                         if (exten) {
2965                                                 /* Check all includes for the requested extension */
2966                                                 show_dialplan_helper(fd, (char *)ast_get_include_name(i), exten, dpc, i);
2967                                         } else {
2968                                                 ast_cli(fd, "  Include =>        %-45s [%s]\n",
2969                                                         buf, ast_get_include_registrar(i));
2970                                         }
2971                                 }
2972
2973                                 /* walk ignore patterns and write info ... */
2974                                 for (ip=ast_walk_context_ignorepats(c, NULL); ip; ip=ast_walk_context_ignorepats(c, ip)) {
2975                                         const char *ipname = ast_get_ignorepat_name(ip);
2976                                         char ignorepat[AST_MAX_EXTENSION];
2977                                         snprintf(buf, sizeof(buf), "'%s'", ipname);
2978                                         snprintf(ignorepat, sizeof(ignorepat), "_%s.", ipname);
2979                                         if ((!exten) || ast_extension_match(ignorepat, exten)) {
2980                                                 ast_cli(fd, "  Ignore pattern => %-45s [%s]\n",
2981                                                         buf, ast_get_ignorepat_registrar(ip));
2982                                         }
2983                                 }
2984                                 if (!rinclude) {
2985                                         for (sw = ast_walk_context_switches(c, NULL); sw; sw = ast_walk_context_switches(c, sw)) {
2986                                                 snprintf(buf, sizeof(buf), "'%s/%s'",
2987                                                         ast_get_switch_name(sw),
2988                                                         ast_get_switch_data(sw));
2989                                                 ast_cli(fd, "  Alt. Switch =>    %-45s [%s]\n",
2990                                                         buf, ast_get_switch_registrar(sw));     
2991                                         }
2992                                 }
2993         
2994                                 ast_unlock_context(c);
2995
2996                                 /* if we print something in context, make an empty line */
2997                                 if (context_info_printed) ast_cli(fd, "\r\n");
2998                         }
2999                 }
3000         }
3001         ast_unlock_contexts();
3002
3003         if (dpc->total_exten == old_total_exten) {
3004                 /* Nothing new under the sun */
3005                 return -1;
3006         } else {
3007                 return res;
3008         }
3009 }
3010
3011 static int handle_show_dialplan(int fd, int argc, char *argv[])
3012 {
3013         char *exten = NULL, *context = NULL;
3014         /* Variables used for different counters */
3015         struct dialplan_counters counters;
3016
3017         memset(&counters, 0, sizeof(counters));
3018
3019         if (argc != 2 && argc != 3) return RESULT_SHOWUSAGE;
3020
3021         /* we obtain [exten@]context? if yes, split them ... */
3022         if (argc == 3) {
3023                 char *splitter = ast_strdupa(argv[2]);
3024                 /* is there a '@' character? */
3025                 if (splitter && strchr(argv[2], '@')) {
3026                         /* yes, split into exten & context ... */
3027                         exten   = strsep(&splitter, "@");
3028                         context = splitter;
3029
3030                         /* check for length and change to NULL if ast_strlen_zero() */
3031                         if (ast_strlen_zero(exten))   exten = NULL;
3032                         if (ast_strlen_zero(context)) context = NULL;
3033                         show_dialplan_helper(fd, context, exten, &counters, NULL);
3034                 } else {
3035                         /* no '@' char, only context given */
3036                         context = argv[2];
3037                         if (ast_strlen_zero(context)) context = NULL;
3038                         show_dialplan_helper(fd, context, exten, &counters, NULL);
3039                 }
3040         } else {
3041                 show_dialplan_helper(fd, NULL, NULL, &counters, NULL);
3042         }
3043
3044         /* check for input failure and throw some error messages */
3045         if (context && !counters.context_existence) {
3046                 ast_cli(fd, "There is no existence of '%s' context\n", context);
3047                 return RESULT_FAILURE;
3048         }
3049
3050         if (exten && !counters.extension_existence) {
3051                 if (context)
3052                         ast_cli(fd, "There is no existence of %s@%s extension\n",
3053                                 exten, context);
3054                 else
3055                         ast_cli(fd,
3056                                 "There is no existence of '%s' extension in all contexts\n",
3057                                 exten);
3058                 return RESULT_FAILURE;
3059         }
3060
3061         ast_cli(fd,"-= %d extensions (%d priorities) in %d contexts. =-\n",
3062                                 counters.total_exten, counters.total_prio, counters.total_context);
3063
3064         /* everything ok */
3065         return RESULT_SUCCESS;
3066 }
3067
3068 /*
3069  * CLI entries for upper commands ...
3070  */
3071 static struct ast_cli_entry show_applications_cli = 
3072         { { "show", "applications", NULL }, 
3073         handle_show_applications, "Shows registered applications",
3074         show_applications_help, complete_show_applications };
3075
3076 static struct ast_cli_entry show_application_cli =
3077         { { "show", "application", NULL }, 
3078         handle_show_application, "Describe a specific application",
3079         show_application_help, complete_show_application };
3080
3081 static struct ast_cli_entry show_dialplan_cli =
3082         { { "show", "dialplan", NULL },
3083                 handle_show_dialplan, "Show dialplan",
3084                 show_dialplan_help, complete_show_dialplan_context };
3085
3086 static struct ast_cli_entry show_switches_cli =
3087         { { "show", "switches", NULL },
3088                 handle_show_switches, "Show alternative switches",
3089                 show_switches_help, NULL };
3090
3091 int ast_unregister_application(const char *app) {
3092         struct ast_app *tmp, *tmpl = NULL;
3093         if (ast_mutex_lock(&applock)) {
3094                 ast_log(LOG_ERROR, "Unable to lock application list\n");
3095                 return -1;
3096         }
3097         tmp = apps;
3098         while(tmp) {
3099                 if (!strcasecmp(app, tmp->name)) {
3100                         if (tmpl)
3101                                 tmpl->next = tmp->next;
3102                         else
3103                                 apps = tmp->next;
3104                         if (option_verbose > 1)
3105                                 ast_verbose( VERBOSE_PREFIX_2 "Unregistered application '%s'\n", tmp->name);
3106                         free(tmp);
3107                         ast_mutex_unlock(&applock);
3108                         return 0;
3109                 }
3110                 tmpl = tmp;
3111                 tmp = tmp->next;
3112         }
3113         ast_mutex_unlock(&applock);
3114         return -1;
3115 }
3116
3117 struct ast_context *ast_context_create(struct ast_context **extcontexts, const char *name, const char *registrar)
3118 {
3119         struct ast_context *tmp, **local_contexts;
3120         int length;
3121         length = sizeof(struct ast_context);
3122         length += strlen(name) + 1;
3123         if (!extcontexts) {
3124                 local_contexts = &contexts;
3125                 ast_mutex_lock(&conlock);
3126         } else
3127                 local_contexts = extcontexts;
3128
3129         tmp = *local_contexts;
3130         while(tmp) {
3131                 if (!strcasecmp(tmp->name, name)) {
3132                         ast_mutex_unlock(&conlock);
3133                         ast_log(LOG_WARNING, "Tried to register context '%s', already in use\n", name);
3134                         if (!extcontexts)
3135                                 ast_mutex_unlock(&conlock);
3136                         return NULL;
3137                 }
3138                 tmp = tmp->next;
3139         }
3140         tmp = malloc(length);
3141         if (tmp) {
3142                 memset(tmp, 0, length);
3143                 ast_mutex_init(&tmp->lock);
3144                 strcpy(tmp->name, name);
3145                 tmp->root = NULL;
3146                 tmp->registrar = registrar;
3147                 tmp->next = *local_contexts;
3148                 tmp->includes = NULL;
3149                 tmp->ignorepats = NULL;
3150                 *local_contexts = tmp;
3151                 if (option_debug)
3152                         ast_log(LOG_DEBUG, "Registered context '%s'\n", tmp->name);
3153                 else if (option_verbose > 2)
3154                         ast_verbose( VERBOSE_PREFIX_3 "Registered extension context '%s'\n", tmp->name);
3155         } else
3156                 ast_log(LOG_ERROR, "Out of memory\n");
3157         
3158         if (!extcontexts)
3159                 ast_mutex_unlock(&conlock);
3160         return tmp;
3161 }
3162
3163 void __ast_context_destroy(struct ast_context *con, const char *registrar);
3164
3165 void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char *registrar) {
3166         struct ast_context *tmp, *lasttmp = NULL;
3167         tmp = *extcontexts;
3168         ast_mutex_lock(&conlock);
3169         if (registrar) {
3170                 __ast_context_destroy(NULL,registrar);
3171                 while (tmp) {
3172                         lasttmp = tmp;
3173                         tmp = tmp->next;
3174                 }
3175         } else {
3176                 while (tmp) {
3177                         __ast_context_destroy(tmp,tmp->registrar);
3178                         lasttmp = tmp;
3179                         tmp = tmp->next;
3180                 }
3181         }
3182         if (lasttmp) {
3183                 lasttmp->next = contexts;
3184                 contexts = *extcontexts;
3185                 *extcontexts = NULL;
3186         } else 
3187                 ast_log(LOG_WARNING, "Requested contexts didn't get merged\n");
3188         ast_mutex_unlock(&conlock);
3189         return; 
3190 }
3191
3192 /*
3193  * errno values
3194  *  EBUSY  - can't lock
3195  *  ENOENT - no existence of context
3196  */
3197 int ast_context_add_include(const char *context, const char *include, const char *registrar)
3198 {
3199         struct ast_context *c;
3200
3201         if (ast_lock_contexts()) {
3202                 errno = EBUSY;
3203                 return -1;
3204         }
3205
3206         /* walk contexts ... */
3207         c = ast_walk_contexts(NULL);
3208         while (c) {
3209                 /* ... search for the right one ... */
3210                 if (!strcmp(ast_get_context_name(c), context)) {
3211                         int ret = ast_context_add_include2(c, include, registrar);
3212                         /* ... unlock contexts list and return */
3213                         ast_unlock_contexts();
3214                         return ret;
3215                 }
3216                 c = ast_walk_contexts(c);
3217         }
3218
3219         /* we can't find the right context */
3220         ast_unlock_contexts();
3221         errno = ENOENT;
3222         return -1;
3223 }
3224
3225 #define FIND_NEXT \
3226 do { \
3227         c = info; \
3228         while(*c && (*c != '|')) c++; \
3229         if (*c) { *c = '\0'; c++; } else c = NULL; \
3230 } while(0)
3231
3232 static void get_timerange(struct ast_timing *i, char *times)
3233 {
3234         char *e;
3235         int x;
3236         int s1, s2;
3237         int e1, e2;
3238         /*      int cth, ctm; */
3239
3240         /* start disabling all times, fill the fields with 0's, as they may contain garbage */
3241         memset(i->minmask, 0, sizeof(i->minmask));
3242         
3243         /* Star is all times */
3244         if (ast_strlen_zero(times) || !strcmp(times, "*")) {
3245                 for (x=0;x<24;x++)
3246                         i->minmask[x] = (1 << 30) - 1;
3247                 return;
3248         }
3249         /* Otherwise expect a range */
3250         e = strchr(times, '-');
3251         if (!e) {
3252                 ast_log(LOG_WARNING, "Time range is not valid. Assuming no restrictions based on time.\n");
3253                 return;
3254         }
3255         *e = '\0';
3256         e++;
3257         while(*e && !isdigit(*e)) e++;
3258         if (!*e) {
3259                 ast_log(LOG_WARNING, "Invalid time range.  Assuming no restrictions based on time.\n");
3260                 return;
3261         }
3262         if (sscanf(times, "%d:%d", &s1, &s2) != 2) {
3263                 ast_log(LOG_WARNING, "%s isn't a time.  Assuming no restrictions based on time.\n", times);
3264                 return;
3265         }
3266         if (sscanf(e, "%d:%d", &e1, &e2) != 2) {
3267                 ast_log(LOG_WARNING, "%s isn't a time.  Assuming no restrictions based on time.\n", e);
3268                 return;
3269         }
3270
3271 #if 1
3272         s1 = s1 * 30 + s2/2;
3273         if ((s1 < 0) || (s1 >= 24*30)) {
3274                 ast_log(LOG_WARNING, "%s isn't a valid start time. Assuming no time.\n", times);
3275                 return;
3276         }
3277         e1 = e1 * 30 + e2/2;
3278         if ((e1 < 0) || (e1 >= 24*30)) {
3279                 ast_log(LOG_WARNING, "%s isn't a valid end time. Assuming no time.\n", e);
3280                 return;
3281         }
3282         /* Go through the time and enable each appropriate bit */
3283         for (x=s1;x != e1;x = (x + 1) % (24 * 30)) {
3284                 i->minmask[x/30] |= (1 << (x % 30));
3285         }
3286         /* Do the last one */
3287         i->minmask[x/30] |= (1 << (x % 30));
3288 #else
3289         for (cth=0;cth<24;cth++) {
3290                 /* Initialize masks to blank */
3291                 i->minmask[cth] = 0;
3292                 for (ctm=0;ctm<30;ctm++) {
3293                         if (
3294                         /* First hour with more than one hour */
3295                               (((cth == s1) && (ctm >= s2)) &&
3296                                ((cth < e1)))
3297                         /* Only one hour */
3298                         ||    (((cth == s1) && (ctm >= s2)) &&
3299                                ((cth == e1) && (ctm <= e2)))
3300                         /* In between first and last hours (more than 2 hours) */
3301                         ||    ((cth > s1) &&
3302                                (cth < e1))
3303                         /* Last hour with more than one hour */
3304                         ||    ((cth > s1) &&
3305                                ((cth == e1) && (ctm <= e2)))
3306                         )
3307                                 i->minmask[cth] |= (1 << (ctm / 2));
3308                 }
3309         }
3310 #endif
3311         /* All done */
3312         return;
3313 }
3314
3315 static char *days[] =
3316 {
3317         "sun",
3318         "mon",
3319         "tue",
3320         "wed",
3321         "thu",
3322         "fri",
3323         "sat",
3324 };
3325
3326 static unsigned int get_dow(char *dow)
3327 {
3328         char *c;
3329         /* The following line is coincidence, really! */
3330         int s, e, x;
3331         unsigned int mask;
3332
3333         /* Check for all days */
3334         if (ast_strlen_zero(dow) || !strcmp(dow, "*"))
3335                 return (1 << 7) - 1;
3336         /* Get start and ending days */
3337         c = strchr(dow, '-');
3338         if (c) {
3339                 *c = '\0';
3340                 c++;
3341         } else
3342                 c = NULL;
3343         /* Find the start */
3344         s = 0;
3345         while((s < 7) && strcasecmp(dow, days[s])) s++;
3346         if (s >= 7) {
3347                 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", dow);
3348                 return 0;
3349         }
3350         if (c) {
3351                 e = 0;
3352                 while((e < 7) && strcasecmp(c, days[e])) e++;
3353                 if (e >= 7) {
3354                         ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
3355                         return 0;
3356                 }
3357         } else
3358                 e = s;
3359         mask = 0;
3360         for (x=s; x != e; x = (x + 1) % 7) {
3361                 mask |= (1 << x);
3362         }
3363         /* One last one */
3364         mask |= (1 << x);
3365         return mask;
3366 }
3367
3368 static unsigned int get_day(char *day)
3369 {
3370         char *c;
3371         /* The following line is coincidence, really! */
3372         int s, e, x;
3373         unsigned int mask;
3374
3375         /* Check for all days */
3376         if (ast_strlen_zero(day) || !strcmp(day, "*")) {
3377                 mask = (1 << 30)  + ((1 << 30) - 1);
3378                 return mask;
3379         }
3380         /* Get start and ending days */
3381         c = strchr(day, '-');
3382         if (c) {
3383                 *c = '\0';
3384                 c++;
3385         }
3386         /* Find the start */
3387         if (sscanf(day, "%d", &s) != 1) {
3388                 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", day);
3389                 return 0;
3390         }
3391         if ((s < 1) || (s > 31)) {
3392                 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", day);
3393                 return 0;
3394         }
3395         s--;
3396         if (c) {
3397                 if (sscanf(c, "%d", &e) != 1) {
3398                         ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
3399                         return 0;
3400                 }
3401                 if ((e < 1) || (e > 31)) {
3402                         ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
3403                         return 0;
3404                 }
3405                 e--;
3406         } else
3407                 e = s;
3408         mask = 0;
3409         for (x=s;x!=e;x = (x + 1) % 31) {
3410                 mask |= (1 << x);
3411         }
3412         mask |= (1 << x);
3413         return mask;
3414 }
3415
3416 static char *months[] =
3417 {
3418         "jan",
3419         "feb",
3420         "mar",
3421         "apr",
3422         "may",
3423         "jun",
3424         "jul",
3425         "aug",
3426         "sep",
3427         "oct",
3428         "nov",
3429         "dec",
3430 };
3431
3432 static unsigned int get_month(char *mon)
3433 {
3434         char *c;
3435         /* The following line is coincidence, really! */
3436         int s, e, x;
3437         unsigned int mask;
3438
3439         /* Check for all days */
3440         if (ast_strlen_zero(mon) || !strcmp(mon, "*"))