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