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