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