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