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