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