803c3fca47bc599bebb9c188f64b668a097de602
[asterisk/asterisk.git] / pbx.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Core PBX routines.
5  * 
6  * Copyright (C) 1999 - 2005, Digium, Inc.
7  *
8  * Mark Spencer <markster@digium.com>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  */
13
14 #include <sys/types.h>
15 #include <string.h>
16 #include <unistd.h>
17 #include <stdlib.h>
18 #include <stdio.h>
19 #include <setjmp.h>
20 #include <ctype.h>
21 #include <errno.h>
22 #include <time.h>
23 #include <sys/time.h>
24
25 #include "asterisk/lock.h"
26 #include "asterisk/cli.h"
27 #include "asterisk/pbx.h"
28 #include "asterisk/channel.h"
29 #include "asterisk/options.h"
30 #include "asterisk/logger.h"
31 #include "asterisk/file.h"
32 #include "asterisk/callerid.h"
33 #include "asterisk/cdr.h"
34 #include "asterisk/config.h"
35 #include "asterisk/term.h"
36 #include "asterisk/manager.h"
37 #include "asterisk/ast_expr.h"
38 #include "asterisk/linkedlists.h"
39 #include "asterisk/say.h"
40 #include "asterisk/utils.h"
41 #include "asterisk/causes.h"
42 #include "asterisk/musiconhold.h"
43 #include "asterisk/app.h"
44 #include "asterisk.h"
45
46 /*
47  * I M P O R T A N T :
48  *
49  *              The speed of extension handling will likely be among the most important
50  * aspects of this PBX.  The switching scheme as it exists right now isn't
51  * terribly bad (it's O(N+M), where N is the # of extensions and M is the avg #
52  * of priorities, but a constant search time here would be great ;-) 
53  *
54  */
55
56 #ifdef LOW_MEMORY
57 #define EXT_DATA_SIZE 256
58 #else
59 #define EXT_DATA_SIZE 8192
60 #endif
61
62 #define SWITCH_DATA_LENGTH 256
63
64
65 #define VAR_NORMAL              1
66 #define VAR_SOFTTRAN    2
67 #define VAR_HARDTRAN    3
68
69 #define BACKGROUND_SKIP         (1 << 0)
70 #define BACKGROUND_NOANSWER     (1 << 1)
71
72 AST_DECLARE_OPTIONS(background_opts,{
73         ['s'] = { BACKGROUND_SKIP },
74         ['n'] = { BACKGROUND_NOANSWER },
75 });
76
77 #define WAITEXTEN_MOH           (1 << 0)
78
79 AST_DECLARE_OPTIONS(waitexten_opts,{
80         ['m'] = { WAITEXTEN_MOH, 1 },
81 });
82
83 struct ast_context;
84
85 /* ast_exten: An extension */
86 struct ast_exten {
87         char *exten;                    /* Extension name */
88         int matchcid;                   /* Match caller id ? */
89         char *cidmatch;                 /* Caller id to match for this extension */
90         int priority;                   /* Priority */
91         char *label;                    /* Label */
92         struct ast_context *parent;     /* The context this extension belongs to  */
93         char *app;                      /* Application to execute */
94         void *data;                     /* Data to use (arguments) */
95         void (*datad)(void *);          /* Data destructor */
96         struct ast_exten *peer;         /* Next higher priority with our extension */
97         const char *registrar;          /* Registrar */
98         struct ast_exten *next;         /* Extension with a greater ID */
99         char stuff[0];
100 };
101
102 /* ast_include: include= support in extensions.conf */
103 struct ast_include {
104         char *name;             
105         char *rname;            /* Context to include */
106         const char *registrar;                  /* Registrar */
107         int hastime;                            /* If time construct exists */
108         struct ast_timing timing;               /* time construct */
109         struct ast_include *next;               /* Link them together */
110         char stuff[0];
111 };
112
113 /* ast_sw: Switch statement in extensions.conf */
114 struct ast_sw {
115         char *name;
116         const char *registrar;                  /* Registrar */
117         char *data;                             /* Data load */
118         int eval;
119         struct ast_sw *next;                    /* Link them together */
120         char *tmpdata;
121         char stuff[0];
122 };
123
124 struct ast_ignorepat {
125         const char *registrar;
126         struct ast_ignorepat *next;
127         char pattern[0];
128 };
129
130 /* ast_context: An extension context */
131 struct ast_context {
132         ast_mutex_t lock;                       /* A lock to prevent multiple threads from clobbering the context */
133         struct ast_exten *root;                 /* The root of the list of extensions */
134         struct ast_context *next;               /* Link them together */
135         struct ast_include *includes;           /* Include other contexts */
136         struct ast_ignorepat *ignorepats;       /* Patterns for which to continue playing dialtone */
137         const char *registrar;                  /* Registrar */
138         struct ast_sw *alts;                    /* Alternative switches */
139         char name[0];                           /* Name of the context */
140 };
141
142
143 /* ast_app: An application */
144 struct ast_app {
145         int (*execute)(struct ast_channel *chan, void *data);
146         const char *synopsis;                   /* Synopsis text for 'show applications' */
147         const char *description;                /* Description (help text) for 'show application <name>' */
148         struct ast_app *next;                   /* Next app in list */
149         char name[0];                           /* Name of the application */
150 };
151
152 /* ast_state_cb: An extension state notify */
153 struct ast_state_cb {
154         int id;
155         void *data;
156         ast_state_cb_type callback;
157         struct ast_state_cb *next;
158 };
159             
160 /* ast_devstate_cb: An extension state notify */
161 struct ast_devstate_cb {
162         void *data;
163         ast_devstate_cb_type callback;
164         struct ast_devstate_cb *next;
165 };
166
167 static struct ast_devstate_cb *devcbs;
168
169 /* Hints are pointers from an extension in the dialplan to one or more devices (tech/name) */
170 struct ast_hint {
171         struct ast_exten *exten;        /* Extension */
172         int laststate;                  /* Last known state */
173         struct ast_state_cb *callbacks; /* Callback list for this extension */
174         struct ast_hint *next;          /* Pointer to next hint in list */
175 };
176
177 int ast_pbx_outgoing_cdr_failed(void);
178
179 static int pbx_builtin_prefix(struct ast_channel *, void *);
180 static int pbx_builtin_suffix(struct ast_channel *, void *);
181 static int pbx_builtin_stripmsd(struct ast_channel *, void *);
182 static int pbx_builtin_answer(struct ast_channel *, void *);
183 static int pbx_builtin_goto(struct ast_channel *, void *);
184 static int pbx_builtin_hangup(struct ast_channel *, void *);
185 static int pbx_builtin_background(struct ast_channel *, void *);
186 static int pbx_builtin_dtimeout(struct ast_channel *, void *);
187 static int pbx_builtin_rtimeout(struct ast_channel *, void *);
188 static int pbx_builtin_atimeout(struct ast_channel *, void *);
189 static int pbx_builtin_wait(struct ast_channel *, void *);
190 static int pbx_builtin_waitexten(struct ast_channel *, void *);
191 static int pbx_builtin_setlanguage(struct ast_channel *, void *);
192 static int pbx_builtin_resetcdr(struct ast_channel *, void *);
193 static int pbx_builtin_setaccount(struct ast_channel *, void *);
194 static int pbx_builtin_setamaflags(struct ast_channel *, void *);
195 static int pbx_builtin_ringing(struct ast_channel *, void *);
196 static int pbx_builtin_progress(struct ast_channel *, void *);
197 static int pbx_builtin_congestion(struct ast_channel *, void *);
198 static int pbx_builtin_busy(struct ast_channel *, void *);
199 static int pbx_builtin_setglobalvar(struct ast_channel *, void *);
200 static int pbx_builtin_noop(struct ast_channel *, void *);
201 static int pbx_builtin_gotoif(struct ast_channel *, void *);
202 static int pbx_builtin_gotoiftime(struct ast_channel *, void *);
203 static int pbx_builtin_execiftime(struct ast_channel *, void *);
204 static int pbx_builtin_saynumber(struct ast_channel *, void *);
205 static int pbx_builtin_saydigits(struct ast_channel *, void *);
206 static int pbx_builtin_saycharacters(struct ast_channel *, void *);
207 static int pbx_builtin_sayphonetic(struct ast_channel *, void *);
208 static int pbx_builtin_setvar_old(struct ast_channel *, void *);
209 int pbx_builtin_setvar(struct ast_channel *, void *);
210 static int pbx_builtin_importvar(struct ast_channel *, void *);
211
212 static struct varshead globals;
213
214 static int autofallthrough = 0;
215
216 AST_MUTEX_DEFINE_STATIC(maxcalllock);
217 static int countcalls = 0;
218
219 AST_MUTEX_DEFINE_STATIC(acflock);               /* Lock for the custom function list */
220 static struct ast_custom_function *acf_root = NULL;
221
222 static struct pbx_builtin {
223         char name[AST_MAX_APP];
224         int (*execute)(struct ast_channel *chan, void *data);
225         char *synopsis;
226         char *description;
227 } builtins[] = 
228 {
229         /* These applications are built into the PBX core and do not
230            need separate modules
231            
232             */
233
234         { "AbsoluteTimeout", pbx_builtin_atimeout,
235         "Set absolute maximum time of call",
236         "  AbsoluteTimeout(seconds): Set the absolute maximum amount of time permitted\n"
237         "for a call.  A setting of 0 disables the timeout.  Always returns 0.\n" 
238         "AbsoluteTimeout has been deprecated in favor of Set(TIMEOUT(absolute)=timeout)\n"
239         },
240
241         { "Answer", pbx_builtin_answer, 
242         "Answer a channel if ringing", 
243         "  Answer([delay]): If the channel is ringing, answer it, otherwise do nothing. \n"
244         "If delay is specified, asterisk will pause execution for the specified amount\n"
245         "of milliseconds if an answer is required, in order to give audio a chance to\n"
246         "become ready. Returns 0 unless it tries to answer the channel and fails.\n"   
247         },
248
249         { "BackGround", pbx_builtin_background,
250         "Play a file while awaiting extension",
251         "  Background(filename1[&filename2...][|options[|langoverride]]): Plays\n"
252         "given files, while simultaneously waiting for the user to begin typing\n"
253         "an extension. The timeouts do not count until the last BackGround\n"
254         "application has ended. Options may also be included following a pipe \n"
255         "symbol. The 'langoverride' may be a language to use for playing the prompt\n"
256         "which differs from the current language of the channel. Returns -1 if \n"
257         "the channel was hung up, or if the file does not exist. Returns 0 otherwise.\n\n"
258         "  Options:\n"
259         "    's' - causes the playback of the message to be skipped\n"
260         "          if the channel is not in the 'up' state (i.e. it\n"
261         "          hasn't been answered yet.) If this happens, the\n"
262         "          application will return immediately.\n"
263         "    'n' - don't answer the channel before playing the files\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
764         if (!ast_strlen_zero(cidpattern))
765                 failresult = 0;
766         else
767                 failresult = 1;
768
769         if (!callerid)
770                 return failresult;
771
772         return ast_extension_match(cidpattern, callerid);
773 }
774
775 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)
776 {
777         int x, res;
778         struct ast_context *tmp;
779         struct ast_exten *e, *eroot;
780         struct ast_include *i;
781         struct ast_sw *sw;
782         struct ast_switch *asw;
783
784         /* Initialize status if appropriate */
785         if (!*stacklen) {
786                 *status = STATUS_NO_CONTEXT;
787                 *swo = NULL;
788                 *data = NULL;
789         }
790         /* Check for stack overflow */
791         if (*stacklen >= AST_PBX_MAX_STACK) {
792                 ast_log(LOG_WARNING, "Maximum PBX stack exceeded\n");
793                 return NULL;
794         }
795         /* Check first to see if we've already been checked */
796         for (x=0; x<*stacklen; x++) {
797                 if (!strcasecmp(incstack[x], context))
798                         return NULL;
799         }
800         if (bypass)
801                 tmp = bypass;
802         else
803                 tmp = contexts;
804         while(tmp) {
805                 /* Match context */
806                 if (bypass || !strcmp(tmp->name, context)) {
807                         struct ast_exten *earlymatch = NULL;
808
809                         if (*status < STATUS_NO_EXTENSION)
810                                 *status = STATUS_NO_EXTENSION;
811                         for (eroot = tmp->root; eroot; eroot=eroot->next) {
812                                 int match = 0;
813                                 /* Match extension */
814                                 if ((((action != HELPER_MATCHMORE) && ast_extension_match(eroot->exten, exten)) ||
815                                      ((action == HELPER_CANMATCH) && (ast_extension_close(eroot->exten, exten, 0))) ||
816                                      ((action == HELPER_MATCHMORE) && (match = ast_extension_close(eroot->exten, exten, 1)))) &&
817                                     (!eroot->matchcid || matchcid(eroot->cidmatch, callerid))) {
818
819                                         if (action == HELPER_MATCHMORE && match == 2 && !earlymatch) {
820                                                 /* It matched an extension ending in a '!' wildcard
821                                                    So ignore it for now, unless there's a better match */
822                                                 earlymatch = eroot;
823                                         } else {
824                                                 e = eroot;
825                                                 if (*status < STATUS_NO_PRIORITY)
826                                                         *status = STATUS_NO_PRIORITY;
827                                                 while(e) {
828                                                         /* Match priority */
829                                                         if (action == HELPER_FINDLABEL) {
830                                                                 if (*status < STATUS_NO_LABEL)
831                                                                         *status = STATUS_NO_LABEL;
832                                                                 if (label && e->label && !strcmp(label, e->label)) {
833                                                                         *status = STATUS_SUCCESS;
834                                                                         *foundcontext = context;
835                                                                         return e;
836                                                                 }
837                                                         } else if (e->priority == priority) {
838                                                                 *status = STATUS_SUCCESS;
839                                                                 *foundcontext = context;
840                                                                 return e;
841                                                         }
842                                                         e = e->peer;
843                                                 }
844                                         }
845                                 }
846                         }
847                         if (earlymatch) {
848                                 /* Bizarre logic for HELPER_MATCHMORE. We return zero to break out 
849                                    of the loop waiting for more digits, and _then_ match (normally)
850                                    the extension we ended up with. We got an early-matching wildcard
851                                    pattern, so return NULL to break out of the loop. */
852                                 return NULL;
853                         }
854                         /* Check alternative switches */
855                         sw = tmp->alts;
856                         while(sw) {
857                                 if ((asw = pbx_findswitch(sw->name))) {
858                                         /* Substitute variables now */
859                                         if (sw->eval) 
860                                                 pbx_substitute_variables_helper(chan, sw->data, sw->tmpdata, SWITCH_DATA_LENGTH - 1);
861                                         if (action == HELPER_CANMATCH)
862                                                 res = asw->canmatch ? asw->canmatch(chan, context, exten, priority, callerid, sw->eval ? sw->tmpdata : sw->data) : 0;
863                                         else if (action == HELPER_MATCHMORE)
864                                                 res = asw->matchmore ? asw->matchmore(chan, context, exten, priority, callerid, sw->eval ? sw->tmpdata : sw->data) : 0;
865                                         else
866                                                 res = asw->exists ? asw->exists(chan, context, exten, priority, callerid, sw->eval ? sw->tmpdata : sw->data) : 0;
867                                         if (res) {
868                                                 /* Got a match */
869                                                 *swo = asw;
870                                                 *data = sw->eval ? sw->tmpdata : sw->data;
871                                                 *foundcontext = context;
872                                                 return NULL;
873                                         }
874                                 } else {
875                                         ast_log(LOG_WARNING, "No such switch '%s'\n", sw->name);
876                                 }
877                                 sw = sw->next;
878                         }
879                         /* Setup the stack */
880                         incstack[*stacklen] = tmp->name;
881                         (*stacklen)++;
882                         /* Now try any includes we have in this context */
883                         i = tmp->includes;
884                         while(i) {
885                                 if (include_valid(i)) {
886                                         if ((e = pbx_find_extension(chan, bypass, i->rname, exten, priority, label, callerid, action, incstack, stacklen, status, swo, data, foundcontext))) 
887                                                 return e;
888                                         if (*swo) 
889                                                 return NULL;
890                                 }
891                                 i = i->next;
892                         }
893                         break;
894                 }
895                 tmp = tmp->next;
896         }
897         return NULL;
898 }
899
900 /*--- pbx_retrieve_variable: Support for Asterisk built-in variables and
901       functions in the dialplan
902   ---*/
903 void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp)
904 {
905         char *first,*second;
906         char tmpvar[80] = "";
907         time_t thistime;
908         struct tm brokentime;
909         int offset,offset2;
910         struct ast_var_t *variables;
911
912         if (c) 
913                 headp=&c->varshead;
914         *ret=NULL;
915         if ((first=strchr(var,':'))) {  /* : Remove characters counting from end or start of string */
916                 strncpy(tmpvar, var, sizeof(tmpvar) - 1);
917                 first = strchr(tmpvar, ':');
918                 if (!first)
919                         first = tmpvar + strlen(tmpvar);
920                 *first='\0';
921                 pbx_retrieve_variable(c,tmpvar,ret,workspace,workspacelen - 1, headp);
922                 if (!(*ret)) 
923                         return;
924                 offset=atoi(first+1);   /* The number of characters, 
925                                            positive: remove # of chars from start
926                                            negative: keep # of chars from end */
927                                                 
928                 if ((second=strchr(first+1,':'))) {     
929                         *second='\0';
930                         offset2 = atoi(second+1);               /* Number of chars to copy */
931                 } else if (offset >= 0) {
932                         offset2 = strlen(*ret)-offset;  /* Rest of string */
933                 } else {
934                         offset2 = abs(offset);
935                 }
936
937                 if (abs(offset) > strlen(*ret)) {       /* Offset beyond string */
938                         if (offset >= 0) 
939                                 offset=strlen(*ret);
940                         else 
941                                 offset=-strlen(*ret);   
942                 }
943                 if ((offset < 0 && offset2 > -offset) || (offset >= 0 && offset+offset2 > strlen(*ret))) {
944                         if (offset >= 0) 
945                                 offset2=strlen(*ret)-offset;
946                         else 
947                                 offset2=strlen(*ret)+offset;
948                 }
949                 if (offset >= 0)
950                         *ret += offset;
951                 else
952                         *ret += strlen(*ret)+offset;
953                 (*ret)[offset2] = '\0';         /* Cut at offset2 position */
954         } else if (c && !strncmp(var, "CALL", 4)) {
955                 if (!strncmp(var + 4, "ER", 2)) {
956                         if (!strncmp(var + 6, "ID", 2)) {
957                                 if (!var[8]) {                  /* CALLERID */
958                                         if (c->cid.cid_num) {
959                                                 if (c->cid.cid_name) {
960                                                         snprintf(workspace, workspacelen, "\"%s\" <%s>", c->cid.cid_name, c->cid.cid_num);
961                                                 } else {
962                                                         strncpy(workspace, c->cid.cid_num, workspacelen - 1);
963                                                 }
964                                                 *ret = workspace;
965                                         } else if (c->cid.cid_name) {
966                                                 strncpy(workspace, c->cid.cid_name, workspacelen - 1);
967                                                 *ret = workspace;
968                                         } else
969                                                 *ret = NULL;
970                                 } else if (!strcmp(var + 8, "NUM")) {
971                                         /* CALLERIDNUM */
972                                         if (c->cid.cid_num) {
973                                                 strncpy(workspace, c->cid.cid_num, workspacelen - 1);
974                                                 *ret = workspace;
975                                         } else
976                                                 *ret = NULL;
977                                 } else if (!strcmp(var + 8, "NAME")) {
978                                         /* CALLERIDNAME */
979                                         if (c->cid.cid_name) {
980                                                 strncpy(workspace, c->cid.cid_name, workspacelen - 1);
981                                                 *ret = workspace;
982                                         } else
983                                                 *ret = NULL;
984                                 }
985                         } else if (!strcmp(var + 6, "ANI")) {
986                                 /* CALLERANI */
987                                 if (c->cid.cid_ani) {
988                                         strncpy(workspace, c->cid.cid_ani, workspacelen - 1);
989                                         *ret = workspace;
990                                 } else
991                                         *ret = NULL;
992                         } else
993                                 goto icky;
994                 } else if (!strncmp(var + 4, "ING", 3)) {
995                         if (!strcmp(var + 7, "PRES")) {
996                                 /* CALLINGPRES */
997                                 snprintf(workspace, workspacelen, "%d", c->cid.cid_pres);
998                                 *ret = workspace;
999                         } else if (!strcmp(var + 7, "ANI2")) {
1000                                 /* CALLINGANI2 */
1001                                 snprintf(workspace, workspacelen, "%d", c->cid.cid_ani2);
1002                                 *ret = workspace;
1003                         } else if (!strcmp(var + 7, "TON")) {
1004                                 /* CALLINGTON */
1005                                 snprintf(workspace, workspacelen, "%d", c->cid.cid_ton);
1006                                 *ret = workspace;
1007                         } else if (!strcmp(var + 7, "TNS")) {
1008                                 /* CALLINGTNS */
1009                                 snprintf(workspace, workspacelen, "%d", c->cid.cid_tns);
1010                                 *ret = workspace;
1011                         } else
1012                                 goto icky;
1013                 } else
1014                         goto icky;
1015         } else if (c && !strcmp(var, "DNID")) {
1016                 if (c->cid.cid_dnid) {
1017                         strncpy(workspace, c->cid.cid_dnid, workspacelen - 1);
1018                         *ret = workspace;
1019                 } else
1020                         *ret = NULL;
1021         } else if (c && !strcmp(var, "HINT")) {
1022                 if (!ast_get_hint(workspace, workspacelen, NULL, 0, c, c->context, c->exten))
1023                         *ret = NULL;
1024                 else
1025                         *ret = workspace;
1026         } else if (c && !strcmp(var, "HINTNAME")) {
1027                 if (!ast_get_hint(NULL, 0, workspace, workspacelen, c, c->context, c->exten))
1028                         *ret = NULL;
1029                 else
1030                         *ret = workspace;
1031         } else if (c && !strcmp(var, "EXTEN")) {
1032                 strncpy(workspace, c->exten, workspacelen - 1);
1033                 *ret = workspace;
1034         } else if (c && !strcmp(var, "RDNIS")) {
1035                 if (c->cid.cid_rdnis) {
1036                         strncpy(workspace, c->cid.cid_rdnis, workspacelen - 1);
1037                         *ret = workspace;
1038                 } else
1039                         *ret = NULL;
1040         } else if (c && !strcmp(var, "CONTEXT")) {
1041                 strncpy(workspace, c->context, workspacelen - 1);
1042                 *ret = workspace;
1043         } else if (c && !strcmp(var, "PRIORITY")) {
1044                 snprintf(workspace, workspacelen, "%d", c->priority);
1045                 *ret = workspace;
1046         } else if (c && !strcmp(var, "CHANNEL")) {
1047                 strncpy(workspace, c->name, workspacelen - 1);
1048                 *ret = workspace;
1049         } else if (!strcmp(var, "EPOCH")) {
1050                 snprintf(workspace, workspacelen, "%u",(int)time(NULL));
1051                 *ret = workspace;
1052         } else if (!strcmp(var, "DATETIME")) {
1053                 thistime=time(NULL);
1054                 localtime_r(&thistime, &brokentime);
1055                 snprintf(workspace, workspacelen, "%02d%02d%04d-%02d:%02d:%02d",
1056                         brokentime.tm_mday,
1057                         brokentime.tm_mon+1,
1058                         brokentime.tm_year+1900,
1059                         brokentime.tm_hour,
1060                         brokentime.tm_min,
1061                         brokentime.tm_sec
1062                 );
1063                 *ret = workspace;
1064         } else if (!strcmp(var, "TIMESTAMP")) {
1065                 thistime=time(NULL);
1066                 localtime_r(&thistime, &brokentime);
1067                 /* 20031130-150612 */
1068                 snprintf(workspace, workspacelen, "%04d%02d%02d-%02d%02d%02d",
1069                         brokentime.tm_year+1900,
1070                         brokentime.tm_mon+1,
1071                         brokentime.tm_mday,
1072                         brokentime.tm_hour,
1073                         brokentime.tm_min,
1074                         brokentime.tm_sec
1075                 );
1076                 *ret = workspace;
1077         } else if (c && !strcmp(var, "UNIQUEID")) {
1078                 snprintf(workspace, workspacelen, "%s", c->uniqueid);
1079                 *ret = workspace;
1080         } else if (c && !strcmp(var, "HANGUPCAUSE")) {
1081                 snprintf(workspace, workspacelen, "%d", c->hangupcause);
1082                 *ret = workspace;
1083         } else if (c && !strcmp(var, "ACCOUNTCODE")) {
1084                 strncpy(workspace, c->accountcode, workspacelen - 1);
1085                 *ret = workspace;
1086         } else if (c && !strcmp(var, "LANGUAGE")) {
1087                 strncpy(workspace, c->language, workspacelen - 1);
1088                 *ret = workspace;
1089         } else {
1090 icky:
1091                 if (headp) {
1092                         AST_LIST_TRAVERSE(headp,variables,entries) {
1093 #if 0
1094                                 ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",var,ast_var_name(variables));
1095 #endif
1096                                 if (strcasecmp(ast_var_name(variables),var)==0) {
1097                                         *ret=ast_var_value(variables);
1098                                         if (*ret) {
1099                                                 strncpy(workspace, *ret, workspacelen - 1);
1100                                                 *ret = workspace;
1101                                         }
1102                                         break;
1103                                 }
1104                         }
1105                 }
1106                 if (!(*ret)) {
1107                         /* Try globals */
1108                         AST_LIST_TRAVERSE(&globals,variables,entries) {
1109 #if 0
1110                                 ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",var,ast_var_name(variables));
1111 #endif
1112                                 if (strcasecmp(ast_var_name(variables),var)==0) {
1113                                         *ret=ast_var_value(variables);
1114                                         if (*ret) {
1115                                                 strncpy(workspace, *ret, workspacelen - 1);
1116                                                 *ret = workspace;
1117                                         }
1118                                 }
1119                         }
1120                 }
1121         }
1122 }
1123
1124 static int handle_show_functions(int fd, int argc, char *argv[])
1125 {
1126         struct ast_custom_function *acf;
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         }
1132         ast_cli(fd, "\n");
1133         return 0;
1134 }
1135
1136 static int handle_show_function(int fd, int argc, char *argv[])
1137 {
1138         struct ast_custom_function *acf;
1139         /* Maximum number of characters added by terminal coloring is 22 */
1140         char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
1141         char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
1142         char stxtitle[40], *syntax = NULL;
1143         int synopsis_size, description_size, syntax_size;
1144
1145         if (argc < 3) return RESULT_SHOWUSAGE;
1146
1147         if (!(acf = ast_custom_function_find(argv[2]))) {
1148                 ast_cli(fd, "No function by that name registered.\n");
1149                 return RESULT_FAILURE;
1150
1151         }
1152
1153         if (acf->synopsis)
1154                 synopsis_size = strlen(acf->synopsis) + 23;
1155         else
1156                 synopsis_size = strlen("Not available") + 23;
1157         synopsis = alloca(synopsis_size);
1158         
1159         if (acf->desc)
1160                 description_size = strlen(acf->desc) + 23;
1161         else
1162                 description_size = strlen("Not available") + 23;
1163         description = alloca(description_size);
1164
1165         if (acf->syntax)
1166                 syntax_size = strlen(acf->syntax) + 23;
1167         else
1168                 syntax_size = strlen("Not available") + 23;
1169         syntax = alloca(syntax_size);
1170
1171         snprintf(info, 64 + AST_MAX_APP, "\n  -= Info about function '%s' =- \n\n", acf->name);
1172         term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
1173         term_color(stxtitle, "[Syntax]\n", COLOR_MAGENTA, 0, 40);
1174         term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
1175         term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
1176         term_color(syntax,
1177                    acf->syntax ? acf->syntax : "Not available",
1178                    COLOR_CYAN, 0, syntax_size);
1179         term_color(synopsis,
1180                    acf->synopsis ? acf->synopsis : "Not available",
1181                    COLOR_CYAN, 0, synopsis_size);
1182         term_color(description,
1183                    acf->desc ? acf->desc : "Not available",
1184                    COLOR_CYAN, 0, description_size);
1185         
1186         ast_cli(fd,"%s%s%s\n\n%s%s\n\n%s%s\n", infotitle, stxtitle, syntax, syntitle, synopsis, destitle, description);
1187
1188         return RESULT_SUCCESS;
1189 }
1190
1191 static char *complete_show_function(char *line, char *word, int pos, int state)
1192 {
1193         struct ast_custom_function *acf;
1194         int which = 0;
1195
1196         /* try to lock functions list ... */
1197         if (ast_mutex_lock(&acflock)) {
1198                 ast_log(LOG_ERROR, "Unable to lock function list\n");
1199                 return NULL;
1200         }
1201
1202         acf = acf_root;
1203         while (acf) {
1204                 if (!strncasecmp(word, acf->name, strlen(word))) {
1205                         if (++which > state) {
1206                                 char *ret = strdup(acf->name);
1207                                 ast_mutex_unlock(&acflock);
1208                                 return ret;
1209                         }
1210                 }
1211                 acf = acf->next; 
1212         }
1213
1214         ast_mutex_unlock(&acflock);
1215         return NULL; 
1216 }
1217
1218 struct ast_custom_function* ast_custom_function_find(char *name) 
1219 {
1220         struct ast_custom_function *acfptr;
1221
1222         /* try to lock functions list ... */
1223         if (ast_mutex_lock(&acflock)) {
1224                 ast_log(LOG_ERROR, "Unable to lock function list\n");
1225                 return NULL;
1226         }
1227
1228         for (acfptr = acf_root; acfptr; acfptr = acfptr->next) {
1229                 if (!strcmp(name, acfptr->name)) {
1230                         break;
1231                 }
1232         }
1233
1234         ast_mutex_unlock(&acflock);
1235         
1236         return acfptr;
1237 }
1238
1239 int ast_custom_function_unregister(struct ast_custom_function *acf) 
1240 {
1241         struct ast_custom_function *acfptr, *lastacf = NULL;
1242         int res = -1;
1243
1244         if (!acf)
1245                 return -1;
1246
1247         /* try to lock functions list ... */
1248         if (ast_mutex_lock(&acflock)) {
1249                 ast_log(LOG_ERROR, "Unable to lock function list\n");
1250                 return -1;
1251         }
1252
1253         for (acfptr = acf_root; acfptr; acfptr = acfptr->next) {
1254                 if (acfptr == acf) {
1255                         if (lastacf) {
1256                                 lastacf->next = acf->next;
1257                         } else {
1258                                 acf_root = acf->next;
1259                         }
1260                         res = 0;
1261                         break;
1262                 }
1263                 lastacf = acfptr;
1264         }
1265
1266         ast_mutex_unlock(&acflock);
1267
1268         if (!res && (option_verbose > 1))
1269                 ast_verbose(VERBOSE_PREFIX_2 "Unregistered custom function %s\n", acf->name);
1270
1271         return res;
1272 }
1273
1274 int ast_custom_function_register(struct ast_custom_function *acf) 
1275 {
1276         if (!acf)
1277                 return -1;
1278
1279         /* try to lock functions list ... */
1280         if (ast_mutex_lock(&acflock)) {
1281                 ast_log(LOG_ERROR, "Unable to lock function list\n");
1282                 return -1;
1283         }
1284
1285         if (ast_custom_function_find(acf->name)) {
1286                 ast_log(LOG_ERROR, "Function %s already registered.\n", acf->name);
1287                 ast_mutex_unlock(&acflock);
1288                 return -1;
1289         }
1290
1291         acf->next = acf_root;
1292         acf_root = acf;
1293
1294         ast_mutex_unlock(&acflock);
1295
1296         if (option_verbose > 1)
1297                 ast_verbose(VERBOSE_PREFIX_2 "Registered custom function %s\n", acf->name);
1298
1299         return 0;
1300 }
1301
1302 char *ast_func_read(struct ast_channel *chan, const char *in, char *workspace, size_t len)
1303 {
1304         char *args = NULL, *function, *p;
1305         char *ret = "0";
1306         struct ast_custom_function *acfptr;
1307
1308         function = ast_strdupa(in);
1309         if (function) {
1310                 if ((args = strchr(function, '('))) {
1311                         *args = '\0';
1312                         args++;
1313                         if ((p = strrchr(args, ')'))) {
1314                                 *p = '\0';
1315                         } else {
1316                                 ast_log(LOG_WARNING, "Can't find trailing parenthesis?\n");
1317                         }
1318                 } else {
1319                         ast_log(LOG_WARNING, "Function doesn't contain parentheses.  Assuming null argument.\n");
1320                 }
1321
1322                 if ((acfptr = ast_custom_function_find(function))) {
1323                         /* run the custom function */
1324                         if (acfptr->read) {
1325                                 return acfptr->read(chan, function, args, workspace, len);
1326                         } else {
1327                                 ast_log(LOG_ERROR, "Function %s cannot be read\n", function);
1328                         }
1329                 } else {
1330                         ast_log(LOG_ERROR, "Function %s not registered\n", function);
1331                 }
1332         } else {
1333                 ast_log(LOG_ERROR, "Out of memory\n");
1334         }
1335         return ret;
1336 }
1337
1338 void ast_func_write(struct ast_channel *chan, const char *in, const char *value)
1339 {
1340         char *args = NULL, *function, *p;
1341         struct ast_custom_function *acfptr;
1342
1343         function = ast_strdupa(in);
1344         if (function) {
1345                 if ((args = strchr(function, '('))) {
1346                         *args = '\0';
1347                         args++;
1348                         if ((p = strrchr(args, ')'))) {
1349                                 *p = '\0';
1350                         } else {
1351                                 ast_log(LOG_WARNING, "Can't find trailing parenthesis?\n");
1352                         }
1353                 } else {
1354                         ast_log(LOG_WARNING, "Function doesn't contain parentheses.  Assuming null argument.\n");
1355                 }
1356
1357                 if ((acfptr = ast_custom_function_find(function))) {
1358                         /* run the custom function */
1359                         if (acfptr->write) {
1360                                 acfptr->write(chan, function, args, value);
1361                         } else {
1362                                 ast_log(LOG_ERROR, "Function %s cannot be written to\n", function);
1363                         }
1364                 } else {
1365                         ast_log(LOG_ERROR, "Function %s not registered\n", function);
1366                 }
1367         } else {
1368                 ast_log(LOG_ERROR, "Out of memory\n");
1369         }
1370 }
1371
1372 static void pbx_substitute_variables_helper_full(struct ast_channel *c, const char *cp1, char *cp2, int count, struct varshead *headp)
1373 {
1374         char *cp4;
1375         const char *tmp, *whereweare;
1376         int length;
1377         char workspace[4096];
1378         char ltmp[4096], var[4096];
1379         char *nextvar, *nextexp, *nextthing;
1380         char *vars, *vare;
1381         int pos, brackets, needsub, len;
1382         
1383         /* Substitutes variables into cp2, based on string cp1, and assuming cp2 to be
1384            zero-filled */
1385         whereweare=tmp=cp1;
1386         while(!ast_strlen_zero(whereweare) && count) {
1387                 /* Assume we're copying the whole remaining string */
1388                 pos = strlen(whereweare);
1389                 nextvar = NULL;
1390                 nextexp = NULL;
1391                 nextthing = strchr(whereweare, '$');
1392                 if (nextthing) {
1393                         switch(nextthing[1]) {
1394                         case '{':
1395                                 nextvar = nextthing;
1396                                 break;
1397                         case '[':
1398                                 nextexp = nextthing;
1399                                 break;
1400                         }
1401                 }
1402                 /* If there is one, we only go that far */
1403                 if (nextvar)
1404                         pos = nextvar - whereweare;
1405                 else if (nextexp)
1406                         pos = nextexp - whereweare;
1407
1408                 /* Can't copy more than 'count' bytes */
1409                 if (pos > count)
1410                         pos = count;
1411
1412                 /* Copy that many bytes */
1413                 memcpy(cp2, whereweare, pos);
1414
1415                 count -= pos;
1416                 cp2 += pos;
1417                 whereweare += pos;
1418                 
1419                 if (nextvar) {
1420                         /* We have a variable.  Find the start and end, and determine
1421                            if we are going to have to recursively call ourselves on the
1422                            contents */
1423                         vars = vare = nextvar + 2;
1424                         brackets = 1;
1425                         needsub = 0;
1426
1427                         /* Find the end of it */
1428                         while(brackets && *vare) {
1429                                 if ((vare[0] == '$') && (vare[1] == '{')) {
1430                                         needsub++;
1431                                         brackets++;
1432                                 } else if (vare[0] == '}') {
1433                                         brackets--;
1434                                 } else if ((vare[0] == '$') && (vare[1] == '['))
1435                                         needsub++;
1436                                 vare++;
1437                         }
1438                         if (brackets)
1439                                 ast_log(LOG_NOTICE, "Error in extension logic (missing '}')\n");
1440                         len = vare - vars - 1;
1441
1442                         /* Skip totally over variable name */
1443                         whereweare += ( len + 3);
1444
1445                         /* Store variable name (and truncate) */
1446                         memset(var, 0, sizeof(var));
1447                         strncpy(var, vars, sizeof(var) - 1);
1448                         var[len] = '\0';
1449
1450                         /* Substitute if necessary */
1451                         if (needsub) {
1452                                 memset(ltmp, 0, sizeof(ltmp));
1453                                 pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1);
1454                                 vars = ltmp;
1455                         } else {
1456                                 vars = var;
1457                         }
1458
1459                         workspace[0] = '\0';
1460
1461                         if (var[len - 1] == ')') {
1462                                 /* Evaluate function */
1463                                 cp4 = ast_func_read(c, vars, workspace, sizeof(workspace));
1464
1465                                 ast_log(LOG_DEBUG, "Function result is '%s'\n", cp4 ? cp4 : "(null)");
1466                         } else {
1467                                 /* Retrieve variable value */
1468                                 pbx_retrieve_variable(c, vars, &cp4, workspace, sizeof(workspace), headp);
1469                         }
1470                         if (cp4) {
1471                                 length = strlen(cp4);
1472                                 if (length > count)
1473                                         length = count;
1474                                 memcpy(cp2, cp4, length);
1475                                 count -= length;
1476                                 cp2 += length;
1477                         }
1478                 } else if (nextexp) {
1479                         /* We have an expression.  Find the start and end, and determine
1480                            if we are going to have to recursively call ourselves on the
1481                            contents */
1482                         vars = vare = nextexp + 2;
1483                         brackets = 1;
1484                         needsub = 0;
1485
1486                         /* Find the end of it */
1487                         while(brackets && *vare) {
1488                                 if ((vare[0] == '$') && (vare[1] == '[')) {
1489                                         needsub++;
1490                                         brackets++;
1491                                         vare++;
1492                                 } else if (vare[0] == '[') {
1493                                         brackets++;
1494                                 } else if (vare[0] == ']') {
1495                                         brackets--;
1496                                 } else if ((vare[0] == '$') && (vare[1] == '{')) {
1497                                         needsub++;
1498                                         vare++;
1499                                 }
1500                                 vare++;
1501                         }
1502                         if (brackets)
1503                                 ast_log(LOG_NOTICE, "Error in extension logic (missing ']')\n");
1504                         len = vare - vars - 1;
1505                         
1506                         /* Skip totally over variable name */
1507                         whereweare += ( len + 3);
1508                         
1509                         /* Store variable name (and truncate) */
1510                         memset(var, 0, sizeof(var));
1511                         strncpy(var, vars, sizeof(var) - 1);
1512                         var[len] = '\0';
1513                         
1514                         /* Substitute if necessary */
1515                         if (needsub) {
1516                                 memset(ltmp, 0, sizeof(ltmp));
1517                                 pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1);
1518                                 vars = ltmp;
1519                         } else {
1520                                 vars = var;
1521                         }
1522
1523                         /* Evaluate expression */                       
1524                         cp4 = ast_expr(vars);
1525                         
1526                         ast_log(LOG_DEBUG, "Expression is '%s'\n", cp4);
1527                         
1528                         if (cp4) {
1529                                 length = strlen(cp4);
1530                                 if (length > count)
1531                                         length = count;
1532                                 memcpy(cp2, cp4, length);
1533                                 count -= length;
1534                                 cp2 += length;
1535                                 free(cp4);
1536                         }
1537                 } else
1538                         break;
1539         }
1540 }
1541
1542 void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
1543 {
1544         pbx_substitute_variables_helper_full(c, cp1, cp2, count, NULL);
1545 }
1546
1547 void pbx_substitute_variables_varshead(struct varshead *headp, const char *cp1, char *cp2, int count)
1548 {
1549         pbx_substitute_variables_helper_full(NULL, cp1, cp2, count, headp);
1550 }
1551
1552 static void pbx_substitute_variables(char *passdata, int datalen, struct ast_channel *c, struct ast_exten *e)
1553 {
1554         memset(passdata, 0, datalen);
1555                 
1556         /* No variables or expressions in e->data, so why scan it? */
1557         if (!strstr(e->data,"${") && !strstr(e->data,"$[") && !strstr(e->data,"$(")) {
1558                 strncpy(passdata, e->data, datalen - 1);
1559                 passdata[datalen-1] = '\0';
1560                 return;
1561         }
1562         
1563         pbx_substitute_variables_helper(c, e->data, passdata, datalen - 1);
1564 }                                                               
1565
1566 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) 
1567 {
1568         struct ast_exten *e;
1569         struct ast_app *app;
1570         struct ast_switch *sw;
1571         char *data;
1572         const char *foundcontext=NULL;
1573         int newstack = 0;
1574         int res;
1575         int status = 0;
1576         char *incstack[AST_PBX_MAX_STACK];
1577         char passdata[EXT_DATA_SIZE];
1578         int stacklen = 0;
1579         char tmp[80];
1580         char tmp2[80];
1581         char tmp3[EXT_DATA_SIZE];
1582         char atmp[80];
1583         char atmp2[EXT_DATA_SIZE+100];
1584
1585         if (ast_mutex_lock(&conlock)) {
1586                 ast_log(LOG_WARNING, "Unable to obtain lock\n");
1587                 if ((action == HELPER_EXISTS) || (action == HELPER_CANMATCH) || (action == HELPER_MATCHMORE))
1588                         return 0;
1589                 else
1590                         return -1;
1591         }
1592         e = pbx_find_extension(c, con, context, exten, priority, label, callerid, action, incstack, &stacklen, &status, &sw, &data, &foundcontext);
1593         if (e) {
1594                 switch(action) {
1595                 case HELPER_CANMATCH:
1596                         ast_mutex_unlock(&conlock);
1597                         return -1;
1598                 case HELPER_EXISTS:
1599                         ast_mutex_unlock(&conlock);
1600                         return -1;
1601                 case HELPER_FINDLABEL:
1602                         res = e->priority;
1603                         ast_mutex_unlock(&conlock);
1604                         return res;
1605                 case HELPER_MATCHMORE:
1606                         ast_mutex_unlock(&conlock);
1607                         return -1;
1608                 case HELPER_SPAWN:
1609                         newstack++;
1610                         /* Fall through */
1611                 case HELPER_EXEC:
1612                         app = pbx_findapp(e->app);
1613                         ast_mutex_unlock(&conlock);
1614                         if (app) {
1615                                 if (c->context != context)
1616                                         strncpy(c->context, context, sizeof(c->context)-1);
1617                                 if (c->exten != exten)
1618                                         strncpy(c->exten, exten, sizeof(c->exten)-1);
1619                                 c->priority = priority;
1620                                 pbx_substitute_variables(passdata, sizeof(passdata), c, e);
1621                                 if (option_debug) {
1622                                                 ast_log(LOG_DEBUG, "Launching '%s'\n", app->name);
1623                                                 snprintf(atmp, 80, "STACK-%s-%s-%d", context, exten, priority);
1624                                                 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"));
1625                                                 pbx_builtin_setvar_helper(c, atmp, atmp2);
1626                                 }
1627                                 if (option_verbose > 2)
1628                                                 ast_verbose( VERBOSE_PREFIX_3 "Executing %s(\"%s\", \"%s\") %s\n", 
1629                                                                 term_color(tmp, app->name, COLOR_BRCYAN, 0, sizeof(tmp)),
1630                                                                 term_color(tmp2, c->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
1631                                                                 term_color(tmp3, (!ast_strlen_zero(passdata) ? (char *)passdata : ""), COLOR_BRMAGENTA, 0, sizeof(tmp3)),
1632                                                                 (newstack ? "in new stack" : "in same stack"));
1633                                 manager_event(EVENT_FLAG_CALL, "Newexten", 
1634                                         "Channel: %s\r\n"
1635                                         "Context: %s\r\n"
1636                                         "Extension: %s\r\n"
1637                                         "Priority: %d\r\n"
1638                                         "Application: %s\r\n"
1639                                         "AppData: %s\r\n"
1640                                         "Uniqueid: %s\r\n",
1641                                         c->name, c->context, c->exten, c->priority, app->name, passdata ? passdata : "(NULL)", c->uniqueid);
1642                                 res = pbx_exec(c, app, passdata, newstack);
1643                                 return res;
1644                         } else {
1645                                 ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
1646                                 return -1;
1647                         }
1648                 default:
1649                         ast_log(LOG_WARNING, "Huh (%d)?\n", action);                    return -1;
1650                 }
1651         } else if (sw) {
1652                 switch(action) {
1653                 case HELPER_CANMATCH:
1654                         ast_mutex_unlock(&conlock);
1655                         return -1;
1656                 case HELPER_EXISTS:
1657                         ast_mutex_unlock(&conlock);
1658                         return -1;
1659                 case HELPER_MATCHMORE:
1660                         ast_mutex_unlock(&conlock);
1661                         return -1;
1662                 case HELPER_FINDLABEL:
1663                         ast_mutex_unlock(&conlock);
1664                         return -1;
1665                 case HELPER_SPAWN:
1666                         newstack++;
1667                         /* Fall through */
1668                 case HELPER_EXEC:
1669                         ast_mutex_unlock(&conlock);
1670                         if (sw->exec)
1671                                 res = sw->exec(c, foundcontext ? foundcontext : context, exten, priority, callerid, newstack, data);
1672                         else {
1673                                 ast_log(LOG_WARNING, "No execution engine for switch %s\n", sw->name);
1674                                 res = -1;
1675                         }
1676                         return res;
1677                 default:
1678                         ast_log(LOG_WARNING, "Huh (%d)?\n", action);
1679                         return -1;
1680                 }
1681         } else {
1682                 ast_mutex_unlock(&conlock);
1683                 switch(status) {
1684                 case STATUS_NO_CONTEXT:
1685                         if ((action != HELPER_EXISTS) && (action != HELPER_MATCHMORE))
1686                                 ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", context);
1687                         break;
1688                 case STATUS_NO_EXTENSION:
1689                         if ((action != HELPER_EXISTS) && (action !=  HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1690                                 ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, context);
1691                         break;
1692                 case STATUS_NO_PRIORITY:
1693                         if ((action != HELPER_EXISTS) && (action !=  HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1694                                 ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, context);
1695                         break;
1696                 case STATUS_NO_LABEL:
1697                         if (context)
1698                                 ast_log(LOG_NOTICE, "No such label '%s' in extension '%s' in context '%s'\n", label, exten, context);
1699                         break;
1700                 default:
1701                         ast_log(LOG_DEBUG, "Shouldn't happen!\n");
1702                 }
1703                 
1704                 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1705                         return -1;
1706                 else
1707                         return 0;
1708         }
1709
1710 }
1711
1712 /*--- ast_hint_extension: Find hint for given extension in context */
1713 static struct ast_exten *ast_hint_extension(struct ast_channel *c, const char *context, const char *exten)
1714 {
1715         struct ast_exten *e;
1716         struct ast_switch *sw;
1717         char *data;
1718         const char *foundcontext = NULL;
1719         int status = 0;
1720         char *incstack[AST_PBX_MAX_STACK];
1721         int stacklen = 0;
1722
1723         if (ast_mutex_lock(&conlock)) {
1724                 ast_log(LOG_WARNING, "Unable to obtain lock\n");
1725                 return NULL;
1726         }
1727         e = pbx_find_extension(c, NULL, context, exten, PRIORITY_HINT, NULL, "", HELPER_EXISTS, incstack, &stacklen, &status, &sw, &data, &foundcontext);
1728         ast_mutex_unlock(&conlock);     
1729         return e;
1730 }
1731
1732 /*--- ast_extensions_state2: Check state of extension by using hints */
1733 static int ast_extension_state2(struct ast_exten *e)
1734 {
1735         char hint[AST_MAX_EXTENSION] = "";    
1736         char *cur, *rest;
1737         int res = -1;
1738         int allunavailable = 1, allbusy = 1, allfree = 1;
1739         int busy = 0;
1740
1741         if (!e)
1742                 return -1;
1743
1744         strncpy(hint, ast_get_extension_app(e), sizeof(hint)-1);
1745
1746         cur = hint;     /* On or more devices separated with a & character */
1747         do {
1748                 rest = strchr(cur, '&');
1749                 if (rest) {
1750                         *rest = 0;
1751                         rest++;
1752                 }
1753         
1754                 res = ast_device_state(cur);
1755                 switch (res) {
1756                 case AST_DEVICE_NOT_INUSE:
1757                         allunavailable = 0;
1758                         allbusy = 0;
1759                         break;
1760                 case AST_DEVICE_INUSE:
1761                         return AST_EXTENSION_INUSE;
1762                 case AST_DEVICE_BUSY:
1763                         allunavailable = 0;
1764                         allfree = 0;
1765                         busy = 1;
1766                         break;
1767                 case AST_DEVICE_UNAVAILABLE:
1768                 case AST_DEVICE_INVALID:
1769                         allbusy = 0;
1770                         allfree = 0;
1771                         break;
1772                 default:
1773                         allunavailable = 0;
1774                         allbusy = 0;
1775                         allfree = 0;
1776                 }
1777                 cur = rest;
1778         } while (cur);
1779
1780         if (allfree)                    
1781                 return AST_EXTENSION_NOT_INUSE;
1782         if (allbusy)            
1783                 return AST_EXTENSION_BUSY;
1784         if (allunavailable)
1785                 return AST_EXTENSION_UNAVAILABLE;
1786         if (busy) 
1787                 return AST_EXTENSION_INUSE;
1788         
1789         return AST_EXTENSION_NOT_INUSE;
1790 }
1791
1792
1793 /*--- ast_extension_state: Check extension state for an extension by using hint */
1794 int ast_extension_state(struct ast_channel *c, char *context, char *exten)
1795 {
1796         struct ast_exten *e;
1797
1798         e = ast_hint_extension(c, context, exten);      /* Do we have a hint for this extension ? */ 
1799         if (!e) 
1800                 return -1;                              /* No hint, return -1 */
1801
1802         return ast_extension_state2(e);                 /* Check all devices in the hint */
1803 }
1804
1805 /*--- ast_device_state_changed: If device state in cblist is changed  - then notify callback function */
1806 int ast_device_state_changed(const char *fmt, ...) 
1807 {
1808         struct ast_hint *list;
1809         struct ast_state_cb *cblist;
1810         struct ast_devstate_cb *devcb;
1811         char hint[AST_MAX_EXTENSION] = "";
1812         char device[AST_MAX_EXTENSION];
1813
1814         char *cur, *rest;
1815         int state;
1816
1817         va_list ap;
1818
1819         va_start(ap, fmt);
1820         vsnprintf(device, sizeof(device), fmt, ap);
1821         va_end(ap);
1822
1823         rest = strchr(device, '-');
1824         if (rest) {
1825                 *rest = 0;
1826         }
1827
1828
1829         state = ast_device_state(device);
1830         if (option_debug > 2)
1831                 ast_log(LOG_DEBUG, "Changing state for %s - state %d\n", device, state);
1832
1833         ast_mutex_lock(&hintlock);
1834
1835         /* First check device callbacks */
1836         devcb = devcbs;
1837         while(devcb) {
1838                 if (devcb->callback)
1839                         devcb->callback(device, state, devcb->data);
1840                 devcb = devcb->next;
1841         }
1842
1843         /* Then check callbacks in hints */
1844         list = hints;
1845
1846         while (list) {
1847
1848                 strncpy(hint, ast_get_extension_app(list->exten), sizeof(hint) - 1);
1849                 cur = hint;
1850                 do {
1851                         rest = strchr(cur, '&');
1852                         if (rest) {
1853                                 *rest = 0;
1854                                 rest++;
1855                         }
1856                         
1857                         if (!strcmp(cur, device)) {     /* Is this device referred to in this hint? */
1858
1859                                 /* Get device state for this hint */
1860                                 state = ast_extension_state2(list->exten);
1861
1862                                 if ((state != -1) && (state != list->laststate)) {
1863                                         /* Device state changed since last check - notify the watcher */
1864
1865                                         /* For general callbacks */
1866                                         cblist = statecbs;
1867                                         while (cblist) {
1868                                                 cblist->callback(list->exten->parent->name, list->exten->exten, state, cblist->data);
1869                                                 cblist = cblist->next;
1870                                         }
1871
1872                                         /* For extension callbacks */
1873                                         cblist = list->callbacks;
1874                                         while (cblist) {
1875                                                 cblist->callback(list->exten->parent->name, list->exten->exten, state, cblist->data);
1876                                                 cblist = cblist->next;
1877                                         }
1878                         
1879                                         list->laststate = state;
1880                                 }
1881                                 break;
1882                         }
1883                         cur = rest;
1884                 } while (cur);
1885                 list = list->next;
1886         }
1887         ast_mutex_unlock(&hintlock);
1888         return 1;
1889 }
1890                         
1891 /*--- ast_devstate_add: Add device state watcher */
1892 int ast_devstate_add(ast_devstate_cb_type callback, void *data)
1893 {
1894         struct ast_devstate_cb *devcb;
1895         devcb = malloc(sizeof(struct ast_devstate_cb));
1896         if (devcb) {
1897                 memset(devcb, 0, sizeof(struct ast_devstate_cb));
1898                 ast_mutex_lock(&hintlock);
1899                 devcb->data = data;
1900                 devcb->callback = callback;
1901                 devcb->next = devcbs;
1902                 devcbs = devcb;
1903                 ast_mutex_unlock(&hintlock);
1904         }
1905         return 0;
1906 }
1907
1908 /*--- ast_devstate_del: Remove device state watcher */
1909 void ast_devstate_del(ast_devstate_cb_type callback, void *data)
1910 {
1911         struct ast_devstate_cb *devcb, *prev = NULL, *next;
1912         ast_mutex_lock(&hintlock);
1913         devcb = devcbs;
1914         while(devcb) {
1915                 next = devcb->next;
1916                 if ((devcb->data == data) && (devcb->callback == callback)) {
1917                         if (prev)
1918                                 prev->next = next;
1919                         else
1920                                 devcbs = next;
1921                         free(devcb);
1922                 } else
1923                         prev = devcb;
1924                 devcb = next;
1925         }
1926         ast_mutex_unlock(&hintlock);
1927 }
1928
1929 /*--- ast_extension_state_add: Add watcher for extension states */
1930 int ast_extension_state_add(const char *context, const char *exten, 
1931                             ast_state_cb_type callback, void *data)
1932 {
1933         struct ast_hint *list;
1934         struct ast_state_cb *cblist;
1935         struct ast_exten *e;
1936
1937         /* If there's no context and extension:  add callback to statecbs list */
1938         if (!context && !exten) {
1939                 ast_mutex_lock(&hintlock);
1940
1941                 cblist = statecbs;
1942                 while (cblist) {
1943                         if (cblist->callback == callback) {
1944                                 cblist->data = data;
1945                                 ast_mutex_unlock(&hintlock);
1946                                 return 0;
1947                         }
1948                         cblist = cblist->next;
1949                 }
1950         
1951                 /* Now insert the callback */
1952                 cblist = malloc(sizeof(struct ast_state_cb));
1953                 if (!cblist) {
1954                         ast_mutex_unlock(&hintlock);
1955                         return -1;
1956                 }
1957                 memset(cblist, 0, sizeof(struct ast_state_cb));
1958                 cblist->id = 0;
1959                 cblist->callback = callback;
1960                 cblist->data = data;
1961         
1962                 cblist->next = statecbs;
1963                 statecbs = cblist;
1964
1965                 ast_mutex_unlock(&hintlock);
1966                 return 0;
1967         }
1968
1969         if (!context || !exten)
1970                 return -1;
1971
1972         /* This callback type is for only one hint, so get the hint */
1973         e = ast_hint_extension(NULL, context, exten);    
1974         if (!e) {
1975                 return -1;
1976         }
1977
1978         /* Find the hint in the list of hints */
1979         ast_mutex_lock(&hintlock);
1980         list = hints;        
1981
1982         while (list) {
1983                 if (list->exten == e)
1984                         break;      
1985                 list = list->next;    
1986         }
1987
1988         if (!list) {
1989                 /* We have no hint, sorry */
1990                 ast_mutex_unlock(&hintlock);
1991                 return -1;
1992         }
1993
1994         /* Now insert the callback in the callback list  */
1995         cblist = malloc(sizeof(struct ast_state_cb));
1996         if (!cblist) {
1997                 ast_mutex_unlock(&hintlock);
1998                 return -1;
1999         }
2000         memset(cblist, 0, sizeof(struct ast_state_cb));
2001         cblist->id = stateid++;         /* Unique ID for this callback */
2002         cblist->callback = callback;    /* Pointer to callback routine */
2003         cblist->data = data;            /* Data for the callback */
2004
2005         cblist->next = list->callbacks;
2006         list->callbacks = cblist;
2007
2008         ast_mutex_unlock(&hintlock);
2009         return cblist->id;
2010 }
2011
2012 /*--- ast_extension_state_del: Remove a watcher from the callback list */
2013 int ast_extension_state_del(int id, ast_state_cb_type callback)
2014 {
2015         struct ast_hint *list;
2016         struct ast_state_cb *cblist, *cbprev;
2017
2018         if (!id && !callback)
2019                 return -1;
2020
2021         ast_mutex_lock(&hintlock);
2022
2023         /* id is zero is a callback without extension */
2024         if (!id) {
2025                 cbprev = NULL;
2026                 cblist = statecbs;
2027                 while (cblist) {
2028                         if (cblist->callback == callback) {
2029                                 if (!cbprev)
2030                                         statecbs = cblist->next;
2031                                 else
2032                                         cbprev->next = cblist->next;
2033
2034                                 free(cblist);
2035
2036                                 ast_mutex_unlock(&hintlock);
2037                                 return 0;
2038                         }
2039                         cbprev = cblist;
2040                         cblist = cblist->next;
2041                 }
2042
2043                 ast_mutex_lock(&hintlock);
2044                 return -1;
2045         }
2046
2047         /* id greater than zero is a callback with extension */
2048         /* Find the callback based on ID */
2049         list = hints;
2050         while (list) {
2051                 cblist = list->callbacks;
2052                 cbprev = NULL;
2053                 while (cblist) {
2054                         if (cblist->id==id) {
2055                                 if (!cbprev)
2056                                         list->callbacks = cblist->next;         
2057                                 else
2058                                         cbprev->next = cblist->next;
2059                 
2060                                 free(cblist);
2061                 
2062                                 ast_mutex_unlock(&hintlock);
2063                                 return 0;               
2064                         }               
2065                         cbprev = cblist;                                
2066                         cblist = cblist->next;
2067                 }
2068                 list = list->next;
2069         }
2070
2071         ast_mutex_unlock(&hintlock);
2072         return -1;
2073 }
2074
2075 /*--- ast_add_hint: Add hint to hint list, check initial extension state */
2076 static int ast_add_hint(struct ast_exten *e)
2077 {
2078         struct ast_hint *list;
2079
2080         if (!e) 
2081                 return -1;
2082
2083         ast_mutex_lock(&hintlock);
2084         list = hints;        
2085
2086         /* Search if hint exists, do nothing */
2087         while (list) {
2088                 if (list->exten == e) {
2089                         ast_mutex_unlock(&hintlock);
2090                         if (option_debug > 1)
2091                                 ast_log(LOG_DEBUG, "HINTS: Not re-adding existing hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
2092                         return -1;
2093                 }
2094                 list = list->next;    
2095         }
2096
2097         if (option_debug > 1)
2098                 ast_log(LOG_DEBUG, "HINTS: Adding hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
2099
2100         list = malloc(sizeof(struct ast_hint));
2101         if (!list) {
2102                 ast_mutex_unlock(&hintlock);
2103                 if (option_debug > 1)
2104                         ast_log(LOG_DEBUG, "HINTS: Out of memory...\n");
2105                 return -1;
2106         }
2107         /* Initialize and insert new item at the top */
2108         memset(list, 0, sizeof(struct ast_hint));
2109         list->exten = e;
2110         list->laststate = ast_extension_state2(e);
2111         list->next = hints;
2112         hints = list;
2113
2114         ast_mutex_unlock(&hintlock);
2115         return 0;
2116 }
2117
2118 /*--- ast_change_hint: Change hint for an extension */
2119 static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
2120
2121         struct ast_hint *list;
2122
2123         ast_mutex_lock(&hintlock);
2124         list = hints;
2125
2126         while(list) {
2127                 if (list->exten == oe) {
2128                         list->exten = ne;
2129                         ast_mutex_unlock(&hintlock);    
2130                         return 0;
2131                 }
2132                 list = list->next;
2133         }
2134         ast_mutex_unlock(&hintlock);
2135
2136         return -1;
2137 }
2138
2139 /*--- ast_remove_hint: Remove hint from extension */
2140 static int ast_remove_hint(struct ast_exten *e)
2141 {
2142         /* Cleanup the Notifys if hint is removed */
2143         struct ast_hint *list, *prev = NULL;
2144         struct ast_state_cb *cblist, *cbprev;
2145
2146         if (!e) 
2147                 return -1;
2148
2149         ast_mutex_lock(&hintlock);
2150
2151         list = hints;    
2152         while(list) {
2153                 if (list->exten==e) {
2154                         cbprev = NULL;
2155                         cblist = list->callbacks;
2156                         while (cblist) {
2157                                 /* Notify with -1 and remove all callbacks */
2158                                 cbprev = cblist;            
2159                                 cblist = cblist->next;
2160                                 cbprev->callback(list->exten->parent->name, list->exten->exten, -1, cbprev->data);
2161                                 free(cbprev);
2162                         }
2163                         list->callbacks = NULL;
2164
2165                         if (!prev)
2166                                 hints = list->next;
2167                         else
2168                                 prev->next = list->next;
2169                         free(list);
2170             
2171                         ast_mutex_unlock(&hintlock);
2172                         return 0;
2173                 } else {
2174                         prev = list;
2175                         list = list->next;    
2176                 }
2177         }
2178
2179         ast_mutex_unlock(&hintlock);
2180         return -1;
2181 }
2182
2183
2184 /*--- ast_get_hint: Get hint for channel */
2185 int ast_get_hint(char *hint, int hintsize, char *name, int namesize, struct ast_channel *c, const char *context, const char *exten)
2186 {
2187         struct ast_exten *e;
2188         void *tmp;
2189         e = ast_hint_extension(c, context, exten);
2190         if (e) {
2191                 if (hint) 
2192                     strncpy(hint, ast_get_extension_app(e), hintsize - 1);
2193                 if (name) {
2194                         tmp = ast_get_extension_app_data(e);
2195                         if (tmp)
2196                                 strncpy(name, (char *)tmp, namesize - 1);
2197                 }
2198             return -1;
2199         }
2200         return 0;       
2201 }
2202
2203 int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid) 
2204 {
2205         return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_EXISTS);
2206 }
2207
2208 int ast_findlabel_extension(struct ast_channel *c, const char *context, const char *exten, const char *label, const char *callerid) 
2209 {
2210         return pbx_extension_helper(c, NULL, context, exten, 0, label, callerid, HELPER_FINDLABEL);
2211 }
2212
2213 int ast_findlabel_extension2(struct ast_channel *c, struct ast_context *con, const char *exten, const char *label, const char *callerid) 
2214 {
2215         return pbx_extension_helper(c, con, NULL, exten, 0, label, callerid, HELPER_FINDLABEL);
2216 }
2217
2218 int ast_canmatch_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
2219 {
2220         return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_CANMATCH);
2221 }
2222
2223 int ast_matchmore_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
2224 {
2225         return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_MATCHMORE);
2226 }
2227
2228 int ast_spawn_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid) 
2229 {
2230         return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_SPAWN);
2231 }
2232
2233 int ast_exec_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid) 
2234 {
2235         return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_EXEC);
2236 }
2237
2238 static int __ast_pbx_run(struct ast_channel *c)
2239 {
2240         int firstpass = 1;
2241         char digit;
2242         char exten[256];
2243         int pos;
2244         int waittime;
2245         int res=0;
2246         int autoloopflag;
2247
2248         /* A little initial setup here */
2249         if (c->pbx)
2250                 ast_log(LOG_WARNING, "%s already has PBX structure??\n", c->name);
2251         c->pbx = malloc(sizeof(struct ast_pbx));
2252         if (!c->pbx) {
2253                 ast_log(LOG_ERROR, "Out of memory\n");
2254                 return -1;
2255         }
2256         if (c->amaflags) {
2257                 if (!c->cdr) {
2258                         c->cdr = ast_cdr_alloc();
2259                         if (!c->cdr) {
2260                                 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
2261                                 free(c->pbx);
2262                                 return -1;
2263                         }
2264                         ast_cdr_init(c->cdr, c);
2265                 }
2266         }
2267         memset(c->pbx, 0, sizeof(struct ast_pbx));
2268         /* Set reasonable defaults */
2269         c->pbx->rtimeout = 10;
2270         c->pbx->dtimeout = 5;
2271
2272         autoloopflag = ast_test_flag(c, AST_FLAG_IN_AUTOLOOP);
2273         ast_set_flag(c, AST_FLAG_IN_AUTOLOOP);
2274
2275         /* Start by trying whatever the channel is set to */
2276         if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2277                 /* If not successful fall back to 's' */
2278                 if (option_verbose > 1)
2279                         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);
2280                 strncpy(c->exten, "s", sizeof(c->exten)-1);
2281                 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2282                         /* JK02: And finally back to default if everything else failed */
2283                         if (option_verbose > 1)
2284                                 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);
2285                         strncpy(c->context, "default", sizeof(c->context)-1);
2286                 }
2287                 c->priority = 1;
2288         }
2289         if (c->cdr && !c->cdr->start.tv_sec && !c->cdr->start.tv_usec)
2290                 ast_cdr_start(c->cdr);
2291         for(;;) {
2292                 pos = 0;
2293                 digit = 0;
2294                 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2295                         memset(exten, 0, sizeof(exten));
2296                         if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
2297                                 /* Something bad happened, or a hangup has been requested. */
2298                                 if (((res >= '0') && (res <= '9')) || ((res >= 'A') && (res <= 'F')) ||
2299                                         (res == '*') || (res == '#')) {
2300                                         ast_log(LOG_DEBUG, "Oooh, got something to jump out with ('%c')!\n", res);
2301                                         memset(exten, 0, sizeof(exten));
2302                                         pos = 0;
2303                                         exten[pos++] = digit = res;
2304                                         break;
2305                                 }
2306                                 switch(res) {
2307                                 case AST_PBX_KEEPALIVE:
2308                                         if (option_debug)
2309                                                 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
2310                                         else if (option_verbose > 1)
2311                                                 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
2312                                         goto out;
2313                                         break;
2314                                 default:
2315                                         if (option_debug)
2316                                                 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2317                                         else if (option_verbose > 1)
2318                                                 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2319                                         if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
2320                                                 c->_softhangup =0;
2321                                                 break;
2322                                         }
2323                                         /* atimeout */
2324                                         if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
2325                                                 break;
2326                                         }
2327
2328                                         if (c->cdr) {
2329                                                 ast_cdr_update(c);
2330                                         }
2331                                         goto out;
2332                                 }
2333                         }
2334                         if ((c->_softhangup == AST_SOFTHANGUP_TIMEOUT) && (ast_exists_extension(c,c->context,"T",1,c->cid.cid_num))) {
2335                                 strncpy(c->exten,"T",sizeof(c->exten) - 1);
2336                                 /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
2337                                 c->whentohangup = 0;
2338                                 c->priority = 0;
2339                                 c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
2340                         } else if (c->_softhangup) {
2341                                 ast_log(LOG_DEBUG, "Extension %s, priority %d returned normally even though call was hung up\n",
2342                                         c->exten, c->priority);
2343                                 goto out;
2344                         }
2345                         firstpass = 0;
2346                         c->priority++;
2347                 }
2348                 if (!ast_exists_extension(c, c->context, c->exten, 1, c->cid.cid_num)) {
2349                         /* It's not a valid extension anymore */
2350                         if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
2351                                 if (option_verbose > 2)
2352                                         ast_verbose(VERBOSE_PREFIX_3 "Sent into invalid extension '%s' in context '%s' on %s\n", c->exten, c->context, c->name);
2353                                 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", c->exten);
2354                                 strncpy(c->exten, "i", sizeof(c->exten)-1);
2355                                 c->priority = 1;
2356                         } else {
2357                                 ast_log(LOG_WARNING, "Channel '%s' sent into invalid extension '%s' in context '%s', but no invalid handler\n",
2358                                         c->name, c->exten, c->context);
2359                                 goto out;
2360                         }
2361                 } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
2362                         /* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */
2363                         c->_softhangup = 0;
2364                 } else {
2365                         /* Done, wait for an extension */
2366                         waittime = 0;
2367                         if (digit)
2368                                 waittime = c->pbx->dtimeout;
2369                         else if (!autofallthrough)
2370                                 waittime = c->pbx->rtimeout;
2371                         if (waittime) {
2372                                 while (ast_matchmore_extension(c, c->context, exten, 1, c->cid.cid_num)) {
2373                                         /* As long as we're willing to wait, and as long as it's not defined, 
2374                                            keep reading digits until we can't possibly get a right answer anymore.  */
2375                                         digit = ast_waitfordigit(c, waittime * 1000);
2376                                         if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
2377                                                 c->_softhangup = 0;
2378                                         } else {
2379                                                 if (!digit)
2380                                                         /* No entry */
2381                                                         break;
2382                                                 if (digit < 0)
2383                                                         /* Error, maybe a  hangup */
2384                                                         goto out;
2385                                                 exten[pos++] = digit;
2386                                                 waittime = c->pbx->dtimeout;
2387                                         }
2388                                 }
2389                                 if (ast_exists_extension(c, c->context, exten, 1, c->cid.cid_num)) {
2390                                         /* Prepare the next cycle */
2391                                         strncpy(c->exten, exten, sizeof(c->exten)-1);
2392                                         c->priority = 1;
2393                                 } else {
2394                                         /* No such extension */
2395                                         if (!ast_strlen_zero(exten)) {
2396                                                 /* An invalid extension */
2397                                                 if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
2398                                                         if (option_verbose > 2)
2399                                                                 ast_verbose( VERBOSE_PREFIX_3 "Invalid extension '%s' in context '%s' on %s\n", exten, c->context, c->name);
2400                                                         pbx_builtin_setvar_helper(c, "INVALID_EXTEN", exten);
2401                                                         strncpy(c->exten, "i", sizeof(c->exten)-1);
2402                                                         c->priority = 1;
2403                                                 } else {
2404                                                         ast_log(LOG_WARNING, "Invalid extension '%s', but no rule 'i' in context '%s'\n", exten, c->context);
2405                                                         goto out;
2406                                                 }
2407                                         } else {
2408                                                 /* A simple timeout */
2409                                                 if (ast_exists_extension(c, c->context, "t", 1, c->cid.cid_num)) {
2410                                                         if (option_verbose > 2)
2411                                                                 ast_verbose( VERBOSE_PREFIX_3 "Timeout on %s\n", c->name);
2412                                                         strncpy(c->exten, "t", sizeof(c->exten)-1);
2413                                                         c->priority = 1;
2414                                                 } else {
2415                                                         ast_log(LOG_WARNING, "Timeout, but no rule 't' in context '%s'\n", c->context);
2416                                                         goto out;
2417                                                 }
2418                                         }       
2419                                 }
2420                                 if (c->cdr) {
2421                                         if (option_verbose > 2)
2422                                                 ast_verbose(VERBOSE_PREFIX_2 "CDR updated on %s\n",c->name);    
2423                                         ast_cdr_update(c);
2424                             }
2425                         } else {
2426                                 char *status;
2427
2428                                 status = pbx_builtin_getvar_helper(c, "DIALSTATUS");
2429                                 if (!status)
2430                                         status = "UNKNOWN";
2431                                 if (option_verbose > 2)
2432                                         ast_verbose(VERBOSE_PREFIX_2 "Auto fallthrough, channel '%s' status is '%s'\n", c->name, status);
2433                                 if (!strcasecmp(status, "CONGESTION"))
2434                                         res = pbx_builtin_congestion(c, "10");
2435                                 else if (!strcasecmp(status, "CHANUNAVAIL"))
2436                                         res = pbx_builtin_congestion(c, "10");
2437                                 else if (!strcasecmp(status, "BUSY"))
2438                                         res = pbx_builtin_busy(c, "10");
2439                                 goto out;
2440                         }
2441                 }
2442         }
2443         if (firstpass) 
2444                 ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", c->name);
2445 out:
2446         if ((res != AST_PBX_KEEPALIVE) && ast_exists_extension(c, c->context, "h", 1, c->cid.cid_num)) {
2447                 c->exten[0] = 'h';
2448                 c->exten[1] = '\0';
2449                 c->priority = 1;
2450                 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2451                         if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
2452                                 /* Something bad happened, or a hangup has been requested. */
2453                                 if (option_debug)
2454                                         ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2455                                 else if (option_verbose > 1)
2456                                         ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2457                                 break;
2458                         }
2459                         c->priority++;
2460                 }
2461         }
2462         ast_set2_flag(c, autoloopflag, AST_FLAG_IN_AUTOLOOP);
2463
2464         pbx_destroy(c->pbx);
2465         c->pbx = NULL;
2466         if (res != AST_PBX_KEEPALIVE)
2467                 ast_hangup(c);
2468         return 0;
2469 }
2470
2471 static void *pbx_thread(void *data)
2472 {
2473         /* Oh joyeous kernel, we're a new thread, with nothing to do but
2474            answer this channel and get it going.  The setjmp stuff is fairly
2475            confusing, but necessary to get smooth transitions between
2476            the execution of different applications (without the use of
2477            additional threads) */
2478         struct ast_channel *c = data;
2479         ast_pbx_run(c);
2480         pthread_exit(NULL);
2481         return NULL;
2482 }
2483
2484 int ast_pbx_start(struct ast_channel *c)
2485 {
2486         pthread_t t;
2487         pthread_attr_t attr;
2488         if (!c) {
2489                 ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
2490                 return -1;
2491         }
2492            
2493         /* Start a new thread, and get something handling this channel. */
2494         pthread_attr_init(&attr);
2495         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
2496         if (ast_pthread_create(&t, &attr, pbx_thread, c)) {
2497                 ast_log(LOG_WARNING, "Failed to create new channel thread\n");
2498                 return -1;
2499         }
2500         return 0;
2501 }
2502
2503 int ast_pbx_run(struct ast_channel *c)
2504 {
2505         int res = 0;
2506         ast_mutex_lock(&maxcalllock);
2507         if (option_maxcalls) {
2508                 if (countcalls >= option_maxcalls) {
2509                         ast_log(LOG_NOTICE, "Maximum call limit of %d calls exceeded by '%s'!\n", option_maxcalls, c->name);
2510                         res = -1;
2511                 }
2512         }
2513         if (!res)
2514                 countcalls++;   
2515         ast_mutex_unlock(&maxcalllock);
2516         if (!res) {
2517                 res = __ast_pbx_run(c);
2518                 ast_mutex_lock(&maxcalllock);
2519                 if (countcalls > 0)
2520                         countcalls--;
2521                 ast_mutex_unlock(&maxcalllock);
2522         }
2523         return res;
2524 }
2525
2526 int ast_active_calls(void)
2527 {
2528         return countcalls;
2529 }
2530
2531 int pbx_set_autofallthrough(int newval)
2532 {
2533         int oldval;
2534         oldval = autofallthrough;
2535         if (oldval != newval)
2536                 autofallthrough = newval;
2537         return oldval;
2538 }
2539
2540 /*
2541  * This function locks contexts list by &conlist, search for the right context
2542  * structure, leave context list locked and call ast_context_remove_include2
2543  * which removes include, unlock contexts list and return ...
2544  */
2545 int ast_context_remove_include(const char *context, const char *include, const char *registrar)
2546 {
2547         struct ast_context *c;
2548
2549         if (ast_lock_contexts()) return -1;
2550
2551         /* walk contexts and search for the right one ...*/
2552         c = ast_walk_contexts(NULL);
2553         while (c) {
2554                 /* we found one ... */
2555                 if (!strcmp(ast_get_context_name(c), context)) {
2556                         int ret;
2557                         /* remove include from this context ... */      
2558                         ret = ast_context_remove_include2(c, include, registrar);
2559
2560                         ast_unlock_contexts();
2561
2562                         /* ... return results */
2563                         return ret;
2564                 }
2565                 c = ast_walk_contexts(c);
2566         }
2567
2568         /* we can't find the right one context */
2569         ast_unlock_contexts();
2570         return -1;
2571 }
2572
2573 /*
2574  * When we call this function, &conlock lock must be locked, because when
2575  * we giving *con argument, some process can remove/change this context
2576  * and after that there can be segfault.
2577  *
2578  * This function locks given context, removes include, unlock context and
2579  * return.
2580  */
2581 int ast_context_remove_include2(struct ast_context *con, const char *include, const char *registrar)
2582 {
2583         struct ast_include *i, *pi = NULL;
2584
2585         if (ast_mutex_lock(&con->lock)) return -1;
2586
2587         /* walk includes */
2588         i = con->includes;
2589         while (i) {
2590                 /* find our include */
2591                 if (!strcmp(i->name, include) && 
2592                         (!registrar || !strcmp(i->registrar, registrar))) {
2593                         /* remove from list */
2594                         if (pi)
2595                                 pi->next = i->next;
2596                         else
2597                                 con->includes = i->next;
2598                         /* free include and return */
2599                         free(i);
2600                         ast_mutex_unlock(&con->lock);
2601                         return 0;
2602                 }
2603                 pi = i;
2604                 i = i->next;
2605         }
2606
2607         /* we can't find the right include */
2608         ast_mutex_unlock(&con->lock);
2609         return -1;
2610 }
2611
2612 /*
2613  * This function locks contexts list by &conlist, search for the rigt context
2614  * structure, leave context list locked and call ast_context_remove_switch2
2615  * which removes switch, unlock contexts list and return ...
2616  */
2617 int ast_context_remove_switch(const char *context, const char *sw, const char *data, const char *registrar)
2618 {
2619         struct ast_context *c;
2620
2621         if (ast_lock_contexts()) return -1;
2622
2623         /* walk contexts and search for the right one ...*/
2624         c = ast_walk_contexts(NULL);
2625         while (c) {
2626                 /* we found one ... */
2627                 if (!strcmp(ast_get_context_name(c), context)) {
2628                         int ret;
2629                         /* remove switch from this context ... */       
2630                         ret = ast_context_remove_switch2(c, sw, data, registrar);
2631
2632                         ast_unlock_contexts();
2633
2634                         /* ... return results */
2635                         return ret;
2636                 }
2637                 c = ast_walk_contexts(c);
2638         }
2639
2640         /* we can't find the right one context */
2641         ast_unlock_contexts();
2642         return -1;
2643 }
2644
2645 /*
2646  * When we call this function, &conlock lock must be locked, because when
2647  * we giving *con argument, some process can remove/change this context
2648  * and after that there can be segfault.
2649  *
2650  * This function locks given context, removes switch, unlock context and
2651  * return.
2652  */
2653 int ast_context_remove_switch2(struct ast_context *con, const char *sw, const char *data, const char *registrar)
2654 {
2655         struct ast_sw *i, *pi = NULL;
2656
2657         if (ast_mutex_lock(&con->lock)) return -1;
2658
2659         /* walk switchs */
2660         i = con->alts;
2661         while (i) {
2662                 /* find our switch */
2663                 if (!strcmp(i->name, sw) && !strcmp(i->data, data) && 
2664                         (!registrar || !strcmp(i->registrar, registrar))) {
2665                         /* remove from list */
2666                         if (pi)
2667                                 pi->next = i->next;
2668                         else
2669                                 con->alts = i->next;
2670                         /* free switch and return */
2671                         free(i);
2672                         ast_mutex_unlock(&con->lock);
2673                         return 0;
2674                 }
2675                 pi = i;
2676                 i = i->next;
2677         }
2678
2679         /* we can't find the right switch */
2680         ast_mutex_unlock(&con->lock);
2681         return -1;
2682 }
2683
2684 /*
2685  * This functions lock contexts list, search for the right context,
2686  * call ast_context_remove_extension2, unlock contexts list and return.
2687  * In this function we are using
2688  */
2689 int ast_context_remove_extension(const char *context, const char *extension, int priority, const char *registrar)
2690 {
2691         struct ast_context *c;
2692
2693         if (ast_lock_contexts()) return -1;
2694
2695         /* walk contexts ... */
2696         c = ast_walk_contexts(NULL);
2697         while (c) {
2698                 /* ... search for the right one ... */
2699                 if (!strcmp(ast_get_context_name(c), context)) {
2700                         /* ... remove extension ... */
2701                         int ret = ast_context_remove_extension2(c, extension, priority,
2702                                 registrar);
2703                         /* ... unlock contexts list and return */
2704                         ast_unlock_contexts();
2705                         return ret;
2706                 }
2707                 c = ast_walk_contexts(c);
2708         }
2709
2710         /* we can't find the right context */
2711         ast_unlock_contexts();
2712         return -1;
2713 }
2714
2715 /*
2716  * When do you want to call this function, make sure that &conlock is locked,
2717  * because some process can handle with your *con context before you lock
2718  * it.
2719  *
2720  * This functionc locks given context, search for the right extension and
2721  * fires out all peer in this extensions with given priority. If priority
2722  * is set to 0, all peers are removed. After that, unlock context and
2723  * return.
2724  */
2725 int ast_context_remove_extension2(struct ast_context *con, const char *extension, int priority, const char *registrar)
2726 {
2727         struct ast_exten *exten, *prev_exten = NULL;
2728
2729         if (ast_mutex_lock(&con->lock)) return -1;
2730
2731         /* go through all extensions in context and search the right one ... */
2732         exten = con->root;
2733         while (exten) {
2734
2735                 /* look for right extension */
2736                 if (!strcmp(exten->exten, extension) &&
2737                         (!registrar || !strcmp(exten->registrar, registrar))) {
2738                         struct ast_exten *peer;
2739
2740                         /* should we free all peers in this extension? (priority == 0)? */
2741                         if (priority == 0) {
2742                                 /* remove this extension from context list */
2743                                 if (prev_exten)
2744                                         prev_exten->next = exten->next;
2745                                 else
2746                                         con->root = exten->next;
2747
2748                                 /* fire out all peers */
2749                                 peer = exten; 
2750                                 while (peer) {
2751                                         exten = peer->peer;
2752                                         
2753                                         if (!peer->priority==PRIORITY_HINT) 
2754                                             ast_remove_hint(peer);
2755
2756                                         peer->datad(peer->data);
2757                                         free(peer);
2758
2759                                         peer = exten;
2760                                 }
2761
2762                                 ast_mutex_unlock(&con->lock);
2763                                 return 0;
2764                         } else {
2765                                 /* remove only extension with exten->priority == priority */
2766                                 struct ast_exten *previous_peer = NULL;
2767
2768                                 peer = exten;
2769                                 while (peer) {
2770                                         /* is this our extension? */
2771                                         if (peer->priority == priority &&
2772                                                 (!registrar || !strcmp(peer->registrar, registrar) )) {
2773                                                 /* we are first priority extension? */
2774                                                 if (!previous_peer) {
2775                                                         /* exists previous extension here? */
2776                                                         if (prev_exten) {
2777                                                                 /* yes, so we must change next pointer in
2778                                                                  * previous connection to next peer
2779                                                                  */
2780                                                                 if (peer->peer) {
2781                                                                         prev_exten->next = peer->peer;
2782                                                                         peer->peer->next = exten->next;
2783                                                                 } else
2784                                                                         prev_exten->next = exten->next;
2785                                                         } else {
2786                                                                 /* no previous extension, we are first
2787                                                                  * extension, so change con->root ...
2788                                                                  */
2789                                                                 if (peer->peer)
2790                                                                         con->root = peer->peer;
2791                                                                 else
2792                                                                         con->root = exten->next; 
2793                                                         }
2794                                                 } else {
2795                                                         /* we are not first priority in extension */
2796                                                         previous_peer->peer = peer->peer;
2797                                                 }
2798
2799                                                 /* now, free whole priority extension */
2800                                                 if (peer->priority==PRIORITY_HINT)
2801                                                     ast_remove_hint(peer);
2802                                                 peer->datad(peer->data);
2803                                                 free(peer);
2804
2805                                                 ast_mutex_unlock(&con->lock);
2806                                                 return 0;
2807                                         } else {
2808                                                 /* this is not right extension, skip to next peer */
2809                                                 previous_peer = peer;
2810                                                 peer = peer->peer;
2811                                         }
2812                                 }
2813
2814                                 ast_mutex_unlock(&con->lock);
2815                                 return -1;
2816                         }
2817                 }
2818
2819                 prev_exten = exten;
2820                 exten = exten->next;
2821         }
2822
2823         /* we can't find right extension */
2824         ast_mutex_unlock(&con->lock);
2825         return -1;
2826 }
2827
2828
2829 int ast_register_application(const char *app, int (*execute)(struct ast_channel *, void *), const char *synopsis, const char *description)
2830 {
2831         struct ast_app *tmp, *prev, *cur;
2832         char tmps[80];
2833         int length;
2834         length = sizeof(struct ast_app);
2835         length += strlen(app) + 1;
2836         if (ast_mutex_lock(&applock)) {
2837                 ast_log(LOG_ERROR, "Unable to lock application list\n");
2838                 return -1;
2839         }
2840         tmp = apps;
2841         while(tmp) {
2842                 if (!strcasecmp(app, tmp->name)) {
2843                         ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
2844                         ast_mutex_unlock(&applock);
2845                         return -1;
2846                 }
2847                 tmp = tmp->next;
2848         }
2849         tmp = malloc(length);
2850         if (tmp) {
2851                 memset(tmp, 0, length);
2852                 strcpy(tmp->name, app);
2853                 tmp->execute = execute;
2854                 tmp->synopsis = synopsis;
2855                 tmp->description = description;
2856                 /* Store in alphabetical order */
2857                 cur = apps;
2858                 prev = NULL;
2859                 while(cur) {
2860                         if (strcasecmp(tmp->name, cur->name) < 0)
2861                                 break;
2862                         prev = cur;
2863                         cur = cur->next;
2864                 }
2865                 if (prev) {
2866                         tmp->next = prev->next;
2867                         prev->next = tmp;
2868                 } else {
2869                         tmp->next = apps;
2870                         apps = tmp;
2871                 }
2872         } else {
2873                 ast_log(LOG_ERROR, "Out of memory\n");
2874                 ast_mutex_unlock(&applock);
2875                 return -1;
2876         }
2877         if (option_verbose > 1)
2878                 ast_verbose( VERBOSE_PREFIX_2 "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
2879         ast_mutex_unlock(&applock);
2880         return 0;
2881 }
2882
2883 int ast_register_switch(struct ast_switch *sw)
2884 {
2885         struct ast_switch *tmp, *prev=NULL;
2886         if (ast_mutex_lock(&switchlock)) {
2887                 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
2888                 return -1;
2889         }
2890         tmp = switches;
2891         while(tmp) {
2892                 if (!strcasecmp(tmp->name, sw->name))
2893                         break;
2894                 prev = tmp;
2895                 tmp = tmp->next;
2896         }
2897         if (tmp) {      
2898                 ast_mutex_unlock(&switchlock);
2899                 ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name);
2900                 return -1;
2901         }
2902         sw->next = NULL;
2903         if (prev) 
2904                 prev->next = sw;
2905         else
2906                 switches = sw;
2907         ast_mutex_unlock(&switchlock);
2908         return 0;
2909 }
2910
2911 void ast_unregister_switch(struct ast_switch *sw)
2912 {
2913         struct ast_switch *tmp, *prev=NULL;
2914         if (ast_mutex_lock(&switchlock)) {
2915                 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
2916                 return;
2917         }
2918         tmp = switches;
2919         while(tmp) {
2920                 if (tmp == sw) {
2921                         if (prev)
2922                                 prev->next = tmp->next;
2923                         else
2924                                 switches = tmp->next;
2925                         tmp->next = NULL;
2926                         break;                  
2927                 }
2928                 prev = tmp;
2929                 tmp = tmp->next;
2930         }
2931         ast_mutex_unlock(&switchlock);
2932 }
2933
2934 /*
2935  * Help for CLI commands ...
2936  */
2937 static char show_application_help[] = 
2938 "Usage: show application <application> [<application> [<application> [...]]]\n"
2939 "       Describes a particular application.\n";
2940
2941 static char show_functions_help[] =
2942 "Usage: show functions\n"
2943 "       List builtin functions accessable as $(function args)\n";
2944
2945 static char show_function_help[] =
2946 "Usage: show function <function>\n"
2947 "       Describe a particular dialplan function.\n";
2948
2949 static char show_applications_help[] =
2950 "Usage: show applications [{like|describing} <text>]\n"
2951 "       List applications which are currently available.\n"
2952 "       If 'like', <text> will be a substring of the app name\n"
2953 "       If 'describing', <text> will be a substring of the description\n";
2954
2955 static char show_dialplan_help[] =
2956 "Usage: show dialplan [exten@][context]\n"
2957 "       Show dialplan\n";
2958
2959 static char show_switches_help[] = 
2960 "Usage: show switches\n"
2961 "       Show registered switches\n";
2962
2963 static char show_hints_help[] = 
2964 "Usage: show hints\n"
2965 "       Show registered hints\n";
2966
2967
2968 /*
2969  * IMPLEMENTATION OF CLI FUNCTIONS IS IN THE SAME ORDER AS COMMANDS HELPS
2970  *
2971  */
2972
2973 /*
2974  * 'show application' CLI command implementation functions ...
2975  */
2976
2977 /*
2978  * There is a possibility to show informations about more than one
2979  * application at one time. You can type 'show application Dial Echo' and
2980  * you will see informations about these two applications ...
2981  */
2982 static char *complete_show_application(char *line, char *word,
2983         int pos, int state)
2984 {
2985         struct ast_app *a;
2986         int which = 0;
2987
2988         /* try to lock applications list ... */
2989         if (ast_mutex_lock(&applock)) {
2990                 ast_log(LOG_ERROR, "Unable to lock application list\n");
2991                 return NULL;
2992         }
2993
2994         /* ... walk all applications ... */
2995         a = apps; 
2996         while (a) {
2997                 /* ... check if word matches this application ... */
2998                 if (!strncasecmp(word, a->name, strlen(word))) {
2999                         /* ... if this is right app serve it ... */
3000                         if (++which > state) {
3001                                 char *ret = strdup(a->name);
3002                                 ast_mutex_unlock(&applock);
3003                                 return ret;
3004                         }
3005                 }
3006                 a = a->next; 
3007         }
3008
3009         /* no application match */
3010         ast_mutex_unlock(&applock);
3011         return NULL; 
3012 }
3013
3014 static int handle_show_application(int fd, int argc, char *argv[])
3015 {
3016         struct ast_app *a;
3017         int app, no_registered_app = 1;
3018
3019         if (argc < 3) return RESULT_SHOWUSAGE;
3020
3021         /* try to lock applications list ... */
3022         if (ast_mutex_lock(&applock)) {
3023                 ast_log(LOG_ERROR, "Unable to lock application list\n");
3024                 return -1;
3025         }
3026
3027         /* ... go through all applications ... */
3028         a = apps; 
3029         while (a) {
3030                 /* ... compare this application name with all arguments given
3031                  * to 'show application' command ... */
3032                 for (app = 2; app < argc; app++) {
3033                         if (!strcasecmp(a->name, argv[app])) {
3034                                 /* Maximum number of characters added by terminal coloring is 22 */
3035                                 char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
3036                                 char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
3037                                 int synopsis_size, description_size;
3038
3039                                 no_registered_app = 0;
3040
3041                                 if (a->synopsis)
3042                                         synopsis_size = strlen(a->synopsis) + 23;
3043                                 else
3044                                         synopsis_size = strlen("Not available") + 23;
3045                                 synopsis = alloca(synopsis_size);
3046
3047                                 if (a->description)
3048                                         description_size = strlen(a->description) + 23;
3049                                 else
3050                                         description_size = strlen("Not available") + 23;
3051                                 description = alloca(description_size);
3052
3053                                 if (synopsis && description) {
3054                                         snprintf(info, 64 + AST_MAX_APP, "\n  -= Info about application '%s' =- \n\n", a->name);
3055                                         term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
3056                                         term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
3057                                         term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
3058                                         term_color(synopsis,
3059                                                                         a->synopsis ? a->synopsis : "Not available",
3060                                                                         COLOR_CYAN, 0, synopsis_size);
3061                                         term_color(description,
3062                                                                         a->description ? a->description : "Not available",
3063                                                                         COLOR_CYAN, 0, description_size);
3064
3065                                         ast_cli(fd,"%s%s%s\n\n%s%s\n", infotitle, syntitle, synopsis, destitle, description);
3066                                 } else {
3067                                         /* ... one of our applications, show info ...*/
3068                                         ast_cli(fd,"\n  -= Info about application '%s' =- \n\n"
3069                                                 "[Synopsis]\n  %s\n\n"
3070                                                 "[Description]\n%s\n",
3071                                                 a->name,
3072                                                 a->synopsis ? a->synopsis : "Not available",
3073                                                 a->description ? a->description : "Not available");
3074                                 }
3075                         }
3076                 }
3077                 a = a->next; 
3078         }
3079
3080         ast_mutex_unlock(&applock);
3081
3082         /* we found at least one app? no? */
3083         if (no_registered_app) {
3084                 ast_cli(fd, "Your application(s) is (are) not registered\n");
3085                 return RESULT_FAILURE;
3086         }
3087
3088         return RESULT_SUCCESS;
3089 }
3090
3091 /*--- handle_show_hints: CLI support for listing registred dial plan hints */
3092 static int handle_show_hints(int fd, int argc, char *argv[])
3093 {
3094         struct ast_hint *hint;
3095         int num = 0;
3096
3097         if (!hints) {
3098                 ast_cli(fd, "There are no registered dialplan hints\n");
3099                 return RESULT_SUCCESS;
3100         }
3101         /* ... we have hints ... */
3102         ast_cli(fd, "\n    -= Registered Asterisk Dial Plan Hints =-\n");
3103         if (ast_mutex_lock(&hintlock)) {
3104                 ast_log(LOG_ERROR, "Unable to lock hints\n");
3105                 return -1;
3106         }
3107         hint = hints;
3108         while (hint) {
3109                 ast_cli(fd, "   %-20.20s: %-20.20s  State %2d\n", ast_get_extension_name(hint->exten), ast_get_extension_app(hint->exten), hint->laststate );
3110                 num++;
3111                 hint = hint->next;
3112         }
3113         ast_cli(fd, "----------------\n");
3114         ast_cli(fd, "- %d hints registred\n", num);
3115         ast_mutex_unlock(&hintlock);
3116         return RESULT_SUCCESS;
3117 }
3118
3119 /*--- handle_show_switches: CLI support for listing registred dial plan switches */
3120 static int handle_show_switches(int fd, int argc, char *argv[])
3121 {
3122         struct ast_switch *sw;
3123         if (!switches) {
3124                 ast_cli(fd, "There are no registered alternative switches\n");
3125                 return RESULT_SUCCESS;
3126         }
3127         /* ... we have applications ... */
3128         ast_cli(fd, "\n    -= Registered Asterisk Alternative Switches =-\n");
3129         if (ast_mutex_lock(&switchlock)) {
3130                 ast_log(LOG_ERROR, "Unable to lock switches\n");
3131                 return -1;
3132         }
3133         sw = switches;
3134         while (sw) {
3135                 ast_cli(fd, "%s: %s\n", sw->name, sw->description);
3136                 sw = sw->next;
3137         }
3138         ast_mutex_unlock(&switchlock);
3139         return RESULT_SUCCESS;
3140 }
3141
3142 /*
3143  * 'show applications' CLI command implementation functions ...
3144  */
3145 static int handle_show_applications(int fd, int argc, char *argv[])
3146 {
3147         struct ast_app *a;
3148         int like=0, describing=0;
3149         int total_match = 0;    /* Number of matches in like clause */
3150         int total_apps = 0;     /* Number of apps registered */
3151         
3152         /* try to lock applications list ... */
3153         if (ast_mutex_lock(&applock)) {
3154                 ast_log(LOG_ERROR, "Unable to lock application list\n");
3155                 return -1;
3156         }
3157
3158         /* ... have we got at least one application (first)? no? */
3159         if (!apps) {
3160                 ast_cli(fd, "There are no registered applications\n");
3161                 ast_mutex_unlock(&applock);
3162                 return -1;
3163         }
3164
3165         /* show applications like <keyword> */
3166         if ((argc == 4) && (!strcmp(argv[2], "like"))) {
3167                 like = 1;
3168         } else if ((argc > 3) && (!strcmp(argv[2], "describing"))) {
3169                 describing = 1;
3170         }
3171
3172         /* show applications describing <keyword1> [<keyword2>] [...] */
3173         if ((!like) && (!describing)) {
3174                 ast_cli(fd, "    -= Registered Asterisk Applications =-\n");
3175         } else {
3176                 ast_cli(fd, "    -= Matching Asterisk Applications =-\n");
3177         }
3178
3179         /* ... go through all applications ... */
3180         for (a = apps; a; a = a->next) {
3181                 /* ... show informations about applications ... */
3182                 int printapp=0;
3183                 total_apps++;
3184                 if (like) {
3185                         if (ast_strcasestr(a->name, argv[3])) {
3186                                 printapp = 1;
3187                                 total_match++;
3188                         }
3189                 } else if (describing) {
3190                         if (a->description) {
3191                                 /* Match all words on command line */
3192                                 int i;
3193                                 printapp = 1;
3194                                 for (i=3;i<argc;i++) {
3195                                         if (! ast_strcasestr(a->description, argv[i])) {
3196                                                 printapp = 0;
3197                                         } else {
3198                                                 total_match++;
3199                                         }
3200                                 }
3201                         }
3202                 } else {
3203                         printapp = 1;
3204                 }
3205
3206                 if (printapp) {
3207                         ast_cli(fd,"  %20s: %s\n", a->name, a->synopsis ? a->synopsis : "<Synopsis not available>");
3208                 }
3209         }
3210         if ((!like) && (!describing)) {
3211                 ast_cli(fd, "    -= %d Applications Registered =-\n",total_apps);
3212         } else {
3213                 ast_cli(fd, "    -= %d Applications Matching =-\n",total_match);
3214         }
3215         
3216         /* ... unlock and return */
3217         ast_mutex_unlock(&applock);
3218
3219         return RESULT_SUCCESS;
3220 }
3221
3222 static char *complete_show_applications(char *line, char *word, int pos, int state)
3223 {
3224         if (pos == 2) {
3225                 if (ast_strlen_zero(word)) {
3226                         switch (state) {
3227                         case 0:
3228                                 return strdup("like");
3229                         case 1:
3230                                 return strdup("describing");
3231                         default:
3232                                 return NULL;
3233                         }
3234                 } else if (! strncasecmp(word, "like", strlen(word))) {
3235                         if (state == 0) {
3236                                 return strdup("like");
3237                         } else {
3238                                 return NULL;
3239                         }
3240                 } else if (! strncasecmp(word, "describing", strlen(word))) {
3241                         if (state == 0) {
3242                                 return strdup("describing");
3243                         } else {
3244                                 return NULL;
3245                         }
3246                 }
3247         }
3248         return NULL;
3249 }
3250
3251 /*
3252  * 'show dialplan' CLI command implementation functions ...
3253  */
3254 static char *complete_show_dialplan_context(char *line, char *word, int pos,
3255         int state)
3256 {
3257         struct ast_context *c;
3258         int which = 0;
3259
3260         /* we are do completion of [exten@]context on second position only */
3261         if (pos != 2) return NULL;
3262
3263         /* try to lock contexts list ... */
3264         if (ast_lock_contexts()) {
3265                 ast_log(LOG_ERROR, "Unable to lock context list\n");
3266                 return NULL;
3267         }
3268
3269         /* ... walk through all contexts ... */
3270         c = ast_walk_contexts(NULL);
3271         while(c) {
3272                 /* ... word matches context name? yes? ... */
3273                 if (!strncasecmp(word, ast_get_context_name(c), strlen(word))) {
3274                         /* ... for serve? ... */
3275                         if (++which > state) {
3276                                 /* ... yes, serve this context name ... */
3277                                 char *ret = strdup(ast_get_context_name(c));
3278                                 ast_unlock_contexts();
3279                                 return ret;
3280                         }
3281                 }
3282                 c = ast_walk_contexts(c);
3283         }
3284
3285         /* ... unlock and return */
3286         ast_unlock_contexts();
3287         return NULL;
3288 }
3289
3290 struct dialplan_counters {
3291         int total_context;
3292         int total_exten;
3293         int total_prio;
3294         int context_existence;
3295         int extension_existence;
3296 };
3297
3298 static int show_dialplan_helper(int fd, char *context, char *exten, struct dialplan_counters *dpc, struct ast_include *rinclude)
3299 {
3300         struct ast_context *c;
3301         int res=0, old_total_exten = dpc->total_exten;
3302
3303         /* try to lock contexts */
3304         if (ast_lock_contexts()) {
3305                 ast_log(LOG_WARNING, "Failed to lock contexts list\n");
3306                 return -1;
3307         }
3308
3309         /* walk all contexts ... */
3310         for (c = ast_walk_contexts(NULL); c ; c = ast_walk_contexts(c)) {
3311                 /* show this context? */
3312                 if (!context ||
3313                         !strcmp(ast_get_context_name(c), context)) {
3314                         dpc->context_existence = 1;
3315
3316                         /* try to lock context before walking in ... */
3317                         if (!ast_lock_context(c)) {
3318                                 struct ast_exten *e;
3319                                 struct ast_include *i;
3320                                 struct ast_ignorepat *ip;
3321                                 struct ast_sw *sw;
3322                                 char buf[256], buf2[256];
3323                                 int context_info_printed = 0;
3324
3325                                 /* are we looking for exten too? if yes, we print context
3326                                  * if we our extension only
3327                                  */
3328                                 if (!exten) {
3329                                         dpc->total_context++;
3330                                         ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
3331                                                 ast_get_context_name(c), ast_get_context_registrar(c));
3332                                         context_info_printed = 1;
3333                                 }
3334
3335                                 /* walk extensions ... */
3336                                 for (e = ast_walk_context_extensions(c, NULL); e; e = ast_walk_context_extensions(c, e)) {
3337                                         struct ast_exten *p;
3338                                         int prio;
3339
3340                                         /* looking for extension? is this our extension? */
3341                                         if (exten &&
3342                                                 !ast_extension_match(ast_get_extension_name(e), exten))
3343                                         {
3344                                                 /* we are looking for extension and it's not our
3345                                                  * extension, so skip to next extension */
3346                                                 continue;
3347                                         }
3348
3349                                         dpc->extension_existence = 1;
3350
3351                                         /* may we print context info? */        
3352                                         if (!context_info_printed) {
3353                                                 dpc->total_context++;
3354                                                 if (rinclude) {
3355                                                         /* TODO Print more info about rinclude */
3356                                                         ast_cli(fd, "[ Included context '%s' created by '%s' ]\n",
3357                                                                 ast_get_context_name(c),
3358                                                                 ast_get_context_registrar(c));
3359                                                 } else {
3360                                                         ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
3361                                                                 ast_get_context_name(c),
3362                                                                 ast_get_context_registrar(c));
3363                                                 }
3364                                                 context_info_printed = 1;
3365                                         }
3366                                         dpc->total_prio++;
3367
3368                                         /* write extension name and first peer */       
3369                                         bzero(buf, sizeof(buf));                
3370                                         snprintf(buf, sizeof(buf), "'%s' =>",
3371                                                 ast_get_extension_name(e));
3372
3373                                         prio = ast_get_extension_priority(e);
3374                                         if (prio == PRIORITY_HINT) {
3375                                                 snprintf(buf2, sizeof(buf2),
3376                                                         "hint: %s",
3377                                                         ast_get_extension_app(e));
3378                                         } else {
3379                                                 snprintf(buf2, sizeof(buf2),
3380                                                         "%d. %s(%s)",
3381                                                         prio,
3382                                                         ast_get_extension_app(e),
3383                                                         (char *)ast_get_extension_app_data(e));
3384                                         }
3385
3386                                         ast_cli(fd, "  %-17s %-45s [%s]\n", buf, buf2,
3387                                                 ast_get_extension_registrar(e));
3388
3389                                         dpc->total_exten++;
3390                                         /* walk next extension peers */
3391                                         for (p=ast_walk_extension_priorities(e, e); p; p=ast_walk_extension_priorities(e, p)) {
3392                                                 dpc->total_prio++;
3393                                                 bzero((void *)buf2, sizeof(buf2));
3394                                                 bzero((void *)buf, sizeof(buf));
3395                                                 if (ast_get_extension_label(p))
3396                                                         snprintf(buf, sizeof(buf), "   [%s]", ast_get_extension_label(p));
3397                                                 prio = ast_get_extension_priority(p);
3398                                                 if (prio == PRIORITY_HINT) {
3399                                                         snprintf(buf2, sizeof(buf2),
3400                                                                 "hint: %s",
3401                                                                 ast_get_extension_app(p));
3402                                                 } else {
3403                                                         snprintf(buf2, sizeof(buf2),
3404                                                                 "%d. %s(%s)",
3405                                                                 prio,
3406                                                                 ast_get_extension_app(p),
3407                                                                 (char *)ast_get_extension_app_data(p));
3408                                                 }
3409
3410                                                 ast_cli(fd,"  %-17s %-45s [%s]\n",
3411                                                         buf, buf2,
3412                                                         ast_get_extension_registrar(p));
3413                                         }
3414                                 }
3415
3416                                 /* walk included and write info ... */
3417                                 for (i = ast_walk_context_includes(c, NULL); i; i = ast_walk_context_includes(c, i)) {
3418                                         bzero(buf, sizeof(buf));
3419                                         snprintf(buf, sizeof(buf), "'%s'",
3420                                                 ast_get_include_name(i));
3421                                         if (exten) {
3422                                                 /* Check all includes for the requested extension */
3423                                                 show_dialplan_helper(fd, (char *)ast_get_include_name(i), exten, dpc, i);
3424                                         } else {
3425                                                 ast_cli(fd, "  Include =>        %-45s [%s]\n",
3426                                   &nbs