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