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