Don't crash if ZapHangup, ZapTransfer, ZapDialOffhook are used on the channel that...
[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 "  SetGlobalVar(#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 'fr/demo-\n"
310 "congrats' 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 if (c && !strcmp(var, "HANGUPCAUSE")) {
866           snprintf(workspace, workspacelen -1, "%i", c->hangupcause);
867           *ret = workspace;
868         } else if (c && !strcmp(var, "ACCOUNTCODE")) {
869           strncpy(workspace, c->accountcode, workspacelen - 1);
870           *ret = workspace;
871         } else {
872                 if (c) {
873                         AST_LIST_TRAVERSE(headp,variables,entries) {
874 #if 0
875                                 ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",var,ast_var_name(variables));
876 #endif
877                                 if (strcasecmp(ast_var_name(variables),var)==0) {
878                                         *ret=ast_var_value(variables);
879                                         if (*ret) {
880                                                 strncpy(workspace, *ret, workspacelen - 1);
881                                                 *ret = workspace;
882                                         }
883                                 }
884                         }
885                 }
886                 if (!(*ret)) {
887                         /* Try globals */
888                         AST_LIST_TRAVERSE(&globals,variables,entries) {
889 #if 0
890                                 ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",var,ast_var_name(variables));
891 #endif
892                                 if (strcasecmp(ast_var_name(variables),var)==0) {
893                                         *ret=ast_var_value(variables);
894                                         if (*ret) {
895                                                 strncpy(workspace, *ret, workspacelen - 1);
896                                                 *ret = workspace;
897                                         }
898                                 }
899                         }
900                 }
901                 if (!(*ret)) {
902                         int len=strlen(var);
903                         int len_env=strlen("ENV(");
904                         if (len > (len_env+1) && !strncasecmp(var,"ENV(",len_env) && !strcmp(var+len-1,")")) {
905                                 char cp3[80] = "";
906                                 strncpy(cp3, var, sizeof(cp3) - 1);
907                                 cp3[len-1]='\0';
908                                 *ret=getenv(cp3+len_env);
909                                 if (*ret) {
910                                         strncpy(workspace, *ret, workspacelen - 1);
911                                         *ret = workspace;
912                                 }
913                         }
914                 }
915                 if (!(*ret) && !strncasecmp(var,"LEN(",4)) {
916                         int len=strlen(var);
917                         int len_len=4;
918                         if (len > (len_len+1) && !strncasecmp(var,"LEN(",len_len) && strchr(var+len_len+2,')')) {
919                                 char cp3[80];
920                                 strncpy(cp3, var, sizeof(cp3) - 1);
921                                 cp3[len-len_len-1]='\0';
922                                 sprintf(workspace,"%d",strlen(cp3));
923                                 *ret = workspace;
924                         } else ast_log(LOG_NOTICE, "Wrong use of LEN(VARIABLE)\n");
925                 }
926         }
927 }
928
929 void pbx_substitute_variables_helper(struct ast_channel *c,const char *cp1,char *cp2,int count)
930 {
931         char *cp4;
932         const char *tmp, *whereweare;
933         int length;
934         char workspace[256];
935         char ltmp[256], var[256];
936         char *nextvar, *nextexp;
937         char *vars, *vare;
938         int pos, brackets, needsub, len;
939
940         /* Substitutes variables into cp2, based on string cp1, and assuming cp2 to be
941            zero-filled */
942         whereweare=tmp=cp1;
943         while(strlen(whereweare) && count) {
944                 /* Assume we're copying the whole remaining string */
945                 pos = strlen(whereweare);
946
947                 /* Look for a variable */
948                 nextvar = strstr(whereweare, "${");
949                 
950                 nextexp = strstr(whereweare, "$[");
951                 
952                 if (nextvar && nextexp) {
953                         if (nextvar < nextexp)
954                                 nextexp = NULL;
955                         else
956                                 nextvar = NULL;
957                 }
958                 
959                 /* If there is one, we only go that far */
960                 if (nextvar)
961                         pos = nextvar - whereweare;
962                 else if (nextexp)
963                         pos = nextexp - whereweare;
964                 
965                 /* Can't copy more than 'count' bytes */
966                 if (pos > count)
967                         pos = count;
968                 
969                 /* Copy that many bytes */
970                 memcpy(cp2, whereweare, pos);
971                 
972                 count -= pos;
973                 cp2 += pos;
974                 whereweare += pos;
975                 
976                 if (nextvar) {
977                         /* We have a variable.  Find the start and end, and determine
978                            if we are going to have to recursively call ourselves on the
979                            contents */
980                         vars = vare = nextvar + 2;
981                         brackets = 1;
982                         needsub = 0;
983                         
984                         /* Find the end of it */
985                         while(brackets && *vare) {
986                                 if ((vare[0] == '$') && (vare[1] == '{')) {
987                                         needsub++;
988                                         brackets++;
989                                 } else if (vare[0] == '}') {
990                                         brackets--;
991                                 } else if ((vare[0] == '$') && (vare[1] == '['))
992                                         needsub++;
993                                 vare++;
994                         }
995                         if (brackets)
996                                 ast_log(LOG_NOTICE, "Error in extension logic (missing '}')\n");
997                         len = vare - vars - 1;
998                         
999                         /* Skip totally over variable name */
1000                         whereweare += ( len + 3);
1001                         
1002                         /* Store variable name (and truncate) */
1003                         memset(var, 0, sizeof(var));
1004                         strncpy(var, vars, sizeof(var) - 1);
1005                         var[len] = '\0';
1006                         
1007                         /* Substitute if necessary */
1008                         if (needsub) {
1009                                 memset(ltmp, 0, sizeof(ltmp));
1010                                 pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1);
1011                                 vars = ltmp;
1012                         } else {
1013                                 vars = var;
1014                         }
1015                         
1016                         /* Retrieve variable value */
1017                         strcpy(workspace, "");
1018                         pbx_substitute_variables_temp(c,vars,&cp4, workspace, sizeof(workspace));
1019                         if (cp4) {
1020                                 length = strlen(cp4);
1021                                 if (length > count)
1022                                         length = count;
1023                                 memcpy(cp2, cp4, length);
1024                                 count -= length;
1025                                 cp2 += length;
1026                         }
1027                         
1028                 } else if (nextexp) {
1029                         /* We have an expression.  Find the start and end, and determine
1030                            if we are going to have to recursively call ourselves on the
1031                            contents */
1032                         vars = vare = nextexp + 2;
1033                         brackets = 1;
1034                         needsub = 0;
1035                         
1036                         /* Find the end of it */
1037                         while(brackets && *vare) {
1038                                 if ((vare[0] == '$') && (vare[1] == '[')) {
1039                                         needsub++;
1040                                         brackets++;
1041                                 } else if (vare[0] == ']') {
1042                                         brackets--;
1043                                 } else if ((vare[0] == '$') && (vare[1] == '{'))
1044                                         needsub++;
1045                                 vare++;
1046                         }
1047                         if (brackets)
1048                                 ast_log(LOG_NOTICE, "Error in extension logic (missing ']')\n");
1049                         len = vare - vars - 1;
1050                         
1051                         /* Skip totally over variable name */
1052                         whereweare += ( len + 3);
1053                         
1054                         /* Store variable name (and truncate) */
1055                         memset(var, 0, sizeof(var));
1056                         strncpy(var, vars, sizeof(var) - 1);
1057                         var[len] = '\0';
1058                         
1059                         /* Substitute if necessary */
1060                         if (needsub) {
1061                                 memset(ltmp, 0, sizeof(ltmp));
1062                                 pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1);
1063                                 vars = ltmp;
1064                         } else {
1065                                 vars = var;
1066                         }
1067
1068                         /* Evaluate expression */                       
1069                         cp4 = ast_expr(vars);
1070                         
1071                         ast_log(LOG_DEBUG, "Expression is '%s'\n", cp4);
1072                         
1073                         if (cp4) {
1074                                 length = strlen(cp4);
1075                                 if (length > count)
1076                                         length = count;
1077                                 memcpy(cp2, cp4, length);
1078                                 count -= length;
1079                                 cp2 += length;
1080                                 free(cp4);
1081                         }
1082                         
1083                 } else
1084                         break;
1085         }
1086 }
1087
1088 static void pbx_substitute_variables(char *passdata, int datalen, struct ast_channel *c, struct ast_exten *e) {
1089         
1090         memset(passdata, 0, datalen);
1091                 
1092         /* No variables or expressions in e->data, so why scan it? */
1093         if (!strstr(e->data,"${") && !strstr(e->data,"$[")) {
1094                 strncpy(passdata, e->data, datalen - 1);
1095                 passdata[datalen-1] = '\0';
1096                 return;
1097         }
1098         
1099         pbx_substitute_variables_helper(c,e->data,passdata, datalen - 1);
1100 }                                                               
1101
1102 static int pbx_extension_helper(struct ast_channel *c, char *context, char *exten, int priority, char *callerid, int action) 
1103 {
1104         struct ast_exten *e;
1105         struct ast_app *app;
1106         struct ast_switch *sw;
1107         char *data;
1108         int newstack = 0;
1109         int res;
1110         int status = 0;
1111         char *incstack[AST_PBX_MAX_STACK];
1112         char passdata[256];
1113         int stacklen = 0;
1114         char tmp[80];
1115         char tmp2[80];
1116         char tmp3[256];
1117         if (ast_mutex_lock(&conlock)) {
1118                 ast_log(LOG_WARNING, "Unable to obtain lock\n");
1119                 if ((action == HELPER_EXISTS) || (action == HELPER_CANMATCH) || (action == HELPER_MATCHMORE))
1120                         return 0;
1121                 else
1122                         return -1;
1123         }
1124         e = pbx_find_extension(c, context, exten, priority, callerid, action, incstack, &stacklen, &status, &sw, &data);
1125         if (e) {
1126                 switch(action) {
1127                 case HELPER_CANMATCH:
1128                         ast_mutex_unlock(&conlock);
1129                         return -1;
1130                 case HELPER_EXISTS:
1131                         ast_mutex_unlock(&conlock);
1132                         return -1;
1133                 case HELPER_MATCHMORE:
1134                         ast_mutex_unlock(&conlock);
1135                         return -1;
1136                 case HELPER_SPAWN:
1137                         newstack++;
1138                         /* Fall through */
1139                 case HELPER_EXEC:
1140                         app = pbx_findapp(e->app);
1141                         ast_mutex_unlock(&conlock);
1142                         if (app) {
1143                                 if (c->context != context)
1144                                         strncpy(c->context, context, sizeof(c->context)-1);
1145                                 if (c->exten != exten)
1146                                         strncpy(c->exten, exten, sizeof(c->exten)-1);
1147                                 c->priority = priority;
1148                                 pbx_substitute_variables(passdata, sizeof(passdata), c, e);
1149                                 if (option_debug)
1150                                                 ast_log(LOG_DEBUG, "Launching '%s'\n", app->name);
1151                                 else if (option_verbose > 2)
1152                                                 ast_verbose( VERBOSE_PREFIX_3 "Executing %s(\"%s\", \"%s\") %s\n", 
1153                                                                 term_color(tmp, app->name, COLOR_BRCYAN, 0, sizeof(tmp)),
1154                                                                 term_color(tmp2, c->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
1155                                                                 term_color(tmp3, (strlen(passdata) ? (char *)passdata : ""), COLOR_BRMAGENTA, 0, sizeof(tmp3)),
1156                                                                 (newstack ? "in new stack" : "in same stack"));
1157                                 res = pbx_exec(c, app, passdata, newstack);
1158                                 return res;
1159                         } else {
1160                                 ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
1161                                 return -1;
1162                         }
1163                 default:
1164                         ast_log(LOG_WARNING, "Huh (%d)?\n", action);                    return -1;
1165                 }
1166         } else if (sw) {
1167                 switch(action) {
1168                 case HELPER_CANMATCH:
1169                         ast_mutex_unlock(&conlock);
1170                         return -1;
1171                 case HELPER_EXISTS:
1172                         ast_mutex_unlock(&conlock);
1173                         return -1;
1174                 case HELPER_MATCHMORE:
1175                         ast_mutex_unlock(&conlock);
1176                         return -1;
1177                 case HELPER_SPAWN:
1178                         newstack++;
1179                         /* Fall through */
1180                 case HELPER_EXEC:
1181                         ast_mutex_unlock(&conlock);
1182                         if (sw->exec)
1183                                 res = sw->exec(c, context, exten, priority, callerid, newstack, data);
1184                         else {
1185                                 ast_log(LOG_WARNING, "No execution engine for switch %s\n", sw->name);
1186                                 res = -1;
1187                         }
1188                         return res;
1189                 default:
1190                         ast_log(LOG_WARNING, "Huh (%d)?\n", action);
1191                         return -1;
1192                 }
1193         } else {
1194                 ast_mutex_unlock(&conlock);
1195                 switch(status) {
1196                 case STATUS_NO_CONTEXT:
1197                         if ((action != HELPER_EXISTS) && (action != HELPER_MATCHMORE))
1198                                 ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", context);
1199                         break;
1200                 case STATUS_NO_EXTENSION:
1201                         if ((action != HELPER_EXISTS) && (action !=  HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1202                                 ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, context);
1203                         break;
1204                 case STATUS_NO_PRIORITY:
1205                         if ((action != HELPER_EXISTS) && (action !=  HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1206                                 ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, context);
1207                         break;
1208                 default:
1209                         ast_log(LOG_DEBUG, "Shouldn't happen!\n");
1210                 }
1211                 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1212                         return -1;
1213                 else
1214                         return 0;
1215         }
1216
1217 }
1218
1219 static struct ast_exten *ast_hint_extension(struct ast_channel *c, char *context, char *exten)
1220 {
1221         struct ast_exten *e;
1222         struct ast_switch *sw;
1223         char *data;
1224         int status = 0;
1225         char *incstack[AST_PBX_MAX_STACK];
1226         int stacklen = 0;
1227
1228         if (ast_mutex_lock(&conlock)) {
1229                 ast_log(LOG_WARNING, "Unable to obtain lock\n");
1230                 return NULL;
1231         }
1232         e = pbx_find_extension(c, context, exten, PRIORITY_HINT, "", HELPER_EXISTS, incstack, &stacklen, &status, &sw, &data);
1233         ast_mutex_unlock(&conlock);     
1234         return e;
1235 }
1236
1237 static int ast_extension_state2(struct ast_exten *e)
1238 {
1239     char hint[AST_MAX_EXTENSION] = "";    
1240     char *cur, *rest;
1241     int res = -1;
1242     int allunavailable = 1, allbusy = 1, allfree = 1;
1243     int busy = 0;
1244
1245     strncpy(hint, ast_get_extension_app(e), sizeof(hint)-1);
1246     
1247     cur = hint;    
1248     do {
1249         rest = strchr(cur, '&');
1250         if (rest) {
1251             *rest = 0;
1252             rest++;
1253         }
1254         
1255         res = ast_device_state(cur);
1256         switch (res) {
1257     case AST_DEVICE_NOT_INUSE:
1258                 allunavailable = 0;
1259                 allbusy = 0;
1260                 break;
1261     case AST_DEVICE_INUSE:
1262                 return AST_EXTENSION_INUSE;
1263     case AST_DEVICE_BUSY:
1264                 allunavailable = 0;
1265                 allfree = 0;
1266                 busy = 1;
1267                 break;
1268     case AST_DEVICE_UNAVAILABLE:
1269     case AST_DEVICE_INVALID:
1270                 allbusy = 0;
1271                 allfree = 0;
1272                 break;
1273     default:
1274                 allunavailable = 0;
1275                 allbusy = 0;
1276                 allfree = 0;
1277         }
1278         cur = rest;
1279     } while (cur);
1280
1281     if (allfree)
1282                 return AST_EXTENSION_NOT_INUSE;
1283     if (allbusy)
1284                 return AST_EXTENSION_BUSY;
1285     if (allunavailable)
1286                 return AST_EXTENSION_UNAVAILABLE;
1287     if (busy) 
1288                 return AST_EXTENSION_INUSE;
1289         
1290     return AST_EXTENSION_NOT_INUSE;
1291 }
1292
1293
1294 int ast_extension_state(struct ast_channel *c, char *context, char *exten)
1295 {
1296     struct ast_exten *e;
1297
1298     e = ast_hint_extension(c, context, exten);    
1299     if (!e) 
1300         return -1;
1301
1302     return ast_extension_state2(e);    
1303 }
1304
1305 int ast_device_state_changed(const char *fmt, ...) 
1306 {
1307     struct ast_hint *list;
1308     struct ast_state_cb *cblist;
1309     char hint[AST_MAX_EXTENSION];
1310     char device[AST_MAX_EXTENSION];
1311     char *cur, *rest;
1312     int state;
1313     
1314     va_list ap;
1315
1316     va_start(ap, fmt);
1317     vsnprintf(device, sizeof(device)-1, fmt, ap);
1318     va_end(ap);
1319
1320     rest = strchr(device, '-');
1321     if (rest) {
1322         *rest = 0;
1323     }
1324         
1325     ast_mutex_lock(&hintlock);
1326
1327     list = hints;
1328     
1329     while (list) {
1330         
1331         strcpy(hint, ast_get_extension_app(list->exten));
1332         cur = hint;
1333         do {
1334             rest = strchr(cur, '&');
1335             if (rest) {
1336                 *rest = 0;
1337                 rest++;
1338             }
1339             
1340             if (!strcmp(cur, device)) {
1341             // Found extension execute callbacks 
1342                 state = ast_extension_state2(list->exten);
1343                 if ((state != -1) && (state != list->laststate)) {
1344                     // For general callbacks
1345                     cblist = statecbs;
1346                     while (cblist) {
1347                         cblist->callback(list->exten->parent->name, list->exten->exten, state, cblist->data);
1348                         cblist = cblist->next;
1349                     }
1350                     
1351                     // For extension callbacks
1352                     cblist = list->callbacks;
1353                     while (cblist) {
1354                         cblist->callback(list->exten->parent->name, list->exten->exten, state, cblist->data);
1355                         cblist = cblist->next;
1356                     }
1357                     
1358                     list->laststate = state;
1359                 }
1360                 break;
1361             }
1362             cur = rest;
1363         } while (cur);
1364         
1365         list = list->next;
1366     }
1367
1368     ast_mutex_unlock(&hintlock);
1369     return 1;
1370 }
1371                         
1372 int ast_extension_state_add(char *context, char *exten, 
1373                             ast_state_cb_type callback, void *data)
1374 {
1375     struct ast_hint *list;
1376     struct ast_state_cb *cblist;
1377     struct ast_exten *e;
1378
1379     /* No context and extension add callback to statecbs list */
1380     if (!context && !exten) {
1381         ast_mutex_lock(&hintlock);
1382
1383         cblist = statecbs;
1384         while (cblist) {
1385             if (cblist->callback == callback) {
1386                 cblist->data = data;
1387                 ast_mutex_unlock(&hintlock);
1388             }
1389             
1390             cblist = cblist->next;
1391         }
1392         
1393         /* Now inserts the callback */
1394         cblist = malloc(sizeof(struct ast_state_cb));
1395         if (!cblist) {
1396             ast_mutex_unlock(&hintlock);
1397             return -1;
1398         }
1399         memset(cblist, 0, sizeof(struct ast_state_cb));
1400         cblist->id = 0;
1401         cblist->callback = callback;
1402         cblist->data = data;
1403
1404         cblist->next = statecbs;
1405         statecbs = cblist;
1406
1407         ast_mutex_unlock(&hintlock);
1408         return 0;
1409     }
1410
1411     if (!context || !exten)
1412         return -1;
1413
1414     /* This callback type is for only one hint */
1415     e = ast_hint_extension(NULL, context, exten);    
1416     if (!e) {
1417         return -1;
1418     }
1419     
1420     ast_mutex_lock(&hintlock);
1421     list = hints;        
1422     
1423     while (list) {
1424         if (list->exten == e)
1425             break;          
1426         list = list->next;    
1427     }
1428
1429     if (!list) {
1430         ast_mutex_unlock(&hintlock);
1431         return -1;
1432     }
1433
1434     /* Now inserts the callback */
1435     cblist = malloc(sizeof(struct ast_state_cb));
1436     if (!cblist) {
1437         ast_mutex_unlock(&hintlock);
1438         return -1;
1439     }
1440     memset(cblist, 0, sizeof(struct ast_state_cb));
1441     cblist->id = stateid++;
1442     cblist->callback = callback;
1443     cblist->data = data;
1444
1445     cblist->next = list->callbacks;
1446     list->callbacks = cblist;
1447
1448     ast_mutex_unlock(&hintlock);
1449     return cblist->id;
1450 }
1451
1452 int ast_extension_state_del(int id, ast_state_cb_type callback)
1453 {
1454     struct ast_hint *list;
1455     struct ast_state_cb *cblist, *cbprev;
1456     
1457     if (!id && !callback)
1458         return -1;
1459             
1460     ast_mutex_lock(&hintlock);
1461
1462     /* id is zero is a callback without extension */
1463     if (!id) {
1464         cbprev = NULL;
1465         cblist = statecbs;
1466         while (cblist) {
1467             if (cblist->callback == callback) {
1468                 if (!cbprev)
1469                     statecbs = cblist->next;
1470                 else
1471                     cbprev->next = cblist->next;
1472
1473                 free(cblist);
1474
1475                 ast_mutex_unlock(&hintlock);
1476                 return 0;
1477             }
1478             cbprev = cblist;
1479             cblist = cblist->next;
1480         }
1481
1482         ast_mutex_lock(&hintlock);
1483         return -1;
1484     }
1485
1486     /* id greater zero is a callback with extension */
1487     list = hints;
1488     while (list) {
1489         cblist = list->callbacks;
1490         cbprev = NULL;
1491         while (cblist) {
1492             if (cblist->id==id) {
1493                 if (!cbprev)
1494                     list->callbacks = cblist->next;             
1495                 else
1496                     cbprev->next = cblist->next;
1497                 
1498                 free(cblist);
1499                 
1500                 ast_mutex_unlock(&hintlock);
1501                 return 0;               
1502             }           
1503             cbprev = cblist;                            
1504             cblist = cblist->next;
1505         }
1506         list = list->next;
1507     }
1508     
1509     ast_mutex_unlock(&hintlock);
1510     return -1;
1511 }
1512
1513 static int ast_add_hint(struct ast_exten *e)
1514 {
1515     struct ast_hint *list;
1516
1517     if (!e) return -1;
1518     
1519     ast_mutex_lock(&hintlock);
1520     list = hints;        
1521     
1522     /* Search if hint exists, do nothing */
1523     while (list) {
1524         if (list->exten == e) {
1525             ast_mutex_unlock(&hintlock);
1526             return -1;
1527         }
1528         list = list->next;    
1529     }
1530
1531     list = malloc(sizeof(struct ast_hint));
1532     if (!list) {
1533         ast_mutex_unlock(&hintlock);
1534         return -1;
1535     }
1536     /* Initialize and insert new item */
1537     memset(list, 0, sizeof(struct ast_hint));
1538     list->exten = e;
1539     list->laststate = ast_extension_state2(e);
1540     list->next = hints;
1541     hints = list;
1542
1543     ast_mutex_unlock(&hintlock);
1544     return 0;
1545 }
1546
1547 static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
1548
1549     struct ast_hint *list;
1550
1551     ast_mutex_lock(&hintlock);
1552     
1553     list = hints;
1554     
1555     while(list) {
1556         if (list->exten == oe) {
1557             list->exten = ne;
1558             ast_mutex_unlock(&hintlock);        
1559             return 0;
1560         }
1561         list = list->next;
1562     }
1563     ast_mutex_unlock(&hintlock);
1564
1565     return -1;
1566 }
1567
1568 static int ast_remove_hint(struct ast_exten *e)
1569 {
1570     /* Cleanup the Notifys if hint is removed */
1571     struct ast_hint *list, *prev = NULL;
1572     struct ast_state_cb *cblist, *cbprev;
1573
1574     if (!e) 
1575         return -1;
1576
1577     ast_mutex_lock(&hintlock);
1578
1579     list = hints;    
1580     while(list) {
1581         if (list->exten==e) {
1582             cbprev = NULL;
1583             cblist = list->callbacks;
1584             while (cblist) {
1585                 /* Notify with -1 and remove all callbacks */
1586                 cbprev = cblist;            
1587                 cblist = cblist->next;
1588                 cbprev->callback(list->exten->parent->name, list->exten->exten, -1, cbprev->data);
1589                 free(cbprev);
1590             }
1591             list->callbacks = NULL;
1592
1593             if (!prev)
1594                 hints = list->next;
1595             else
1596                 prev->next = list->next;
1597
1598             free(list);
1599             
1600             ast_mutex_unlock(&hintlock);
1601             return 0;
1602         } else {
1603             prev = list;
1604             list = list->next;    
1605         }
1606     }
1607
1608     ast_mutex_unlock(&hintlock);
1609     return -1;
1610 }
1611
1612
1613 int ast_get_hint(char *hint, int maxlen, struct ast_channel *c, char *context, char *exten)
1614 {
1615         struct ast_exten *e;
1616         e = ast_hint_extension(c, context, exten);
1617         if (e) {        
1618             strncpy(hint, ast_get_extension_app(e), maxlen);
1619             return -1;
1620         }
1621         return 0;       
1622 }
1623
1624 int ast_exists_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid) 
1625 {
1626         return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_EXISTS);
1627 }
1628
1629 int ast_canmatch_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid)
1630 {
1631         return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_CANMATCH);
1632 }
1633
1634 int ast_matchmore_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid)
1635 {
1636         return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_MATCHMORE);
1637 }
1638
1639 int ast_spawn_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid) 
1640 {
1641         return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_SPAWN);
1642 }
1643
1644 int ast_pbx_run(struct ast_channel *c)
1645 {
1646         int firstpass = 1;
1647         char digit;
1648         char exten[256];
1649         int pos;
1650         int waittime;
1651         int res=0;
1652
1653         /* A little initial setup here */
1654         if (c->pbx)
1655                 ast_log(LOG_WARNING, "%s already has PBX structure??\n", c->name);
1656         c->pbx = malloc(sizeof(struct ast_pbx));
1657         if (!c->pbx) {
1658                 ast_log(LOG_WARNING, "Out of memory\n");
1659                 return -1;
1660         }
1661         if (c->amaflags) {
1662                 if (c->cdr) {
1663                         ast_log(LOG_WARNING, "%s already has a call record??\n", c->name);
1664                 } else {
1665                         c->cdr = ast_cdr_alloc();
1666                         if (!c->cdr) {
1667                                 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
1668                                 free(c->pbx);
1669                                 return -1;
1670                         }
1671                         ast_cdr_init(c->cdr, c);
1672                 }
1673         }
1674         memset(c->pbx, 0, sizeof(struct ast_pbx));
1675         /* Set reasonable defaults */
1676         c->pbx->rtimeout = 10;
1677         c->pbx->dtimeout = 5;
1678
1679         /* Start by trying whatever the channel is set to */
1680         if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
1681                 /* JK02: If not successfull fall back to 's' */
1682                 strncpy(c->exten, "s", sizeof(c->exten)-1);
1683                 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
1684                         /* JK02: And finally back to default if everything else failed */
1685                         strncpy(c->context, "default", sizeof(c->context)-1);
1686                 }
1687                 c->priority = 1;
1688         }
1689         if (c->cdr)
1690                 ast_cdr_start(c->cdr);
1691         for(;;) {
1692                 pos = 0;
1693                 digit = 0;
1694                 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
1695                         memset(exten, 0, sizeof(exten));
1696                         manager_event(EVENT_FLAG_CALL, "Newexten", 
1697                                 "Channel: %s\r\n"
1698                                 "Context: %s\r\n"
1699                                 "Extension: %s\r\n"
1700                                 "Priority: %d\r\n"
1701                                 "Uniqueid: %s\r\n",
1702                                 c->name, c->context, c->exten, c->priority, c->uniqueid);
1703                         if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->callerid))) {
1704                                 /* Something bad happened, or a hangup has been requested. */
1705                                 if (((res >= '0') && (res <= '9')) || ((res >= 'A') && (res <= 'F')) ||
1706                                         (res == '*') || (res == '#')) {
1707                                         ast_log(LOG_DEBUG, "Oooh, got something to jump out with ('%c')!\n", res);
1708                                         memset(exten, 0, sizeof(exten));
1709                                         pos = 0;
1710                                         exten[pos++] = digit = res;
1711                                         break;
1712                                 }
1713                                 switch(res) {
1714                                 case AST_PBX_KEEPALIVE:
1715                                         if (option_debug)
1716                                                 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
1717                                         else if (option_verbose > 1)
1718                                                 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
1719                                         goto out;
1720                                         break;
1721                                 default:
1722                                         if (option_debug)
1723                                                 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
1724                                         else if (option_verbose > 1)
1725                                                 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
1726                                         if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
1727                                                 c->_softhangup =0;
1728                                                 break;
1729                                         }
1730                                         /* atimeout */
1731                                         if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
1732                                                 break;
1733                                         }
1734                                         goto out;
1735                                 }
1736                         }
1737                         if ((c->_softhangup == AST_SOFTHANGUP_TIMEOUT) && (ast_exists_extension(c,c->context,"T",1,c->callerid))) {
1738                                 strncpy(c->exten,"T",sizeof(c->exten) - 1);
1739                                 /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
1740                                 c->whentohangup = 0;
1741                                 c->priority = 0;
1742                                 c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
1743                         } else if (c->_softhangup) {
1744                                 ast_log(LOG_DEBUG, "Extension %s, priority %d returned normally even though call was hung up\n",
1745                                         c->exten, c->priority);
1746                                 goto out;
1747                         }
1748                         firstpass = 0;
1749                         c->priority++;
1750                 }
1751                 if (!ast_exists_extension(c, c->context, c->exten, 1, c->callerid)) {
1752                         /* It's not a valid extension anymore */
1753                         if (ast_exists_extension(c, c->context, "i", 1, c->callerid)) {
1754                                 if (option_verbose > 2)
1755                                         ast_verbose(VERBOSE_PREFIX_3 "Sent into invalid extension '%s' in context '%s' on %s\n", c->exten, c->context, c->name);
1756                                 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", c->exten);
1757                                 strncpy(c->exten, "i", sizeof(c->exten)-1);
1758                                 c->priority = 1;
1759                         } else {
1760                                 ast_log(LOG_WARNING, "Channel '%s' sent into invalid extension '%s' in context '%s', but no invalid handler\n",
1761                                         c->name, c->exten, c->context);
1762                                 goto out;
1763                         }
1764                 } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
1765                         /* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */
1766                         c->_softhangup = 0;
1767                 } else {
1768                         /* Done, wait for an extension */
1769                         if (digit)
1770                                 waittime = c->pbx->dtimeout;
1771                         else
1772                                 waittime = c->pbx->rtimeout;
1773                         while (ast_matchmore_extension(c, c->context, exten, 1, c->callerid)) {
1774                                 /* As long as we're willing to wait, and as long as it's not defined, 
1775                                    keep reading digits until we can't possibly get a right answer anymore.  */
1776                                 digit = ast_waitfordigit(c, waittime * 1000);
1777                                 if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
1778                                         c->_softhangup = 0;
1779                                 } else {
1780                                         if (!digit)
1781                                                 /* No entry */
1782                                                 break;
1783                                         if (digit < 0)
1784                                                 /* Error, maybe a  hangup */
1785                                                 goto out;
1786                                         exten[pos++] = digit;
1787                                         waittime = c->pbx->dtimeout;
1788                                 }
1789                         }
1790                         if (ast_exists_extension(c, c->context, exten, 1, c->callerid)) {
1791                                 /* Prepare the next cycle */
1792                                 strncpy(c->exten, exten, sizeof(c->exten)-1);
1793                                 c->priority = 1;
1794                         } else {
1795                                 /* No such extension */
1796                                 if (strlen(exten)) {
1797                                         /* An invalid extension */
1798                                         if (ast_exists_extension(c, c->context, "i", 1, c->callerid)) {
1799                                                 if (option_verbose > 2)
1800                                                         ast_verbose( VERBOSE_PREFIX_3 "Invalid extension '%s' in context '%s' on %s\n", exten, c->context, c->name);
1801                                                 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", exten);
1802                                                 strncpy(c->exten, "i", sizeof(c->exten)-1);
1803                                                 c->priority = 1;
1804                                         } else {
1805                                                 ast_log(LOG_WARNING, "Invalid extension, but no rule 'i' in context '%s'\n", c->context);
1806                                                 goto out;
1807                                         }
1808                                 } else {
1809                                         /* A simple timeout */
1810                                         if (ast_exists_extension(c, c->context, "t", 1, c->callerid)) {
1811                                                 if (option_verbose > 2)
1812                                                         ast_verbose( VERBOSE_PREFIX_3 "Timeout on %s\n", c->name);
1813                                                 strncpy(c->exten, "t", sizeof(c->exten)-1);
1814                                                 c->priority = 1;
1815                                         } else {
1816                                                 ast_log(LOG_WARNING, "Timeout, but no rule 't' in context '%s'\n", c->context);
1817                                                 goto out;
1818                                         }
1819                                 }       
1820                         }
1821                         if (c->cdr) {
1822                             if (option_verbose > 2)
1823                                 ast_verbose(VERBOSE_PREFIX_2 "CDR updated on %s\n",c->name);    
1824                             ast_cdr_update(c);
1825                     }
1826                 }
1827         }
1828         if (firstpass) 
1829                 ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", c->name);
1830 out:
1831         if ((res != AST_PBX_KEEPALIVE) && ast_exists_extension(c, c->context, "h", 1, c->callerid)) {
1832                 strcpy(c->exten, "h");
1833                 c->priority = 1;
1834                 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
1835                         if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->callerid))) {
1836                                 /* Something bad happened, or a hangup has been requested. */
1837                                 if (option_debug)
1838                                         ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
1839                                 else if (option_verbose > 1)
1840                                         ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
1841                                 break;
1842                         }
1843                         c->priority++;
1844                 }
1845         }
1846
1847         pbx_destroy(c->pbx);
1848         c->pbx = NULL;
1849         if (res != AST_PBX_KEEPALIVE)
1850                 ast_hangup(c);
1851         return 0;
1852 }
1853
1854 static void *pbx_thread(void *data)
1855 {
1856         /* Oh joyeous kernel, we're a new thread, with nothing to do but
1857            answer this channel and get it going.  The setjmp stuff is fairly
1858            confusing, but necessary to get smooth transitions between
1859            the execution of different applications (without the use of
1860            additional threads) */
1861         struct ast_channel *c = data;
1862         ast_pbx_run(c);
1863         pthread_exit(NULL);
1864         return NULL;
1865 }
1866
1867 int ast_pbx_start(struct ast_channel *c)
1868 {
1869         pthread_t t;
1870         pthread_attr_t attr;
1871         if (!c) {
1872                 ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
1873                 return -1;
1874         }
1875            
1876         /* Start a new thread, and get something handling this channel. */
1877         pthread_attr_init(&attr);
1878         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1879         if (pthread_create(&t, &attr, pbx_thread, c)) {
1880                 ast_log(LOG_WARNING, "Failed to create new channel thread\n");
1881                 return -1;
1882         }
1883         return 0;
1884 }
1885
1886 /*
1887  * This function locks contexts list by &conlist, search for the rigt context
1888  * structure, leave context list locked and call ast_context_remove_include2
1889  * which removes include, unlock contexts list and return ...
1890  */
1891 int ast_context_remove_include(char *context, char *include, char *registrar)
1892 {
1893         struct ast_context *c;
1894
1895         if (ast_lock_contexts()) return -1;
1896
1897         /* walk contexts and search for the right one ...*/
1898         c = ast_walk_contexts(NULL);
1899         while (c) {
1900                 /* we found one ... */
1901                 if (!strcmp(ast_get_context_name(c), context)) {
1902                         int ret;
1903                         /* remove include from this context ... */      
1904                         ret = ast_context_remove_include2(c, include, registrar);
1905
1906                         ast_unlock_contexts();
1907
1908                         /* ... return results */
1909                         return ret;
1910                 }
1911                 c = ast_walk_contexts(c);
1912         }
1913
1914         /* we can't find the right one context */
1915         ast_unlock_contexts();
1916         return -1;
1917 }
1918
1919 /*
1920  * When we call this function, &conlock lock must be locked, because when
1921  * we giving *con argument, some process can remove/change this context
1922  * and after that there can be segfault.
1923  *
1924  * This function locks given context, removes include, unlock context and
1925  * return.
1926  */
1927 int ast_context_remove_include2(struct ast_context *con, char *include, char *registrar)
1928 {
1929         struct ast_include *i, *pi = NULL;
1930
1931         if (ast_mutex_lock(&con->lock)) return -1;
1932
1933         /* walk includes */
1934         i = con->includes;
1935         while (i) {
1936                 /* find our include */
1937                 if (!strcmp(i->name, include) && 
1938                         (!strcmp(i->registrar, registrar) || !registrar)) {
1939                         /* remove from list */
1940                         if (pi)
1941                                 pi->next = i->next;
1942                         else
1943                                 con->includes = i->next;
1944                         /* free include and return */
1945                         free(i);
1946                         ast_mutex_unlock(&con->lock);
1947                         return 0;
1948                 }
1949                 pi = i;
1950                 i = i->next;
1951         }
1952
1953         /* we can't find the right include */
1954         ast_mutex_unlock(&con->lock);
1955         return -1;
1956 }
1957
1958 /*
1959  * This function locks contexts list by &conlist, search for the rigt context
1960  * structure, leave context list locked and call ast_context_remove_switch2
1961  * which removes switch, unlock contexts list and return ...
1962  */
1963 int ast_context_remove_switch(char *context, char *sw, char *data, char *registrar)
1964 {
1965         struct ast_context *c;
1966
1967         if (ast_lock_contexts()) return -1;
1968
1969         /* walk contexts and search for the right one ...*/
1970         c = ast_walk_contexts(NULL);
1971         while (c) {
1972                 /* we found one ... */
1973                 if (!strcmp(ast_get_context_name(c), context)) {
1974                         int ret;
1975                         /* remove switch from this context ... */       
1976                         ret = ast_context_remove_switch2(c, sw, data, registrar);
1977
1978                         ast_unlock_contexts();
1979
1980                         /* ... return results */
1981                         return ret;
1982                 }
1983                 c = ast_walk_contexts(c);
1984         }
1985
1986         /* we can't find the right one context */
1987         ast_unlock_contexts();
1988         return -1;
1989 }
1990
1991 /*
1992  * When we call this function, &conlock lock must be locked, because when
1993  * we giving *con argument, some process can remove/change this context
1994  * and after that there can be segfault.
1995  *
1996  * This function locks given context, removes switch, unlock context and
1997  * return.
1998  */
1999 int ast_context_remove_switch2(struct ast_context *con, char *sw, char *data, char *registrar)
2000 {
2001         struct ast_sw *i, *pi = NULL;
2002
2003         if (ast_mutex_lock(&con->lock)) return -1;
2004
2005         /* walk switchs */
2006         i = con->alts;
2007         while (i) {
2008                 /* find our switch */
2009                 if (!strcmp(i->name, sw) && !strcmp(i->data, data) && 
2010                         (!strcmp(i->registrar, registrar) || !registrar)) {
2011                         /* remove from list */
2012                         if (pi)
2013                                 pi->next = i->next;
2014                         else
2015                                 con->alts = i->next;
2016                         /* free switch and return */
2017                         free(i);
2018                         ast_mutex_unlock(&con->lock);
2019                         return 0;
2020                 }
2021                 pi = i;
2022                 i = i->next;
2023         }
2024
2025         /* we can't find the right switch */
2026         ast_mutex_unlock(&con->lock);
2027         return -1;
2028 }
2029
2030 /*
2031  * This functions lock contexts list, search for the right context,
2032  * call ast_context_remove_extension2, unlock contexts list and return.
2033  * In this function we are using
2034  */
2035 int ast_context_remove_extension(char *context, char *extension, int priority, char *registrar)
2036 {
2037         struct ast_context *c;
2038
2039         if (ast_lock_contexts()) return -1;
2040
2041         /* walk contexts ... */
2042         c = ast_walk_contexts(NULL);
2043         while (c) {
2044                 /* ... search for the right one ... */
2045                 if (!strcmp(ast_get_context_name(c), context)) {
2046                         /* ... remove extension ... */
2047                         int ret = ast_context_remove_extension2(c, extension, priority,
2048                                 registrar);
2049                         /* ... unlock contexts list and return */
2050                         ast_unlock_contexts();
2051                         return ret;
2052                 }
2053                 c = ast_walk_contexts(c);
2054         }
2055
2056         /* we can't find the right context */
2057         ast_unlock_contexts();
2058         return -1;
2059 }
2060
2061 /*
2062  * When do you want to call this function, make sure that &conlock is locked,
2063  * because some process can handle with your *con context before you lock
2064  * it.
2065  *
2066  * This functionc locks given context, search for the right extension and
2067  * fires out all peer in this extensions with given priority. If priority
2068  * is set to 0, all peers are removed. After that, unlock context and
2069  * return.
2070  */
2071 int ast_context_remove_extension2(struct ast_context *con, char *extension, int priority, char *registrar)
2072 {
2073         struct ast_exten *exten, *prev_exten = NULL;
2074
2075         if (ast_mutex_lock(&con->lock)) return -1;
2076
2077         /* go through all extensions in context and search the right one ... */
2078         exten = con->root;
2079         while (exten) {
2080
2081                 /* look for right extension */
2082                 if (!strcmp(exten->exten, extension) &&
2083                         (!strcmp(exten->registrar, registrar) || !registrar)) {
2084                         struct ast_exten *peer;
2085
2086                         /* should we free all peers in this extension? (priority == 0)? */
2087                         if (priority == 0) {
2088                                 /* remove this extension from context list */
2089                                 if (prev_exten)
2090                                         prev_exten->next = exten->next;
2091                                 else
2092                                         con->root = exten->next;
2093
2094                                 /* fire out all peers */
2095                                 peer = exten; 
2096                                 while (peer) {
2097                                         exten = peer->peer;
2098                                         
2099                                         if (!peer->priority==PRIORITY_HINT) 
2100                                             ast_remove_hint(peer);
2101
2102                                         peer->datad(peer->data);
2103                                         free(peer);
2104
2105                                         peer = exten;
2106                                 }
2107
2108                                 ast_mutex_unlock(&con->lock);
2109                                 return 0;
2110                         } else {
2111                                 /* remove only extension with exten->priority == priority */
2112                                 struct ast_exten *previous_peer = NULL;
2113
2114                                 peer = exten;
2115                                 while (peer) {
2116                                         /* is this our extension? */
2117                                         if (peer->priority == priority &&
2118                                                 (!strcmp(peer->registrar, registrar) || !registrar)) {
2119                                                 /* we are first priority extension? */
2120                                                 if (!previous_peer) {
2121                                                         /* exists previous extension here? */
2122                                                         if (prev_exten) {
2123                                                                 /* yes, so we must change next pointer in
2124                                                                  * previous connection to next peer
2125                                                                  */
2126                                                                 if (peer->peer) {
2127                                                                         prev_exten->next = peer->peer;
2128                                                                         peer->peer->next = exten->next;
2129                                                                 } else
2130                                                                         prev_exten->next = exten->next;
2131                                                         } else {
2132                                                                 /* no previous extension, we are first
2133                                                                  * extension, so change con->root ...
2134                                                                  */
2135                                                                 if (peer->peer)
2136                                                                         con->root = peer->peer;
2137                                                                 else
2138                                                                         con->root = exten->next; 
2139                                                         }
2140                                                 } else {
2141                                                         /* we are not first priority in extension */
2142                                                         previous_peer->peer = peer->peer;
2143                                                 }
2144
2145                                                 /* now, free whole priority extension */
2146                                                 if (peer->priority==PRIORITY_HINT)
2147                                                     ast_remove_hint(peer);
2148                                                 peer->datad(peer->data);
2149                                                 free(peer);
2150
2151                                                 ast_mutex_unlock(&con->lock);
2152                                                 return 0;
2153                                         } else {
2154                                                 /* this is not right extension, skip to next peer */
2155                                                 previous_peer = peer;
2156                                                 peer = peer->peer;
2157                                         }
2158                                 }
2159
2160                                 ast_mutex_unlock(&con->lock);
2161                                 return -1;
2162                         }
2163                 }
2164
2165                 prev_exten = exten;
2166                 exten = exten->next;
2167         }
2168
2169         /* we can't find right extension */
2170         ast_mutex_unlock(&con->lock);
2171         return -1;
2172 }
2173
2174
2175 int ast_register_application(char *app, int (*execute)(struct ast_channel *, void *), char *synopsis, char *description)
2176 {
2177         struct ast_app *tmp, *prev, *cur;
2178         char tmps[80];
2179         if (ast_mutex_lock(&applock)) {
2180                 ast_log(LOG_ERROR, "Unable to lock application list\n");
2181                 return -1;
2182         }
2183         tmp = apps;
2184         while(tmp) {
2185                 if (!strcasecmp(app, tmp->name)) {
2186                         ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
2187                         ast_mutex_unlock(&applock);
2188                         return -1;
2189                 }
2190                 tmp = tmp->next;
2191         }
2192         tmp = malloc(sizeof(struct ast_app));
2193         if (tmp) {
2194                 memset(tmp, 0, sizeof(struct ast_app));
2195                 strncpy(tmp->name, app, sizeof(tmp->name)-1);
2196                 tmp->execute = execute;
2197                 tmp->synopsis = synopsis;
2198                 tmp->description = description;
2199                 /* Store in alphabetical order */
2200                 cur = apps;
2201                 prev = NULL;
2202                 while(cur) {
2203                         if (strcasecmp(tmp->name, cur->name) < 0)
2204                                 break;
2205                         prev = cur;
2206                         cur = cur->next;
2207                 }
2208                 if (prev) {
2209                         tmp->next = prev->next;
2210                         prev->next = tmp;
2211                 } else {
2212                         tmp->next = apps;
2213                         apps = tmp;
2214                 }
2215         } else {
2216                 ast_log(LOG_WARNING, "Out of memory\n");
2217                 ast_mutex_unlock(&applock);
2218                 return -1;
2219         }
2220         if (option_verbose > 1)
2221                 ast_verbose( VERBOSE_PREFIX_2 "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
2222         ast_mutex_unlock(&applock);
2223         return 0;
2224 }
2225
2226 int ast_register_switch(struct ast_switch *sw)
2227 {
2228         struct ast_switch *tmp, *prev=NULL;
2229         if (ast_mutex_lock(&switchlock)) {
2230                 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
2231                 return -1;
2232         }
2233         tmp = switches;
2234         while(tmp) {
2235                 if (!strcasecmp(tmp->name, sw->name))
2236                         break;
2237                 prev = tmp;
2238                 tmp = tmp->next;
2239         }
2240         if (tmp) {      
2241                 ast_mutex_unlock(&switchlock);
2242                 ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name);
2243                 return -1;
2244         }
2245         sw->next = NULL;
2246         if (prev) 
2247                 prev->next = sw;
2248         else
2249                 switches = sw;
2250         ast_mutex_unlock(&switchlock);
2251         return 0;
2252 }
2253
2254 void ast_unregister_switch(struct ast_switch *sw)
2255 {
2256         struct ast_switch *tmp, *prev=NULL;
2257         if (ast_mutex_lock(&switchlock)) {
2258                 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
2259                 return;
2260         }
2261         tmp = switches;
2262         while(tmp) {
2263                 if (tmp == sw) {
2264                         if (prev)
2265                                 prev->next = tmp->next;
2266                         else
2267                                 switches = tmp->next;
2268                         tmp->next = NULL;
2269                         break;                  
2270                 }
2271                 prev = tmp;
2272                 tmp = tmp->next;
2273         }
2274         ast_mutex_unlock(&switchlock);
2275 }
2276
2277 /*
2278  * Help for CLI commands ...
2279  */
2280 static char show_application_help[] = 
2281 "Usage: show application <application> [<application> [<application> [...]]]\n"
2282 "       Describes a particular application.\n";
2283
2284 static char show_applications_help[] =
2285 "Usage: show applications\n"
2286 "       List applications which are currently available.\n";
2287
2288 static char show_dialplan_help[] =
2289 "Usage: show dialplan [exten@][context]\n"
2290 "       Show dialplan\n";
2291
2292 static char show_switches_help[] = 
2293 "Usage: show switches\n"
2294 "       Show registered switches\n";
2295
2296 /*
2297  * IMPLEMENTATION OF CLI FUNCTIONS IS IN THE SAME ORDER AS COMMANDS HELPS
2298  *
2299  */
2300
2301 /*
2302  * 'show application' CLI command implementation functions ...
2303  */
2304
2305 /*
2306  * There is a possibility to show informations about more than one
2307  * application at one time. You can type 'show application Dial Echo' and
2308  * you will see informations about these two applications ...
2309  */
2310 static char *complete_show_application(char *line, char *word,
2311         int pos, int state)
2312 {
2313         struct ast_app *a;
2314         int which = 0;
2315
2316         /* try to lock applications list ... */
2317         if (ast_mutex_lock(&applock)) {
2318                 ast_log(LOG_ERROR, "Unable to lock application list\n");
2319                 return NULL;
2320         }
2321
2322         /* ... walk all applications ... */
2323         a = apps; 
2324         while (a) {
2325                 /* ... check if word matches this application ... */
2326                 if (!strncasecmp(word, a->name, strlen(word))) {
2327                         /* ... if this is right app serve it ... */
2328                         if (++which > state) {
2329                                 char *ret = strdup(a->name);
2330                                 ast_mutex_unlock(&applock);
2331                                 return ret;
2332                         }
2333                 }
2334                 a = a->next; 
2335         }
2336
2337         /* no application match */
2338         ast_mutex_unlock(&applock);
2339         return NULL; 
2340 }
2341
2342 static int handle_show_application(int fd, int argc, char *argv[])
2343 {
2344         struct ast_app *a;
2345         int n, app, no_registered_app = 1;
2346         char *buf;
2347
2348         if (argc < 3) return RESULT_SHOWUSAGE;
2349
2350         /* try to lock applications list ... */
2351         if (ast_mutex_lock(&applock)) {
2352                 ast_log(LOG_ERROR, "Unable to lock application list\n");
2353                 return -1;
2354         }
2355
2356         /* ... go through all applications ... */
2357         a = apps; 
2358         while (a) {
2359                 /* ... compare this application name with all arguments given
2360                  * to 'show application' command ... */
2361                 for (app = 2; app < argc; app++) {
2362                         if (!strcasecmp(a->name, argv[app])) {
2363                                 no_registered_app = 0;
2364
2365                                 /* ... one of our applications, show info ...*/
2366                                 n = asprintf(&buf,
2367                                         "\n  -= Info about application '%s' =- \n\n"
2368                                         "[Synopsis]:\n  %s\n\n"
2369                                         "[Description]:\n%s\n",
2370                                         a->name,
2371                                         a->synopsis ? a->synopsis : "Not available",
2372                                         a->description ? a-> description : "Not available");
2373                                 if (n >= 0) {
2374                                         ast_cli(fd, buf);
2375                                         free(buf);
2376                                 }
2377                         }
2378                 }
2379                 a = a->next; 
2380         }
2381
2382         ast_mutex_unlock(&applock);
2383
2384         /* we found at least one app? no? */
2385         if (no_registered_app) {
2386                 ast_cli(fd, "Your application(s) is (are) not registered\n");
2387                 return RESULT_FAILURE;
2388         }
2389
2390         return RESULT_SUCCESS;
2391 }
2392
2393 static int handle_show_switches(int fd, int argc, char *argv[])
2394 {
2395         struct ast_switch *sw;
2396         if (!switches) {
2397                 ast_cli(fd, "There are no registered alternative switches\n");
2398                 return RESULT_SUCCESS;
2399         }
2400         /* ... we have applications ... */
2401         ast_cli(fd, "\n    -= Registered Asterisk Alternative Switches =-\n");
2402         if (ast_mutex_lock(&switchlock)) {
2403                 ast_log(LOG_ERROR, "Unable to lock switches\n");
2404                 return -1;
2405         }
2406         sw = switches;
2407         while (sw) {
2408                 ast_cli(fd, "%s: %s\n", sw->name, sw->description);
2409                 sw = sw->next;
2410         }
2411         ast_mutex_unlock(&switchlock);
2412         return RESULT_SUCCESS;
2413 }
2414
2415 /*
2416  * 'show applications' CLI command implementation functions ...
2417  */
2418 static int handle_show_applications(int fd, int argc, char *argv[])
2419 {
2420         struct ast_app *a;
2421
2422         /* try to lock applications list ... */
2423         if (ast_mutex_lock(&applock)) {
2424                 ast_log(LOG_ERROR, "Unable to lock application list\n");
2425                 return -1;
2426         }
2427
2428         /* ... go to first application ... */
2429         a = apps; 
2430
2431         /* ... have we got at least one application (first)? no? */
2432         if (!a) {
2433                 ast_cli(fd, "There is no registered applications\n");
2434                 ast_mutex_unlock(&applock);
2435                 return -1;
2436         }
2437
2438         /* ... we have applications ... */
2439         ast_cli(fd, "\n    -= Registered Asterisk Applications =-\n");
2440
2441         /* ... go through all applications ... */
2442         while (a) {
2443                 /* ... show informations about applications ... */
2444                 ast_cli(fd,"  %15s: %s\n",
2445                         a->name,
2446                         a->synopsis ? a->synopsis : "<Synopsis not available>");
2447                 a = a->next; 
2448         }
2449
2450         /* ... unlock and return */
2451         ast_mutex_unlock(&applock);
2452
2453         return RESULT_SUCCESS;
2454 }
2455
2456 /*
2457  * 'show dialplan' CLI command implementation functions ...
2458  */
2459 static char *complete_show_dialplan_context(char *line, char *word, int pos,
2460         int state)
2461 {
2462         struct ast_context *c;
2463         int which = 0;
2464
2465         /* we are do completion of [exten@]context on second position only */
2466         if (pos != 2) return NULL;
2467
2468         /* try to lock contexts list ... */
2469         if (ast_lock_contexts()) {
2470                 ast_log(LOG_ERROR, "Unable to lock context list\n");
2471                 return NULL;
2472         }
2473
2474         /* ... walk through all contexts ... */
2475         c = ast_walk_contexts(NULL);
2476         while(c) {
2477                 /* ... word matches context name? yes? ... */
2478                 if (!strncasecmp(word, ast_get_context_name(c), strlen(word))) {
2479                         /* ... for serve? ... */
2480                         if (++which > state) {
2481                                 /* ... yes, serve this context name ... */
2482                                 char *ret = strdup(ast_get_context_name(c));
2483                                 ast_unlock_contexts();
2484                                 return ret;
2485                         }
2486                 }
2487                 c = ast_walk_contexts(c);
2488         }
2489
2490         /* ... unlock and return */
2491         ast_unlock_contexts();
2492         return NULL;
2493 }
2494
2495 static int handle_show_dialplan(int fd, int argc, char *argv[])
2496 {
2497         struct ast_context *c;
2498         char *exten = NULL, *context = NULL;
2499         int context_existence = 0, extension_existence = 0;
2500
2501         if (argc != 3 && argc != 2) return -1;
2502
2503         /* we obtain [exten@]context? if yes, split them ... */
2504         if (argc == 3) {
2505                 char *splitter = argv[2];
2506                 /* is there a '@' character? */
2507                 if (strchr(argv[2], '@')) {
2508                         /* yes, split into exten & context ... */
2509                         exten   = strsep(&splitter, "@");
2510                         context = splitter;
2511
2512                         /* check for length and change to NULL if !strlen() */
2513                         if (!strlen(exten))   exten = NULL;
2514                         if (!strlen(context)) context = NULL;
2515                 } else
2516                 {
2517                         /* no '@' char, only context given */
2518                         context = argv[2];
2519                         if (!strlen(context)) context = NULL;
2520                 }
2521         }
2522
2523         /* try to lock contexts */
2524         if (ast_lock_contexts()) {
2525                 ast_log(LOG_WARNING, "Failed to lock contexts list\n");
2526                 return RESULT_FAILURE;
2527         }
2528
2529         /* walk all contexts ... */
2530         c = ast_walk_contexts(NULL);
2531         while (c) {
2532                 /* show this context? */
2533                 if (!context ||
2534                         !strcmp(ast_get_context_name(c), context)) {
2535                         context_existence = 1;
2536
2537                         /* try to lock context before walking in ... */
2538                         if (!ast_lock_context(c)) {
2539                                 struct ast_exten *e;
2540                                 struct ast_include *i;
2541                                 struct ast_ignorepat *ip;
2542                                 struct ast_sw *sw;
2543                                 char buf[256], buf2[256];
2544                                 int context_info_printed = 0;
2545
2546                                 /* are we looking for exten too? if yes, we print context
2547                                  * if we our extension only
2548                                  */
2549                                 if (!exten) {
2550                                         ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
2551                                                 ast_get_context_name(c), ast_get_context_registrar(c));
2552                                         context_info_printed = 1;
2553                                 }
2554
2555                                 /* walk extensions ... */
2556                                 e = ast_walk_context_extensions(c, NULL);
2557                                 while (e) {
2558                                         struct ast_exten *p;
2559
2560                                         /* looking for extension? is this our extension? */
2561                                         if (exten &&
2562                                                 strcmp(ast_get_extension_name(e), exten))
2563                                         {
2564                                                 /* we are looking for extension and it's not our
2565                                                  * extension, so skip to next extension */
2566                                                 e = ast_walk_context_extensions(c, e);
2567                                                 continue;
2568                                         }
2569
2570                                         extension_existence = 1;
2571
2572                                         /* may we print context info? */        
2573                                         if (!context_info_printed) {
2574                                                 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
2575                                                         ast_get_context_name(c),
2576                                                         ast_get_context_registrar(c));
2577                                                 context_info_printed = 1;
2578                                         }
2579
2580                                         /* write extension name and first peer */       
2581                                         bzero(buf, sizeof(buf));                
2582                                         snprintf(buf, sizeof(buf), "'%s' =>",
2583                                                 ast_get_extension_name(e));
2584
2585                                         snprintf(buf2, sizeof(buf2),
2586                                                 "%d. %s(%s)",
2587                                                 ast_get_extension_priority(e),
2588                                                 ast_get_extension_app(e),
2589                                                 (char *)ast_get_extension_app_data(e));
2590
2591                                         ast_cli(fd, "  %-17s %-45s [%s]\n", buf, buf2,
2592                                                 ast_get_extension_registrar(e));
2593
2594                                         /* walk next extension peers */
2595                                         p = ast_walk_extension_priorities(e, e);
2596                                         while (p) {
2597                                                 bzero((void *)buf2, sizeof(buf2));
2598
2599                                                 snprintf(buf2, sizeof(buf2),
2600                                                         "%d. %s(%s)",
2601                                                         ast_get_extension_priority(p),
2602                                                         ast_get_extension_app(p),
2603                                                         (char *)ast_get_extension_app_data(p));
2604
2605                                                 ast_cli(fd,"  %-17s %-45s [%s]\n",
2606                                                         "", buf2,
2607                                                         ast_get_extension_registrar(p));        
2608
2609                                                 p = ast_walk_extension_priorities(e, p);
2610                                         }
2611                                         e = ast_walk_context_extensions(c, e);
2612                                 }
2613
2614                                 /* include & ignorepat we all printing if we are not
2615                                  * looking for exact extension
2616                                  */
2617                                 if (!exten) {
2618                                         if (ast_walk_context_extensions(c, NULL))
2619                                                 ast_cli(fd, "\n");
2620
2621                                         /* walk included and write info ... */
2622                                         i = ast_walk_context_includes(c, NULL);
2623                                         while (i) {
2624                                                 bzero(buf, sizeof(buf));
2625                                                 snprintf(buf, sizeof(buf), "'%s'",
2626                                                         ast_get_include_name(i));
2627                                                 ast_cli(fd, "  Include =>        %-45s [%s]\n",
2628                                                         buf, ast_get_include_registrar(i));
2629                                                 i = ast_walk_context_includes(c, i);
2630                                         }
2631
2632                                         /* walk ignore patterns and write info ... */
2633                                         ip = ast_walk_context_ignorepats(c, NULL);
2634                                         while (ip) {
2635                                                 bzero(buf, sizeof(buf));
2636                                                 snprintf(buf, sizeof(buf), "'%s'",
2637                                                         ast_get_ignorepat_name(ip));
2638                                                 ast_cli(fd, "  Ignore pattern => %-45s [%s]\n",
2639                                                         buf, ast_get_ignorepat_registrar(ip));  
2640                                                 ip = ast_walk_context_ignorepats(c, ip);
2641                                         }
2642                                         sw = ast_walk_context_switches(c, NULL);
2643                                         while(sw) {
2644                                                 bzero(buf, sizeof(buf));
2645                                                 snprintf(buf, sizeof(buf), "'%s/%s'",
2646                                                         ast_get_switch_name(sw),
2647                                                         ast_get_switch_data(sw));
2648                                                 ast_cli(fd, "  Alt. Switch =>    %-45s [%s]\n",
2649                                                         buf, ast_get_switch_registrar(sw));     
2650                                                 sw = ast_walk_context_switches(c, sw);
2651                                         }
2652                                 }
2653         
2654                                 ast_unlock_context(c);
2655
2656                                 /* if we print something in context, make an empty line */
2657                                 if (context_info_printed) ast_cli(fd, "\n");
2658                         }
2659                 }
2660                 c = ast_walk_contexts(c);
2661         }
2662         ast_unlock_contexts();
2663
2664         /* check for input failure and throw some error messages */
2665         if (context && !context_existence) {
2666                 ast_cli(fd, "There is no existence of '%s' context\n",
2667                         context);
2668                 return RESULT_FAILURE;
2669         }
2670
2671         if (exten && !extension_existence) {
2672                 if (context)
2673                         ast_cli(fd, "There is no existence of %s@%s extension\n",
2674                                 exten, context);
2675                 else
2676                         ast_cli(fd,
2677                                 "There is no existence of '%s' extension in all contexts\n",
2678                                 exten);
2679                 return RESULT_FAILURE;
2680         }
2681
2682         /* everything ok */
2683         return RESULT_SUCCESS;
2684 }
2685
2686 /*
2687  * CLI entries for upper commands ...
2688  */
2689 static struct ast_cli_entry show_applications_cli = 
2690         { { "show", "applications", NULL }, 
2691         handle_show_applications, "Shows registered applications",
2692         show_applications_help };
2693
2694 static struct ast_cli_entry show_application_cli =
2695         { { "show", "application", NULL }, 
2696         handle_show_application, "Describe a specific application",
2697         show_application_help, complete_show_application };
2698
2699 static struct ast_cli_entry show_dialplan_cli =
2700         { { "show", "dialplan", NULL },
2701                 handle_show_dialplan, "Show dialplan",
2702                 show_dialplan_help, complete_show_dialplan_context };
2703
2704 static struct ast_cli_entry show_switches_cli =
2705         { { "show", "switches", NULL },
2706                 handle_show_switches, "Show alternative switches",
2707                 show_switches_help, NULL };
2708
2709 int ast_unregister_application(char *app) {
2710         struct ast_app *tmp, *tmpl = NULL;
2711         if (ast_mutex_lock(&applock)) {
2712                 ast_log(LOG_ERROR, "Unable to lock application list\n");
2713                 return -1;
2714         }
2715         tmp = apps;
2716         while(tmp) {
2717                 if (!strcasecmp(app, tmp->name)) {
2718                         if (tmpl)
2719                                 tmpl->next = tmp->next;
2720                         else
2721                                 apps = tmp->next;
2722                         if (option_verbose > 1)
2723                                 ast_verbose( VERBOSE_PREFIX_2 "Unregistered application '%s'\n", tmp->name);
2724                         ast_mutex_unlock(&applock);
2725                         return 0;
2726                 }
2727                 tmpl = tmp;
2728                 tmp = tmp->next;
2729         }
2730         ast_mutex_unlock(&applock);
2731         return -1;
2732 }
2733
2734 struct ast_context *ast_context_create(struct ast_context **extcontexts, char *name, char *registrar)
2735 {
2736         struct ast_context *tmp, **local_contexts;
2737         if (!extcontexts) {
2738                 local_contexts = &contexts;
2739                 ast_mutex_lock(&conlock);
2740         } else
2741                 local_contexts = extcontexts;
2742
2743         tmp = *local_contexts;
2744         while(tmp) {
2745                 if (!strcasecmp(tmp->name, name)) {
2746                         ast_mutex_unlock(&conlock);
2747                         ast_log(LOG_WARNING, "Tried to register context '%s', already in use\n", name);
2748                         if (!extcontexts)
2749                                 ast_mutex_unlock(&conlock);
2750                         return NULL;
2751                 }
2752                 tmp = tmp->next;
2753         }
2754         tmp = malloc(sizeof(struct ast_context));
2755         if (tmp) {
2756                 memset(tmp, 0, sizeof(struct ast_context));
2757                 ast_mutex_init(&tmp->lock);
2758                 strncpy(tmp->name, name, sizeof(tmp->name)-1);
2759                 tmp->root = NULL;
2760                 tmp->registrar = registrar;
2761                 tmp->next = *local_contexts;
2762                 tmp->includes = NULL;
2763                 tmp->ignorepats = NULL;
2764                 *local_contexts = tmp;
2765                 if (option_debug)
2766                         ast_log(LOG_DEBUG, "Registered context '%s'\n", tmp->name);
2767                 else if (option_verbose > 2)
2768                         ast_verbose( VERBOSE_PREFIX_3 "Registered extension context '%s'\n", tmp->name);
2769         } else
2770                 ast_log(LOG_WARNING, "Out of memory\n");
2771         
2772         if (!extcontexts)
2773                 ast_mutex_unlock(&conlock);
2774         return tmp;
2775 }
2776
2777 void __ast_context_destroy(struct ast_context *con, char *registrar, int lock);
2778
2779 void ast_merge_contexts_and_delete(struct ast_context **extcontexts, char *registrar) {
2780         struct ast_context *tmp, *lasttmp = NULL;
2781         tmp = *extcontexts;
2782         ast_mutex_lock(&conlock);
2783         if (registrar) {
2784                 __ast_context_destroy(NULL,registrar,0);
2785                 while (tmp) {
2786                         lasttmp = tmp;
2787                         tmp = tmp->next;
2788                 }
2789         } else {
2790                 while (tmp) {
2791                         __ast_context_destroy(tmp,tmp->registrar,0);
2792                         lasttmp = tmp;
2793                         tmp = tmp->next;
2794                 }
2795         }
2796         if (lasttmp) {
2797                 lasttmp->next = contexts;
2798                 contexts = *extcontexts;
2799                 *extcontexts = NULL;
2800         } else 
2801                 ast_log(LOG_WARNING, "Requested contexts didn't get merged\n");
2802         ast_mutex_unlock(&conlock);
2803         return; 
2804 }
2805
2806 /*
2807  * errno values
2808  *  EBUSY  - can't lock
2809  *  ENOENT - no existence of context
2810  */
2811 int ast_context_add_include(char *context, char *include, char *registrar)
2812 {
2813         struct ast_context *c;
2814
2815         if (ast_lock_contexts()) {
2816                 errno = EBUSY;
2817                 return -1;
2818         }
2819
2820         /* walk contexts ... */
2821         c = ast_walk_contexts(NULL);
2822         while (c) {
2823                 /* ... search for the right one ... */
2824                 if (!strcmp(ast_get_context_name(c), context)) {
2825                         int ret = ast_context_add_include2(c, include, registrar);
2826                         /* ... unlock contexts list and return */
2827                         ast_unlock_contexts();
2828                         return ret;
2829                 }
2830                 c = ast_walk_contexts(c);
2831         }
2832
2833         /* we can't find the right context */
2834         ast_unlock_contexts();
2835         errno = ENOENT;
2836         return -1;
2837 }
2838
2839 #define FIND_NEXT \
2840 do { \
2841         c = info; \
2842         while(*c && (*c != '|')) c++; \
2843         if (*c) { *c = '\0'; c++; } else c = NULL; \
2844 } while(0)
2845
2846 static void get_timerange(struct ast_include *i, char *times)
2847 {
2848         char *e;
2849         int x;
2850         int s1, s2;
2851         int e1, e2;
2852
2853         //[PHM 07/01/03]
2854         //start disabling all times, fill the fields with 0's, as they may contain garbage
2855         memset(i->minmask, 0, sizeof(i->minmask));
2856         
2857         /* Star is all times */
2858         if (!strlen(times) || !strcmp(times, "*")) {
2859                 for (x=0;x<24;x++)
2860                         i->minmask[x] = (1 << 30) - 1;
2861                 return;
2862         }
2863         /* Otherwise expect a range */
2864         e = strchr(times, '-');
2865         if (!e) {
2866                 ast_log(LOG_WARNING, "Time range is not valid. Assuming no time.\n");
2867                 return;
2868         }
2869         *e = '\0';
2870         e++;
2871         while(*e && !isdigit(*e)) e++;
2872         if (!*e) {
2873                 ast_log(LOG_WARNING, "Invalid time range.  Assuming no time.\n");
2874                 return;
2875         }
2876         if (sscanf(times, "%d:%d", &s1, &s2) != 2) {
2877                 ast_log(LOG_WARNING, "%s isn't a time.  Assuming no time.\n", times);
2878                 return;
2879         }
2880         if (sscanf(e, "%d:%d", &e1, &e2) != 2) {
2881                 ast_log(LOG_WARNING, "%s isn't a time.  Assuming no time.\n", e);
2882                 return;
2883         }
2884         s1 = s1 * 30 + s2/2;
2885         if ((s1 < 0) || (s1 >= 24*30)) {
2886                 ast_log(LOG_WARNING, "%s isn't a valid star time. Assuming no time.\n", times);
2887                 return;
2888         }
2889         e1 = e1 * 30 + e2/2;
2890         if ((e1 < 0) || (e2 >= 24*30)) {
2891                 ast_log(LOG_WARNING, "%s isn't a valid start time. Assuming no time.\n", times);
2892                 return;
2893         }
2894         /* Go through the time and enable each appropriate bit */
2895         for (x=s1;x != e1;x = (x + 1) % (24 * 30)) {
2896                 i->minmask[x/30] |= (1 << (x % 30));
2897         }
2898         /* Do the last one */
2899         i->minmask[x/30] |= (1 << (x % 30));
2900         /* All done */
2901         return;
2902 }
2903
2904 static char *days[] =
2905 {
2906         "sun",
2907         "mon",
2908         "tue",
2909         "wed",
2910         "thu",
2911         "fri",
2912         "sat",
2913 };
2914
2915 static unsigned int get_dow(char *dow)
2916 {
2917         char *c;
2918         /* The following line is coincidence, really! */
2919         int s, e, x;
2920         unsigned int mask;
2921         /* Check for all days */
2922         if (!strlen(dow) || !strcmp(dow, "*"))
2923                 return (1 << 7) - 1;
2924         /* Get start and ending days */
2925         c = strchr(dow, '-');
2926         if (c) {
2927                 *c = '\0';
2928                 c++;
2929         } else
2930                 c = NULL;
2931         /* Find the start */
2932         s = 0;
2933         while((s < 7) && strcasecmp(dow, days[s])) s++;
2934         if (s >= 7) {
2935                 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", dow);
2936                 return 0;
2937         }
2938         if (c) {
2939                 e = 0;
2940                 while((e < 7) && strcasecmp(c, days[e])) e++;
2941                 if (e >= 7) {
2942                         ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
2943                         return 0;
2944                 }
2945         } else
2946                 e = s;
2947         mask = 0;
2948         for (x=s;x!=e;x = (x + 1) % 7) {
2949                 mask |= (1 << x);
2950         }
2951         /* One last one */
2952         mask |= (1 << x);
2953         return mask;
2954 }
2955
2956 static unsigned int get_day(char *day)
2957 {
2958         char *c;
2959         /* The following line is coincidence, really! */
2960         int s, e, x;
2961         unsigned int mask;
2962         /* Check for all days */
2963         if (!strlen(day) || !strcmp(day, "*")) {
2964                 mask = (1 << 30)  + ((1 << 30) - 1);
2965                 return mask;
2966         }
2967         /* Get start and ending days */
2968         c = strchr(day, '-');
2969         if (c) {
2970                 *c = '\0';
2971                 c++;
2972         }
2973         /* Find the start */
2974         if (sscanf(day, "%d", &s) != 1) {
2975                 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", day);
2976                 return 0;
2977         }
2978         if ((s < 1) || (s > 31)) {
2979                 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", day);
2980                 return 0;
2981         }
2982         s--;
2983         if (c) {
2984                 if (sscanf(c, "%d", &e) != 1) {
2985                         ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
2986                         return 0;
2987                 }
2988                 if ((e < 1) || (e > 31)) {
2989                         ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
2990                         return 0;
2991                 }
2992                 e--;
2993         } else
2994                 e = s;
2995         mask = 0;
2996         for (x=s;x!=e;x = (x + 1) % 31) {
2997                 mask |= (1 << x);
2998         }
2999         mask |= (1 << x);
3000         return mask;
3001 }
3002
3003 static char *months[] =
3004 {
3005         "jan",
3006         "feb",
3007         "mar",
3008         "apr",
3009         "may",
3010         "jun",
3011         "jul",
3012         "aug",
3013         "sep",
3014         "oct",
3015         "nov",
3016         "dec",
3017 };
3018
3019 static unsigned int get_month(char *mon)
3020 {
3021         char *c;
3022         /* The following line is coincidence, really! */
3023         int s, e, x;
3024         unsigned int mask;
3025         /* Check for all days */
3026         if (!strlen(mon) || !strcmp(mon, "*")) 
3027                 return (1 << 12) - 1;
3028         /* Get start and ending days */
3029         c = strchr(mon, '-');
3030         if (c) {
3031                 *c = '\0';
3032                 c++;
3033         }
3034         /* Find the start */
3035         s = 0;
3036         while((s < 12) && strcasecmp(mon, months[s])) s++;
3037         if (s >= 12) {
3038                 ast_log(LOG_WARNING, "Invalid month '%s', assuming none\n", mon);
3039                 return 0;
3040         }
3041         if (c) {
3042                 e = 0;
3043                 while((e < 12) && strcasecmp(mon, months[e])) e++;
3044                 if (e >= 12) {
3045                         ast_log(LOG_WARNING, "Invalid month '%s', assuming none\n", c);
3046                         return 0;
3047                 }
3048         } else
3049                 e = s;
3050         mask = 0;
3051         for (x=s;x!=e;x = (x + 1) % 12) {
3052                 mask |= (1 << x);
3053         }
3054         /* One last one */
3055         mask |= (1 << x);
3056         return mask;
3057 }
3058
3059 static void build_timing(struct ast_include *i, char *info)
3060 {
3061         char *c;
3062         /* Check for empty just in case */
3063         if (!strlen(info))
3064                 return;
3065         i->hastime = 1;
3066         /* Assume everything except time */
3067         i->monthmask = (1 << 12) - 1;
3068         i->daymask = (1 << 30) - 1 + (1 << 30);
3069         i->dowmask = (1 << 7) - 1;
3070         /* Avoid using str tok */
3071         FIND_NEXT;
3072         /* Info has the time range, start with that */
3073         get_timerange(i, info);
3074         info = c;
3075         if (!info)
3076                 return;
3077         FIND_NEXT;
3078         /* Now check for day of week */
3079         i->dowmask = get_dow(info);
3080
3081         info = c;
3082         if (!info)
3083                 return;
3084         FIND_NEXT;
3085         /* Now check for the day of the month */
3086         i->daymask = get_day(info);
3087         info = c;
3088         if (!info)
3089                 return;
3090         FIND_NEXT;
3091         /* And finally go for the month */
3092         i->monthmask = get_month(info);
3093 }
3094
3095 /*
3096  * errno values
3097  *  ENOMEM - out of memory
3098  *  EBUSY  - can't lock
3099  *  EEXIST - already included
3100  *  EINVAL - there is no existence of context for inclusion
3101  */
3102 int ast_context_add_include2(struct ast_context *con, char *value,
3103         char *registrar)
3104 {
3105         struct ast_include *new_include;
3106         char *c;
3107         struct ast_include *i, *il = NULL; /* include, include_last */
3108
3109         /* allocate new include structure ... */
3110         if (!(new_include = malloc(sizeof(struct ast_include)))) {
3111                 ast_log(LOG_WARNING, "Out of memory\n");
3112                 errno = ENOMEM;
3113                 return -1;
3114         }
3115         
3116         /* ... fill in this structure ... */
3117         memset(new_include, 0, sizeof(struct ast_include));
3118         strncpy(new_include->name, value, sizeof(new_include->name)-1);
3119         strncpy(new_include->rname, value, sizeof(new_include->rname)-1);
3120         c = new_include->rname;
3121         /* Strip off timing info */
3122         while(*c && (*c != '|')) c++; 
3123         /* Process if it's there */
3124         if (*c) {
3125                 build_timing(new_include, c+1);
3126                 *c = '\0';
3127         }
3128         new_include->next      = NULL;