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