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