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