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