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