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