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