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