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