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