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