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