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