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