First pass at properly handling account codes in forwarding
[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 - 1, 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 -1, "%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 -1, "%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 -1, "%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 -1, "%s", c->uniqueid);
940                 *ret = workspace;
941         } else if (c && !strcmp(var, "HANGUPCAUSE")) {
942                 snprintf(workspace, workspacelen -1, "%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                         strcpy(workspace, "");
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)-1, 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         strcpy(hint, ast_get_extension_app(list->exten));
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 maxlen, 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), maxlen);
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                 strcpy(c->exten, "h");
1911                 c->priority = 1;
1912                 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
1913                         if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->callerid))) {
1914                                 /* Something bad happened, or a hangup has been requested. */
1915                                 if (option_debug)
1916                                         ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
1917                                 else if (option_verbose > 1)
1918                                         ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
1919                                 break;
1920                         }
1921                         c->priority++;
1922                 }
1923         }
1924
1925         pbx_destroy(c->pbx);
1926         c->pbx = NULL;
1927         if (res != AST_PBX_KEEPALIVE)
1928                 ast_hangup(c);
1929         return 0;
1930 }
1931
1932 static void *pbx_thread(void *data)
1933 {
1934         /* Oh joyeous kernel, we're a new thread, with nothing to do but
1935            answer this channel and get it going.  The setjmp stuff is fairly
1936            confusing, but necessary to get smooth transitions between
1937            the execution of different applications (without the use of
1938            additional threads) */
1939         struct ast_channel *c = data;
1940         ast_pbx_run(c);
1941         pthread_exit(NULL);
1942         return NULL;
1943 }
1944
1945 int ast_pbx_start(struct ast_channel *c)
1946 {
1947         pthread_t t;
1948         pthread_attr_t attr;
1949         if (!c) {
1950                 ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
1951                 return -1;
1952         }
1953            
1954         /* Start a new thread, and get something handling this channel. */
1955         pthread_attr_init(&attr);
1956         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1957         if (pthread_create(&t, &attr, pbx_thread, c)) {
1958                 ast_log(LOG_WARNING, "Failed to create new channel thread\n");
1959                 return -1;
1960         }
1961         return 0;
1962 }
1963
1964 /*
1965  * This function locks contexts list by &conlist, search for the rigt context
1966  * structure, leave context list locked and call ast_context_remove_include2
1967  * which removes include, unlock contexts list and return ...
1968  */
1969 int ast_context_remove_include(char *context, char *include, char *registrar)
1970 {
1971         struct ast_context *c;
1972
1973         if (ast_lock_contexts()) return -1;
1974
1975         /* walk contexts and search for the right one ...*/
1976         c = ast_walk_contexts(NULL);
1977         while (c) {
1978                 /* we found one ... */
1979                 if (!strcmp(ast_get_context_name(c), context)) {
1980                         int ret;
1981                         /* remove include from this context ... */      
1982                         ret = ast_context_remove_include2(c, include, registrar);
1983
1984                         ast_unlock_contexts();
1985
1986                         /* ... return results */
1987                         return ret;
1988                 }
1989                 c = ast_walk_contexts(c);
1990         }
1991
1992         /* we can't find the right one context */
1993         ast_unlock_contexts();
1994         return -1;
1995 }
1996
1997 /*
1998  * When we call this function, &conlock lock must be locked, because when
1999  * we giving *con argument, some process can remove/change this context
2000  * and after that there can be segfault.
2001  *
2002  * This function locks given context, removes include, unlock context and
2003  * return.
2004  */
2005 int ast_context_remove_include2(struct ast_context *con, char *include, char *registrar)
2006 {
2007         struct ast_include *i, *pi = NULL;
2008
2009         if (ast_mutex_lock(&con->lock)) return -1;
2010
2011         /* walk includes */
2012         i = con->includes;
2013         while (i) {
2014                 /* find our include */
2015                 if (!strcmp(i->name, include) && 
2016                         (!strcmp(i->registrar, registrar) || !registrar)) {
2017                         /* remove from list */
2018                         if (pi)
2019                                 pi->next = i->next;
2020                         else
2021                                 con->includes = i->next;
2022                         /* free include and return */
2023                         free(i);
2024                         ast_mutex_unlock(&con->lock);
2025                         return 0;
2026                 }
2027                 pi = i;
2028                 i = i->next;
2029         }
2030
2031         /* we can't find the right include */
2032         ast_mutex_unlock(&con->lock);
2033         return -1;
2034 }
2035
2036 /*
2037  * This function locks contexts list by &conlist, search for the rigt context
2038  * structure, leave context list locked and call ast_context_remove_switch2
2039  * which removes switch, unlock contexts list and return ...
2040  */
2041 int ast_context_remove_switch(char *context, char *sw, char *data, char *registrar)
2042 {
2043         struct ast_context *c;
2044
2045         if (ast_lock_contexts()) return -1;
2046
2047         /* walk contexts and search for the right one ...*/
2048         c = ast_walk_contexts(NULL);
2049         while (c) {
2050                 /* we found one ... */
2051                 if (!strcmp(ast_get_context_name(c), context)) {
2052                         int ret;
2053                         /* remove switch from this context ... */       
2054                         ret = ast_context_remove_switch2(c, sw, data, registrar);
2055
2056                         ast_unlock_contexts();
2057
2058                         /* ... return results */
2059                         return ret;
2060                 }
2061                 c = ast_walk_contexts(c);
2062         }
2063
2064         /* we can't find the right one context */
2065         ast_unlock_contexts();
2066         return -1;
2067 }
2068
2069 /*
2070  * When we call this function, &conlock lock must be locked, because when
2071  * we giving *con argument, some process can remove/change this context
2072  * and after that there can be segfault.
2073  *
2074  * This function locks given context, removes switch, unlock context and
2075  * return.
2076  */
2077 int ast_context_remove_switch2(struct ast_context *con, char *sw, char *data, char *registrar)
2078 {
2079         struct ast_sw *i, *pi = NULL;
2080
2081         if (ast_mutex_lock(&con->lock)) return -1;
2082
2083         /* walk switchs */
2084         i = con->alts;
2085         while (i) {
2086                 /* find our switch */
2087                 if (!strcmp(i->name, sw) && !strcmp(i->data, data) && 
2088                         (!strcmp(i->registrar, registrar) || !registrar)) {
2089                         /* remove from list */
2090                         if (pi)
2091                                 pi->next = i->next;
2092                         else
2093                                 con->alts = i->next;
2094                         /* free switch and return */
2095                         free(i);
2096                         ast_mutex_unlock(&con->lock);
2097                         return 0;
2098                 }
2099                 pi = i;
2100                 i = i->next;
2101         }
2102
2103         /* we can't find the right switch */
2104         ast_mutex_unlock(&con->lock);
2105         return -1;
2106 }
2107
2108 /*
2109  * This functions lock contexts list, search for the right context,
2110  * call ast_context_remove_extension2, unlock contexts list and return.
2111  * In this function we are using
2112  */
2113 int ast_context_remove_extension(char *context, char *extension, int priority, char *registrar)
2114 {
2115         struct ast_context *c;
2116
2117         if (ast_lock_contexts()) return -1;
2118
2119         /* walk contexts ... */
2120         c = ast_walk_contexts(NULL);
2121         while (c) {
2122                 /* ... search for the right one ... */
2123                 if (!strcmp(ast_get_context_name(c), context)) {
2124                         /* ... remove extension ... */
2125                         int ret = ast_context_remove_extension2(c, extension, priority,
2126                                 registrar);
2127                         /* ... unlock contexts list and return */
2128                         ast_unlock_contexts();
2129                         return ret;
2130                 }
2131                 c = ast_walk_contexts(c);
2132         }
2133
2134         /* we can't find the right context */
2135         ast_unlock_contexts();
2136         return -1;
2137 }
2138
2139 /*
2140  * When do you want to call this function, make sure that &conlock is locked,
2141  * because some process can handle with your *con context before you lock
2142  * it.
2143  *
2144  * This functionc locks given context, search for the right extension and
2145  * fires out all peer in this extensions with given priority. If priority
2146  * is set to 0, all peers are removed. After that, unlock context and
2147  * return.
2148  */
2149 int ast_context_remove_extension2(struct ast_context *con, char *extension, int priority, char *registrar)
2150 {
2151         struct ast_exten *exten, *prev_exten = NULL;
2152
2153         if (ast_mutex_lock(&con->lock)) return -1;
2154
2155         /* go through all extensions in context and search the right one ... */
2156         exten = con->root;
2157         while (exten) {
2158
2159                 /* look for right extension */
2160                 if (!strcmp(exten->exten, extension) &&
2161                         (!strcmp(exten->registrar, registrar) || !registrar)) {
2162                         struct ast_exten *peer;
2163
2164                         /* should we free all peers in this extension? (priority == 0)? */
2165                         if (priority == 0) {
2166                                 /* remove this extension from context list */
2167                                 if (prev_exten)
2168                                         prev_exten->next = exten->next;
2169                                 else
2170                                         con->root = exten->next;
2171
2172                                 /* fire out all peers */
2173                                 peer = exten; 
2174                                 while (peer) {
2175                                         exten = peer->peer;
2176                                         
2177                                         if (!peer->priority==PRIORITY_HINT) 
2178                                             ast_remove_hint(peer);
2179
2180                                         peer->datad(peer->data);
2181                                         free(peer);
2182
2183                                         peer = exten;
2184                                 }
2185
2186                                 ast_mutex_unlock(&con->lock);
2187                                 return 0;
2188                         } else {
2189                                 /* remove only extension with exten->priority == priority */
2190                                 struct ast_exten *previous_peer = NULL;
2191
2192                                 peer = exten;
2193                                 while (peer) {
2194                                         /* is this our extension? */
2195                                         if (peer->priority == priority &&
2196                                                 (!strcmp(peer->registrar, registrar) || !registrar)) {
2197                                                 /* we are first priority extension? */
2198                                                 if (!previous_peer) {
2199                                                         /* exists previous extension here? */
2200                                                         if (prev_exten) {
2201                                                                 /* yes, so we must change next pointer in
2202                                                                  * previous connection to next peer
2203                                                                  */
2204                                                                 if (peer->peer) {
2205                                                                         prev_exten->next = peer->peer;
2206                                                                         peer->peer->next = exten->next;
2207                                                                 } else
2208                                                                         prev_exten->next = exten->next;
2209                                                         } else {
2210                                                                 /* no previous extension, we are first
2211                                                                  * extension, so change con->root ...
2212                                                                  */
2213                                                                 if (peer->peer)
2214                                                                         con->root = peer->peer;
2215                                                                 else
2216                                                                         con->root = exten->next; 
2217                                                         }
2218                                                 } else {
2219                                                         /* we are not first priority in extension */
2220                                                         previous_peer->peer = peer->peer;
2221                                                 }
2222
2223                                                 /* now, free whole priority extension */
2224                                                 if (peer->priority==PRIORITY_HINT)
2225                                                     ast_remove_hint(peer);
2226                                                 peer->datad(peer->data);
2227                                                 free(peer);
2228
2229                                                 ast_mutex_unlock(&con->lock);
2230                                                 return 0;
2231                                         } else {
2232                                                 /* this is not right extension, skip to next peer */
2233                                                 previous_peer = peer;
2234                                                 peer = peer->peer;
2235                                         }
2236                                 }
2237
2238                                 ast_mutex_unlock(&con->lock);
2239                                 return -1;
2240                         }
2241                 }
2242
2243                 prev_exten = exten;
2244                 exten = exten->next;
2245         }
2246
2247         /* we can't find right extension */
2248         ast_mutex_unlock(&con->lock);
2249         return -1;
2250 }
2251
2252
2253 int ast_register_application(char *app, int (*execute)(struct ast_channel *, void *), char *synopsis, char *description)
2254 {
2255         struct ast_app *tmp, *prev, *cur;
2256         char tmps[80];
2257         if (ast_mutex_lock(&applock)) {
2258                 ast_log(LOG_ERROR, "Unable to lock application list\n");
2259                 return -1;
2260         }
2261         tmp = apps;
2262         while(tmp) {
2263                 if (!strcasecmp(app, tmp->name)) {
2264                         ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
2265                         ast_mutex_unlock(&applock);
2266                         return -1;
2267                 }
2268                 tmp = tmp->next;
2269         }
2270         tmp = malloc(sizeof(struct ast_app));
2271         if (tmp) {
2272                 memset(tmp, 0, sizeof(struct ast_app));
2273                 strncpy(tmp->name, app, sizeof(tmp->name)-1);
2274                 tmp->execute = execute;
2275                 tmp->synopsis = synopsis;
2276                 tmp->description = description;
2277                 /* Store in alphabetical order */
2278                 cur = apps;
2279                 prev = NULL;
2280                 while(cur) {
2281                         if (strcasecmp(tmp->name, cur->name) < 0)
2282                                 break;
2283                         prev = cur;
2284                         cur = cur->next;
2285                 }
2286                 if (prev) {
2287                         tmp->next = prev->next;
2288                         prev->next = tmp;
2289                 } else {
2290                         tmp->next = apps;
2291                         apps = tmp;
2292                 }
2293         } else {
2294                 ast_log(LOG_ERROR, "Out of memory\n");
2295                 ast_mutex_unlock(&applock);
2296                 return -1;
2297         }
2298         if (option_verbose > 1)
2299                 ast_verbose( VERBOSE_PREFIX_2 "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
2300         ast_mutex_unlock(&applock);
2301         return 0;
2302 }
2303
2304 int ast_register_switch(struct ast_switch *sw)
2305 {
2306         struct ast_switch *tmp, *prev=NULL;
2307         if (ast_mutex_lock(&switchlock)) {
2308                 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
2309                 return -1;
2310         }
2311         tmp = switches;
2312         while(tmp) {
2313                 if (!strcasecmp(tmp->name, sw->name))
2314                         break;
2315                 prev = tmp;
2316                 tmp = tmp->next;
2317         }
2318         if (tmp) {      
2319                 ast_mutex_unlock(&switchlock);
2320                 ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name);
2321                 return -1;
2322         }
2323         sw->next = NULL;
2324         if (prev) 
2325                 prev->next = sw;
2326         else
2327                 switches = sw;
2328         ast_mutex_unlock(&switchlock);
2329         return 0;
2330 }
2331
2332 void ast_unregister_switch(struct ast_switch *sw)
2333 {
2334         struct ast_switch *tmp, *prev=NULL;
2335         if (ast_mutex_lock(&switchlock)) {
2336                 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
2337                 return;
2338         }
2339         tmp = switches;
2340         while(tmp) {
2341                 if (tmp == sw) {
2342                         if (prev)
2343                                 prev->next = tmp->next;
2344                         else
2345                                 switches = tmp->next;
2346                         tmp->next = NULL;
2347                         break;                  
2348                 }
2349                 prev = tmp;
2350                 tmp = tmp->next;
2351         }
2352         ast_mutex_unlock(&switchlock);
2353 }
2354
2355 /*
2356  * Help for CLI commands ...
2357  */
2358 static char show_application_help[] = 
2359 "Usage: show application <application> [<application> [<application> [...]]]\n"
2360 "       Describes a particular application.\n";
2361
2362 static char show_applications_help[] =
2363 "Usage: show applications\n"
2364 "       List applications which are currently available.\n";
2365
2366 static char show_dialplan_help[] =
2367 "Usage: show dialplan [exten@][context]\n"
2368 "       Show dialplan\n";
2369
2370 static char show_switches_help[] = 
2371 "Usage: show switches\n"
2372 "       Show registered switches\n";
2373
2374 /*
2375  * IMPLEMENTATION OF CLI FUNCTIONS IS IN THE SAME ORDER AS COMMANDS HELPS
2376  *
2377  */
2378
2379 /*
2380  * 'show application' CLI command implementation functions ...
2381  */
2382
2383 /*
2384  * There is a possibility to show informations about more than one
2385  * application at one time. You can type 'show application Dial Echo' and
2386  * you will see informations about these two applications ...
2387  */
2388 static char *complete_show_application(char *line, char *word,
2389         int pos, int state)
2390 {
2391         struct ast_app *a;
2392         int which = 0;
2393
2394         /* try to lock applications list ... */
2395         if (ast_mutex_lock(&applock)) {
2396                 ast_log(LOG_ERROR, "Unable to lock application list\n");
2397                 return NULL;
2398         }
2399
2400         /* ... walk all applications ... */
2401         a = apps; 
2402         while (a) {
2403                 /* ... check if word matches this application ... */
2404                 if (!strncasecmp(word, a->name, strlen(word))) {
2405                         /* ... if this is right app serve it ... */
2406                         if (++which > state) {
2407                                 char *ret = strdup(a->name);
2408                                 ast_mutex_unlock(&applock);
2409                                 return ret;
2410                         }
2411                 }
2412                 a = a->next; 
2413         }
2414
2415         /* no application match */
2416         ast_mutex_unlock(&applock);
2417         return NULL; 
2418 }
2419
2420 static int handle_show_application(int fd, int argc, char *argv[])
2421 {
2422         struct ast_app *a;
2423         int app, no_registered_app = 1;
2424
2425         if (argc < 3) return RESULT_SHOWUSAGE;
2426
2427         /* try to lock applications list ... */
2428         if (ast_mutex_lock(&applock)) {
2429                 ast_log(LOG_ERROR, "Unable to lock application list\n");
2430                 return -1;
2431         }
2432
2433         /* ... go through all applications ... */
2434         a = apps; 
2435         while (a) {
2436                 /* ... compare this application name with all arguments given
2437                  * to 'show application' command ... */
2438                 for (app = 2; app < argc; app++) {
2439                         if (!strcasecmp(a->name, argv[app])) {
2440                                 /* Maximum number of characters added by terminal coloring is 22 */
2441                                 char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
2442                                 char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
2443                                 int synopsis_size, description_size;
2444
2445                                 no_registered_app = 0;
2446
2447                                 if (a->synopsis)
2448                                         synopsis_size = strlen(a->synopsis) + 23;
2449                                 else
2450                                         synopsis_size = strlen("Not available") + 23;
2451                                 synopsis = alloca(synopsis_size);
2452
2453                                 if (a->description)
2454                                         description_size = strlen(a->description) + 23;
2455                                 else
2456                                         description_size = strlen("Not available") + 23;
2457                                 description = alloca(description_size);
2458
2459                                 if (synopsis && description) {
2460                                         snprintf(info, 64 + AST_MAX_APP, "\n  -= Info about application '%s' =- \n\n", a->name);
2461                                         term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
2462                                         term_color(syntitle, "[Synopsis]:\n", COLOR_MAGENTA, 0, 40);
2463                                         term_color(destitle, "[Description]:\n", COLOR_MAGENTA, 0, 40);
2464                                         term_color(synopsis,
2465                                                                         a->synopsis ? a->synopsis : "Not available",
2466                                                                         COLOR_CYAN, 0, synopsis_size);
2467                                         term_color(description,
2468                                                                         a->description ? a->description : "Not available",
2469                                                                         COLOR_CYAN, 0, description_size);
2470
2471                                         ast_cli(fd,"%s%s%s\n\n%s%s\n", infotitle, syntitle, synopsis, destitle, description);
2472                                 } else {
2473                                         /* ... one of our applications, show info ...*/
2474                                         ast_cli(fd,"\n  -= Info about application '%s' =- \n\n"
2475                                                 "[Synopsis]:\n  %s\n\n"
2476                                                 "[Description]:\n%s\n",
2477                                                 a->name,
2478                                                 a->synopsis ? a->synopsis : "Not available",
2479                                                 a->description ? a->description : "Not available");
2480                                 }
2481                         }
2482                 }
2483                 a = a->next; 
2484         }
2485
2486         ast_mutex_unlock(&applock);
2487
2488         /* we found at least one app? no? */
2489         if (no_registered_app) {
2490                 ast_cli(fd, "Your application(s) is (are) not registered\n");
2491                 return RESULT_FAILURE;
2492         }
2493
2494         return RESULT_SUCCESS;
2495 }
2496
2497 static int handle_show_switches(int fd, int argc, char *argv[])
2498 {
2499         struct ast_switch *sw;
2500         if (!switches) {
2501                 ast_cli(fd, "There are no registered alternative switches\n");
2502                 return RESULT_SUCCESS;
2503         }
2504         /* ... we have applications ... */
2505         ast_cli(fd, "\n    -= Registered Asterisk Alternative Switches =-\n");
2506         if (ast_mutex_lock(&switchlock)) {
2507                 ast_log(LOG_ERROR, "Unable to lock switches\n");
2508                 return -1;
2509         }
2510         sw = switches;
2511         while (sw) {
2512                 ast_cli(fd, "%s: %s\n", sw->name, sw->description);
2513                 sw = sw->next;
2514         }
2515         ast_mutex_unlock(&switchlock);
2516         return RESULT_SUCCESS;
2517 }
2518
2519 /*
2520  * 'show applications' CLI command implementation functions ...
2521  */
2522 static int handle_show_applications(int fd, int argc, char *argv[])
2523 {
2524         struct ast_app *a;
2525
2526         /* try to lock applications list ... */
2527         if (ast_mutex_lock(&applock)) {
2528                 ast_log(LOG_ERROR, "Unable to lock application list\n");
2529                 return -1;
2530         }
2531
2532         /* ... go to first application ... */
2533         a = apps; 
2534
2535         /* ... have we got at least one application (first)? no? */
2536         if (!a) {
2537                 ast_cli(fd, "There is no registered applications\n");
2538                 ast_mutex_unlock(&applock);
2539                 return -1;
2540         }
2541
2542         /* ... we have applications ... */
2543         ast_cli(fd, "\n    -= Registered Asterisk Applications =-\n");
2544
2545         /* ... go through all applications ... */
2546         while (a) {
2547                 /* ... show informations about applications ... */
2548                 ast_cli(fd,"  %20s: %s\n",
2549                         a->name,
2550                         a->synopsis ? a->synopsis : "<Synopsis not available>");
2551                 a = a->next; 
2552         }
2553
2554         /* ... unlock and return */
2555         ast_mutex_unlock(&applock);
2556
2557         return RESULT_SUCCESS;
2558 }
2559
2560 /*
2561  * 'show dialplan' CLI command implementation functions ...
2562  */
2563 static char *complete_show_dialplan_context(char *line, char *word, int pos,
2564         int state)
2565 {
2566         struct ast_context *c;
2567         int which = 0;
2568
2569         /* we are do completion of [exten@]context on second position only */
2570         if (pos != 2) return NULL;
2571
2572         /* try to lock contexts list ... */
2573         if (ast_lock_contexts()) {
2574                 ast_log(LOG_ERROR, "Unable to lock context list\n");
2575                 return NULL;
2576         }
2577
2578         /* ... walk through all contexts ... */
2579         c = ast_walk_contexts(NULL);
2580         while(c) {
2581                 /* ... word matches context name? yes? ... */
2582                 if (!strncasecmp(word, ast_get_context_name(c), strlen(word))) {
2583                         /* ... for serve? ... */
2584                         if (++which > state) {
2585                                 /* ... yes, serve this context name ... */
2586                                 char *ret = strdup(ast_get_context_name(c));
2587                                 ast_unlock_contexts();
2588                                 return ret;
2589                         }
2590                 }
2591                 c = ast_walk_contexts(c);
2592         }
2593
2594         /* ... unlock and return */
2595         ast_unlock_contexts();
2596         return NULL;
2597 }
2598
2599 static int handle_show_dialplan(int fd, int argc, char *argv[])
2600 {
2601         struct ast_context *c;
2602         char *exten = NULL, *context = NULL;
2603         int context_existence = 0, extension_existence = 0;
2604
2605         if (argc != 3 && argc != 2) return -1;
2606
2607         /* we obtain [exten@]context? if yes, split them ... */
2608         if (argc == 3) {
2609                 char *splitter = argv[2];
2610                 /* is there a '@' character? */
2611                 if (strchr(argv[2], '@')) {
2612                         /* yes, split into exten & context ... */
2613                         exten   = strsep(&splitter, "@");
2614                         context = splitter;
2615
2616                         /* check for length and change to NULL if ast_strlen_zero() */
2617                         if (ast_strlen_zero(exten))   exten = NULL;
2618                         if (ast_strlen_zero(context)) context = NULL;
2619                 } else
2620                 {
2621                         /* no '@' char, only context given */
2622                         context = argv[2];
2623                         if (ast_strlen_zero(context)) context = NULL;
2624                 }
2625         }
2626
2627         /* try to lock contexts */
2628         if (ast_lock_contexts()) {
2629                 ast_log(LOG_WARNING, "Failed to lock contexts list\n");
2630                 return RESULT_FAILURE;
2631         }
2632
2633         /* walk all contexts ... */
2634         c = ast_walk_contexts(NULL);
2635         while (c) {
2636                 /* show this context? */
2637                 if (!context ||
2638                         !strcmp(ast_get_context_name(c), context)) {
2639                         context_existence = 1;
2640
2641                         /* try to lock context before walking in ... */
2642                         if (!ast_lock_context(c)) {
2643                                 struct ast_exten *e;
2644                                 struct ast_include *i;
2645                                 struct ast_ignorepat *ip;
2646                                 struct ast_sw *sw;
2647                                 char buf[256], buf2[256];
2648                                 int context_info_printed = 0;
2649
2650                                 /* are we looking for exten too? if yes, we print context
2651                                  * if we our extension only
2652                                  */
2653                                 if (!exten) {
2654                                         ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
2655                                                 ast_get_context_name(c), ast_get_context_registrar(c));
2656                                         context_info_printed = 1;
2657                                 }
2658
2659                                 /* walk extensions ... */
2660                                 e = ast_walk_context_extensions(c, NULL);
2661                                 while (e) {
2662                                         struct ast_exten *p;
2663
2664                                         /* looking for extension? is this our extension? */
2665                                         if (exten &&
2666                                                 strcmp(ast_get_extension_name(e), exten))
2667                                         {
2668                                                 /* we are looking for extension and it's not our
2669                                                  * extension, so skip to next extension */
2670                                                 e = ast_walk_context_extensions(c, e);
2671                                                 continue;
2672                                         }
2673
2674                                         extension_existence = 1;
2675
2676                                         /* may we print context info? */        
2677                                         if (!context_info_printed) {
2678                                                 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
2679                                                         ast_get_context_name(c),
2680                                                         ast_get_context_registrar(c));
2681                                                 context_info_printed = 1;
2682                                         }
2683
2684                                         /* write extension name and first peer */       
2685                                         bzero(buf, sizeof(buf));                
2686                                         snprintf(buf, sizeof(buf), "'%s' =>",
2687                                                 ast_get_extension_name(e));
2688
2689                                         snprintf(buf2, sizeof(buf2),
2690                                                 "%d. %s(%s)",
2691                                                 ast_get_extension_priority(e),
2692                                                 ast_get_extension_app(e),
2693                                                 (char *)ast_get_extension_app_data(e));
2694
2695                                         ast_cli(fd, "  %-17s %-45s [%s]\n", buf, buf2,
2696                                                 ast_get_extension_registrar(e));
2697
2698                                         /* walk next extension peers */
2699                                         p = ast_walk_extension_priorities(e, e);
2700                                         while (p) {
2701                                                 bzero((void *)buf2, sizeof(buf2));
2702
2703                                                 snprintf(buf2, sizeof(buf2),
2704                                                         "%d. %s(%s)",
2705                                                         ast_get_extension_priority(p),
2706                                                         ast_get_extension_app(p),
2707                                                         (char *)ast_get_extension_app_data(p));
2708
2709                                                 ast_cli(fd,"  %-17s %-45s [%s]\n",
2710                                                         "", buf2,
2711                                                         ast_get_extension_registrar(p));        
2712
2713                                                 p = ast_walk_extension_priorities(e, p);
2714                                         }
2715                                         e = ast_walk_context_extensions(c, e);
2716                                 }
2717
2718                                 /* include & ignorepat we all printing if we are not
2719                                  * looking for exact extension
2720                                  */
2721                                 if (!exten) {
2722                                         if (ast_walk_context_extensions(c, NULL))
2723                                                 ast_cli(fd, "\n");
2724
2725                                         /* walk included and write info ... */
2726                                         i = ast_walk_context_includes(c, NULL);
2727                                         while (i) {
2728                                                 bzero(buf, sizeof(buf));
2729                                                 snprintf(buf, sizeof(buf), "'%s'",
2730                                                         ast_get_include_name(i));
2731                                                 ast_cli(fd, "  Include =>        %-45s [%s]\n",
2732                                                         buf, ast_get_include_registrar(i));
2733                                                 i = ast_walk_context_includes(c, i);
2734                                         }
2735
2736                                         /* walk ignore patterns and write info ... */
2737                                         ip = ast_walk_context_ignorepats(c, NULL);
2738                                         while (ip) {
2739                                                 bzero(buf, sizeof(buf));
2740                                                 snprintf(buf, sizeof(buf), "'%s'",
2741                                                         ast_get_ignorepat_name(ip));
2742                                                 ast_cli(fd, "  Ignore pattern => %-45s [%s]\n",
2743                                                         buf, ast_get_ignorepat_registrar(ip));  
2744                                                 ip = ast_walk_context_ignorepats(c, ip);
2745                                         }
2746                                         sw = ast_walk_context_switches(c, NULL);
2747                                         while(sw) {
2748                                                 bzero(buf, sizeof(buf));
2749                                                 snprintf(buf, sizeof(buf), "'%s/%s'",
2750                                                         ast_get_switch_name(sw),
2751                                                         ast_get_switch_data(sw));
2752                                                 ast_cli(fd, "  Alt. Switch =>    %-45s [%s]\n",
2753                                                         buf, ast_get_switch_registrar(sw));     
2754                                                 sw = ast_walk_context_switches(c, sw);
2755                                         }
2756                                 }
2757         
2758                                 ast_unlock_context(c);
2759
2760                                 /* if we print something in context, make an empty line */
2761                                 if (context_info_printed) ast_cli(fd, "\n");
2762                         }
2763                 }
2764                 c = ast_walk_contexts(c);
2765         }
2766         ast_unlock_contexts();
2767
2768         /* check for input failure and throw some error messages */
2769         if (context && !context_existence) {
2770                 ast_cli(fd, "There is no existence of '%s' context\n",
2771                         context);
2772                 return RESULT_FAILURE;
2773         }
2774
2775         if (exten && !extension_existence) {
2776                 if (context)
2777                         ast_cli(fd, "There is no existence of %s@%s extension\n",
2778                                 exten, context);
2779                 else
2780                         ast_cli(fd,
2781                                 "There is no existence of '%s' extension in all contexts\n",
2782                                 exten);
2783                 return RESULT_FAILURE;
2784         }
2785
2786         /* everything ok */
2787         return RESULT_SUCCESS;
2788 }
2789
2790 /*
2791  * CLI entries for upper commands ...
2792  */
2793 static struct ast_cli_entry show_applications_cli = 
2794         { { "show", "applications", NULL }, 
2795         handle_show_applications, "Shows registered applications",
2796         show_applications_help };
2797
2798 static struct ast_cli_entry show_application_cli =
2799         { { "show", "application", NULL }, 
2800         handle_show_application, "Describe a specific application",
2801         show_application_help, complete_show_application };
2802
2803 static struct ast_cli_entry show_dialplan_cli =
2804         { { "show", "dialplan", NULL },
2805                 handle_show_dialplan, "Show dialplan",
2806                 show_dialplan_help, complete_show_dialplan_context };
2807
2808 static struct ast_cli_entry show_switches_cli =
2809         { { "show", "switches", NULL },
2810                 handle_show_switches, "Show alternative switches",
2811                 show_switches_help, NULL };
2812
2813 int ast_unregister_application(char *app) {
2814         struct ast_app *tmp, *tmpl = NULL;
2815         if (ast_mutex_lock(&applock)) {
2816                 ast_log(LOG_ERROR, "Unable to lock application list\n");
2817                 return -1;
2818         }
2819         tmp = apps;
2820         while(tmp) {
2821                 if (!strcasecmp(app, tmp->name)) {
2822                         if (tmpl)
2823                                 tmpl->next = tmp->next;
2824                         else
2825                                 apps = tmp->next;
2826                         if (option_verbose > 1)
2827                                 ast_verbose( VERBOSE_PREFIX_2 "Unregistered application '%s'\n", tmp->name);
2828                         ast_mutex_unlock(&applock);
2829                         return 0;
2830                 }
2831                 tmpl = tmp;
2832                 tmp = tmp->next;
2833         }
2834         ast_mutex_unlock(&applock);
2835         return -1;
2836 }
2837
2838 struct ast_context *ast_context_create(struct ast_context **extcontexts, char *name, char *registrar)
2839 {
2840         struct ast_context *tmp, **local_contexts;
2841         if (!extcontexts) {
2842                 local_contexts = &contexts;
2843                 ast_mutex_lock(&conlock);
2844         } else
2845                 local_contexts = extcontexts;
2846
2847         tmp = *local_contexts;
2848         while(tmp) {
2849                 if (!strcasecmp(tmp->name, name)) {
2850                         ast_mutex_unlock(&conlock);
2851                         ast_log(LOG_WARNING, "Tried to register context '%s', already in use\n", name);
2852                         if (!extcontexts)
2853                                 ast_mutex_unlock(&conlock);
2854                         return NULL;
2855                 }
2856                 tmp = tmp->next;
2857         }
2858         tmp = malloc(sizeof(struct ast_context));
2859         if (tmp) {
2860                 memset(tmp, 0, sizeof(struct ast_context));
2861                 ast_mutex_init(&tmp->lock);
2862                 strncpy(tmp->name, name, sizeof(tmp->name)-1);
2863                 tmp->root = NULL;
2864                 tmp->registrar = registrar;
2865                 tmp->next = *local_contexts;
2866                 tmp->includes = NULL;
2867                 tmp->ignorepats = NULL;
2868                 *local_contexts = tmp;
2869                 if (option_debug)
2870                         ast_log(LOG_DEBUG, "Registered context '%s'\n", tmp->name);
2871                 else if (option_verbose > 2)
2872                         ast_verbose( VERBOSE_PREFIX_3 "Registered extension context '%s'\n", tmp->name);
2873         } else
2874                 ast_log(LOG_ERROR, "Out of memory\n");
2875         
2876         if (!extcontexts)
2877                 ast_mutex_unlock(&conlock);
2878         return tmp;
2879 }
2880
2881 void __ast_context_destroy(struct ast_context *con, char *registrar);
2882
2883 void ast_merge_contexts_and_delete(struct ast_context **extcontexts, char *registrar) {
2884         struct ast_context *tmp, *lasttmp = NULL;
2885         tmp = *extcontexts;
2886         ast_mutex_lock(&conlock);
2887         if (registrar) {
2888                 __ast_context_destroy(NULL,registrar);
2889                 while (tmp) {
2890                         lasttmp = tmp;
2891                         tmp = tmp->next;
2892                 }
2893         } else {
2894                 while (tmp) {
2895                         __ast_context_destroy(tmp,tmp->registrar);
2896                         lasttmp = tmp;
2897                         tmp = tmp->next;
2898                 }
2899         }
2900         if (lasttmp) {
2901                 lasttmp->next = contexts;
2902                 contexts = *extcontexts;
2903                 *extcontexts = NULL;
2904         } else 
2905                 ast_log(LOG_WARNING, "Requested contexts didn't get merged\n");
2906         ast_mutex_unlock(&conlock);
2907         return; 
2908 }
2909
2910 /*
2911  * errno values
2912  *  EBUSY  - can't lock
2913  *  ENOENT - no existence of context
2914  */
2915 int ast_context_add_include(char *context, char *include, char *registrar)
2916 {
2917         struct ast_context *c;
2918
2919         if (ast_lock_contexts()) {
2920                 errno = EBUSY;
2921                 return -1;
2922         }
2923
2924         /* walk contexts ... */
2925         c = ast_walk_contexts(NULL);
2926         while (c) {
2927                 /* ... search for the right one ... */
2928                 if (!strcmp(ast_get_context_name(c), context)) {
2929                         int ret = ast_context_add_include2(c, include, registrar);
2930                         /* ... unlock contexts list and return */
2931                         ast_unlock_contexts();
2932                         return ret;
2933                 }
2934                 c = ast_walk_contexts(c);
2935         }
2936
2937         /* we can't find the right context */
2938         ast_unlock_contexts();
2939         errno = ENOENT;
2940         return -1;
2941 }
2942
2943 #define FIND_NEXT \
2944 do { \
2945         c = info; \
2946         while(*c && (*c != '|')) c++; \
2947         if (*c) { *c = '\0'; c++; } else c = NULL; \
2948 } while(0)
2949
2950 static void get_timerange(struct ast_include *i, char *times)
2951 {
2952         char *e;
2953         int x;
2954         int s1, s2;
2955         int e1, e2;
2956 //      int cth, ctm;
2957
2958         //[PHM 07/01/03]
2959         //start disabling all times, fill the fields with 0's, as they may contain garbage
2960         memset(i->minmask, 0, sizeof(i->minmask));
2961         
2962         /* Star is all times */
2963         if (ast_strlen_zero(times) || !strcmp(times, "*")) {
2964                 for (x=0;x<24;x++)
2965                         i->minmask[x] = (1 << 30) - 1;
2966                 return;
2967         }
2968         /* Otherwise expect a range */
2969         e = strchr(times, '-');
2970         if (!e) {
2971                 ast_log(LOG_WARNING, "Time range is not valid. Assuming no restrictions based on time.\n");
2972                 return;
2973         }
2974         *e = '\0';
2975         e++;
2976         while(*e && !isdigit(*e)) e++;
2977         if (!*e) {
2978                 ast_log(LOG_WARNING, "Invalid time range.  Assuming no restrictions based on time.\n");
2979                 return;
2980         }
2981         if (sscanf(times, "%d:%d", &s1, &s2) != 2) {
2982                 ast_log(LOG_WARNING, "%s isn't a time.  Assuming no restrictions based on time.\n", times);
2983                 return;
2984         }
2985         if (sscanf(e, "%d:%d", &e1, &e2) != 2) {
2986                 ast_log(LOG_WARNING, "%s isn't a time.  Assuming no restrictions based on time.\n", e);
2987                 return;
2988         }
2989
2990 #if 1
2991         s1 = s1 * 30 + s2/2;
2992         if ((s1 < 0) || (s1 >= 24*30)) {
2993                 ast_log(LOG_WARNING, "%s isn't a valid start time. Assuming no time.\n", times);
2994                 return;
2995         }
2996         e1 = e1 * 30 + e2/2;
2997         if ((e1 < 0) || (e1 >= 24*30)) {
2998                 ast_log(LOG_WARNING, "%s isn't a valid end time. Assuming no time.\n", e);
2999                 return;
3000         }
3001         /* Go through the time and enable each appropriate bit */
3002         for (x=s1;x != e1;x = (x + 1) % (24 * 30)) {
3003                 i->minmask[x/30] |= (1 << (x % 30));
3004         }
3005         /* Do the last one */
3006         i->minmask[x/30] |= (1 << (x % 30));
3007 #else
3008         for (cth=0;cth<24;cth++) {
3009                 /* Initialize masks to blank */
3010                 i->minmask[cth] = 0;
3011                 for (ctm=0;ctm<30;ctm++) {
3012                         if (
3013                         /* First hour with more than one hour */
3014                               (((cth == s1) && (ctm >= s2)) &&
3015                                ((cth < e1)))
3016                         /* Only one hour */
3017                         ||    (((cth == s1) && (ctm >= s2)) &&
3018                                ((cth == e1) && (ctm <= e2)))
3019                         /* In between first and last hours (more than 2 hours) */
3020                         ||    ((cth > s1) &&
3021                                (cth < e1))
3022                         /* Last hour with more than one hour */
3023                         ||    ((cth > s1) &&
3024                                ((cth == e1) && (ctm <= e2)))
3025                         )
3026                                 i->minmask[cth] |= (1 << (ctm / 2));
3027                 }
3028         }
3029 #endif
3030         /* All done */
3031         return;
3032 }
3033
3034 static char *days[] =
3035 {
3036         "sun",
3037         "mon",
3038         "tue",
3039         "wed",
3040         "thu",
3041         "fri",
3042         "sat",
3043 };
3044
3045 static unsigned int get_dow(char *dow)
3046 {
3047         char *c;
3048         /* The following line is coincidence, really! */
3049         int s, e, x;
3050         unsigned int mask;
3051         /* Check for all days */
3052         if (ast_strlen_zero(dow) || !strcmp(dow, "*"))
3053                 return (1 << 7) - 1;
3054         /* Get start and ending days */
3055         c = strchr(dow, '-');
3056         if (c) {
3057                 *c = '\0';
3058                 c++;
3059         } else
3060                 c = NULL;
3061         /* Find the start */
3062         s = 0;
3063         while((s < 7) && strcasecmp(dow, days[s])) s++;
3064         if (s >= 7) {
3065                 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", dow);
3066                 return 0;
3067         }
3068         if (c) {
3069                 e = 0;
3070                 while((e < 7) && strcasecmp(c, days[e])) e++;
3071                 if (e >= 7) {
3072                         ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
3073                         return 0;
3074                 }
3075         } else
3076                 e = s;
3077         mask = 0;
3078         for (x=s;x!=e;x = (x + 1) % 7) {
3079                 mask |= (1 << x);
3080         }
3081         /* One last one */
3082         mask |= (1 << x);
3083         return mask;
3084 }
3085
3086 static unsigned int get_day(char *day)
3087 {
3088         char *c;
3089         /* The following line is coincidence, really! */
3090         int s, e, x;
3091         unsigned int mask;
3092         /* Check for all days */
3093         if (ast_strlen_zero(day) || !strcmp(day, "*")) {
3094                 mask = (1 << 30)  + ((1 << 30) - 1);
3095                 return mask;
3096         }
3097         /* Get start and ending days */
3098         c = strchr(day, '-');