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