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