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