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