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