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