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