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