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