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