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