00de3ae90d12340b9594f8df2fb0d483cd490e19
[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         pthread_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 user language",
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 pthread_mutex_t applock = AST_MUTEX_INITIALIZER;
339 static struct ast_context *contexts = NULL;
340 /* Lock for the ast_context list */
341 static pthread_mutex_t conlock = AST_MUTEX_INITIALIZER;
342 static struct ast_app *apps = NULL;
343
344 /* Lock for switches */
345 static pthread_mutex_t switchlock = AST_MUTEX_INITIALIZER;
346 struct ast_switch *switches = NULL;
347
348 /* Lock for extension state notifys */
349 static pthread_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_pthread_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_pthread_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_pthread_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_pthread_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_pthread_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_pthread_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;
742         headp=&c->varshead;
743     *ret=NULL;
744         /* Now we have the variable name on cp3 */
745         if ((first=strchr(var,':'))) {
746                 strncpy(tmpvar, var, sizeof(tmpvar) - 1);
747                 first = strchr(tmpvar, ':');
748                 if (!first)
749                         first = tmpvar + strlen(tmpvar);
750                 *first='\0';
751                 pbx_substitute_variables_temp(c,tmpvar,ret,workspace,workspacelen - 1);
752                 if (!(*ret)) return;
753                 offset=atoi(first+1);
754                 if ((second=strchr(first+1,':'))) {
755                         *second='\0';
756                         offset2=atoi(second+1);
757                 } else
758                         offset2=strlen(*ret)-offset;
759                 if (abs(offset)>strlen(*ret)) {
760                         if (offset>=0) 
761                                 offset=strlen(*ret);
762                         else 
763                                 offset=-strlen(*ret);
764                 }
765                 if ((offset<0 && offset2>-offset) || (offset>=0 && offset+offset2>strlen(*ret))) {
766                         if (offset>=0) 
767                                 offset2=strlen(*ret)-offset;
768                         else 
769                                 offset2=strlen(*ret)+offset;
770                 }
771                 if (offset>=0)
772                         *ret+=offset;
773                 else
774                         *ret+=strlen(*ret)+offset;
775                 (*ret)[offset2] = '\0';
776         } else if (!strcmp(var, "CALLERIDNUM")) {
777                 if (c->callerid)
778                         strncpy(workspace, c->callerid, workspacelen - 1);
779                 ast_callerid_parse(workspace, &name, &num);
780                 if (num) {
781                         ast_shrink_phone_number(num);
782                         *ret = num;
783                 } else
784                         *ret = workspace;
785         } else if (!strcmp(var, "CALLERIDNAME")) {
786                 if (c->callerid)
787                         strncpy(workspace, c->callerid, workspacelen - 1);
788                 ast_callerid_parse(workspace, &name, &num);
789                 if (name)
790                         *ret = name;
791                 else
792                         *ret = workspace;
793         } else if (!strcmp(var, "CALLERID")) {
794                 if (c->callerid) {
795                         strncpy(workspace, c->callerid, workspacelen - 1);
796                         *ret = workspace;
797                 } else 
798                         *ret = NULL;
799         } else if (!strcmp(var, "HINT")) {
800                 if (!ast_get_hint(workspace, workspacelen - 1, c, c->context, c->exten))
801                         *ret = NULL;
802                 else
803                         *ret = workspace;
804         } else if (!strcmp(var, "EXTEN")) {
805                 strncpy(workspace, c->exten, workspacelen - 1);
806                 *ret = workspace;
807         } else if (!strncmp(var, "EXTEN-", strlen("EXTEN-")) && 
808                 /* XXX Remove me eventually */
809                 (sscanf(var + strlen("EXTEN-"), "%d", &offset) == 1)) {
810                 if (offset < 0)
811                         offset=0;
812                 if (offset > strlen(c->exten))
813                         offset = strlen(c->exten);
814                 strncpy(workspace, c->exten + offset, workspacelen - 1);
815                 *ret = workspace;
816                 ast_log(LOG_WARNING, "The use of 'EXTEN-foo' has been derprecated in favor of 'EXTEN:foo'\n");
817         } else if (!strcmp(var, "RDNIS")) {
818                 if (c->rdnis) {
819                         strncpy(workspace, c->rdnis, workspacelen - 1);
820                         *ret = workspace;
821                 } else
822                         *ret = NULL;
823         } else if (!strcmp(var, "CONTEXT")) {
824                 strncpy(workspace, c->context, workspacelen - 1);
825                 *ret = workspace;
826         } else if (!strcmp(var, "PRIORITY")) {
827                 snprintf(workspace, workspacelen, "%d", c->priority);
828                 *ret = workspace;
829         } else if (!strcmp(var, "CHANNEL")) {
830                 strncpy(workspace, c->name, workspacelen - 1);
831                 *ret = workspace;
832         } else if (!strcmp(var, "EPOCH")) {
833           snprintf(workspace, workspacelen -1, "%u",(int)time(NULL));
834           *ret = workspace;
835         } else if (!strcmp(var, "DATETIME")) {
836           thistime=time(NULL);
837           localtime_r(&thistime, &brokentime);
838           snprintf(workspace, workspacelen -1, "%02d%02d%04d-%02d:%02d:%02d",
839                    brokentime.tm_mday,
840                    brokentime.tm_mon+1,
841                    brokentime.tm_year+1900,
842                    brokentime.tm_hour,
843                    brokentime.tm_min,
844                    brokentime.tm_sec
845                    );
846           *ret = workspace;
847         } else if (!strcmp(var, "UNIQUEID")) {
848           snprintf(workspace, workspacelen -1, "%s", c->uniqueid);
849         } else {
850                 AST_LIST_TRAVERSE(headp,variables,entries) {
851 #if 0
852                         ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",var,ast_var_name(variables));
853 #endif
854                         if (strcasecmp(ast_var_name(variables),var)==0) {
855                                 *ret=ast_var_value(variables);
856                                 if (*ret) {
857                                         strncpy(workspace, *ret, workspacelen - 1);
858                                         *ret = workspace;
859                                 }
860                         }
861                 }
862                 if (!(*ret)) {
863                         /* Try globals */
864                         AST_LIST_TRAVERSE(&globals,variables,entries) {
865 #if 0
866                                 ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",var,ast_var_name(variables));
867 #endif
868                                 if (strcasecmp(ast_var_name(variables),var)==0) {
869                                         *ret=ast_var_value(variables);
870                                         if (*ret) {
871                                                 strncpy(workspace, *ret, workspacelen - 1);
872                                                 *ret = workspace;
873                                         }
874                                 }
875                         }
876                 }
877                 if (!(*ret)) {
878                         int len=strlen(var);
879                         int len_env=strlen("ENV(");
880                         if (len > (len_env+1) && !strncasecmp(var,"ENV(",len_env) && !strcmp(var+len-1,")")) {
881                                 char cp3[80] = "";
882                                 strncpy(cp3, var, sizeof(cp3) - 1);
883                                 cp3[len-1]='\0';
884                                 *ret=getenv(cp3+len_env);
885                                 if (*ret) {
886                                         strncpy(workspace, *ret, workspacelen - 1);
887                                         *ret = workspace;
888                                 }
889                         }
890                 }
891                 if (!(*ret) && !strcasecmp(var,"LEN(",4)) {
892                         int len=strlen(var);
893                         int len_len=4;
894                         if (len > (len_len+1) && !strncasecmp(var,"LEN(",len_len) && strchr(var+len_len+2,')')) {
895                                 char cp3[80];
896                                 strncpy(cp3, var, sizeof(cp3) - 1);
897                                 cp3[len-len_len-1]='\0';
898                                 sprintf(workspace,"%d",strlen(cp3));
899                                 *ret = workspace;
900                         } else ast_log(LOG_NOTICE, "Wrong use of LEN(VARIABLE)\n");
901                 }
902         }
903 }
904
905 void pbx_substitute_variables_helper(struct ast_channel *c,const char *cp1,char *cp2,int count)
906 {
907         char *cp4;
908         const char *tmp, *whereweare;
909         int length;
910         char workspace[256];
911         char ltmp[256], var[256];
912         char *nextvar, *nextexp;
913         char *vars, *vare;
914         int pos, brackets, needsub, len;
915
916         /* Substitutes variables into cp2, based on string cp1, and assuming cp2 to be
917            zero-filled */
918         whereweare=tmp=cp1;
919         while(strlen(whereweare) && count) {
920                 /* Assume we're copying the whole remaining string */
921                 pos = strlen(whereweare);
922
923                 /* Look for a variable */
924                 nextvar = strstr(whereweare, "${");
925                 
926                 nextexp = strstr(whereweare, "$[");
927                 
928                 if (nextvar && nextexp) {
929                         if (nextvar < nextexp)
930                                 nextexp = NULL;
931                         else
932                                 nextvar = NULL;
933                 }
934                 
935                 /* If there is one, we only go that far */
936                 if (nextvar)
937                         pos = nextvar - whereweare;
938                 else if (nextexp)
939                         pos = nextexp - whereweare;
940                 
941                 /* Can't copy more than 'count' bytes */
942                 if (pos > count)
943                         pos = count;
944                 
945                 /* Copy that many bytes */
946                 memcpy(cp2, whereweare, pos);
947                 
948                 count -= pos;
949                 cp2 += pos;
950                 whereweare += pos;
951                 
952                 if (nextvar) {
953                         /* We have a variable.  Find the start and end, and determine
954                            if we are going to have to recursively call ourselves on the
955                            contents */
956                         vars = vare = nextvar + 2;
957                         brackets = 1;
958                         needsub = 0;
959                         
960                         /* Find the end of it */
961                         while(brackets && *vare) {
962                                 if ((vare[0] == '$') && (vare[1] == '{')) {
963                                         needsub++;
964                                         brackets++;
965                                 } else if (vare[0] == '}') {
966                                         brackets--;
967                                 } else if ((vare[0] == '$') && (vare[1] == '['))
968                                         needsub++;
969                                 vare++;
970                         }
971                         if (brackets)
972                                 ast_log(LOG_NOTICE, "Error in extension logic (missing '}')\n");
973                         len = vare - vars - 1;
974                         
975                         /* Skip totally over variable name */
976                         whereweare += ( len + 3);
977                         
978                         /* Store variable name (and truncate) */
979                         memset(var, 0, sizeof(var));
980                         strncpy(var, vars, sizeof(var) - 1);
981                         var[len] = '\0';
982                         
983                         /* Substitute if necessary */
984                         if (needsub) {
985                                 memset(ltmp, 0, sizeof(ltmp));
986                                 pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1);
987                                 vars = ltmp;
988                         } else {
989                                 vars = var;
990                         }
991                         
992                         /* Retrieve variable value */
993                         pbx_substitute_variables_temp(c,vars,&cp4, workspace, sizeof(workspace));
994                         if (cp4) {
995                                 length = strlen(cp4);
996                                 if (length > count)
997                                         length = count;
998                                 memcpy(cp2, cp4, length);
999                                 count -= length;
1000                                 cp2 += length;
1001                         }
1002                         
1003                 } else if (nextexp) {
1004                         /* We have an expression.  Find the start and end, and determine
1005                            if we are going to have to recursively call ourselves on the
1006                            contents */
1007                         vars = vare = nextexp + 2;
1008                         brackets = 1;
1009                         needsub = 0;
1010                         
1011                         /* Find the end of it */
1012                         while(brackets && *vare) {
1013                                 if ((vare[0] == '$') && (vare[1] == '[')) {
1014                                         needsub++;
1015                                         brackets++;
1016                                 } else if (vare[0] == ']') {
1017                                         brackets--;
1018                                 } else if ((vare[0] == '$') && (vare[1] == '{'))
1019                                         needsub++;
1020                                 vare++;
1021                         }
1022                         if (brackets)
1023                                 ast_log(LOG_NOTICE, "Error in extension logic (missing ']')\n");
1024                         len = vare - vars - 1;
1025                         
1026                         /* Skip totally over variable name */
1027                         whereweare += ( len + 3);
1028                         
1029                         /* Store variable name (and truncate) */
1030                         memset(var, 0, sizeof(var));
1031                         strncpy(var, vars, sizeof(var) - 1);
1032                         var[len] = '\0';
1033                         
1034                         /* Substitute if necessary */
1035                         if (needsub) {
1036                                 memset(ltmp, 0, sizeof(ltmp));
1037                                 pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1);
1038                                 vars = ltmp;
1039                         } else {
1040                                 vars = var;
1041                         }
1042
1043                         /* Evaluate expression */                       
1044                         cp4 = ast_expr(vars);
1045                         
1046                         printf("Expression is '%s'\n", cp4);
1047                         
1048                         if (cp4) {
1049                                 length = strlen(cp4);
1050                                 if (length > count)
1051                                         length = count;
1052                                 memcpy(cp2, cp4, length);
1053                                 count -= length;
1054                                 cp2 += length;
1055                                 free(cp4);
1056                         }
1057                         
1058                 } else
1059                         break;
1060         }
1061 }
1062
1063 static void pbx_substitute_variables(char *passdata, int datalen, struct ast_channel *c, struct ast_exten *e) {
1064         
1065         memset(passdata, 0, datalen);
1066                 
1067         /* No variables or expressions in e->data, so why scan it? */
1068         if (!strstr(e->data,"${") && !strstr(e->data,"$[")) {
1069                 strncpy(passdata, e->data, datalen - 1);
1070                 passdata[datalen-1] = '\0';
1071                 return;
1072         }
1073         
1074         pbx_substitute_variables_helper(c,e->data,passdata, datalen - 1);
1075 }                                                               
1076
1077 static int pbx_extension_helper(struct ast_channel *c, char *context, char *exten, int priority, char *callerid, int action) 
1078 {
1079         struct ast_exten *e;
1080         struct ast_app *app;
1081         struct ast_switch *sw;
1082         char *data;
1083         int newstack = 0;
1084         int res;
1085         int status = 0;
1086         char *incstack[AST_PBX_MAX_STACK];
1087         char passdata[256];
1088         int stacklen = 0;
1089         char tmp[80];
1090         char tmp2[80];
1091         char tmp3[256];
1092         if (ast_pthread_mutex_lock(&conlock)) {
1093                 ast_log(LOG_WARNING, "Unable to obtain lock\n");
1094                 if ((action == HELPER_EXISTS) || (action == HELPER_CANMATCH) || (action == HELPER_MATCHMORE))
1095                         return 0;
1096                 else
1097                         return -1;
1098         }
1099         e = pbx_find_extension(c, context, exten, priority, callerid, action, incstack, &stacklen, &status, &sw, &data);
1100         if (e) {
1101                 switch(action) {
1102                 case HELPER_CANMATCH:
1103                         pthread_mutex_unlock(&conlock);
1104                         return -1;
1105                 case HELPER_EXISTS:
1106                         pthread_mutex_unlock(&conlock);
1107                         return -1;
1108                 case HELPER_MATCHMORE:
1109                         pthread_mutex_unlock(&conlock);
1110                         return -1;
1111                 case HELPER_SPAWN:
1112                         newstack++;
1113                         /* Fall through */
1114                 case HELPER_EXEC:
1115                         app = pbx_findapp(e->app);
1116                         pthread_mutex_unlock(&conlock);
1117                         if (app) {
1118                                 strncpy(c->context, context, sizeof(c->context-1));
1119                                 strncpy(c->exten, exten, sizeof(c->exten)-1);
1120                                 c->priority = priority;
1121                                 pbx_substitute_variables(passdata, sizeof(passdata), c, e);
1122                                 if (option_debug)
1123                                                 ast_log(LOG_DEBUG, "Launching '%s'\n", app->name);
1124                                 else if (option_verbose > 2)
1125                                                 ast_verbose( VERBOSE_PREFIX_3 "Executing %s(\"%s\", \"%s\") %s\n", 
1126                                                                 term_color(tmp, app->name, COLOR_BRCYAN, 0, sizeof(tmp)),
1127                                                                 term_color(tmp2, c->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
1128                                                                 term_color(tmp3, (strlen(passdata) ? (char *)passdata : ""), COLOR_BRMAGENTA, 0, sizeof(tmp3)),
1129                                                                 (newstack ? "in new stack" : "in same stack"));
1130                                 res = pbx_exec(c, app, passdata, newstack);
1131                                 return res;
1132                         } else {
1133                                 ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
1134                                 return -1;
1135                         }
1136                 default:
1137                         ast_log(LOG_WARNING, "Huh (%d)?\n", action);                    return -1;
1138                 }
1139         } else if (sw) {
1140                 switch(action) {
1141                 case HELPER_CANMATCH:
1142                         pthread_mutex_unlock(&conlock);
1143                         return -1;
1144                 case HELPER_EXISTS:
1145                         pthread_mutex_unlock(&conlock);
1146                         return -1;
1147                 case HELPER_MATCHMORE:
1148                         pthread_mutex_unlock(&conlock);
1149                         return -1;
1150                 case HELPER_SPAWN:
1151                         newstack++;
1152                         /* Fall through */
1153                 case HELPER_EXEC:
1154                         pthread_mutex_unlock(&conlock);
1155                         if (sw->exec)
1156                                 res = sw->exec(c, context, exten, priority, callerid, newstack, data);
1157                         else {
1158                                 ast_log(LOG_WARNING, "No execution engine for switch %s\n", sw->name);
1159                                 res = -1;
1160                         }
1161                         return res;
1162                 default:
1163                         ast_log(LOG_WARNING, "Huh (%d)?\n", action);
1164                         return -1;
1165                 }
1166         } else {
1167                 pthread_mutex_unlock(&conlock);
1168                 switch(status) {
1169                 case STATUS_NO_CONTEXT:
1170                         if ((action != HELPER_EXISTS) && (action != HELPER_MATCHMORE))
1171                                 ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", context);
1172                         break;
1173                 case STATUS_NO_EXTENSION:
1174                         if ((action != HELPER_EXISTS) && (action !=  HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1175                                 ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, context);
1176                         break;
1177                 case STATUS_NO_PRIORITY:
1178                         if ((action != HELPER_EXISTS) && (action !=  HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1179                                 ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, context);
1180                         break;
1181                 default:
1182                         ast_log(LOG_DEBUG, "Shouldn't happen!\n");
1183                 }
1184                 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1185                         return -1;
1186                 else
1187                         return 0;
1188         }
1189
1190 }
1191
1192 static struct ast_exten *ast_hint_extension(struct ast_channel *c, char *context, char *exten)
1193 {
1194         struct ast_exten *e;
1195         struct ast_switch *sw;
1196         char *data;
1197         int status = 0;
1198         char *incstack[AST_PBX_MAX_STACK];
1199         int stacklen = 0;
1200
1201         if (ast_pthread_mutex_lock(&conlock)) {
1202                 ast_log(LOG_WARNING, "Unable to obtain lock\n");
1203                 return NULL;
1204         }
1205         e = pbx_find_extension(c, context, exten, PRIORITY_HINT, "", HELPER_EXISTS, incstack, &stacklen, &status, &sw, &data);
1206         ast_pthread_mutex_unlock(&conlock);     
1207         return e;
1208 }
1209
1210 static int ast_extension_state2(struct ast_exten *e)
1211 {
1212     char hint[AST_MAX_EXTENSION] = "";    
1213     char *cur, *rest;
1214     int res = -1;
1215     int allunavailable = 1, allbusy = 1, allfree = 1;
1216     int busy = 0;
1217
1218     strncpy(hint, ast_get_extension_app(e), sizeof(hint)-1);
1219     
1220     cur = hint;    
1221     do {
1222         rest = strchr(cur, '&');
1223         if (rest) {
1224             *rest = 0;
1225             rest++;
1226         }
1227         
1228         res = ast_device_state(cur);
1229         switch (res) {
1230     case AST_DEVICE_NOT_INUSE:
1231                 allunavailable = 0;
1232                 allbusy = 0;
1233                 break;
1234     case AST_DEVICE_INUSE:
1235                 return AST_EXTENSION_INUSE;
1236     case AST_DEVICE_BUSY:
1237                 allunavailable = 0;
1238                 allfree = 0;
1239                 busy = 1;
1240                 break;
1241     case AST_DEVICE_UNAVAILABLE:
1242     case AST_DEVICE_INVALID:
1243                 allbusy = 0;
1244                 allfree = 0;
1245                 break;
1246     default:
1247                 allunavailable = 0;
1248                 allbusy = 0;
1249                 allfree = 0;
1250         }
1251         cur = rest;
1252     } while (cur);
1253
1254     if (allfree)
1255                 return AST_EXTENSION_NOT_INUSE;
1256     if (allbusy)
1257                 return AST_EXTENSION_BUSY;
1258     if (allunavailable)
1259                 return AST_EXTENSION_UNAVAILABLE;
1260     if (busy) 
1261                 return AST_EXTENSION_INUSE;
1262         
1263     return AST_EXTENSION_NOT_INUSE;
1264 }
1265
1266
1267 int ast_extension_state(struct ast_channel *c, char *context, char *exten)
1268 {
1269     struct ast_exten *e;
1270
1271     e = ast_hint_extension(c, context, exten);    
1272     if (!e) 
1273         return -1;
1274
1275     return ast_extension_state2(e);    
1276 }
1277
1278 int ast_device_state_changed(const char *fmt, ...) 
1279 {
1280     struct ast_hint *list;
1281     struct ast_state_cb *cblist;
1282     char hint[AST_MAX_EXTENSION];
1283     char device[AST_MAX_EXTENSION];
1284     char *cur, *rest;
1285     int state;
1286     
1287     va_list ap;
1288
1289     va_start(ap, fmt);
1290     vsnprintf(device, sizeof(device)-1, fmt, ap);
1291     va_end(ap);
1292
1293     rest = strchr(device, '-');
1294     if (rest) {
1295         *rest = 0;
1296     }
1297         
1298     pthread_mutex_lock(&hintlock);
1299
1300     list = hints;
1301     
1302     while (list) {
1303         
1304         strcpy(hint, ast_get_extension_app(list->exten));
1305         cur = hint;
1306         do {
1307             rest = strchr(cur, '&');
1308             if (rest) {
1309                 *rest = 0;
1310                 rest++;
1311             }
1312             
1313             if (!strcmp(cur, device)) {
1314             // Found extension execute callbacks 
1315                 state = ast_extension_state2(list->exten);
1316                 if ((state != -1) && (state != list->laststate)) {
1317                     // For general callbacks
1318                     cblist = statecbs;
1319                     while (cblist) {
1320                         cblist->callback(list->exten->parent->name, list->exten->exten, state, cblist->data);
1321                         cblist = cblist->next;
1322                     }
1323                     
1324                     // For extension callbacks
1325                     cblist = list->callbacks;
1326                     while (cblist) {
1327                         cblist->callback(list->exten->parent->name, list->exten->exten, state, cblist->data);
1328                         cblist = cblist->next;
1329                     }
1330                     
1331                     list->laststate = state;
1332                 }
1333                 break;
1334             }
1335             cur = rest;
1336         } while (cur);
1337         
1338         list = list->next;
1339     }
1340
1341     pthread_mutex_unlock(&hintlock);
1342     return 1;
1343 }
1344                         
1345 int ast_extension_state_add(char *context, char *exten, 
1346                             ast_state_cb_type callback, void *data)
1347 {
1348     struct ast_hint *list;
1349     struct ast_state_cb *cblist;
1350     struct ast_exten *e;
1351
1352     /* No context and extension add callback to statecbs list */
1353     if (!context && !exten) {
1354         pthread_mutex_lock(&hintlock);
1355
1356         cblist = statecbs;
1357         while (cblist) {
1358             if (cblist->callback == callback) {
1359                 cblist->data = data;
1360                 pthread_mutex_unlock(&hintlock);
1361             }
1362             
1363             cblist = cblist->next;
1364         }
1365         
1366         /* Now inserts the callback */
1367         cblist = malloc(sizeof(struct ast_state_cb));
1368         if (!cblist) {
1369             pthread_mutex_unlock(&hintlock);
1370             return -1;
1371         }
1372         memset(cblist, 0, sizeof(struct ast_state_cb));
1373         cblist->id = 0;
1374         cblist->callback = callback;
1375         cblist->data = data;
1376
1377         cblist->next = statecbs;
1378         statecbs = cblist;
1379
1380         pthread_mutex_unlock(&hintlock);
1381         return 0;
1382     }
1383
1384     if (!context || !exten)
1385         return -1;
1386
1387     /* This callback type is for only one hint */
1388     e = ast_hint_extension(NULL, context, exten);    
1389     if (!e) {
1390         return -1;
1391     }
1392     
1393     pthread_mutex_lock(&hintlock);
1394     list = hints;        
1395     
1396     while (list) {
1397         if (list->exten == e)
1398             break;          
1399         list = list->next;    
1400     }
1401
1402     if (!list) {
1403         pthread_mutex_unlock(&hintlock);
1404         return -1;
1405     }
1406
1407     /* Now inserts the callback */
1408     cblist = malloc(sizeof(struct ast_state_cb));
1409     if (!cblist) {
1410         pthread_mutex_unlock(&hintlock);
1411         return -1;
1412     }
1413     memset(cblist, 0, sizeof(struct ast_state_cb));
1414     cblist->id = stateid++;
1415     cblist->callback = callback;
1416     cblist->data = data;
1417
1418     cblist->next = list->callbacks;
1419     list->callbacks = cblist;
1420
1421     pthread_mutex_unlock(&hintlock);
1422     return cblist->id;
1423 }
1424
1425 int ast_extension_state_del(int id, ast_state_cb_type callback)
1426 {
1427     struct ast_hint *list;
1428     struct ast_state_cb *cblist, *cbprev;
1429     
1430     if (!id && !callback)
1431         return -1;
1432             
1433     pthread_mutex_lock(&hintlock);
1434
1435     /* id is zero is a callback without extension */
1436     if (!id) {
1437         cbprev = NULL;
1438         cblist = statecbs;
1439         while (cblist) {
1440             if (cblist->callback == callback) {
1441                 if (!cbprev)
1442                     statecbs = cblist->next;
1443                 else
1444                     cbprev->next = cblist->next;
1445
1446                 free(cblist);
1447
1448                 pthread_mutex_unlock(&hintlock);
1449                 return 0;
1450             }
1451             cbprev = cblist;
1452             cblist = cblist->next;
1453         }
1454
1455         pthread_mutex_lock(&hintlock);
1456         return -1;
1457     }
1458
1459     /* id greater zero is a callback with extension */
1460     list = hints;
1461     while (list) {
1462         cblist = list->callbacks;
1463         cbprev = NULL;
1464         while (cblist) {
1465             if (cblist->id==id) {
1466                 if (!cbprev)
1467                     list->callbacks = cblist->next;             
1468                 else
1469                     cbprev->next = cblist->next;
1470                 
1471                 free(cblist);
1472                 
1473                 pthread_mutex_unlock(&hintlock);
1474                 return 0;               
1475             }           
1476             cbprev = cblist;                            
1477             cblist = cblist->next;
1478         }
1479         list = list->next;
1480     }
1481     
1482     pthread_mutex_unlock(&hintlock);
1483     return -1;
1484 }
1485
1486 static int ast_add_hint(struct ast_exten *e)
1487 {
1488     struct ast_hint *list;
1489
1490     if (!e) return -1;
1491     
1492     pthread_mutex_lock(&hintlock);
1493     list = hints;        
1494     
1495     /* Search if hint exists, do nothing */
1496     while (list) {
1497         if (list->exten == e) {
1498             pthread_mutex_unlock(&hintlock);
1499             return -1;
1500         }
1501         list = list->next;    
1502     }
1503
1504     list = malloc(sizeof(struct ast_hint));
1505     if (!list) {
1506         pthread_mutex_unlock(&hintlock);
1507         return -1;
1508     }
1509     /* Initialize and insert new item */
1510     memset(list, 0, sizeof(struct ast_hint));
1511     list->exten = e;
1512     list->laststate = ast_extension_state2(e);
1513     list->next = hints;
1514     hints = list;
1515
1516     pthread_mutex_unlock(&hintlock);
1517     return 0;
1518 }
1519
1520 static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
1521
1522     struct ast_hint *list;
1523
1524     pthread_mutex_lock(&hintlock);
1525     
1526     list = hints;
1527     
1528     while(list) {
1529         if (list->exten == oe) {
1530             list->exten = ne;
1531             pthread_mutex_unlock(&hintlock);    
1532             return 0;
1533         }
1534         list = list->next;
1535     }
1536     pthread_mutex_unlock(&hintlock);
1537
1538     return -1;
1539 }
1540
1541 static int ast_remove_hint(struct ast_exten *e)
1542 {
1543     /* Cleanup the Notifys if hint is removed */
1544     struct ast_hint *list, *prev = NULL;
1545     struct ast_state_cb *cblist, *cbprev;
1546
1547     if (!e) 
1548         return -1;
1549
1550     pthread_mutex_lock(&hintlock);
1551
1552     list = hints;    
1553     while(list) {
1554         if (list->exten==e) {
1555             cbprev = NULL;
1556             cblist = list->callbacks;
1557             while (cblist) {
1558                 /* Notify with -1 and remove all callbacks */
1559                 cbprev = cblist;            
1560                 cblist = cblist->next;
1561                 cbprev->callback(list->exten->parent->name, list->exten->exten, -1, cbprev->data);
1562                 free(cbprev);
1563             }
1564             list->callbacks = NULL;
1565
1566             if (!prev)
1567                 hints = list->next;
1568             else
1569                 prev->next = list->next;
1570
1571             free(list);
1572             
1573             pthread_mutex_unlock(&hintlock);
1574             return 0;
1575         } else {
1576             prev = list;
1577             list = list->next;    
1578         }
1579     }
1580
1581     pthread_mutex_unlock(&hintlock);
1582     return -1;
1583 }
1584
1585
1586 int ast_get_hint(char *hint, int maxlen, struct ast_channel *c, char *context, char *exten)
1587 {
1588         struct ast_exten *e;
1589         e = ast_hint_extension(c, context, exten);
1590         if (e) {        
1591             strncpy(hint, ast_get_extension_app(e), maxlen);
1592             return -1;
1593         }
1594         return 0;       
1595 }
1596
1597 int ast_exists_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid) 
1598 {
1599         return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_EXISTS);
1600 }
1601
1602 int ast_canmatch_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid)
1603 {
1604         return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_CANMATCH);
1605 }
1606
1607 int ast_matchmore_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid)
1608 {
1609         return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_MATCHMORE);
1610 }
1611
1612 int ast_spawn_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid) 
1613 {
1614         return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_SPAWN);
1615 }
1616
1617 int ast_pbx_run(struct ast_channel *c)
1618 {
1619         int firstpass = 1;
1620         char digit;
1621         char exten[256];
1622         int pos;
1623         int waittime;
1624         int res=0;
1625
1626         /* A little initial setup here */
1627         if (c->pbx)
1628                 ast_log(LOG_WARNING, "%s already has PBX structure??\n", c->name);
1629         c->pbx = malloc(sizeof(struct ast_pbx));
1630         if (!c->pbx) {
1631                 ast_log(LOG_WARNING, "Out of memory\n");
1632                 return -1;
1633         }
1634         if (c->amaflags) {
1635                 if (c->cdr) {
1636                         ast_log(LOG_WARNING, "%s already has a call record??\n", c->name);
1637                 } else {
1638                         c->cdr = ast_cdr_alloc();
1639                         if (!c->cdr) {
1640                                 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
1641                                 free(c->pbx);
1642                                 return -1;
1643                         }
1644                         ast_cdr_init(c->cdr, c);
1645                 }
1646         }
1647         memset(c->pbx, 0, sizeof(struct ast_pbx));
1648         /* Set reasonable defaults */
1649         c->pbx->rtimeout = 10;
1650         c->pbx->dtimeout = 5;
1651
1652         /* Start by trying whatever the channel is set to */
1653         if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
1654                 /* JK02: If not successfull fall back to 's' */
1655                 strncpy(c->exten, "s", sizeof(c->exten)-1);
1656                 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
1657                         /* JK02: And finally back to default if everything else failed */
1658                         strncpy(c->context, "default", sizeof(c->context)-1);
1659                 }
1660                 c->priority = 1;
1661         }
1662         if (c->cdr)
1663                 ast_cdr_start(c->cdr);
1664         for(;;) {
1665                 pos = 0;
1666                 digit = 0;
1667                 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
1668                         memset(exten, 0, sizeof(exten));
1669                         manager_event(EVENT_FLAG_CALL, "Newexten", 
1670                                 "Channel: %s\r\n"
1671                                 "Context: %s\r\n"
1672                                 "Extension: %s\r\n"
1673                                 "Priority: %d\r\n"
1674                                 "Uniqueid: %s\r\n",
1675                                 c->name, c->context, c->exten, c->priority, c->uniqueid);
1676                         if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->callerid))) {
1677                                 /* Something bad happened, or a hangup has been requested. */
1678                                 if (((res >= '0') && (res <= '9')) || ((res >= 'A') && (res <= 'F')) ||
1679                                         (res == '*') || (res == '#')) {
1680                                         ast_log(LOG_DEBUG, "Oooh, got something to jump out with ('%c')!\n", res);
1681                                         memset(exten, 0, sizeof(exten));
1682                                         pos = 0;
1683                                         exten[pos++] = digit = res;
1684                                         break;
1685                                 }
1686                                 switch(res) {
1687                                 case AST_PBX_KEEPALIVE:
1688                                         if (option_debug)
1689                                                 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
1690                                         else if (option_verbose > 1)
1691                                                 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
1692                                         goto out;
1693                                         break;
1694                                 default:
1695                                         if (option_debug)
1696                                                 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
1697                                         else if (option_verbose > 1)
1698                                                 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
1699                                         if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
1700                                                 c->_softhangup =0;
1701                                                 break;
1702                                         }
1703                                         /* atimeout */
1704                                         if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
1705                                                 break;
1706                                         }
1707                                         goto out;
1708                                 }
1709                         }
1710                         if ((c->_softhangup == AST_SOFTHANGUP_TIMEOUT) && (ast_exists_extension(c,c->context,"T",1,c->callerid))) {
1711                                 strncpy(c->exten,"T",sizeof(c->exten) - 1);
1712                                 /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
1713                                 c->whentohangup = 0;
1714                                 c->priority = 0;
1715                                 c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
1716                         } else if (c->_softhangup) {
1717                                 ast_log(LOG_DEBUG, "Extension %s, priority %d returned normally even though call was hung up\n",
1718                                         c->exten, c->priority);
1719                                 goto out;
1720                         }
1721                         firstpass = 0;
1722                         c->priority++;
1723                 }
1724                 if (!ast_exists_extension(c, c->context, c->exten, 1, c->callerid)) {
1725                         /* It's not a valid extension anymore */
1726                         if (ast_exists_extension(c, c->context, "i", 1, c->callerid)) {
1727                                 if (option_verbose > 2)
1728                                         ast_verbose(VERBOSE_PREFIX_3 "Sent into invalid extension '%s' in context '%s' on %s\n", c->exten, c->context, c->name);
1729                                 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", c->exten);
1730                                 strncpy(c->exten, "i", sizeof(c->exten)-1);
1731                                 c->priority = 1;
1732                         } else {
1733                                 ast_log(LOG_WARNING, "Channel '%s' sent into invalid extension '%s' in context '%s', but no invalid handler\n",
1734                                         c->name, c->exten, c->context);
1735                                 goto out;
1736                         }
1737                 } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
1738                         /* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */
1739                         c->_softhangup = 0;
1740                 } else {
1741                         /* Done, wait for an extension */
1742                         if (digit)
1743                                 waittime = c->pbx->dtimeout;
1744                         else
1745                                 waittime = c->pbx->rtimeout;
1746                         while (ast_matchmore_extension(c, c->context, exten, 1, c->callerid)) {
1747                                 /* As long as we're willing to wait, and as long as it's not defined, 
1748                                    keep reading digits until we can't possibly get a right answer anymore.  */
1749                                 digit = ast_waitfordigit(c, waittime * 1000);
1750                                 if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
1751                                         c->_softhangup = 0;
1752                                 } else {
1753                                         if (!digit)
1754                                                 /* No entry */
1755                                                 break;
1756                                         if (digit < 0)
1757                                                 /* Error, maybe a  hangup */
1758                                                 goto out;
1759                                         exten[pos++] = digit;
1760                                         waittime = c->pbx->dtimeout;
1761                                 }
1762                         }
1763                         if (ast_exists_extension(c, c->context, exten, 1, c->callerid)) {
1764                                 /* Prepare the next cycle */
1765                                 strncpy(c->exten, exten, sizeof(c->exten)-1);
1766                                 c->priority = 1;
1767                         } else {
1768                                 /* No such extension */
1769                                 if (strlen(exten)) {
1770                                         /* An invalid extension */
1771                                         if (ast_exists_extension(c, c->context, "i", 1, c->callerid)) {
1772                                                 if (option_verbose > 2)
1773                                                         ast_verbose( VERBOSE_PREFIX_3 "Invalid extension '%s' in context '%s' on %s\n", exten, c->context, c->name);
1774                                                 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", exten);
1775                                                 strncpy(c->exten, "i", sizeof(c->exten)-1);
1776                                                 c->priority = 1;
1777                                         } else {
1778                                                 ast_log(LOG_WARNING, "Invalid extension, but no rule 'i' in context '%s'\n", c->context);
1779                                                 goto out;
1780                                         }
1781                                 } else {
1782                                         /* A simple timeout */
1783                                         if (ast_exists_extension(c, c->context, "t", 1, c->callerid)) {
1784                                                 if (option_verbose > 2)
1785                                                         ast_verbose( VERBOSE_PREFIX_3 "Timeout on %s\n", c->name);
1786                                                 strncpy(c->exten, "t", sizeof(c->exten)-1);
1787                                                 c->priority = 1;
1788                                         } else {
1789                                                 ast_log(LOG_WARNING, "Timeout, but no rule 't' in context '%s'\n", c->context);
1790                                                 goto out;
1791                                         }
1792                                 }       
1793                         }
1794                 }
1795         }
1796         if (firstpass) 
1797                 ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", c->name);
1798 out:
1799         if (ast_exists_extension(c, c->context, "h", 1, c->callerid)) {
1800                 strcpy(c->exten, "h");
1801                 c->priority = 1;
1802                 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
1803                         if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->callerid))) {
1804                                 /* Something bad happened, or a hangup has been requested. */
1805                                 if (option_debug)
1806                                         ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
1807                                 else if (option_verbose > 1)
1808                                         ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
1809                                 break;
1810                         }
1811                         c->priority++;
1812                 }
1813         }
1814
1815         pbx_destroy(c->pbx);
1816         c->pbx = NULL;
1817         if (res != AST_PBX_KEEPALIVE)
1818                 ast_hangup(c);
1819         return 0;
1820 }
1821
1822 static void *pbx_thread(void *data)
1823 {
1824         /* Oh joyeous kernel, we're a new thread, with nothing to do but
1825            answer this channel and get it going.  The setjmp stuff is fairly
1826            confusing, but necessary to get smooth transitions between
1827            the execution of different applications (without the use of
1828            additional threads) */
1829         struct ast_channel *c = data;
1830         ast_pbx_run(c);
1831         pthread_exit(NULL);
1832         return NULL;
1833 }
1834
1835 int ast_pbx_start(struct ast_channel *c)
1836 {
1837         pthread_t t;
1838         pthread_attr_t attr;
1839         if (!c) {
1840                 ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
1841                 return -1;
1842         }
1843            
1844         /* Start a new thread, and get something handling this channel. */
1845         pthread_attr_init(&attr);
1846         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1847         if (pthread_create(&t, &attr, pbx_thread, c)) {
1848                 ast_log(LOG_WARNING, "Failed to create new channel thread\n");
1849                 return -1;
1850         }
1851         return 0;
1852 }
1853
1854 /*
1855  * This function locks contexts list by &conlist, search for the rigt context
1856  * structure, leave context list locked and call ast_context_remove_include2
1857  * which removes include, unlock contexts list and return ...
1858  */
1859 int ast_context_remove_include(char *context, char *include, char *registrar)
1860 {
1861         struct ast_context *c;
1862
1863         if (ast_lock_contexts()) return -1;
1864
1865         /* walk contexts and search for the right one ...*/
1866         c = ast_walk_contexts(NULL);
1867         while (c) {
1868                 /* we found one ... */
1869                 if (!strcmp(ast_get_context_name(c), context)) {
1870                         int ret;
1871                         /* remove include from this context ... */      
1872                         ret = ast_context_remove_include2(c, include, registrar);
1873
1874                         ast_unlock_contexts();
1875
1876                         /* ... return results */
1877                         return ret;
1878                 }
1879                 c = ast_walk_contexts(c);
1880         }
1881
1882         /* we can't find the right one context */
1883         ast_unlock_contexts();
1884         return -1;
1885 }
1886
1887 /*
1888  * When we call this function, &conlock lock must be locked, because when
1889  * we giving *con argument, some process can remove/change this context
1890  * and after that there can be segfault.
1891  *
1892  * This function locks given context, removes include, unlock context and
1893  * return.
1894  */
1895 int ast_context_remove_include2(struct ast_context *con, char *include, char *registrar)
1896 {
1897         struct ast_include *i, *pi = NULL;
1898
1899         if (ast_pthread_mutex_lock(&con->lock)) return -1;
1900
1901         /* walk includes */
1902         i = con->includes;
1903         while (i) {
1904                 /* find our include */
1905                 if (!strcmp(i->name, include) && 
1906                         (!strcmp(i->registrar, registrar) || !registrar)) {
1907                         /* remove from list */
1908                         if (pi)
1909                                 pi->next = i->next;
1910                         else
1911                                 con->includes = i->next;
1912                         /* free include and return */
1913                         free(i);
1914                         ast_pthread_mutex_unlock(&con->lock);
1915                         return 0;
1916                 }
1917                 pi = i;
1918                 i = i->next;
1919         }
1920
1921         /* we can't find the right include */
1922         ast_pthread_mutex_unlock(&con->lock);
1923         return -1;
1924 }
1925
1926 /*
1927  * This function locks contexts list by &conlist, search for the rigt context
1928  * structure, leave context list locked and call ast_context_remove_switch2
1929  * which removes switch, unlock contexts list and return ...
1930  */
1931 int ast_context_remove_switch(char *context, char *sw, char *data, char *registrar)
1932 {
1933         struct ast_context *c;
1934
1935         if (ast_lock_contexts()) return -1;
1936
1937         /* walk contexts and search for the right one ...*/
1938         c = ast_walk_contexts(NULL);
1939         while (c) {
1940                 /* we found one ... */
1941                 if (!strcmp(ast_get_context_name(c), context)) {
1942                         int ret;
1943                         /* remove switch from this context ... */       
1944                         ret = ast_context_remove_switch2(c, sw, data, registrar);
1945
1946                         ast_unlock_contexts();
1947
1948                         /* ... return results */
1949                         return ret;
1950                 }
1951                 c = ast_walk_contexts(c);
1952         }
1953
1954         /* we can't find the right one context */
1955         ast_unlock_contexts();
1956         return -1;
1957 }
1958
1959 /*
1960  * When we call this function, &conlock lock must be locked, because when
1961  * we giving *con argument, some process can remove/change this context
1962  * and after that there can be segfault.
1963  *
1964  * This function locks given context, removes switch, unlock context and
1965  * return.
1966  */
1967 int ast_context_remove_switch2(struct ast_context *con, char *sw, char *data, char *registrar)
1968 {
1969         struct ast_sw *i, *pi = NULL;
1970
1971         if (ast_pthread_mutex_lock(&con->lock)) return -1;
1972
1973         /* walk switchs */
1974         i = con->alts;
1975         while (i) {
1976                 /* find our switch */
1977                 if (!strcmp(i->name, sw) && !strcmp(i->data, data) && 
1978                         (!strcmp(i->registrar, registrar) || !registrar)) {
1979                         /* remove from list */
1980                         if (pi)
1981                                 pi->next = i->next;
1982                         else
1983                                 con->alts = i->next;
1984                         /* free switch and return */
1985                         free(i);
1986                         ast_pthread_mutex_unlock(&con->lock);
1987                         return 0;
1988                 }
1989                 pi = i;
1990                 i = i->next;
1991         }
1992
1993         /* we can't find the right switch */
1994         ast_pthread_mutex_unlock(&con->lock);
1995         return -1;
1996 }
1997
1998 /*
1999  * This functions lock contexts list, search for the right context,
2000  * call ast_context_remove_extension2, unlock contexts list and return.
2001  * In this function we are using
2002  */
2003 int ast_context_remove_extension(char *context, char *extension, int priority, char *registrar)
2004 {
2005         struct ast_context *c;
2006
2007         if (ast_lock_contexts()) return -1;
2008
2009         /* walk contexts ... */
2010         c = ast_walk_contexts(NULL);
2011         while (c) {
2012                 /* ... search for the right one ... */
2013                 if (!strcmp(ast_get_context_name(c), context)) {
2014                         /* ... remove extension ... */
2015                         int ret = ast_context_remove_extension2(c, extension, priority,
2016                                 registrar);
2017                         /* ... unlock contexts list and return */
2018                         ast_unlock_contexts();
2019                         return ret;
2020                 }
2021                 c = ast_walk_contexts(c);
2022         }
2023
2024         /* we can't find the right context */
2025         ast_unlock_contexts();
2026         return -1;
2027 }
2028
2029 /*
2030  * When do you want to call this function, make sure that &conlock is locked,
2031  * because some process can handle with your *con context before you lock
2032  * it.
2033  *
2034  * This functionc locks given context, search for the right extension and
2035  * fires out all peer in this extensions with given priority. If priority
2036  * is set to 0, all peers are removed. After that, unlock context and
2037  * return.
2038  */
2039 int ast_context_remove_extension2(struct ast_context *con, char *extension, int priority, char *registrar)
2040 {
2041         struct ast_exten *exten, *prev_exten = NULL;
2042
2043         if (ast_pthread_mutex_lock(&con->lock)) return -1;
2044
2045         /* go through all extensions in context and search the right one ... */
2046         exten = con->root;
2047         while (exten) {
2048
2049                 /* look for right extension */
2050                 if (!strcmp(exten->exten, extension) &&
2051                         (!strcmp(exten->registrar, registrar) || !registrar)) {
2052                         struct ast_exten *peer;
2053
2054                         /* should we free all peers in this extension? (priority == 0)? */
2055                         if (priority == 0) {
2056                                 /* remove this extension from context list */
2057                                 if (prev_exten)
2058                                         prev_exten->next = exten->next;
2059                                 else
2060                                         con->root = exten->next;
2061
2062                                 /* fire out all peers */
2063                                 peer = exten; 
2064                                 while (peer) {
2065                                         exten = peer->peer;
2066                                         
2067                                         if (!peer->priority==PRIORITY_HINT) 
2068                                             ast_remove_hint(peer);
2069
2070                                         peer->datad(peer->data);
2071                                         free(peer);
2072
2073                                         peer = exten;
2074                                 }
2075
2076                                 ast_pthread_mutex_unlock(&con->lock);
2077                                 return 0;
2078                         } else {
2079                                 /* remove only extension with exten->priority == priority */
2080                                 struct ast_exten *previous_peer = NULL;
2081
2082                                 peer = exten;
2083                                 while (peer) {
2084                                         /* is this our extension? */
2085                                         if (peer->priority == priority &&
2086                                                 (!strcmp(peer->registrar, registrar) || !registrar)) {
2087                                                 /* we are first priority extension? */
2088                                                 if (!previous_peer) {
2089                                                         /* exists previous extension here? */
2090                                                         if (prev_exten) {
2091                                                                 /* yes, so we must change next pointer in
2092                                                                  * previous connection to next peer
2093                                                                  */
2094                                                                 if (peer->peer) {
2095                                                                         prev_exten->next = peer->peer;
2096                                                                         peer->peer->next = exten->next;
2097                                                                 } else
2098                                                                         prev_exten->next = exten->next;
2099                                                         } else {
2100                                                                 /* no previous extension, we are first
2101                                                                  * extension, so change con->root ...
2102                                                                  */
2103                                                                 if (peer->peer)
2104                                                                         con->root = peer->peer;
2105                                                                 else
2106                                                                         con->root = exten->next; 
2107                                                         }
2108                                                 } else {
2109                                                         /* we are not first priority in extension */
2110                                                         previous_peer->peer = peer->peer;
2111                                                 }
2112
2113                                                 /* now, free whole priority extension */
2114                                                 if (peer->priority==PRIORITY_HINT)
2115                                                     ast_remove_hint(peer);
2116                                                 peer->datad(peer->data);
2117                                                 free(peer);
2118
2119                                                 ast_pthread_mutex_unlock(&con->lock);
2120                                                 return 0;
2121                                         } else {
2122                                                 /* this is not right extension, skip to next peer */
2123                                                 previous_peer = peer;
2124                                                 peer = peer->peer;
2125                                         }
2126                                 }
2127
2128                                 ast_pthread_mutex_unlock(&con->lock);
2129                                 return -1;
2130                         }
2131                 }
2132
2133                 prev_exten = exten;
2134                 exten = exten->next;
2135         }
2136
2137         /* we can't find right extension */
2138         ast_pthread_mutex_unlock(&con->lock);
2139         return -1;
2140 }
2141
2142
2143 int ast_register_application(char *app, int (*execute)(struct ast_channel *, void *), char *synopsis, char *description)
2144 {
2145         struct ast_app *tmp, *prev, *cur;
2146         char tmps[80];
2147         if (ast_pthread_mutex_lock(&applock)) {
2148                 ast_log(LOG_ERROR, "Unable to lock application list\n");
2149                 return -1;
2150         }
2151         tmp = apps;
2152         while(tmp) {
2153                 if (!strcasecmp(app, tmp->name)) {
2154                         ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
2155                         ast_pthread_mutex_unlock(&applock);
2156                         return -1;
2157                 }
2158                 tmp = tmp->next;
2159         }
2160         tmp = malloc(sizeof(struct ast_app));
2161         if (tmp) {
2162                 memset(tmp, 0, sizeof(struct ast_app));
2163                 strncpy(tmp->name, app, sizeof(tmp->name)-1);
2164                 tmp->execute = execute;
2165                 tmp->synopsis = synopsis;
2166                 tmp->description = description;
2167                 /* Store in alphabetical order */
2168                 cur = apps;
2169                 prev = NULL;
2170                 while(cur) {
2171                         if (strcasecmp(tmp->name, cur->name) < 0)
2172                                 break;
2173                         prev = cur;
2174                         cur = cur->next;
2175                 }
2176                 if (prev) {
2177                         tmp->next = prev->next;
2178                         prev->next = tmp;
2179                 } else {
2180                         tmp->next = apps;
2181                         apps = tmp;
2182                 }
2183         } else {
2184                 ast_log(LOG_WARNING, "Out of memory\n");
2185                 ast_pthread_mutex_unlock(&applock);
2186                 return -1;
2187         }
2188         if (option_verbose > 1)
2189                 ast_verbose( VERBOSE_PREFIX_2 "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
2190         ast_pthread_mutex_unlock(&applock);
2191         return 0;
2192 }
2193
2194 int ast_register_switch(struct ast_switch *sw)
2195 {
2196         struct ast_switch *tmp, *prev=NULL;
2197         if (ast_pthread_mutex_lock(&switchlock)) {
2198                 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
2199                 return -1;
2200         }
2201         tmp = switches;
2202         while(tmp) {
2203                 if (!strcasecmp(tmp->name, sw->name))
2204                         break;
2205                 prev = tmp;
2206                 tmp = tmp->next;
2207         }
2208         if (tmp) {      
2209                 ast_pthread_mutex_unlock(&switchlock);
2210                 ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name);
2211                 return -1;
2212         }
2213         sw->next = NULL;
2214         if (prev) 
2215                 prev->next = sw;
2216         else
2217                 switches = sw;
2218         ast_pthread_mutex_unlock(&switchlock);
2219         return 0;
2220 }
2221
2222 void ast_unregister_switch(struct ast_switch *sw)
2223 {
2224         struct ast_switch *tmp, *prev=NULL;
2225         if (ast_pthread_mutex_lock(&switchlock)) {
2226                 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
2227                 return;
2228         }
2229         tmp = switches;
2230         while(tmp) {
2231                 if (tmp == sw) {
2232                         if (prev)
2233                                 prev->next = tmp->next;
2234                         else
2235                                 switches = tmp->next;
2236                         tmp->next = NULL;
2237                         break;                  
2238                 }
2239                 prev = tmp;
2240                 tmp = tmp->next;
2241         }
2242         ast_pthread_mutex_unlock(&switchlock);
2243 }
2244
2245 /*
2246  * Help for CLI commands ...
2247  */
2248 static char show_application_help[] = 
2249 "Usage: show application <application> [<application> [<application> [...]]]\n"
2250 "       Describes a particular application.\n";
2251
2252 static char show_applications_help[] =
2253 "Usage: show applications\n"
2254 "       List applications which are currently available.\n";
2255
2256 static char show_dialplan_help[] =
2257 "Usage: show dialplan [exten@][context]\n"
2258 "       Show dialplan\n";
2259
2260 static char show_switches_help[] = 
2261 "Usage: show switches\n"
2262 "       Show registered switches\n";
2263
2264 /*
2265  * IMPLEMENTATION OF CLI FUNCTIONS IS IN THE SAME ORDER AS COMMANDS HELPS
2266  *
2267  */
2268
2269 /*
2270  * 'show application' CLI command implementation functions ...
2271  */
2272
2273 /*
2274  * There is a possibility to show informations about more than one
2275  * application at one time. You can type 'show application Dial Echo' and
2276  * you will see informations about these two applications ...
2277  */
2278 static char *complete_show_application(char *line, char *word,
2279         int pos, int state)
2280 {
2281         struct ast_app *a;
2282         int which = 0;
2283
2284         /* try to lock applications list ... */
2285         if (ast_pthread_mutex_lock(&applock)) {
2286                 ast_log(LOG_ERROR, "Unable to lock application list\n");
2287                 return NULL;
2288         }
2289
2290         /* ... walk all applications ... */
2291         a = apps; 
2292         while (a) {
2293                 /* ... check if word matches this application ... */
2294                 if (!strncasecmp(word, a->name, strlen(word))) {
2295                         /* ... if this is right app serve it ... */
2296                         if (++which > state) {
2297                                 char *ret = strdup(a->name);
2298                                 ast_pthread_mutex_unlock(&applock);
2299                                 return ret;
2300                         }
2301                 }
2302                 a = a->next; 
2303         }
2304
2305         /* no application match */
2306         ast_pthread_mutex_unlock(&applock);
2307         return NULL; 
2308 }
2309
2310 static int handle_show_application(int fd, int argc, char *argv[])
2311 {
2312         struct ast_app *a;
2313         char buf[2048];
2314         int app, no_registered_app = 1;
2315
2316         if (argc < 3) return RESULT_SHOWUSAGE;
2317
2318         /* try to lock applications list ... */
2319         if (ast_pthread_mutex_lock(&applock)) {
2320                 ast_log(LOG_ERROR, "Unable to lock application list\n");
2321                 return -1;
2322         }
2323
2324         /* ... go through all applications ... */
2325         a = apps; 
2326         while (a) {
2327                 /* ... compare this application name with all arguments given
2328                  * to 'show application' command ... */
2329                 for (app = 2; app < argc; app++) {
2330                         if (!strcasecmp(a->name, argv[app])) {
2331                                 no_registered_app = 0;
2332
2333                                 /* ... one of our applications, show info ...*/
2334                                 snprintf(buf, sizeof(buf),
2335                                         "\n  -= Info about application '%s' =- \n\n"
2336                                         "[Synopsis]:\n  %s\n\n"
2337                                         "[Description]:\n%s\n",
2338                                         a->name,
2339                                         a->synopsis ? a->synopsis : "Not available",
2340                                         a->description ? a-> description : "Not available");
2341                                 ast_cli(fd, buf);
2342                         }
2343                 }
2344                 a = a->next; 
2345         }
2346
2347         ast_pthread_mutex_unlock(&applock);
2348
2349         /* we found at least one app? no? */
2350         if (no_registered_app) {
2351                 ast_cli(fd, "Your application(s) is (are) not registered\n");
2352                 return RESULT_FAILURE;
2353         }
2354
2355         return RESULT_SUCCESS;
2356 }
2357
2358 static int handle_show_switches(int fd, int argc, char *argv[])
2359 {
2360         struct ast_switch *sw;
2361         if (!switches) {
2362                 ast_cli(fd, "There are no registered alternative switches\n");
2363                 return RESULT_SUCCESS;
2364         }
2365         /* ... we have applications ... */
2366         ast_cli(fd, "\n    -= Registered Asterisk Alternative Switches =-\n");
2367         if (ast_pthread_mutex_lock(&switchlock)) {
2368                 ast_log(LOG_ERROR, "Unable to lock switches\n");
2369                 return -1;
2370         }
2371         sw = switches;
2372         while (sw) {
2373                 ast_cli(fd, "%s: %s\n", sw->name, sw->description);
2374                 sw = sw->next;
2375         }
2376         ast_pthread_mutex_unlock(&switchlock);
2377         return RESULT_SUCCESS;
2378 }
2379
2380 /*
2381  * 'show applications' CLI command implementation functions ...
2382  */
2383 static int handle_show_applications(int fd, int argc, char *argv[])
2384 {
2385         struct ast_app *a;
2386
2387         /* try to lock applications list ... */
2388         if (ast_pthread_mutex_lock(&applock)) {
2389                 ast_log(LOG_ERROR, "Unable to lock application list\n");
2390                 return -1;
2391         }
2392
2393         /* ... go to first application ... */
2394         a = apps; 
2395
2396         /* ... have we got at least one application (first)? no? */
2397         if (!a) {
2398                 ast_cli(fd, "There is no registered applications\n");
2399                 ast_pthread_mutex_unlock(&applock);
2400                 return -1;
2401         }
2402
2403         /* ... we have applications ... */
2404         ast_cli(fd, "\n    -= Registered Asterisk Applications =-\n");
2405
2406         /* ... go through all applications ... */
2407         while (a) {
2408                 /* ... show informations about applications ... */
2409                 ast_cli(fd,"  %15s: %s\n",
2410                         a->name,
2411                         a->synopsis ? a->synopsis : "<Synopsis not available>");
2412                 a = a->next; 
2413         }
2414
2415         /* ... unlock and return */
2416         ast_pthread_mutex_unlock(&applock);
2417
2418         return RESULT_SUCCESS;
2419 }
2420
2421 /*
2422  * 'show dialplan' CLI command implementation functions ...
2423  */
2424 static char *complete_show_dialplan_context(char *line, char *word, int pos,
2425         int state)
2426 {
2427         struct ast_context *c;
2428         int which = 0;
2429
2430         /* we are do completion of [exten@]context on second position only */
2431         if (pos != 2) return NULL;
2432
2433         /* try to lock contexts list ... */
2434         if (ast_lock_contexts()) {
2435                 ast_log(LOG_ERROR, "Unable to lock context list\n");
2436                 return NULL;
2437         }
2438
2439         /* ... walk through all contexts ... */
2440         c = ast_walk_contexts(NULL);
2441         while(c) {
2442                 /* ... word matches context name? yes? ... */
2443                 if (!strncasecmp(word, ast_get_context_name(c), strlen(word))) {
2444                         /* ... for serve? ... */
2445                         if (++which > state) {
2446                                 /* ... yes, serve this context name ... */
2447                                 char *ret = strdup(ast_get_context_name(c));
2448                                 ast_unlock_contexts();
2449                                 return ret;
2450                         }
2451                 }
2452                 c = ast_walk_contexts(c);
2453         }
2454
2455         /* ... unlock and return */
2456         ast_unlock_contexts();
2457         return NULL;
2458 }
2459
2460 static int handle_show_dialplan(int fd, int argc, char *argv[])
2461 {
2462         struct ast_context *c;
2463         char *exten = NULL, *context = NULL;
2464         int context_existence = 0, extension_existence = 0;
2465
2466         if (argc != 3 && argc != 2) return -1;
2467
2468         /* we obtain [exten@]context? if yes, split them ... */
2469         if (argc == 3) {
2470                 char *splitter = argv[2];
2471                 /* is there a '@' character? */
2472                 if (strchr(argv[2], '@')) {
2473                         /* yes, split into exten & context ... */
2474                         exten   = strsep(&splitter, "@");
2475                         context = splitter;
2476
2477                         /* check for length and change to NULL if !strlen() */
2478                         if (!strlen(exten))   exten = NULL;
2479                         if (!strlen(context)) context = NULL;
2480                 } else
2481                 {
2482                         /* no '@' char, only context given */
2483                         context = argv[2];
2484                         if (!strlen(context)) context = NULL;
2485                 }
2486         }
2487
2488         /* try to lock contexts */
2489         if (ast_lock_contexts()) {
2490                 ast_cli(LOG_WARNING, "Failed to lock contexts list\n");
2491                 return RESULT_FAILURE;
2492         }
2493
2494         /* walk all contexts ... */
2495         c = ast_walk_contexts(NULL);
2496         while (c) {
2497                 /* show this context? */
2498                 if (!context ||
2499                         !strcmp(ast_get_context_name(c), context)) {
2500                         context_existence = 1;
2501
2502                         /* try to lock context before walking in ... */
2503                         if (!ast_lock_context(c)) {
2504                                 struct ast_exten *e;
2505                                 struct ast_include *i;
2506                                 struct ast_ignorepat *ip;
2507                                 struct ast_sw *sw;
2508                                 char buf[256], buf2[256];
2509                                 int context_info_printed = 0;
2510
2511                                 /* are we looking for exten too? if yes, we print context
2512                                  * if we our extension only
2513                                  */
2514                                 if (!exten) {
2515                                         ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
2516                                                 ast_get_context_name(c), ast_get_context_registrar(c));
2517                                         context_info_printed = 1;
2518                                 }
2519
2520                                 /* walk extensions ... */
2521                                 e = ast_walk_context_extensions(c, NULL);
2522                                 while (e) {
2523                                         struct ast_exten *p;
2524
2525                                         /* looking for extension? is this our extension? */
2526                                         if (exten &&
2527                                                 strcmp(ast_get_extension_name(e), exten))
2528                                         {
2529                                                 /* we are looking for extension and it's not our
2530                                                  * extension, so skip to next extension */
2531                                                 e = ast_walk_context_extensions(c, e);
2532                                                 continue;
2533                                         }
2534
2535                                         extension_existence = 1;
2536
2537                                         /* may we print context info? */        
2538                                         if (!context_info_printed) {
2539                                                 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
2540                                                         ast_get_context_name(c),
2541                                                         ast_get_context_registrar(c));
2542                                                 context_info_printed = 1;
2543                                         }
2544
2545                                         /* write extension name and first peer */       
2546                                         bzero(buf, sizeof(buf));                
2547                                         snprintf(buf, sizeof(buf), "'%s' =>",
2548                                                 ast_get_extension_name(e));
2549
2550                                         snprintf(buf2, sizeof(buf2),
2551                                                 "%d. %s(%s)",
2552                                                 ast_get_extension_priority(e),
2553                                                 ast_get_extension_app(e),
2554                                                 (char *)ast_get_extension_app_data(e));
2555
2556                                         ast_cli(fd, "  %-17s %-45s [%s]\n", buf, buf2,
2557                                                 ast_get_extension_registrar(e));
2558
2559                                         /* walk next extension peers */
2560                                         p = ast_walk_extension_priorities(e, e);
2561                                         while (p) {
2562                                                 bzero((void *)buf2, sizeof(buf2));
2563
2564                                                 snprintf(buf2, sizeof(buf2),
2565                                                         "%d. %s(%s)",
2566                                                         ast_get_extension_priority(p),
2567                                                         ast_get_extension_app(p),
2568                                                         (char *)ast_get_extension_app_data(p));
2569
2570                                                 ast_cli(fd,"  %-17s %-45s [%s]\n",
2571                                                         "", buf2,
2572                                                         ast_get_extension_registrar(p));        
2573
2574                                                 p = ast_walk_extension_priorities(e, p);
2575                                         }
2576                                         e = ast_walk_context_extensions(c, e);
2577                                 }
2578
2579                                 /* include & ignorepat we all printing if we are not
2580                                  * looking for exact extension
2581                                  */
2582                                 if (!exten) {
2583                                         if (ast_walk_context_extensions(c, NULL))
2584                                                 ast_cli(fd, "\n");
2585
2586                                         /* walk included and write info ... */
2587                                         i = ast_walk_context_includes(c, NULL);
2588                                         while (i) {
2589                                                 bzero(buf, sizeof(buf));
2590                                                 snprintf(buf, sizeof(buf), "'%s'",
2591                                                         ast_get_include_name(i));
2592                                                 ast_cli(fd, "  Include =>        %-45s [%s]\n",
2593                                                         buf, ast_get_include_registrar(i));
2594                                                 i = ast_walk_context_includes(c, i);
2595                                         }
2596
2597                                         /* walk ignore patterns and write info ... */
2598                                         ip = ast_walk_context_ignorepats(c, NULL);
2599                                         while (ip) {
2600                                                 bzero(buf, sizeof(buf));
2601                                                 snprintf(buf, sizeof(buf), "'%s'",
2602                                                         ast_get_ignorepat_name(ip));
2603                                                 ast_cli(fd, "  Ignore pattern => %-45s [%s]\n",
2604                                                         buf, ast_get_ignorepat_registrar(ip));  
2605                                                 ip = ast_walk_context_ignorepats(c, ip);
2606                                         }
2607                                         sw = ast_walk_context_switches(c, NULL);
2608                                         while(sw) {
2609                                                 bzero(buf, sizeof(buf));
2610                                                 snprintf(buf, sizeof(buf), "'%s/%s'",
2611                                                         ast_get_switch_name(sw),
2612                                                         ast_get_switch_data(sw));
2613                                                 ast_cli(fd, "  Alt. Switch =>    %-45s [%s]\n",
2614                                                         buf, ast_get_switch_registrar(sw));     
2615                                                 sw = ast_walk_context_switches(c, sw);
2616                                         }
2617                                 }
2618         
2619                                 ast_unlock_context(c);
2620
2621                                 /* if we print something in context, make an empty line */
2622                                 if (context_info_printed) ast_cli(fd, "\n");
2623                         }
2624                 }
2625                 c = ast_walk_contexts(c);
2626         }
2627         ast_unlock_contexts();
2628
2629         /* check for input failure and throw some error messages */
2630         if (context && !context_existence) {
2631                 ast_cli(fd, "There is no existence of '%s' context\n",
2632                         context);
2633                 return RESULT_FAILURE;
2634         }
2635
2636         if (exten && !extension_existence) {
2637                 if (context)
2638                         ast_cli(fd, "There is no existence of %s@%s extension\n",
2639                                 exten, context);
2640                 else
2641                         ast_cli(fd,
2642                                 "There is no existence of '%s' extension in all contexts\n",
2643                                 exten);
2644                 return RESULT_FAILURE;
2645         }
2646
2647         /* everything ok */
2648         return RESULT_SUCCESS;
2649 }
2650
2651 /*
2652  * CLI entries for upper commands ...
2653  */
2654 static struct ast_cli_entry show_applications_cli = 
2655         { { "show", "applications", NULL }, 
2656         handle_show_applications, "Shows registered applications",
2657         show_applications_help };
2658
2659 static struct ast_cli_entry show_application_cli =
2660         { { "show", "application", NULL }, 
2661         handle_show_application, "Describe a specific application",
2662         show_application_help, complete_show_application };
2663
2664 static struct ast_cli_entry show_dialplan_cli =
2665         { { "show", "dialplan", NULL },
2666                 handle_show_dialplan, "Show dialplan",
2667                 show_dialplan_help, complete_show_dialplan_context };
2668
2669 static struct ast_cli_entry show_switches_cli =
2670         { { "show", "switches", NULL },
2671                 handle_show_switches, "Show alternative switches",
2672                 show_switches_help, NULL };
2673
2674 int ast_unregister_application(char *app) {
2675         struct ast_app *tmp, *tmpl = NULL;
2676         if (ast_pthread_mutex_lock(&applock)) {
2677                 ast_log(LOG_ERROR, "Unable to lock application list\n");
2678                 return -1;
2679         }
2680         tmp = apps;
2681         while(tmp) {
2682                 if (!strcasecmp(app, tmp->name)) {
2683                         if (tmpl)
2684                                 tmpl->next = tmp->next;
2685                         else
2686                                 apps = tmp->next;
2687                         if (option_verbose > 1)
2688                                 ast_verbose( VERBOSE_PREFIX_2 "Unregistered application '%s'\n", tmp->name);
2689                         ast_pthread_mutex_unlock(&applock);
2690                         return 0;
2691                 }
2692                 tmpl = tmp;
2693                 tmp = tmp->next;
2694         }
2695         ast_pthread_mutex_unlock(&applock);
2696         return -1;
2697 }
2698
2699 struct ast_context *ast_context_create(char *name, char *registrar)
2700 {
2701         struct ast_context *tmp;
2702         
2703         ast_pthread_mutex_lock(&conlock);
2704         tmp = contexts;
2705         while(tmp) {
2706                 if (!strcasecmp(tmp->name, name)) {
2707                         ast_pthread_mutex_unlock(&conlock);
2708                         ast_log(LOG_WARNING, "Tried to register context '%s', already in use\n", name);
2709                         return NULL;
2710                 }
2711                 tmp = tmp->next;
2712         }
2713         tmp = malloc(sizeof(struct ast_context));
2714         if (tmp) {
2715                 memset(tmp, 0, sizeof(struct ast_context));
2716                 ast_pthread_mutex_init(&tmp->lock);
2717                 strncpy(tmp->name, name, sizeof(tmp->name)-1);
2718                 tmp->root = NULL;
2719                 tmp->registrar = registrar;
2720                 tmp->next = contexts;
2721                 tmp->includes = NULL;
2722                 tmp->ignorepats = NULL;
2723                 contexts = tmp;
2724                 if (option_debug)
2725                         ast_log(LOG_DEBUG, "Registered context '%s'\n", tmp->name);
2726                 else if (option_verbose > 2)
2727                         ast_verbose( VERBOSE_PREFIX_3 "Registered extension context '%s'\n", tmp->name);
2728         } else
2729                 ast_log(LOG_WARNING, "Out of memory\n");
2730         
2731         ast_pthread_mutex_unlock(&conlock);
2732         return tmp;
2733 }
2734
2735 /*
2736  * errno values
2737  *  EBUSY  - can't lock
2738  *  ENOENT - no existence of context
2739  */
2740 int ast_context_add_include(char *context, char *include, char *registrar)
2741 {
2742         struct ast_context *c;
2743
2744         if (ast_lock_contexts()) {
2745                 errno = EBUSY;
2746                 return -1;
2747         }
2748
2749         /* walk contexts ... */
2750         c = ast_walk_contexts(NULL);
2751         while (c) {
2752                 /* ... search for the right one ... */
2753                 if (!strcmp(ast_get_context_name(c), context)) {
2754                         int ret = ast_context_add_include2(c, include, registrar);
2755                         /* ... unlock contexts list and return */
2756                         ast_unlock_contexts();
2757                         return ret;
2758                 }
2759                 c = ast_walk_contexts(c);
2760         }
2761
2762         /* we can't find the right context */
2763         ast_unlock_contexts();
2764         errno = ENOENT;
2765         return -1;
2766 }
2767
2768 #define FIND_NEXT \
2769 do { \
2770         c = info; \
2771         while(*c && (*c != '|')) c++; \
2772         if (*c) { *c = '\0'; c++; } else c = NULL; \
2773 } while(0)
2774
2775 static void get_timerange(struct ast_include *i, char *times)
2776 {
2777         char *e;
2778         int x;
2779         int s1, s2;
2780         int e1, e2;
2781
2782         //[PHM 07/01/03]
2783         //start disabling all times, fill the fields with 0's, as they may contain garbage
2784         for(x=0;x<24;x++)
2785                 i->minmask[x]=0;
2786         
2787         /* Star is all times */
2788         if (!strlen(times) || !strcmp(times, "*")) {
2789                 for (x=0;x<24;x++)
2790                         i->minmask[x] = (1 << 30) - 1;
2791                 return;
2792         }
2793         /* Otherwise expect a range */
2794         e = strchr(times, '-');
2795         if (!e) {
2796                 ast_log(LOG_WARNING, "Time range is not valid. Assuming no time.\n");
2797                 return;
2798         }
2799         *e = '\0';
2800         e++;
2801         while(*e && !isdigit(*e)) e++;
2802         if (!*e) {
2803                 ast_log(LOG_WARNING, "Invalid time range.  Assuming no time.\n");
2804                 return;
2805         }
2806         if (sscanf(times, "%d:%d", &s1, &s2) != 2) {
2807                 ast_log(LOG_WARNING, "%s isn't a time.  Assuming no time.\n", times);
2808                 return;
2809         }
2810         if (sscanf(e, "%d:%d", &e1, &e2) != 2) {
2811                 ast_log(LOG_WARNING, "%s isn't a time.  Assuming no time.\n", e);
2812                 return;
2813         }
2814         s1 = s1 * 30 + s2/2;
2815         if ((s1 < 0) || (s1 >= 24*30)) {
2816                 ast_log(LOG_WARNING, "%s isn't a valid star time. Assuming no time.\n", times);
2817                 return;
2818         }
2819         e1 = e1 * 30 + e2/2;
2820         if ((e1 < 0) || (e2 >= 24*30)) {
2821                 ast_log(LOG_WARNING, "%s isn't a valid start time. Assuming no time.\n", times);
2822                 return;
2823         }
2824         /* Go through the time and enable each appropriate bit */
2825         for (x=s1;x != e1;x = (x + 1) % (24 * 30)) {
2826                 i->minmask[x/30] |= (1 << (x % 30));
2827         }
2828         /* Do the last one */
2829         i->minmask[x/30] |= (1 << (x % 30));
2830         /* All done */
2831 }
2832
2833 static char *days[] =
2834 {
2835         "sun",
2836         "mon",
2837         "tue",
2838         "wed",
2839         "thu",
2840         "fri",
2841         "sat",
2842 };
2843
2844 static unsigned int get_dow(char *dow)
2845 {
2846         char *c;
2847         /* The following line is coincidence, really! */
2848         int s, e, x;
2849         unsigned int mask;
2850         /* Check for all days */
2851         if (!strlen(dow) || !strcmp(dow, "*"))
2852                 return (1 << 7) - 1;
2853         /* Get start and ending days */
2854         c = strchr(dow, '-');
2855         if (c) {
2856                 *c = '\0';
2857                 c++;
2858         } else
2859                 c = NULL;
2860         /* Find the start */
2861         s = 0;
2862         while((s < 7) && strcasecmp(dow, days[s])) s++;
2863         if (s >= 7) {
2864                 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", dow);
2865                 return 0;
2866         }
2867         if (c) {
2868                 e = 0;
2869                 while((e < 7) && strcasecmp(c, days[e])) e++;
2870                 if (e >= 7) {
2871                         ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
2872                         return 0;
2873                 }
2874         } else
2875                 e = s;
2876         mask = 0;
2877         for (x=s;x!=e;x = (x + 1) % 7) {
2878                 mask |= (1 << x);
2879         }
2880         /* One last one */
2881         mask |= (1 << x);
2882         return mask;
2883 }
2884
2885 static unsigned int get_day(char *day)
2886 {
2887         char *c;
2888         /* The following line is coincidence, really! */
2889         int s, e, x;
2890         unsigned int mask;
2891         /* Check for all days */
2892         if (!strlen(day) || !strcmp(day, "*")) {
2893                 mask = (1 << 30)  + ((1 << 30) - 1);
2894                 return mask;
2895         }
2896         /* Get start and ending days */
2897         c = strchr(day, '-');
2898         if (c) {
2899                 *c = '\0';
2900                 c++;
2901         }
2902         /* Find the start */
2903         if (sscanf(day, "%d", &s) != 1) {
2904                 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", day);
2905                 return 0;
2906         }
2907         if ((s < 1) || (s > 31)) {
2908                 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", day);
2909                 return 0;
2910         }
2911         s--;
2912         if (c) {
2913                 if (sscanf(c, "%d", &e) != 1) {
2914                         ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
2915                         return 0;
2916                 }
2917                 if ((e < 1) || (e > 31)) {
2918                         ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
2919                         return 0;
2920                 }
2921                 e--;
2922         } else
2923                 e = s;
2924         mask = 0;
2925         for (x=s;x!=e;x = (x + 1) % 31) {
2926                 mask |= (1 << x);
2927         }
2928         mask |= (1 << x);
2929         return mask;
2930 }
2931
2932 static char *months[] =
2933 {
2934         "jan",
2935         "feb",
2936         "mar",
2937         "apr",
2938         "may",
2939         "jun",
2940         "jul",
2941         "aug",
2942         "sep",
2943         "oct",
2944         "nov",
2945         "dec",
2946 };
2947
2948 static unsigned int get_month(char *mon)
2949 {
2950         char *c;
2951         /* The following line is coincidence, really! */
2952         int s, e, x;
2953         unsigned int mask;
2954         /* Check for all days */
2955         if (!strlen(mon) || !strcmp(mon, "*")) 
2956                 return (1 << 12) - 1;
2957         /* Get start and ending days */
2958         c = strchr(mon, '-');
2959         if (c) {
2960                 *c = '\0';
2961                 c++;
2962         }
2963         /* Find the start */
2964         s = 0;
2965         while((s < 12) && strcasecmp(mon, months[s])) s++;
2966         if (s >= 12) {
2967                 ast_log(LOG_WARNING, "Invalid month '%s', assuming none\n", mon);
2968                 return 0;
2969         }
2970         if (c) {
2971                 e = 0;
2972                 while((e < 12) && strcasecmp(mon, months[e])) e++;
2973                 if (e >= 12) {
2974                         ast_log(LOG_WARNING, "Invalid month '%s', assuming none\n", c);
2975                         return 0;
2976                 }
2977         } else
2978                 e = s;
2979         mask = 0;
2980         for (x=s;x!=e;x = (x + 1) % 12) {
2981                 mask |= (1 << x);
2982         }
2983         /* One last one */
2984         mask |= (1 << x);
2985         return mask;
2986 }
2987
2988 static void build_timing(struct ast_include *i, char *info)
2989 {
2990         char *c;
2991         /* Check for empty just in case */
2992         if (!strlen(info))
2993                 return;
2994         i->hastime = 1;
2995         /* Assume everything except time */
2996         i->monthmask = (1 << 12) - 1;
2997         i->daymask = (1 << 30) - 1 + (1 << 30);
2998         i->dowmask = (1 << 7) - 1;
2999         /* Avoid using str tok */
3000         FIND_NEXT;
3001         /* Info has the time range, start with that */
3002         get_timerange(i, info);
3003         info = c;
3004         if (!info)
3005                 return;
3006         FIND_NEXT;
3007         /* Now check for day of week */
3008         i->dowmask = get_dow(info);
3009
3010         info = c;
3011         if (!info)
3012                 return;
3013         FIND_NEXT;
3014         /* Now check for the day of the month */
3015         i->daymask = get_day(info);
3016         info = c;
3017         if (!info)
3018                 return;
3019         FIND_NEXT;
3020         /* And finally go for the month */
3021         i->monthmask = get_month(info);
3022 }
3023
3024 /*
3025  * errno values
3026  *  ENOMEM - out of memory
3027  *  EBUSY  - can't lock
3028  *  EEXIST - already included
3029  *  EINVAL - there is no existence of context for inclusion
3030  */
3031 int ast_context_add_include2(struct ast_context *con, char *value,
3032         char *registrar)
3033 {
3034         struct ast_include *new_include;
3035         char *c;
3036         struct ast_include *i, *il = NULL; /* include, include_last */
3037
3038         /* allocate new include structure ... */
3039         if (!(new_include = malloc(sizeof(struct ast_include)))) {
3040                 ast_log(LOG_WARNING, "Out of memory\n");
3041                 errno = ENOMEM;
3042                 return -1;
3043         }
3044         
3045         /* ... fill in this structure ... */
3046         memset(new_include, 0, sizeof(struct ast_include));
3047         strncpy(new_include->name, value, sizeof(new_include->name)-1);
3048         strncpy(new_include->rname, value, sizeof(new_include->rname)-1);
3049         c = new_include->rname;
3050         /* Strip off timing info */
3051         while(*c && (*c != '|')) c++; 
3052         /* Process if it's there */
3053         if (*c) {
3054                 build_timing(new_include, c+1);
3055                 *c = '\0';
3056         }
3057         new_include->next      = NULL;
3058         new_include->registrar = registrar;
3059
3060         /* ... try to lock this context ... */
3061         if (ast_pthread_mutex_lock(&con->lock)) {
3062                 free(new_include);
3063                 errno = EBUSY;
3064                 return -1;
3065         }
3066
3067         /* ... go to last include and check if context is already included too... */
3068         i = con->includes;
3069         while (i) {
3070                 if (!strcasecmp(i->name, new_include->name)) {
3071                         free(new_include);
3072                         ast_pthread_mutex_unlock(&con->lock);
3073                         errno = EEXIST;
3074                         return -1;
3075                 }
3076                 il = i;
3077                 i = i->next;
3078         }
3079
3080         /* ... include new context into context list, unlock, return */
3081         if (il)
3082                 il->next = new_include;
3083         else
3084                 con->includes = new_include;
3085         if (option_verbose > 2)
3086                 ast_verbose(VERBOSE_PREFIX_3 "Including context '%s' in context '%s'\n", new_include->name, ast_get_context_name(con)); 
3087         ast_pthread_mutex_unlock(&con->lock);
3088
3089         return 0;
3090 }
3091
3092 /*
3093  * errno values
3094  *  EBUSY  - can't lock
3095  *  ENOENT - no existence of context
3096  */
3097 int ast_context_add_switch(char *context, char *sw, char *data, char *registrar)
3098 {
3099         struct ast_context *c;
3100
3101         if (ast_lock_contexts()) {
3102                 errno = EBUSY;
3103                 return -1;
3104         }
3105
3106         /* walk contexts ... */
3107         c = ast_walk_contexts(NULL);
3108         while (c) {
3109                 /* ... search for the right one ... */
3110                 if (!strcmp(ast_get_context_name(c), context)) {
3111                         int ret = ast_context_add_switch2(c, sw, data, registrar);
3112                         /* ... unlock contexts list and return */
3113                         ast_unlock_contexts();
3114                         return ret;
3115                 }
3116                 c = ast_walk_contexts(c);
3117         }
3118
3119         /* we can't find the right context */
3120         ast_unlock_contexts();
3121         errno = ENOENT;
3122         return -1;
3123 }
3124
3125 /*
3126  * errno values
3127  *  ENOMEM - out of memory
3128  *  EBUSY  - can't lock
3129  *  EEXIST - already included
3130  *  EINVAL - there is no existence of context for inclusion
3131  */
3132 int ast_context_add_switch2(struct ast_context *con, char *value,
3133         char *data, char *registrar)
3134 {
3135         struct ast_sw *new_sw;
3136         struct ast_sw *i, *il = NULL; /* sw, sw_last */
3137
3138         /* allocate new sw structure ... */
3139         if (!(new_sw = malloc(sizeof(struct ast_sw)))) {
3140                 ast_log(LOG_WARNING, "Out of memory\n");
3141                 errno = ENOMEM;
3142                 return -1;
3143         }
3144         
3145         /* ... fill in this structure ... */
3146         memset(new_sw, 0, sizeof(struct ast_sw));
3147         strncpy(new_sw->name, value, sizeof(new_sw->name)-1);
3148         if (data)
3149                 strncpy(new_sw->data, data, sizeof(new_sw->data)-1);
3150         else
3151                 strncpy(new_sw->data, "", sizeof(new_sw->data)-1);
3152         new_sw->next      = NULL;
3153         new_sw->registrar = registrar;
3154
3155         /* ... try to lock this context ... */
3156         if (ast_pthread_mutex_lock(&con->lock)) {
3157                 free(new_sw);
3158                 errno = EBUSY;
3159                 return -1;
3160         }
3161
3162         /* ... go to last sw and check if context is already swd too... */
3163         i = con->alts;
3164         while (i) {
3165                 if (!strcasecmp(i->name, new_sw->name)) {
3166                         free(new_sw);
3167                         ast_pthread_mutex_unlock(&con->lock);
3168                         errno = EEXIST;
3169                         return -1;
3170                 }
3171                 il = i;
3172                 i = i->next;
3173         }
3174
3175         /* ... sw new context into context list, unlock, return */
3176         if (il)
3177                 il->next = new_sw;
3178         else
3179                 con->alts = new_sw;
3180         if (option_verbose > 2)
3181                 ast_verbose(VERBOSE_PREFIX_3 "Including switch '%s/%s' in context '%s'\n", new_sw->name, new_sw->data, ast_get_context_name(con)); 
3182         ast_pthread_mutex_unlock(&con->lock);
3183
3184         return 0;
3185 }
3186
3187 /*
3188  * EBUSY  - can't lock
3189  * ENOENT - there is not context existence
3190  */
3191 int ast_context_remove_ignorepat(char *context, char *ignorepat, char *registrar)
3192 {
3193         struct ast_context *c;
3194
3195         if (ast_lock_contexts()) {
3196                 errno = EBUSY;
3197                 return -1;
3198         }
3199
3200         c = ast_walk_contexts(NULL);
3201         while (c) {
3202                 if (!strcmp(ast_get_context_name(c), context)) {
3203                         int ret = ast_context_remove_ignorepat2(c, ignorepat, registrar);
3204                         ast_unlock_contexts();
3205                         return ret;
3206                 }
3207                 c = ast_walk_contexts(c);
3208         }
3209
3210         ast_unlock_contexts();
3211         errno = ENOENT;
3212         return -1;
3213 }
3214
3215 int ast_context_remove_ignorepat2(struct ast_context *con, char *ignorepat, char *registrar)
3216 {
3217         struct ast_ignorepat *ip, *ipl = NULL;
3218
3219         if (ast_pthread_mutex_lock(&con->lock)) {
3220                 errno = EBUSY;
3221                 return -1;
3222         }
3223
3224         ip = con->ignorepats;
3225         while (ip) {
3226                 if (!strcmp(ip->pattern, ignorepat) &&
3227                         (registrar == ip->registrar || !registrar)) {
3228                         if (ipl) {
3229                                 ipl->next = ip->next;
3230                                 free(ip);
3231                         } else {
3232                                 con->ignorepats = ip->next;
3233                                 free(ip);
3234                         }
3235                         ast_pthread_mutex_unlock(&con->lock);
3236                         return 0;
3237                 }
3238                 ipl = ip; ip = ip->next;
3239         }
3240
3241         ast_pthread_mutex_unlock(&con->lock);
3242         errno = EINVAL;
3243         return -1;
3244 }
3245
3246 /*
3247  * EBUSY - can't lock
3248  * ENOENT - there is no existence of context
3249  */
3250 int ast_context_add_ignorepat(char *con, char *value, char *registrar)
3251 {
3252         struct ast_context *c;
3253
3254         if (ast_lock_contexts()) {
3255                 errno = EBUSY;
3256                 return -1;
3257         }
3258
3259         c = ast_walk_contexts(NULL);
3260         while (c) {
3261                 if (!strcmp(ast_get_context_name(c), con)) {
3262                         int ret = ast_context_add_ignorepat2(c, value, registrar);
3263                         ast_unlock_contexts();
3264                         return ret;
3265                 } 
3266                 c = ast_walk_contexts(c);
3267         }
3268
3269         ast_unlock_contexts();
3270         errno = ENOENT;
3271         return -1;
3272 }
3273
3274 int ast_context_add_ignorepat2(struct ast_context *con, char *value, char *registrar)
3275 {
3276         struct ast_ignorepat *ignorepat, *ignorepatc, *ignorepatl = NULL;
3277         ignorepat = malloc(sizeof(struct ast_ignorepat));
3278         if (!ignorepat) {
3279                 ast_log(LOG_WARNING, "Out of memory\n");
3280                 errno = ENOMEM;
3281                 return -1;
3282         }
3283         memset(ignorepat, 0, sizeof(struct ast_ignorepat));
3284         strncpy(ignorepat->pattern, value, sizeof(ignorepat->pattern)-1);
3285         ignorepat->next = NULL;
3286         ignorepat->registrar = registrar;
3287         ast_pthread_mutex_lock(&con->lock);
3288         ignorepatc = con->ignorepats;
3289         while(ignorepatc) {
3290                 ignorepatl = ignorepatc;
3291                 if (!strcasecmp(ignorepatc->pattern, value)) {
3292                         /* Already there */
3293                         pthread_mutex_unlock(&con->lock);
3294                         errno = EEXIST;
3295                         return -1;
3296                 }
3297                 ignorepatc = ignorepatc->next;
3298         }
3299         if (ignorepatl) 
3300                 ignorepatl->next = ignorepat;
3301         else
3302                 con->ignorepats = ignorepat;
3303         pthread_mutex_unlock(&con->lock);
3304         return 0;
3305         
3306 }
3307
3308 int ast_ignore_pattern(char *context, char *pattern)
3309 {
3310         struct ast_context *con;
3311         struct ast_ignorepat *pat;
3312         con = ast_context_find(context);
3313         if (con) {
3314                 pat = con->ignorepats;
3315                 while (pat) {
3316                         if (ast_extension_match(pat->pattern, pattern))
3317                                 return 1;
3318                         pat = pat->next;
3319                 }
3320         } 
3321         return 0;
3322 }
3323
3324 /*
3325  * EBUSY   - can't lock
3326  * ENOENT  - no existence of context
3327  *
3328  */
3329 int ast_add_extension(char *context, int replace, char *extension, int priority, char *callerid,
3330         char *application, void *data, void (*datad)(void *), char *registrar)
3331 {
3332         struct ast_context *c;
3333
3334         if (ast_lock_contexts()) {
3335                 errno = EBUSY;
3336                 return -1;
3337         }
3338
3339         c = ast_walk_contexts(NULL);
3340         while (c) {
3341                 if (!strcmp(context, ast_get_context_name(c))) {
3342                         int ret = ast_add_extension2(c, replace, extension, priority, callerid,
3343                                 application, data, datad, registrar);
3344                         ast_unlock_contexts();
3345                         return ret;
3346                 }
3347                 c = ast_walk_contexts(c);
3348         }
3349
3350         ast_unlock_contexts();
3351         errno = ENOENT;
3352         return -1;
3353 }
3354
3355 int ast_async_goto(struct ast_channel *chan, char *context, char *exten, int priority, int needlock)
3356 {
3357         int res = 0;
3358         if (needlock)
3359                 ast_pthread_mutex_lock(&chan->lock);
3360         if (chan->pbx) {
3361                 /* This channel is currently in the PBX */
3362                 if (context && strlen(context))
3363                         strncpy(chan->context, context, sizeof(chan->context) - 1);
3364                 if (exten && strlen(exten))
3365                         strncpy(chan->exten, exten, sizeof(chan->context) - 1);
3366                 if (priority)
3367                         chan->priority = priority - 1;
3368                 ast_softhangup_nolock(chan, AST_SOFTHANGUP_ASYNCGOTO);
3369                 if (needlock)
3370                         ast_pthread_mutex_unlock(&chan->lock);
3371         } else {
3372                 /* In order to do it when the channel doesn't really exist within
3373                    the PBX, we have to make a new channel, masquerade, and start the PBX
3374                    at the new location */
3375                 struct ast_channel *tmpchan;
3376                 struct ast_frame *f;
3377                 tmpchan = ast_channel_alloc(0);
3378                 if (tmpchan) {
3379                         snprintf(tmpchan->name, sizeof(tmpchan->name), "AsyncGoto/%s", chan->name);
3380                         ast_setstate(tmpchan, chan->_state);
3381                         /* Make formats okay */
3382                         tmpchan->readformat = chan->readformat;
3383                         tmpchan->writeformat = chan->writeformat;
3384                         /* Setup proper location */
3385                         if (context && strlen(context))
3386                                 strncpy(tmpchan->context, context, sizeof(tmpchan->context) - 1);
3387                         else
3388                                 strncpy(tmpchan->context, chan->context, sizeof(tmpchan->context) - 1);
3389                         if (exten && strlen(exten))
3390                                 strncpy(tmpchan->exten, exten, sizeof(tmpchan->exten) - 1);
3391                         else
3392                                 strncpy(tmpchan->exten, chan->exten, sizeof(tmpchan->exten) - 1);
3393                         if (priority)
3394                                 tmpchan->priority = priority;
3395                         else
3396                                 tmpchan->priority = chan->priority;
3397                         if (needlock)
3398                                 ast_pthread_mutex_unlock(&chan->lock);
3399                         
3400                         /* Masquerade into temp channel */
3401                         ast_channel_masquerade(tmpchan, chan);
3402                         
3403                         /* Make the masquerade happen by reading a frame from the tmp channel */
3404                         f = ast_read(tmpchan);
3405                         if (f)
3406                                 ast_frfree(f);
3407                         /* Start the PBX going on our stolen channel */
3408                         if (ast_pbx_start(tmpchan)) {
3409                                 ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmpchan->name);
3410                                 ast_hangup(tmpchan);
3411                                 res = -1;
3412                         }
3413                 } else {
3414                         res = -1;
3415                         if (needlock)
3416                                 ast_pthread_mutex_unlock(&chan->lock);
3417                 }
3418         }
3419         return res;
3420 }
3421
3422 int ast_async_goto_by_name(char *channame, char *context, char *exten, int priority)
3423 {
3424         struct ast_channel *chan;
3425         chan = ast_channel_walk(NULL);
3426         while(chan) {
3427                 if (!strcasecmp(channame, chan->name))
3428                         break;
3429                 chan = ast_channel_walk(chan);
3430         }
3431         if (chan)
3432                 return ast_async_goto(chan, context, exten, priority, 1);
3433         return -1;
3434 }
3435
3436 static void ext_strncpy(char *dst, char *src, int len)
3437 {
3438         int count=0;
3439         while(*src && (count < len - 1)) {
3440                 switch(*src) {
3441                 case ' ':
3442 //otherwise exten => [a-b],1,... doesn't work
3443 //              case '-':
3444                         /* Ignore */
3445                         break;
3446                 default:
3447                         *dst = *src;
3448                         dst++;
3449                 }
3450                 src++;
3451                 count++;
3452         }
3453         *dst = '\0';
3454 }
3455
3456 /*
3457  * EBUSY - can't lock
3458  * EEXIST - extension with the same priority exist and no replace is set
3459  *
3460  */
3461 int ast_add_extension2(struct ast_context *con,
3462                                           int replace, char *extension, int priority, char *callerid,
3463                                           char *application, void *data, void (*datad)(void *),
3464                                           char *registrar)
3465 {
3466
3467 #define LOG do {        if (option_debug) {\
3468                 if (tmp->matchcid) { \
3469                         ast_log(LOG_DEBUG, "Added extension '%s' priority %d (CID match '%s') to %s\n", tmp->exten, tmp->priority, tmp->cidmatch, con->name); \
3470                 } else { \
3471                         ast_log(LOG_DEBUG, "Added extension '%s' priority %d to %s\n", tmp->exten, tmp->priority, con->name); \
3472                 } \
3473         } else if (option_verbose > 2) { \
3474                 if (tmp->matchcid) { \
3475                         ast_verbose( VERBOSE_PREFIX_3 "Added extension '%s' priority %d (CID match '%s')to %s\n", tmp->exten, tmp->priority, tmp->cidmatch, con->name); \
3476                 } else {  \
3477                         ast_verbose( VERBOSE_PREFIX_3 "Added extension '%s' priority %d to %s\n", tmp->exten, tmp->priority, con->name); \
3478                 } \
3479         } } while(0)
3480
3481         /*
3482          * This is a fairly complex routine.  Different extensions are kept
3483          * in order by the extension number.  Then, extensions of different
3484          * priorities (same extension) are kept in a list, according to the
3485          * peer pointer.
3486          */
3487         struct ast_exten *tmp, *e, *el = NULL, *ep = NULL;
3488         int res;
3489         /* Be optimistic:  Build the extension structure first */
3490         tmp = malloc(sizeof(struct ast_exten));
3491         if (tmp) {
3492                 memset(tmp, 0, sizeof(struct ast_exten));
3493                 ext_strncpy(tmp->exten, extension, sizeof(tmp->exten));
3494                 tmp->priority = priority;
3495                 if (callerid) {
3496                         ext_strncpy(tmp->cidmatch, callerid, sizeof(tmp->cidmatch));
3497                         tmp->matchcid = 1;
3498                 } else {
3499                         strcpy(tmp->cidmatch, "");
3500                         tmp->matchcid = 0;
3501                 }
3502                 strncpy(tmp->app, application, sizeof(tmp->app)-1);
3503                 tmp->parent = con;
3504                 tmp->data = data;
3505                 tmp->datad = datad;
3506                 tmp->registrar = registrar;
3507                 tmp->peer = NULL;
3508                 tmp->next =  NULL;
3509         } else {
3510                 ast_log(LOG_WARNING, "Out of memory\n");
3511                 errno = ENOMEM;
3512                 return -1;
3513         }
3514         if (ast_pthread_mutex_lock(&con->lock)) {
3515                 free(tmp);
3516                 /* And properly destroy the data */
3517                 datad(data);
3518                 ast_log(LOG_WARNING, "Failed to lock context '%s'\n", con->name);
3519                 errno = EBUSY;
3520                 return -1;
3521         }
3522         e = con->root;
3523         while(e) {
3524                 res= strcasecmp(e->exten, extension);
3525                 if (!res) {
3526                         if (!e->matchcid && !tmp->matchcid)
3527                                 res = 0;
3528                         else if (tmp->matchcid && !e->matchcid)
3529                                 res = 1;
3530                         else if (e->matchcid && !tmp->matchcid)
3531                                 res = -1;
3532                         else
3533                                 res = strcasecmp(e->cidmatch, tmp->cidmatch);
3534                 }
3535                 if (res == 0) {
3536                         /* We have an exact match, now we find where we are
3537                            and be sure there's no duplicates */
3538                         while(e) {
3539                                 if (e->priority == tmp->priority) {
3540                                         /* Can't have something exactly the same.  Is this a
3541                                            replacement?  If so, replace, otherwise, bonk. */
3542                                         if (replace) {
3543                                                 if (ep) {
3544                                                         /* We're in the peer list, insert ourselves */
3545                                                         ep->peer = tmp;
3546                                                         tmp->peer = e->peer;
3547                                                 } else if (el) {
3548                                                         /* We're the first extension. Take over e's functions */
3549                                                         el->next = tmp;
3550                                                         tmp->next = e->next;
3551                                                         tmp->peer = e->peer;
3552                                                 } else {
3553                                                         /* We're the very first extension.  */
3554                                                         con->root = tmp;
3555                                                         tmp->next = e->next;
3556                                                         tmp->peer = e->peer;
3557                                                 }
3558                                                 if (tmp->priority == PRIORITY_HINT)
3559                                                     ast_change_hint(e,tmp);
3560                                                 /* Destroy the old one */
3561                                                 e->datad(e->data);
3562                                                 free(e);
3563                                                 ast_pthread_mutex_unlock(&con->lock);
3564                                                 if (tmp->priority == PRIORITY_HINT)
3565                                                     ast_change_hint(e, tmp);
3566                                                 /* And immediately return success. */
3567                                                 LOG;
3568                                                 return 0;
3569                                         } else {
3570                                                 ast_log(LOG_WARNING, "Unable to register extension '%s', priority %d in '%s', already in use\n", tmp->exten, tmp->priority, con->name);
3571                                                 tmp->datad(tmp->data);
3572                                                 free(tmp);
3573                                                 ast_pthread_mutex_unlock(&con->lock);
3574                                                 errno = EEXIST;
3575                                                 return -1;
3576                                         }
3577                                 } else if (e->priority > tmp->priority) {
3578                                         /* Slip ourselves in just before e */
3579                                         if (ep) {
3580                                                 /* Easy enough, we're just in the peer list */
3581                                                 ep->peer = tmp;
3582                                                 tmp->peer = e;
3583                                         } else if (el) {
3584                                                 /* We're the first extension in this peer list */
3585                                                 el->next = tmp;
3586                                                 tmp->next = e->next;
3587                                                 e->next = NULL;
3588                                                 tmp->peer = e;
3589                                         } else {
3590                                                 /* We're the very first extension altogether */
3591                                                 tmp->next = con->root;
3592                                                 /* Con->root must always exist or we couldn't get here */
3593                                                 tmp->peer = con->root->peer;
3594                      &