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