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