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