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