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