constify arguments in more places where strings should not be modified (issue #6286)
[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];
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          */
922         s = &not_found; /* default value */
923         if (c) {        /* This group requires a valid channel */
924                 /* Names with common parts are looked up a piece at a time using strncmp. */
925                 if (!strncmp(var, "CALL", 4)) {
926                         if (!strncmp(var + 4, "ING", 3)) {
927                                 if (!strcmp(var + 7, "PRES")) {                 /* CALLINGPRES */
928                                         snprintf(workspace, workspacelen, "%d", c->cid.cid_pres);
929                                         s = workspace;
930                                 } else if (!strcmp(var + 7, "ANI2")) {          /* CALLINGANI2 */
931                                         snprintf(workspace, workspacelen, "%d", c->cid.cid_ani2);
932                                         s = workspace;
933                                 } else if (!strcmp(var + 7, "TON")) {           /* CALLINGTON */
934                                         snprintf(workspace, workspacelen, "%d", c->cid.cid_ton);
935                                         s = workspace;
936                                 } else if (!strcmp(var + 7, "TNS")) {           /* CALLINGTNS */
937                                         snprintf(workspace, workspacelen, "%d", c->cid.cid_tns);
938                                         s = workspace;
939                                 }
940                         }
941                 } else if (!strcmp(var, "HINT")) {
942                         s = ast_get_hint(workspace, workspacelen, NULL, 0, c, c->context, c->exten) ? workspace : NULL;
943                 } else if (!strcmp(var, "HINTNAME")) {
944                         s = ast_get_hint(NULL, 0, workspace, workspacelen, c, c->context, c->exten) ? workspace : NULL;
945                 } else if (!strcmp(var, "EXTEN")) {
946                         s = c->exten;
947                 } else if (!strcmp(var, "CONTEXT")) {
948                         s = c->context;
949                 } else if (!strcmp(var, "PRIORITY")) {
950                         snprintf(workspace, workspacelen, "%d", c->priority);
951                         s = workspace;
952                 } else if (!strcmp(var, "CHANNEL")) {
953                         s = c->name;
954                 } else if (!strcmp(var, "UNIQUEID")) {
955                         s = c->uniqueid;
956                 } else if (!strcmp(var, "HANGUPCAUSE")) {
957                         snprintf(workspace, workspacelen, "%d", c->hangupcause);
958                         s = workspace;
959                 }
960         }
961         if (s == &not_found) { /* look for more */
962                 if (!strcmp(var, "EPOCH")) {
963                         snprintf(workspace, workspacelen, "%u",(int)time(NULL));
964                         s = workspace;
965                 }
966         }
967         /* if not found, look into chanvars or global vars */
968         for (i = 0; s == &not_found && i < (sizeof(places) / sizeof(places[0])); i++) {
969                 struct ast_var_t *variables;
970                 if (!places[i])
971                         continue;
972                 AST_LIST_TRAVERSE(places[i], variables, entries) {
973                         if (strcasecmp(ast_var_name(variables), var)==0) {
974                                 s = ast_var_value(variables);
975                                 break;
976                         }
977                 }
978         }
979         if (s == &not_found || s == NULL)
980                 *ret = NULL;
981         else {
982                 if (s != workspace)
983                         ast_copy_string(workspace, s, workspacelen);
984                 *ret = workspace;
985                 if (need_substring)
986                         *ret = substring(*ret, offset, length, workspace, workspacelen);
987         }
988 }
989
990 /*! \brief CLI function to show installed custom functions 
991     \addtogroup CLI_functions
992  */
993 static int handle_show_functions(int fd, int argc, char *argv[])
994 {
995         struct ast_custom_function *acf;
996         int count_acf = 0;
997         int print_acf = 0;
998         int like = 0;
999
1000         if (argc == 4 && (!strcmp(argv[2], "like")) ) {
1001                 like = 1;
1002         } else if (argc != 2) {
1003                 return RESULT_SHOWUSAGE;
1004         }
1005
1006         ast_cli(fd, "%s Custom Functions:\n--------------------------------------------------------------------------------\n", like ? "Matching" : "Installed");
1007         
1008         for (acf = acf_root ; acf; acf = acf->next) {
1009                 print_acf = 0;
1010                 if (like) {
1011                         if (strstr(acf->name, argv[3])) {
1012                                 print_acf = 1;
1013                                 count_acf++;
1014                         }
1015                 } else {
1016                         print_acf = 1;
1017                         count_acf++;
1018                 } 
1019
1020                 if (print_acf) {
1021                         ast_cli(fd, "%-20.20s  %-35.35s  %s\n", acf->name, acf->syntax, acf->synopsis);
1022                 }
1023         }
1024
1025         ast_cli(fd, "%d %scustom functions installed.\n", count_acf, like ? "matching " : "");
1026
1027         return 0;
1028 }
1029
1030 static int handle_show_function(int fd, int argc, char *argv[])
1031 {
1032         struct ast_custom_function *acf;
1033         /* Maximum number of characters added by terminal coloring is 22 */
1034         char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
1035         char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
1036         char stxtitle[40], *syntax = NULL;
1037         int synopsis_size, description_size, syntax_size;
1038
1039         if (argc < 3) return RESULT_SHOWUSAGE;
1040
1041         if (!(acf = ast_custom_function_find(argv[2]))) {
1042                 ast_cli(fd, "No function by that name registered.\n");
1043                 return RESULT_FAILURE;
1044
1045         }
1046
1047         if (acf->synopsis)
1048                 synopsis_size = strlen(acf->synopsis) + 23;
1049         else
1050                 synopsis_size = strlen("Not available") + 23;
1051         synopsis = alloca(synopsis_size);
1052         
1053         if (acf->desc)
1054                 description_size = strlen(acf->desc) + 23;
1055         else
1056                 description_size = strlen("Not available") + 23;
1057         description = alloca(description_size);
1058
1059         if (acf->syntax)
1060                 syntax_size = strlen(acf->syntax) + 23;
1061         else
1062                 syntax_size = strlen("Not available") + 23;
1063         syntax = alloca(syntax_size);
1064
1065         snprintf(info, 64 + AST_MAX_APP, "\n  -= Info about function '%s' =- \n\n", acf->name);
1066         term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
1067         term_color(stxtitle, "[Syntax]\n", COLOR_MAGENTA, 0, 40);
1068         term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
1069         term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
1070         term_color(syntax,
1071                    acf->syntax ? acf->syntax : "Not available",
1072                    COLOR_CYAN, 0, syntax_size);
1073         term_color(synopsis,
1074                    acf->synopsis ? acf->synopsis : "Not available",
1075                    COLOR_CYAN, 0, synopsis_size);
1076         term_color(description,
1077                    acf->desc ? acf->desc : "Not available",
1078                    COLOR_CYAN, 0, description_size);
1079         
1080         ast_cli(fd,"%s%s%s\n\n%s%s\n\n%s%s\n", infotitle, stxtitle, syntax, syntitle, synopsis, destitle, description);
1081
1082         return RESULT_SUCCESS;
1083 }
1084
1085 static char *complete_show_function(const char *line, const char *word, int pos, int state)
1086 {
1087         struct ast_custom_function *acf;
1088         char *ret = NULL;
1089         int which = 0;
1090         int wordlen = strlen(word);
1091
1092         /* try to lock functions list ... */
1093         if (ast_mutex_lock(&acflock)) {
1094                 ast_log(LOG_ERROR, "Unable to lock function list\n");
1095                 return NULL;
1096         }
1097
1098         /* case-insensitive for convenience in this 'complete' function */
1099         for (acf = acf_root; acf && !ret; acf = acf->next) {
1100                 if (!strncasecmp(word, acf->name, wordlen) && ++which > state)
1101                         ret = strdup(acf->name);
1102         }
1103
1104         ast_mutex_unlock(&acflock);
1105
1106         return ret; 
1107 }
1108
1109 struct ast_custom_function* ast_custom_function_find(const char *name) 
1110 {
1111         struct ast_custom_function *acfptr;
1112
1113         /* try to lock functions list ... */
1114         if (ast_mutex_lock(&acflock)) {
1115                 ast_log(LOG_ERROR, "Unable to lock function list\n");
1116                 return NULL;
1117         }
1118
1119         for (acfptr = acf_root; acfptr; acfptr = acfptr->next) {
1120                 if (!strcmp(name, acfptr->name))
1121                         break;
1122         }
1123
1124         ast_mutex_unlock(&acflock);
1125         
1126         return acfptr;
1127 }
1128
1129 int ast_custom_function_unregister(struct ast_custom_function *acf) 
1130 {
1131         struct ast_custom_function *acfptr, *lastacf = NULL;
1132         int res = -1;
1133
1134         if (!acf)
1135                 return -1;
1136
1137         /* try to lock functions list ... */
1138         if (ast_mutex_lock(&acflock)) {
1139                 ast_log(LOG_ERROR, "Unable to lock function list\n");
1140                 return -1;
1141         }
1142
1143         for (acfptr = acf_root; acfptr; acfptr = acfptr->next) {
1144                 if (acfptr == acf) {
1145                         if (lastacf) {
1146                                 lastacf->next = acf->next;
1147                         } else {
1148                                 acf_root = acf->next;
1149                         }
1150                         res = 0;
1151                         break;
1152                 }
1153                 lastacf = acfptr;
1154         }
1155
1156         ast_mutex_unlock(&acflock);
1157
1158         if (!res && (option_verbose > 1))
1159                 ast_verbose(VERBOSE_PREFIX_2 "Unregistered custom function %s\n", acf->name);
1160
1161         return res;
1162 }
1163
1164 int ast_custom_function_register(struct ast_custom_function *acf) 
1165 {
1166         struct ast_custom_function *cur, *last = NULL;
1167         int found = 0;
1168
1169         if (!acf)
1170                 return -1;
1171
1172         /* try to lock functions list ... */
1173         if (ast_mutex_lock(&acflock)) {
1174                 ast_log(LOG_ERROR, "Unable to lock function list. Failed registering function %s\n", acf->name);
1175                 return -1;
1176         }
1177
1178         if (ast_custom_function_find(acf->name)) {
1179                 ast_log(LOG_ERROR, "Function %s already registered.\n", acf->name);
1180                 ast_mutex_unlock(&acflock);
1181                 return -1;
1182         }
1183
1184         for (cur = acf_root; cur; cur = cur->next) {
1185                 if (strcmp(acf->name, cur->name) < 0) {
1186                         found = 1;
1187                         if (last) {
1188                                 acf->next = cur;
1189                                 last->next = acf;
1190                         } else {
1191                                 acf->next = acf_root;
1192                                 acf_root = acf;
1193                         }
1194                         break;
1195                 }
1196                 last = cur;
1197         }
1198
1199         /* Wasn't before anything else, put it at the end */
1200         if (!found) {
1201                 if (last)
1202                         last->next = acf;
1203                 else
1204                         acf_root = acf;
1205                 acf->next = NULL;
1206         }
1207
1208         ast_mutex_unlock(&acflock);
1209
1210         if (option_verbose > 1)
1211                 ast_verbose(VERBOSE_PREFIX_2 "Registered custom function %s\n", acf->name);
1212
1213         return 0;
1214 }
1215
1216 char *ast_func_read(struct ast_channel *chan, const char *in, char *workspace, size_t len)
1217 {
1218         char *args = NULL, *function, *p;
1219         char *ret = "0";
1220         struct ast_custom_function *acfptr;
1221
1222         function = ast_strdupa(in);
1223         if (!function) {
1224                 ast_log(LOG_ERROR, "Out of memory\n");
1225                 return ret;
1226         }
1227         if ((args = strchr(function, '('))) {
1228                 *args = '\0';
1229                 args++;
1230                 if ((p = strrchr(args, ')'))) {
1231                         *p = '\0';
1232                 } else {
1233                         ast_log(LOG_WARNING, "Can't find trailing parenthesis?\n");
1234                 }
1235         } else {
1236                 ast_log(LOG_WARNING, "Function doesn't contain parentheses.  Assuming null argument.\n");
1237         }
1238
1239         if ((acfptr = ast_custom_function_find(function))) {
1240                 /* run the custom function */
1241                 if (acfptr->read) {
1242                         return acfptr->read(chan, function, args, workspace, len);
1243                 } else {
1244                         ast_log(LOG_ERROR, "Function %s cannot be read\n", function);
1245                 }
1246         } else {
1247                 ast_log(LOG_ERROR, "Function %s not registered\n", function);
1248         }
1249         return ret;
1250 }
1251
1252 void ast_func_write(struct ast_channel *chan, const char *in, const char *value)
1253 {
1254         char *args = NULL, *function, *p;
1255         struct ast_custom_function *acfptr;
1256
1257         function = ast_strdupa(in);
1258         if (!function) {
1259                 ast_log(LOG_ERROR, "Out of memory\n");
1260                 return;
1261         }
1262         if ((args = strchr(function, '('))) {
1263                 *args = '\0';
1264                 args++;
1265                 if ((p = strrchr(args, ')'))) {
1266                         *p = '\0';
1267                 } else {
1268                         ast_log(LOG_WARNING, "Can't find trailing parenthesis?\n");
1269                 }
1270         } else {
1271                 ast_log(LOG_WARNING, "Function doesn't contain parentheses.  Assuming null argument.\n");
1272         }
1273
1274         if ((acfptr = ast_custom_function_find(function))) {
1275                 /* run the custom function */
1276                 if (acfptr->write) {
1277                         acfptr->write(chan, function, args, value);
1278                 } else {
1279                         ast_log(LOG_ERROR, "Function %s is read-only, it cannot be written to\n", function);
1280                 }
1281         } else {
1282                 ast_log(LOG_ERROR, "Function %s not registered\n", function);
1283         }
1284 }
1285
1286 static void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int count)
1287 {
1288         char *cp4;
1289         const char *tmp, *whereweare;
1290         int length, offset, offset2, isfunction;
1291         char *workspace = NULL;
1292         char *ltmp = NULL, *var = NULL;
1293         char *nextvar, *nextexp, *nextthing;
1294         char *vars, *vare;
1295         int pos, brackets, needsub, len;
1296         
1297         /* Substitutes variables into cp2, based on string cp1, and assuming cp2 to be
1298            zero-filled */
1299         whereweare=tmp=cp1;
1300         while(!ast_strlen_zero(whereweare) && count) {
1301                 /* Assume we're copying the whole remaining string */
1302                 pos = strlen(whereweare);
1303                 nextvar = NULL;
1304                 nextexp = NULL;
1305                 nextthing = strchr(whereweare, '$');
1306                 if (nextthing) {
1307                         switch(nextthing[1]) {
1308                         case '{':
1309                                 nextvar = nextthing;
1310                                 pos = nextvar - whereweare;
1311                                 break;
1312                         case '[':
1313                                 nextexp = nextthing;
1314                                 pos = nextexp - whereweare;
1315                                 break;
1316                         }
1317                 }
1318
1319                 if (pos) {
1320                         /* Can't copy more than 'count' bytes */
1321                         if (pos > count)
1322                                 pos = count;
1323                         
1324                         /* Copy that many bytes */
1325                         memcpy(cp2, whereweare, pos);
1326                         
1327                         count -= pos;
1328                         cp2 += pos;
1329                         whereweare += pos;
1330                 }
1331                 
1332                 if (nextvar) {
1333                         /* We have a variable.  Find the start and end, and determine
1334                            if we are going to have to recursively call ourselves on the
1335                            contents */
1336                         vars = vare = nextvar + 2;
1337                         brackets = 1;
1338                         needsub = 0;
1339
1340                         /* Find the end of it */
1341                         while(brackets && *vare) {
1342                                 if ((vare[0] == '$') && (vare[1] == '{')) {
1343                                         needsub++;
1344                                         brackets++;
1345                                 } else if (vare[0] == '}') {
1346                                         brackets--;
1347                                 } else if ((vare[0] == '$') && (vare[1] == '['))
1348                                         needsub++;
1349                                 vare++;
1350                         }
1351                         if (brackets)
1352                                 ast_log(LOG_NOTICE, "Error in extension logic (missing '}')\n");
1353                         len = vare - vars - 1;
1354
1355                         /* Skip totally over variable string */
1356                         whereweare += (len + 3);
1357
1358                         if (!var)
1359                                 var = alloca(VAR_BUF_SIZE);
1360
1361                         /* Store variable name (and truncate) */
1362                         ast_copy_string(var, vars, len + 1);
1363
1364                         /* Substitute if necessary */
1365                         if (needsub) {
1366                                 if (!ltmp)
1367                                         ltmp = alloca(VAR_BUF_SIZE);
1368
1369                                 memset(ltmp, 0, VAR_BUF_SIZE);
1370                                 pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1);
1371                                 vars = ltmp;
1372                         } else {
1373                                 vars = var;
1374                         }
1375
1376                         if (!workspace)
1377                                 workspace = alloca(VAR_BUF_SIZE);
1378
1379                         workspace[0] = '\0';
1380
1381                         parse_variable_name(vars, &offset, &offset2, &isfunction);
1382                         if (isfunction) {
1383                                 /* Evaluate function */
1384                                 cp4 = ast_func_read(c, vars, workspace, VAR_BUF_SIZE);
1385
1386                                 ast_log(LOG_DEBUG, "Function result is '%s'\n", cp4 ? cp4 : "(null)");
1387                         } else {
1388                                 /* Retrieve variable value */
1389                                 pbx_retrieve_variable(c, vars, &cp4, workspace, VAR_BUF_SIZE, headp);
1390                         }
1391                         if (cp4) {
1392                                 cp4 = substring(cp4, offset, offset2, workspace, VAR_BUF_SIZE);
1393
1394                                 length = strlen(cp4);
1395                                 if (length > count)
1396                                         length = count;
1397                                 memcpy(cp2, cp4, length);
1398                                 count -= length;
1399                                 cp2 += length;
1400                         }
1401                 } else if (nextexp) {
1402                         /* We have an expression.  Find the start and end, and determine
1403                            if we are going to have to recursively call ourselves on the
1404                            contents */
1405                         vars = vare = nextexp + 2;
1406                         brackets = 1;
1407                         needsub = 0;
1408
1409                         /* Find the end of it */
1410                         while(brackets && *vare) {
1411                                 if ((vare[0] == '$') && (vare[1] == '[')) {
1412                                         needsub++;
1413                                         brackets++;
1414                                         vare++;
1415                                 } else if (vare[0] == '[') {
1416                                         brackets++;
1417                                 } else if (vare[0] == ']') {
1418                                         brackets--;
1419                                 } else if ((vare[0] == '$') && (vare[1] == '{')) {
1420                                         needsub++;
1421                                         vare++;
1422                                 }
1423                                 vare++;
1424                         }
1425                         if (brackets)
1426                                 ast_log(LOG_NOTICE, "Error in extension logic (missing ']')\n");
1427                         len = vare - vars - 1;
1428                         
1429                         /* Skip totally over expression */
1430                         whereweare += (len + 3);
1431                         
1432                         if (!var)
1433                                 var = alloca(VAR_BUF_SIZE);
1434
1435                         /* Store variable name (and truncate) */
1436                         ast_copy_string(var, vars, len + 1);
1437                         
1438                         /* Substitute if necessary */
1439                         if (needsub) {
1440                                 if (!ltmp)
1441                                         ltmp = alloca(VAR_BUF_SIZE);
1442
1443                                 memset(ltmp, 0, VAR_BUF_SIZE);
1444                                 pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1);
1445                                 vars = ltmp;
1446                         } else {
1447                                 vars = var;
1448                         }
1449
1450                         length = ast_expr(vars, cp2, count);
1451
1452                         if (length) {
1453                                 ast_log(LOG_DEBUG, "Expression result is '%s'\n", cp2);
1454                                 count -= length;
1455                                 cp2 += length;
1456                         }
1457                 } else
1458                         break;
1459         }
1460 }
1461
1462 void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
1463 {
1464         pbx_substitute_variables_helper_full(c, (c) ? &c->varshead : NULL, cp1, cp2, count);
1465 }
1466
1467 void pbx_substitute_variables_varshead(struct varshead *headp, const char *cp1, char *cp2, int count)
1468 {
1469         pbx_substitute_variables_helper_full(NULL, headp, cp1, cp2, count);
1470 }
1471
1472 static void pbx_substitute_variables(char *passdata, int datalen, struct ast_channel *c, struct ast_exten *e)
1473 {
1474         memset(passdata, 0, datalen);
1475                 
1476         /* No variables or expressions in e->data, so why scan it? */
1477         if (!strchr(e->data, '$') && !strstr(e->data,"${") && !strstr(e->data,"$[") && !strstr(e->data,"$(")) {
1478                 ast_copy_string(passdata, e->data, datalen);
1479                 return;
1480         }
1481         
1482         pbx_substitute_variables_helper(c, e->data, passdata, datalen - 1);
1483 }                                                               
1484
1485 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) 
1486 {
1487         struct ast_exten *e;
1488         struct ast_app *app;
1489         struct ast_switch *sw;
1490         char *data;
1491         const char *foundcontext=NULL;
1492         int newstack = 0;
1493         int res;
1494         int status = 0;
1495         char *incstack[AST_PBX_MAX_STACK];
1496         char passdata[EXT_DATA_SIZE];
1497         int stacklen = 0;
1498         char tmp[80];
1499         char tmp2[80];
1500         char tmp3[EXT_DATA_SIZE];
1501         char atmp[80];
1502         char atmp2[EXT_DATA_SIZE+100];
1503
1504         if (ast_mutex_lock(&conlock)) {
1505                 ast_log(LOG_WARNING, "Unable to obtain lock\n");
1506                 if ((action == HELPER_EXISTS) || (action == HELPER_CANMATCH) || (action == HELPER_MATCHMORE))
1507                         return 0;
1508                 else
1509                         return -1;
1510         }
1511         e = pbx_find_extension(c, con, context, exten, priority, label, callerid, action, incstack, &stacklen, &status, &sw, &data, &foundcontext);
1512         if (e) {
1513                 switch(action) {
1514                 case HELPER_CANMATCH:
1515                         ast_mutex_unlock(&conlock);
1516                         return -1;
1517                 case HELPER_EXISTS:
1518                         ast_mutex_unlock(&conlock);
1519                         return -1;
1520                 case HELPER_FINDLABEL:
1521                         res = e->priority;
1522                         ast_mutex_unlock(&conlock);
1523                         return res;
1524                 case HELPER_MATCHMORE:
1525                         ast_mutex_unlock(&conlock);
1526                         return -1;
1527                 case HELPER_SPAWN:
1528                         newstack++;
1529                         /* Fall through */
1530                 case HELPER_EXEC:
1531                         app = pbx_findapp(e->app);
1532                         ast_mutex_unlock(&conlock);
1533                         if (app) {
1534                                 if (c->context != context)
1535                                         ast_copy_string(c->context, context, sizeof(c->context));
1536                                 if (c->exten != exten)
1537                                         ast_copy_string(c->exten, exten, sizeof(c->exten));
1538                                 c->priority = priority;
1539                                 pbx_substitute_variables(passdata, sizeof(passdata), c, e);
1540                                 if (option_debug) {
1541                                                 ast_log(LOG_DEBUG, "Launching '%s'\n", app->name);
1542                                                 snprintf(atmp, 80, "STACK-%s-%s-%d", context, exten, priority);
1543                                                 snprintf(atmp2, EXT_DATA_SIZE+100, "%s(\"%s\", \"%s\") %s", app->name, c->name, passdata, (newstack ? "in new stack" : "in same stack"));
1544                                                 pbx_builtin_setvar_helper(c, atmp, atmp2);
1545                                 }
1546                                 if (option_verbose > 2)
1547                                                 ast_verbose( VERBOSE_PREFIX_3 "Executing %s(\"%s\", \"%s\") %s\n", 
1548                                                                 term_color(tmp, app->name, COLOR_BRCYAN, 0, sizeof(tmp)),
1549                                                                 term_color(tmp2, c->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
1550                                                                 term_color(tmp3, passdata, COLOR_BRMAGENTA, 0, sizeof(tmp3)),
1551                                                                 (newstack ? "in new stack" : "in same stack"));
1552                                 manager_event(EVENT_FLAG_CALL, "Newexten", 
1553                                         "Channel: %s\r\n"
1554                                         "Context: %s\r\n"
1555                                         "Extension: %s\r\n"
1556                                         "Priority: %d\r\n"
1557                                         "Application: %s\r\n"
1558                                         "AppData: %s\r\n"
1559                                         "Uniqueid: %s\r\n",
1560                                         c->name, c->context, c->exten, c->priority, app->name, passdata, c->uniqueid);
1561                                 res = pbx_exec(c, app, passdata, newstack);
1562                                 return res;
1563                         } else {
1564                                 ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
1565                                 return -1;
1566                         }
1567                 default:
1568                         ast_log(LOG_WARNING, "Huh (%d)?\n", action);
1569                         return -1;
1570                 }
1571         } else if (sw) {
1572                 switch(action) {
1573                 case HELPER_CANMATCH:
1574                         ast_mutex_unlock(&conlock);
1575                         return -1;
1576                 case HELPER_EXISTS:
1577                         ast_mutex_unlock(&conlock);
1578                         return -1;
1579                 case HELPER_MATCHMORE:
1580                         ast_mutex_unlock(&conlock);
1581                         return -1;
1582                 case HELPER_FINDLABEL:
1583                         ast_mutex_unlock(&conlock);
1584                         return -1;
1585                 case HELPER_SPAWN:
1586                         newstack++;
1587                         /* Fall through */
1588                 case HELPER_EXEC:
1589                         ast_mutex_unlock(&conlock);
1590                         if (sw->exec)
1591                                 res = sw->exec(c, foundcontext ? foundcontext : context, exten, priority, callerid, newstack, data);
1592                         else {
1593                                 ast_log(LOG_WARNING, "No execution engine for switch %s\n", sw->name);
1594                                 res = -1;
1595                         }
1596                         return res;
1597                 default:
1598                         ast_log(LOG_WARNING, "Huh (%d)?\n", action);
1599                         return -1;
1600                 }
1601         } else {
1602                 ast_mutex_unlock(&conlock);
1603                 switch(status) {
1604                 case STATUS_NO_CONTEXT:
1605                         if ((action != HELPER_EXISTS) && (action != HELPER_MATCHMORE))
1606                                 ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", context);
1607                         break;
1608                 case STATUS_NO_EXTENSION:
1609                         if ((action != HELPER_EXISTS) && (action !=  HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1610                                 ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, context);
1611                         break;
1612                 case STATUS_NO_PRIORITY:
1613                         if ((action != HELPER_EXISTS) && (action !=  HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1614                                 ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, context);
1615                         break;
1616                 case STATUS_NO_LABEL:
1617                         if (context)
1618                                 ast_log(LOG_NOTICE, "No such label '%s' in extension '%s' in context '%s'\n", label, exten, context);
1619                         break;
1620                 default:
1621                         ast_log(LOG_DEBUG, "Shouldn't happen!\n");
1622                 }
1623                 
1624                 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
1625                         return -1;
1626                 else
1627                         return 0;
1628         }
1629
1630 }
1631
1632 /*! \brief  ast_hint_extension: Find hint for given extension in context */
1633 static struct ast_exten *ast_hint_extension(struct ast_channel *c, const char *context, const char *exten)
1634 {
1635         struct ast_exten *e;
1636         struct ast_switch *sw;
1637         char *data;
1638         const char *foundcontext = NULL;
1639         int status = 0;
1640         char *incstack[AST_PBX_MAX_STACK];
1641         int stacklen = 0;
1642
1643         if (ast_mutex_lock(&conlock)) {
1644                 ast_log(LOG_WARNING, "Unable to obtain lock\n");
1645                 return NULL;
1646         }
1647         e = pbx_find_extension(c, NULL, context, exten, PRIORITY_HINT, NULL, "", HELPER_EXISTS, incstack, &stacklen, &status, &sw, &data, &foundcontext);
1648         ast_mutex_unlock(&conlock);     
1649         return e;
1650 }
1651
1652 /*! \brief  ast_extensions_state2: Check state of extension by using hints */
1653 static int ast_extension_state2(struct ast_exten *e)
1654 {
1655         char hint[AST_MAX_EXTENSION] = "";    
1656         char *cur, *rest;
1657         int res = -1;
1658         int allunavailable = 1, allbusy = 1, allfree = 1;
1659         int busy = 0, inuse = 0, ring = 0;
1660
1661         if (!e)
1662                 return -1;
1663
1664         ast_copy_string(hint, ast_get_extension_app(e), sizeof(hint));
1665
1666         cur = hint;     /* On or more devices separated with a & character */
1667         do {
1668                 rest = strchr(cur, '&');
1669                 if (rest) {
1670                         *rest = 0;
1671                         rest++;
1672                 }
1673         
1674                 res = ast_device_state(cur);
1675                 switch (res) {
1676                 case AST_DEVICE_NOT_INUSE:
1677                         allunavailable = 0;
1678                         allbusy = 0;
1679                         break;
1680                 case AST_DEVICE_INUSE:
1681                         inuse = 1;
1682                         allunavailable = 0;
1683                         allfree = 0;
1684                         break;
1685                 case AST_DEVICE_RINGING:
1686                         ring = 1;
1687                         allunavailable = 0;
1688                         allfree = 0;
1689                         break;
1690                 case AST_DEVICE_BUSY:
1691                         allunavailable = 0;
1692                         allfree = 0;
1693                         busy = 1;
1694                         break;
1695                 case AST_DEVICE_UNAVAILABLE:
1696                 case AST_DEVICE_INVALID:
1697                         allbusy = 0;
1698                         allfree = 0;
1699                         break;
1700                 default:
1701                         allunavailable = 0;
1702                         allbusy = 0;
1703                         allfree = 0;
1704                 }
1705                 cur = rest;
1706         } while (cur);
1707
1708         if (!inuse && ring)
1709                 return AST_EXTENSION_RINGING;
1710         if (inuse && ring)
1711                 return (AST_EXTENSION_INUSE | AST_EXTENSION_RINGING);
1712         if (inuse)
1713                 return AST_EXTENSION_INUSE;
1714         if (allfree)
1715                 return AST_EXTENSION_NOT_INUSE;
1716         if (allbusy)            
1717                 return AST_EXTENSION_BUSY;
1718         if (allunavailable)
1719                 return AST_EXTENSION_UNAVAILABLE;
1720         if (busy) 
1721                 return AST_EXTENSION_INUSE;
1722         
1723         return AST_EXTENSION_NOT_INUSE;
1724 }
1725
1726 /*! \brief  ast_extension_state2str: Return extension_state as string */
1727 const char *ast_extension_state2str(int extension_state)
1728 {
1729         int i;
1730
1731         for (i = 0; (i < (sizeof(extension_states) / sizeof(extension_states[0]))); i++) {
1732                 if (extension_states[i].extension_state == extension_state) {
1733                         return extension_states[i].text;
1734                 }
1735         }
1736         return "Unknown";       
1737 }
1738
1739 /*! \brief  ast_extension_state: Check extension state for an extension by using hint */
1740 int ast_extension_state(struct ast_channel *c, const char *context, const char *exten)
1741 {
1742         struct ast_exten *e;
1743
1744         e = ast_hint_extension(c, context, exten);      /* Do we have a hint for this extension ? */ 
1745         if (!e) 
1746                 return -1;                              /* No hint, return -1 */
1747
1748         return ast_extension_state2(e);                 /* Check all devices in the hint */
1749 }
1750
1751 void ast_hint_state_changed(const char *device)
1752 {
1753         struct ast_hint *hint;
1754         struct ast_state_cb *cblist;
1755         char buf[AST_MAX_EXTENSION];
1756         char *parse;
1757         char *cur;
1758         int state;
1759
1760         AST_LIST_LOCK(&hints);
1761
1762         AST_LIST_TRAVERSE(&hints, hint, list) {
1763                 ast_copy_string(buf, ast_get_extension_app(hint->exten), sizeof(buf));
1764                 parse = buf;
1765                 for (cur = strsep(&parse, "&"); cur; cur = strsep(&parse, "&")) {
1766                         if (strcasecmp(cur, device))
1767                                 continue;
1768
1769                         /* Get device state for this hint */
1770                         state = ast_extension_state2(hint->exten);
1771                         
1772                         if ((state == -1) || (state == hint->laststate))
1773                                 continue;
1774
1775                         /* Device state changed since last check - notify the watchers */
1776                         
1777                         /* For general callbacks */
1778                         for (cblist = statecbs; cblist; cblist = cblist->next)
1779                                 cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data);
1780                         
1781                         /* For extension callbacks */
1782                         for (cblist = hint->callbacks; cblist; cblist = cblist->next)
1783                                 cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data);
1784                         
1785                         hint->laststate = state;
1786                         break;
1787                 }
1788         }
1789
1790         AST_LIST_UNLOCK(&hints);
1791 }
1792                         
1793 /*! \brief  ast_extension_state_add: Add watcher for extension states */
1794 int ast_extension_state_add(const char *context, const char *exten, 
1795                             ast_state_cb_type callback, void *data)
1796 {
1797         struct ast_hint *hint;
1798         struct ast_state_cb *cblist;
1799         struct ast_exten *e;
1800
1801         /* If there's no context and extension:  add callback to statecbs list */
1802         if (!context && !exten) {
1803                 AST_LIST_LOCK(&hints);
1804
1805                 for (cblist = statecbs; cblist; cblist = cblist->next) {
1806                         if (cblist->callback == callback) {
1807                                 cblist->data = data;
1808                                 AST_LIST_UNLOCK(&hints);
1809                                 return 0;
1810                         }
1811                 }
1812         
1813                 /* Now insert the callback */
1814                 cblist = calloc(1, sizeof(struct ast_state_cb));
1815                 if (!cblist) {
1816                         AST_LIST_UNLOCK(&hints);        
1817                         return -1;
1818                 }
1819                 cblist->id = 0;
1820                 cblist->callback = callback;
1821                 cblist->data = data;
1822         
1823                 cblist->next = statecbs;
1824                 statecbs = cblist;
1825
1826                 AST_LIST_UNLOCK(&hints);
1827                 return 0;
1828         }
1829
1830         if (!context || !exten)
1831                 return -1;
1832
1833         /* This callback type is for only one hint, so get the hint */
1834         e = ast_hint_extension(NULL, context, exten);    
1835         if (!e) {
1836                 return -1;
1837         }
1838
1839         /* Find the hint in the list of hints */
1840         AST_LIST_LOCK(&hints);
1841         
1842         AST_LIST_TRAVERSE(&hints, hint, list) {
1843                 if (hint->exten == e)
1844                         break;      
1845         }
1846
1847         if (!hint) {
1848                 /* We have no hint, sorry */
1849                 AST_LIST_UNLOCK(&hints);
1850                 return -1;
1851         }
1852
1853         /* Now insert the callback in the callback list  */
1854         cblist = calloc(1, sizeof(struct ast_state_cb));
1855         if (!cblist) {
1856                 AST_LIST_UNLOCK(&hints);
1857                 return -1;
1858         }
1859         cblist->id = stateid++;         /* Unique ID for this callback */
1860         cblist->callback = callback;    /* Pointer to callback routine */
1861         cblist->data = data;            /* Data for the callback */
1862
1863         cblist->next = hint->callbacks;
1864         hint->callbacks = cblist;
1865
1866         AST_LIST_UNLOCK(&hints);
1867         return cblist->id;
1868 }
1869
1870 /*! \brief  ast_extension_state_del: Remove a watcher from the callback list */
1871 int ast_extension_state_del(int id, ast_state_cb_type callback)
1872 {
1873         struct ast_hint *hint;
1874         struct ast_state_cb *cblist, *cbprev;
1875
1876         if (!id && !callback)
1877                 return -1;
1878
1879         AST_LIST_LOCK(&hints);
1880
1881         /* id is zero is a callback without extension */
1882         if (!id) {
1883                 cbprev = NULL;
1884                 for (cblist = statecbs; cblist; cblist = cblist->next) {
1885                         if (cblist->callback == callback) {
1886                                 if (!cbprev)
1887                                         statecbs = cblist->next;
1888                                 else
1889                                         cbprev->next = cblist->next;
1890
1891                                 free(cblist);
1892
1893                                 AST_LIST_UNLOCK(&hints);
1894                                 return 0;
1895                         }
1896                         cbprev = cblist;
1897                 }
1898
1899                 AST_LIST_UNLOCK(&hints);
1900                 return -1;
1901         }
1902
1903         /* id greater than zero is a callback with extension */
1904         /* Find the callback based on ID */
1905         AST_LIST_TRAVERSE(&hints, hint, list) {
1906                 cbprev = NULL;
1907                 for (cblist = hint->callbacks; cblist; cblist = cblist->next) {
1908                         if (cblist->id==id) {
1909                                 if (!cbprev)
1910                                         hint->callbacks = cblist->next;         
1911                                 else
1912                                         cbprev->next = cblist->next;
1913                 
1914                                 free(cblist);
1915                 
1916                                 AST_LIST_UNLOCK(&hints);
1917                                 return 0;               
1918                         }               
1919                         cbprev = cblist;                                
1920                 }
1921         }
1922
1923         AST_LIST_UNLOCK(&hints);
1924         return -1;
1925 }
1926
1927 /*! \brief  ast_add_hint: Add hint to hint list, check initial extension state */
1928 static int ast_add_hint(struct ast_exten *e)
1929 {
1930         struct ast_hint *hint;
1931
1932         if (!e) 
1933                 return -1;
1934
1935         AST_LIST_LOCK(&hints);
1936
1937         /* Search if hint exists, do nothing */
1938         AST_LIST_TRAVERSE(&hints, hint, list) {
1939                 if (hint->exten == e) {
1940                         AST_LIST_UNLOCK(&hints);
1941                         if (option_debug > 1)
1942                                 ast_log(LOG_DEBUG, "HINTS: Not re-adding existing hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
1943                         return -1;
1944                 }
1945         }
1946
1947         if (option_debug > 1)
1948                 ast_log(LOG_DEBUG, "HINTS: Adding hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
1949
1950         hint = calloc(1, sizeof(struct ast_hint));
1951         if (!hint) {
1952                 AST_LIST_UNLOCK(&hints);
1953                 if (option_debug > 1)
1954                         ast_log(LOG_DEBUG, "HINTS: Out of memory...\n");
1955                 return -1;
1956         }
1957         /* Initialize and insert new item at the top */
1958         hint->exten = e;
1959         hint->laststate = ast_extension_state2(e);
1960         AST_LIST_INSERT_HEAD(&hints, hint, list);
1961
1962         AST_LIST_UNLOCK(&hints);
1963         return 0;
1964 }
1965
1966 /*! \brief  ast_change_hint: Change hint for an extension */
1967 static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
1968
1969         struct ast_hint *hint;
1970         int res = -1;
1971
1972         AST_LIST_LOCK(&hints);
1973         AST_LIST_TRAVERSE(&hints, hint, list) {
1974                 if (hint->exten == oe) {
1975                         hint->exten = ne;
1976                         res = 0;
1977                         break;
1978                 }
1979         }
1980         AST_LIST_UNLOCK(&hints);
1981
1982         return res;
1983 }
1984
1985 /*! \brief  ast_remove_hint: Remove hint from extension */
1986 static int ast_remove_hint(struct ast_exten *e)
1987 {
1988         /* Cleanup the Notifys if hint is removed */
1989         struct ast_hint *hint;
1990         struct ast_state_cb *cblist, *cbprev;
1991         int res = -1;
1992
1993         if (!e) 
1994                 return -1;
1995
1996         AST_LIST_LOCK(&hints);
1997         AST_LIST_TRAVERSE_SAFE_BEGIN(&hints, hint, list) {
1998                 if (hint->exten == e) {
1999                         cbprev = NULL;
2000                         cblist = hint->callbacks;
2001                         while (cblist) {
2002                                 /* Notify with -1 and remove all callbacks */
2003                                 cbprev = cblist;            
2004                                 cblist = cblist->next;
2005                                 cbprev->callback(hint->exten->parent->name, hint->exten->exten, AST_EXTENSION_DEACTIVATED, cbprev->data);
2006                                 free(cbprev);
2007                         }
2008                         hint->callbacks = NULL;
2009                         AST_LIST_REMOVE_CURRENT(&hints, list);
2010                         free(hint);
2011                         res = 0;
2012                         break; 
2013                 }
2014         }
2015         AST_LIST_TRAVERSE_SAFE_END
2016         AST_LIST_UNLOCK(&hints);
2017         
2018         return res;
2019 }
2020
2021
2022 /*! \brief  ast_get_hint: Get hint for channel */
2023 int ast_get_hint(char *hint, int hintsize, char *name, int namesize, struct ast_channel *c, const char *context, const char *exten)
2024 {
2025         struct ast_exten *e;
2026         void *tmp;
2027
2028         e = ast_hint_extension(c, context, exten);
2029         if (e) {
2030                 if (hint) 
2031                     ast_copy_string(hint, ast_get_extension_app(e), hintsize);
2032                 if (name) {
2033                         tmp = ast_get_extension_app_data(e);
2034                         if (tmp)
2035                                 ast_copy_string(name, (char *) tmp, namesize);
2036                 }
2037                 return -1;
2038         }
2039         return 0;       
2040 }
2041
2042 int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid) 
2043 {
2044         return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_EXISTS);
2045 }
2046
2047 int ast_findlabel_extension(struct ast_channel *c, const char *context, const char *exten, const char *label, const char *callerid) 
2048 {
2049         return pbx_extension_helper(c, NULL, context, exten, 0, label, callerid, HELPER_FINDLABEL);
2050 }
2051
2052 int ast_findlabel_extension2(struct ast_channel *c, struct ast_context *con, const char *exten, const char *label, const char *callerid) 
2053 {
2054         return pbx_extension_helper(c, con, NULL, exten, 0, label, callerid, HELPER_FINDLABEL);
2055 }
2056
2057 int ast_canmatch_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
2058 {
2059         return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_CANMATCH);
2060 }
2061
2062 int ast_matchmore_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
2063 {
2064         return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_MATCHMORE);
2065 }
2066
2067 int ast_spawn_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid) 
2068 {
2069         return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_SPAWN);
2070 }
2071
2072 int ast_exec_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid) 
2073 {
2074         return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_EXEC);
2075 }
2076
2077 static int __ast_pbx_run(struct ast_channel *c)
2078 {
2079         int firstpass = 1;
2080         int digit;
2081         char exten[256];
2082         int pos;
2083         int waittime;
2084         int res=0;
2085         int autoloopflag;
2086
2087         /* A little initial setup here */
2088         if (c->pbx)
2089                 ast_log(LOG_WARNING, "%s already has PBX structure??\n", c->name);
2090         c->pbx = calloc(1, sizeof(struct ast_pbx));
2091         if (!c->pbx) {
2092                 ast_log(LOG_ERROR, "Out of memory\n");
2093                 return -1;
2094         }
2095         if (c->amaflags) {
2096                 if (!c->cdr) {
2097                         c->cdr = ast_cdr_alloc();
2098                         if (!c->cdr) {
2099                                 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
2100                                 free(c->pbx);
2101                                 return -1;
2102                         }
2103                         ast_cdr_init(c->cdr, c);
2104                 }
2105         }
2106         /* Set reasonable defaults */
2107         c->pbx->rtimeout = 10;
2108         c->pbx->dtimeout = 5;
2109
2110         autoloopflag = ast_test_flag(c, AST_FLAG_IN_AUTOLOOP);
2111         ast_set_flag(c, AST_FLAG_IN_AUTOLOOP);
2112
2113         /* Start by trying whatever the channel is set to */
2114         if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2115                 /* If not successful fall back to 's' */
2116                 if (option_verbose > 1)
2117                         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);
2118                 ast_copy_string(c->exten, "s", sizeof(c->exten));
2119                 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2120                         /* JK02: And finally back to default if everything else failed */
2121                         if (option_verbose > 1)
2122                                 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);
2123                         ast_copy_string(c->context, "default", sizeof(c->context));
2124                 }
2125                 c->priority = 1;
2126         }
2127         if (c->cdr && !c->cdr->start.tv_sec && !c->cdr->start.tv_usec)
2128                 ast_cdr_start(c->cdr);
2129         for (;;) {
2130                 pos = 0;
2131                 digit = 0;
2132                 while (ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2133                         memset(exten, 0, sizeof(exten));
2134                         if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
2135                                 /* Something bad happened, or a hangup has been requested. */
2136                                 if (((res >= '0') && (res <= '9')) || ((res >= 'A') && (res <= 'F')) ||
2137                                         (res == '*') || (res == '#')) {
2138                                         ast_log(LOG_DEBUG, "Oooh, got something to jump out with ('%c')!\n", res);
2139                                         memset(exten, 0, sizeof(exten));
2140                                         pos = 0;
2141                                         exten[pos++] = digit = res;
2142                                         break;
2143                                 }
2144                                 switch(res) {
2145                                 case AST_PBX_KEEPALIVE:
2146                                         if (option_debug)
2147                                                 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
2148                                         else if (option_verbose > 1)
2149                                                 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
2150                                         goto out;
2151                                         break;
2152                                 default:
2153                                         if (option_debug)
2154                                                 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2155                                         else if (option_verbose > 1)
2156                                                 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2157                                         if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
2158                                                 c->_softhangup =0;
2159                                                 break;
2160                                         }
2161                                         /* atimeout */
2162                                         if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
2163                                                 break;
2164                                         }
2165
2166                                         if (c->cdr) {
2167                                                 ast_cdr_update(c);
2168                                         }
2169                                         goto out;
2170                                 }
2171                         }
2172                         if ((c->_softhangup == AST_SOFTHANGUP_TIMEOUT) && (ast_exists_extension(c,c->context,"T",1,c->cid.cid_num))) {
2173                                 ast_copy_string(c->exten, "T", sizeof(c->exten));
2174                                 /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
2175                                 c->whentohangup = 0;
2176                                 c->priority = 0;
2177                                 c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
2178                         } else if (c->_softhangup) {
2179                                 ast_log(LOG_DEBUG, "Extension %s, priority %d returned normally even though call was hung up\n",
2180                                         c->exten, c->priority);
2181                                 goto out;
2182                         }
2183                         firstpass = 0;
2184                         c->priority++;
2185                 }
2186                 if (!ast_exists_extension(c, c->context, c->exten, 1, c->cid.cid_num)) {
2187                         /* It's not a valid extension anymore */
2188                         if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
2189                                 if (option_verbose > 2)
2190                                         ast_verbose(VERBOSE_PREFIX_3 "Sent into invalid extension '%s' in context '%s' on %s\n", c->exten, c->context, c->name);
2191                                 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", c->exten);
2192                                 ast_copy_string(c->exten, "i", sizeof(c->exten));
2193                                 c->priority = 1;
2194                         } else {
2195                                 ast_log(LOG_WARNING, "Channel '%s' sent into invalid extension '%s' in context '%s', but no invalid handler\n",
2196                                         c->name, c->exten, c->context);
2197                                 goto out;
2198                         }
2199                 } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
2200                         /* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */
2201                         c->_softhangup = 0;
2202                 } else {
2203                         /* Done, wait for an extension */
2204                         waittime = 0;
2205                         if (digit)
2206                                 waittime = c->pbx->dtimeout;
2207                         else if (!autofallthrough)
2208                                 waittime = c->pbx->rtimeout;
2209                         if (waittime) {
2210                                 while (ast_matchmore_extension(c, c->context, exten, 1, c->cid.cid_num)) {
2211                                         /* As long as we're willing to wait, and as long as it's not defined, 
2212                                            keep reading digits until we can't possibly get a right answer anymore.  */
2213                                         digit = ast_waitfordigit(c, waittime * 1000);
2214                                         if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
2215                                                 c->_softhangup = 0;
2216                                         } else {
2217                                                 if (!digit)
2218                                                         /* No entry */
2219                                                         break;
2220                                                 if (digit < 0)
2221                                                         /* Error, maybe a  hangup */
2222                                                         goto out;
2223                                                 exten[pos++] = digit;
2224                                                 waittime = c->pbx->dtimeout;
2225                                         }
2226                                 }
2227                                 if (ast_exists_extension(c, c->context, exten, 1, c->cid.cid_num)) {
2228                                         /* Prepare the next cycle */
2229                                         ast_copy_string(c->exten, exten, sizeof(c->exten));
2230                                         c->priority = 1;
2231                                 } else {
2232                                         /* No such extension */
2233                                         if (!ast_strlen_zero(exten)) {
2234                                                 /* An invalid extension */
2235                                                 if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
2236                                                         if (option_verbose > 2)
2237                                                                 ast_verbose( VERBOSE_PREFIX_3 "Invalid extension '%s' in context '%s' on %s\n", exten, c->context, c->name);
2238                                                         pbx_builtin_setvar_helper(c, "INVALID_EXTEN", exten);
2239                                                         ast_copy_string(c->exten, "i", sizeof(c->exten));
2240                                                         c->priority = 1;
2241                                                 } else {
2242                                                         ast_log(LOG_WARNING, "Invalid extension '%s', but no rule 'i' in context '%s'\n", exten, c->context);
2243                                                         goto out;
2244                                                 }
2245                                         } else {
2246                                                 /* A simple timeout */
2247                                                 if (ast_exists_extension(c, c->context, "t", 1, c->cid.cid_num)) {
2248                                                         if (option_verbose > 2)
2249                                                                 ast_verbose( VERBOSE_PREFIX_3 "Timeout on %s\n", c->name);
2250                                                         ast_copy_string(c->exten, "t", sizeof(c->exten));
2251                                                         c->priority = 1;
2252                                                 } else {
2253                                                         ast_log(LOG_WARNING, "Timeout, but no rule 't' in context '%s'\n", c->context);
2254                                                         goto out;
2255                                                 }
2256                                         }       
2257                                 }
2258                                 if (c->cdr) {
2259                                         if (option_verbose > 2)
2260                                                 ast_verbose(VERBOSE_PREFIX_2 "CDR updated on %s\n",c->name);    
2261                                         ast_cdr_update(c);
2262                             }
2263                         } else {
2264                                 const char *status;
2265
2266                                 status = pbx_builtin_getvar_helper(c, "DIALSTATUS");
2267                                 if (!status)
2268                                         status = "UNKNOWN";
2269                                 if (option_verbose > 2)
2270                                         ast_verbose(VERBOSE_PREFIX_2 "Auto fallthrough, channel '%s' status is '%s'\n", c->name, status);
2271                                 if (!strcasecmp(status, "CONGESTION"))
2272                                         res = pbx_builtin_congestion(c, "10");
2273                                 else if (!strcasecmp(status, "CHANUNAVAIL"))
2274                                         res = pbx_builtin_congestion(c, "10");
2275                                 else if (!strcasecmp(status, "BUSY"))
2276                                         res = pbx_builtin_busy(c, "10");
2277                                 goto out;
2278                         }
2279                 }
2280         }
2281         if (firstpass) 
2282                 ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", c->name);
2283 out:
2284         if ((res != AST_PBX_KEEPALIVE) && ast_exists_extension(c, c->context, "h", 1, c->cid.cid_num)) {
2285                 c->exten[0] = 'h';
2286                 c->exten[1] = '\0';
2287                 c->priority = 1;
2288                 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
2289                         if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
2290                                 /* Something bad happened, or a hangup has been requested. */
2291                                 if (option_debug)
2292                                         ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2293                                 else if (option_verbose > 1)
2294                                         ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
2295                                 break;
2296                         }
2297                         c->priority++;
2298                 }
2299         }
2300         ast_set2_flag(c, autoloopflag, AST_FLAG_IN_AUTOLOOP);
2301
2302         pbx_destroy(c->pbx);
2303         c->pbx = NULL;
2304         if (res != AST_PBX_KEEPALIVE)
2305                 ast_hangup(c);
2306         return 0;
2307 }
2308
2309 /* Returns 0 on success, non-zero if call limit was reached */
2310 static int increase_call_count(const struct ast_channel *c)
2311 {
2312         int failed = 0;
2313         double curloadavg;
2314         ast_mutex_lock(&maxcalllock);
2315         if (option_maxcalls) {
2316                 if (countcalls >= option_maxcalls) {
2317                         ast_log(LOG_NOTICE, "Maximum call limit of %d calls exceeded by '%s'!\n", option_maxcalls, c->name);
2318                         failed = -1;
2319                 }
2320         }
2321         if (option_maxload) {
2322                 getloadavg(&curloadavg, 1);
2323                 if (curloadavg >= option_maxload) {
2324                         ast_log(LOG_NOTICE, "Maximum loadavg limit of %f load exceeded by '%s' (currently %f)!\n", option_maxload, c->name, curloadavg);
2325                         failed = -1;
2326                 }
2327         }
2328         if (!failed)
2329                 countcalls++;   
2330         ast_mutex_unlock(&maxcalllock);
2331
2332         return failed;
2333 }
2334
2335 static void decrease_call_count(void)
2336 {
2337         ast_mutex_lock(&maxcalllock);
2338         if (countcalls > 0)
2339                 countcalls--;
2340         ast_mutex_unlock(&maxcalllock);
2341 }
2342
2343 static void *pbx_thread(void *data)
2344 {
2345         /* Oh joyeous kernel, we're a new thread, with nothing to do but
2346            answer this channel and get it going.
2347         */
2348         /* NOTE:
2349            The launcher of this function _MUST_ increment 'countcalls'
2350            before invoking the function; it will be decremented when the
2351            PBX has finished running on the channel
2352          */
2353         struct ast_channel *c = data;
2354
2355         __ast_pbx_run(c);
2356         decrease_call_count();
2357
2358         pthread_exit(NULL);
2359
2360         return NULL;
2361 }
2362
2363 enum ast_pbx_result ast_pbx_start(struct ast_channel *c)
2364 {
2365         pthread_t t;
2366         pthread_attr_t attr;
2367
2368         if (!c) {
2369                 ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
2370                 return AST_PBX_FAILED;
2371         }
2372            
2373         if (increase_call_count(c))
2374                 return AST_PBX_CALL_LIMIT;
2375
2376         /* Start a new thread, and get something handling this channel. */
2377         pthread_attr_init(&attr);
2378         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
2379         if (ast_pthread_create(&t, &attr, pbx_thread, c)) {
2380                 ast_log(LOG_WARNING, "Failed to create new channel thread\n");
2381                 return AST_PBX_FAILED;
2382         }
2383
2384         return AST_PBX_SUCCESS;
2385 }
2386
2387 enum ast_pbx_result ast_pbx_run(struct ast_channel *c)
2388 {
2389         enum ast_pbx_result res = AST_PBX_SUCCESS;
2390
2391         if (increase_call_count(c))
2392                 return AST_PBX_CALL_LIMIT;
2393
2394         res = __ast_pbx_run(c);
2395         decrease_call_count();
2396
2397         return res;
2398 }
2399
2400 int ast_active_calls(void)
2401 {
2402         return countcalls;
2403 }
2404
2405 int pbx_set_autofallthrough(int newval)
2406 {
2407         int oldval;
2408         oldval = autofallthrough;
2409         if (oldval != newval)
2410                 autofallthrough = newval;
2411         return oldval;
2412 }
2413
2414 /*
2415  * This function locks contexts list by &conlist, search for the right context
2416  * structure, leave context list locked and call ast_context_remove_include2
2417  * which removes include, unlock contexts list and return ...
2418  */
2419 int ast_context_remove_include(const char *context, const char *include, const char *registrar)
2420 {
2421         struct ast_context *c = NULL;
2422
2423         if (ast_lock_contexts())
2424                 return -1;
2425
2426         /* walk contexts and search for the right one ...*/
2427         while ( (c = ast_walk_contexts(c)) ) {
2428                 /* we found one ... */
2429                 if (!strcmp(ast_get_context_name(c), context)) {
2430                         int ret;
2431                         /* remove include from this context ... */      
2432                         ret = ast_context_remove_include2(c, include, registrar);
2433
2434                         ast_unlock_contexts();
2435
2436                         /* ... return results */
2437                         return ret;
2438                 }
2439         }
2440
2441         /* we can't find the right one context */
2442         ast_unlock_contexts();
2443         return -1;
2444 }
2445
2446 /*
2447  * When we call this function, &conlock lock must be locked, because when
2448  * we giving *con argument, some process can remove/change this context
2449  * and after that there can be segfault.
2450  *
2451  * This function locks given context, removes include, unlock context and
2452  * return.
2453  */
2454 int ast_context_remove_include2(struct ast_context *con, const char *include, const char *registrar)
2455 {
2456         struct ast_include *i, *pi = NULL;
2457
2458         if (ast_mutex_lock(&con->lock)) return -1;
2459
2460         /* walk includes */
2461         for (i = con->includes; i; i = i->next) {
2462                 /* find our include */
2463                 if (!strcmp(i->name, include) && 
2464                         (!registrar || !strcmp(i->registrar, registrar))) {
2465                         /* remove from list */
2466                         if (pi)
2467                                 pi->next = i->next;
2468                         else
2469                                 con->includes = i->next;
2470                         /* free include and return */
2471                         free(i);
2472                         ast_mutex_unlock(&con->lock);
2473                         return 0;
2474                 }
2475                 pi = i;
2476         }
2477
2478         /* we can't find the right include */
2479         ast_mutex_unlock(&con->lock);
2480         return -1;
2481 }
2482
2483 /*!
2484  * \note This function locks contexts list by &conlist, search for the rigt context
2485  * structure, leave context list locked and call ast_context_remove_switch2
2486  * which removes switch, unlock contexts list and return ...
2487  */
2488 int ast_context_remove_switch(const char *context, const char *sw, const char *data, const char *registrar)
2489 {
2490         struct ast_context *c = NULL;
2491         int ret = -1; /* default error return */
2492
2493         if (ast_lock_contexts())
2494                 return -1;
2495
2496         /* walk contexts and search for the right one ...*/
2497         while ( (c = ast_walk_contexts(c)) ) {
2498                 /* we found one ... */
2499                 if (!strcmp(ast_get_context_name(c), context)) {
2500                         /* remove switch from this context ... */       
2501                         ret = ast_context_remove_switch2(c, sw, data, registrar);
2502                         break;
2503                 }
2504         }
2505
2506         /* found or error */
2507         ast_unlock_contexts();
2508         return ret;
2509 }
2510
2511 /*!
2512  * \brief This function locks given context, removes switch, unlock context and
2513  * return.
2514  * \note When we call this function, &conlock lock must be locked, because when
2515  * we giving *con argument, some process can remove/change this context
2516  * and after that there can be segfault.
2517  *
2518  */
2519 int ast_context_remove_switch2(struct ast_context *con, const char *sw, const char *data, const char *registrar)
2520 {
2521         struct ast_sw *i, *pi = NULL;
2522
2523         if (ast_mutex_lock(&con->lock)) return -1;
2524
2525         /* walk switchs */
2526         for (i = con->alts; i; i = i->next) {
2527                 /* find our switch */
2528                 if (!strcmp(i->name, sw) && !strcmp(i->data, data) && 
2529                         (!registrar || !strcmp(i->registrar, registrar))) {
2530                         /* remove from list */
2531                         if (pi)
2532                                 pi->next = i->next;
2533                         else
2534                                 con->alts = i->next;
2535                         /* free switch and return */
2536                         free(i);
2537                         ast_mutex_unlock(&con->lock);
2538                         return 0;
2539                 }
2540                 pi = i;
2541         }
2542
2543         /* we can't find the right switch */
2544         ast_mutex_unlock(&con->lock);
2545         return -1;
2546 }
2547
2548 /*
2549  * \note This functions lock contexts list, search for the right context,
2550  * call ast_context_remove_extension2, unlock contexts list and return.
2551  * In this function we are using
2552  */
2553 int ast_context_remove_extension(const char *context, const char *extension, int priority, const char *registrar)
2554 {
2555         struct ast_context *c = NULL;
2556         int ret = -1; /* default error return */
2557
2558         if (ast_lock_contexts())
2559                 return -1;
2560
2561         /* walk contexts ... */
2562         while ( (c = ast_walk_contexts(c)) ) {
2563                 /* ... search for the right one ... */
2564                 if (!strcmp(ast_get_context_name(c), context)) {
2565                         /* ... remove extension ... */
2566                         ret = ast_context_remove_extension2(c, extension, priority,
2567                                 registrar);
2568                         break;
2569                 }
2570         }
2571         /* found or error */
2572         ast_unlock_contexts();
2573         return ret;
2574 }
2575
2576 /*!
2577  * \brief This functionc locks given context, search for the right extension and
2578  * fires out all peer in this extensions with given priority. If priority
2579  * is set to 0, all peers are removed. After that, unlock context and
2580  * return.
2581  * \note When do you want to call this function, make sure that &conlock is locked,
2582  * because some process can handle with your *con context before you lock
2583  * it.
2584  *
2585  */
2586 int ast_context_remove_extension2(struct ast_context *con, const char *extension, int priority, const char *registrar)
2587 {
2588         struct ast_exten *exten, *prev_exten = NULL;
2589
2590         if (ast_mutex_lock(&con->lock)) return -1;
2591
2592         /* go through all extensions in context and search the right one ... */
2593         exten = con->root;
2594         while (exten) {
2595
2596                 /* look for right extension */
2597                 if (!strcmp(exten->exten, extension) &&
2598                         (!registrar || !strcmp(exten->registrar, registrar))) {
2599                         struct ast_exten *peer;
2600
2601                         /* should we free all peers in this extension? (priority == 0)? */
2602                         if (priority == 0) {
2603                                 /* remove this extension from context list */
2604                                 if (prev_exten)
2605                                         prev_exten->next = exten->next;
2606                                 else
2607                                         con->root = exten->next;
2608
2609                                 /* fire out all peers */
2610                                 peer = exten; 
2611                                 while (peer) {
2612                                         exten = peer->peer;
2613                                         
2614                                         if (!peer->priority==PRIORITY_HINT) 
2615                                             ast_remove_hint(peer);
2616
2617                                         peer->datad(peer->data);
2618                                         free(peer);
2619
2620                                         peer = exten;
2621                                 }
2622
2623                                 ast_mutex_unlock(&con->lock);
2624                                 return 0;
2625                         } else {
2626                                 /* remove only extension with exten->priority == priority */
2627                                 struct ast_exten *previous_peer = NULL;
2628
2629                                 peer = exten;
2630                                 while (peer) {
2631                                         /* is this our extension? */
2632                                         if (peer->priority == priority &&
2633                                                 (!registrar || !strcmp(peer->registrar, registrar) )) {
2634                                                 /* we are first priority extension? */
2635                                                 if (!previous_peer) {
2636                                                         /* exists previous extension here? */
2637                                                         if (prev_exten) {
2638                                                                 /* yes, so we must change next pointer in
2639                                                                  * previous connection to next peer
2640                                                                  */
2641                                                                 if (peer->peer) {
2642                                                                         prev_exten->next = peer->peer;
2643                                                                         peer->peer->next = exten->next;
2644                                                                 } else
2645                                                                         prev_exten->next = exten->next;
2646                                                         } else {
2647                                                                 /* no previous extension, we are first
2648                                                                  * extension, so change con->root ...
2649                                                                  */
2650                                                                 if (peer->peer)
2651                                                                         con->root = peer->peer;
2652                                                                 else
2653                                                                         con->root = exten->next; 
2654                                                         }
2655                                                 } else {
2656                                                         /* we are not first priority in extension */
2657                                                         previous_peer->peer = peer->peer;
2658                                                 }
2659
2660                                                 /* now, free whole priority extension */
2661                                                 if (peer->priority==PRIORITY_HINT)
2662                                                     ast_remove_hint(peer);
2663                                                 peer->datad(peer->data);
2664                                                 free(peer);
2665
2666                                                 ast_mutex_unlock(&con->lock);
2667                                                 return 0;
2668                                         } else {
2669                                                 /* this is not right extension, skip to next peer */
2670                                                 previous_peer = peer;
2671                                                 peer = peer->peer;
2672                                         }
2673                                 }
2674
2675                                 ast_mutex_unlock(&con->lock);
2676                                 return -1;
2677                         }
2678                 }
2679
2680                 prev_exten = exten;
2681                 exten = exten->next;
2682         }
2683
2684         /* we can't find right extension */
2685         ast_mutex_unlock(&con->lock);
2686         return -1;
2687 }
2688
2689
2690 /*! \brief Dynamically register a new dial plan application */
2691 int ast_register_application(const char *app, int (*execute)(struct ast_channel *, void *), const char *synopsis, const char *description)
2692 {
2693         struct ast_app *tmp, *prev, *cur;
2694         char tmps[80];
2695         int length;
2696         length = sizeof(struct ast_app);
2697         length += strlen(app) + 1;
2698         if (ast_mutex_lock(&applock)) {
2699                 ast_log(LOG_ERROR, "Unable to lock application list\n");
2700                 return -1;
2701         }
2702         for (tmp = apps; tmp; tmp = tmp->next) {
2703                 if (!strcasecmp(app, tmp->name)) {
2704                         ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
2705                         ast_mutex_unlock(&applock);
2706                         return -1;
2707                 }
2708         }
2709         
2710         tmp = calloc(1, length);
2711         if (!tmp) {
2712                 ast_log(LOG_ERROR, "Out of memory\n");
2713                 ast_mutex_unlock(&applock);
2714                 return -1;
2715         }
2716
2717         strcpy(tmp->name, app);
2718         tmp->execute = execute;
2719         tmp->synopsis = synopsis;
2720         tmp->description = description;
2721         /* Store in alphabetical order */
2722         prev = NULL;
2723         for (cur = apps; cur; cur = cur->next) {
2724                 if (strcasecmp(tmp->name, cur->name) < 0)
2725                         break;
2726                 prev = cur;
2727         }
2728         if (prev) {
2729                 tmp->next = prev->next;
2730                 prev->next = tmp;
2731         } else {
2732                 tmp->next = apps;
2733                 apps = tmp;
2734         }
2735         
2736         if (option_verbose > 1)
2737                 ast_verbose( VERBOSE_PREFIX_2 "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
2738         ast_mutex_unlock(&applock);
2739         return 0;
2740 }
2741
2742 int ast_register_switch(struct ast_switch *sw)
2743 {
2744         struct ast_switch *tmp, *prev=NULL;
2745         if (ast_mutex_lock(&switchlock)) {
2746                 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
2747                 return -1;
2748         }
2749         for (tmp = switches; tmp; tmp = tmp->next) {
2750                 if (!strcasecmp(tmp->name, sw->name))
2751                         break;
2752                 prev = tmp;
2753         }
2754         if (tmp) {      
2755                 ast_mutex_unlock(&switchlock);
2756                 ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name);
2757                 return -1;
2758         }
2759         sw->next = NULL;
2760         if (prev) 
2761                 prev->next = sw;
2762         else
2763                 switches = sw;
2764         ast_mutex_unlock(&switchlock);
2765         return 0;
2766 }
2767
2768 void ast_unregister_switch(struct ast_switch *sw)
2769 {
2770         struct ast_switch *tmp, *prev=NULL;
2771         if (ast_mutex_lock(&switchlock)) {
2772                 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
2773                 return;
2774         }
2775         for (tmp = switches; tmp; tmp = tmp->next) {
2776                 if (tmp == sw) {
2777                         if (prev)
2778                                 prev->next = tmp->next;
2779                         else
2780                                 switches = tmp->next;
2781                         tmp->next = NULL;
2782                         break;                  
2783                 }
2784                 prev = tmp;
2785         }
2786         ast_mutex_unlock(&switchlock);
2787 }
2788
2789 /*
2790  * Help for CLI commands ...
2791  */
2792 static char show_application_help[] = 
2793 "Usage: show application <application> [<application> [<application> [...]]]\n"
2794 "       Describes a particular application.\n";
2795
2796 static char show_functions_help[] =
2797 "Usage: show functions [like <text>]\n"
2798 "       List builtin functions, optionally only those matching a given string\n";
2799
2800 static char show_function_help[] =
2801 "Usage: show function <function>\n"
2802 "       Describe a particular dialplan function.\n";
2803
2804 static char show_applications_help[] =
2805 "Usage: show applications [{like|describing} <text>]\n"
2806 "       List applications which are currently available.\n"
2807 "       If 'like', <text> will be a substring of the app name\n"
2808 "       If 'describing', <text> will be a substring of the description\n";
2809
2810 static char show_dialplan_help[] =
2811 "Usage: show dialplan [exten@][context]\n"
2812 "       Show dialplan\n";
2813
2814 static char show_switches_help[] = 
2815 "Usage: show switches\n"
2816 "       Show registered switches\n";
2817
2818 static char show_hints_help[] = 
2819 "Usage: show hints\n"
2820 "       Show registered hints\n";
2821
2822
2823 /*
2824  * IMPLEMENTATION OF CLI FUNCTIONS IS IN THE SAME ORDER AS COMMANDS HELPS
2825  *
2826  */
2827
2828 /*
2829  * \brief 'show application' CLI command implementation functions ...
2830  */
2831
2832 /*
2833  * There is a possibility to show informations about more than one
2834  * application at one time. You can type 'show application Dial Echo' and
2835  * you will see informations about these two applications ...
2836  */
2837 static char *complete_show_application(const char *line, const char *word, int pos, int state)
2838 {
2839         struct ast_app *a;
2840         char *ret = NULL;
2841         int which = 0;
2842         int wordlen = strlen(word);
2843
2844         /* try to lock applications list ... */
2845         if (ast_mutex_lock(&applock)) {
2846                 ast_log(LOG_ERROR, "Unable to lock application list\n");
2847                 return NULL;
2848         }
2849
2850         /* return the n-th [partial] matching entry */
2851         for (a = apps; a && !ret; a = a->next) {
2852                 if (!strncasecmp(word, a->name, wordlen) && ++which > state)
2853                         ret = strdup(a->name);
2854         }
2855
2856         ast_mutex_unlock(&applock);
2857
2858         return ret; 
2859 }
2860
2861 static int handle_show_application(int fd, int argc, char *argv[])
2862 {
2863         struct ast_app *a;
2864         int app, no_registered_app = 1;
2865
2866         if (argc < 3) return RESULT_SHOWUSAGE;
2867
2868         /* try to lock applications list ... */
2869         if (ast_mutex_lock(&applock)) {
2870                 ast_log(LOG_ERROR, "Unable to lock application list\n");
2871                 return -1;
2872         }
2873
2874         /* ... go through all applications ... */
2875         for (a = apps; a; a = a->next) {
2876                 /* ... compare this application name with all arguments given
2877                  * to 'show application' command ... */
2878                 for (app = 2; app < argc; app++) {
2879                         if (!strcasecmp(a->name, argv[app])) {
2880                                 /* Maximum number of characters added by terminal coloring is 22 */
2881                                 char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
2882                                 char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
2883                                 int synopsis_size, description_size;
2884
2885                                 no_registered_app = 0;
2886
2887                                 if (a->synopsis)
2888                                         synopsis_size = strlen(a->synopsis) + 23;
2889                                 else
2890                                         synopsis_size = strlen("Not available") + 23;
2891                                 synopsis = alloca(synopsis_size);
2892
2893                                 if (a->description)
2894                                         description_size = strlen(a->description) + 23;
2895                                 else
2896                                         description_size = strlen("Not available") + 23;
2897                                 description = alloca(description_size);
2898
2899                                 if (synopsis && description) {
2900                                         snprintf(info, 64 + AST_MAX_APP, "\n  -= Info about application '%s' =- \n\n", a->name);
2901                                         term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
2902                                         term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
2903                                         term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
2904                                         term_color(synopsis,
2905                                                                         a->synopsis ? a->synopsis : "Not available",
2906                                                                         COLOR_CYAN, 0, synopsis_size);
2907                                         term_color(description,
2908                                                                         a->description ? a->description : "Not available",
2909                                                                         COLOR_CYAN, 0, description_size);
2910
2911                                         ast_cli(fd,"%s%s%s\n\n%s%s\n", infotitle, syntitle, synopsis, destitle, description);
2912                                 } else {
2913                                         /* ... one of our applications, show info ...*/
2914                                         ast_cli(fd,"\n  -= Info about application '%s' =- \n\n"
2915                                                 "[Synopsis]\n  %s\n\n"
2916                                                 "[Description]\n%s\n",
2917                                                 a->name,
2918                                                 a->synopsis ? a->synopsis : "Not available",
2919                                                 a->description ? a->description : "Not available");
2920                                 }
2921                         }
2922                 }
2923         }
2924
2925         ast_mutex_unlock(&applock);
2926
2927         /* we found at least one app? no? */
2928         if (no_registered_app) {
2929                 ast_cli(fd, "Your application(s) is (are) not registered\n");
2930                 return RESULT_FAILURE;
2931         }
2932
2933         return RESULT_SUCCESS;
2934 }
2935
2936 /*! \brief  handle_show_hints: CLI support for listing registred dial plan hints */
2937 static int handle_show_hints(int fd, int argc, char *argv[])
2938 {
2939         struct ast_hint *hint;
2940         int num = 0;
2941         int watchers;
2942         struct ast_state_cb *watcher;
2943
2944         if (AST_LIST_EMPTY(&hints)) {
2945                 ast_cli(fd, "There are no registered dialplan hints\n");
2946                 return RESULT_SUCCESS;
2947         }
2948         /* ... we have hints ... */
2949         ast_cli(fd, "\n    -= Registered Asterisk Dial Plan Hints =-\n");
2950         if (AST_LIST_LOCK(&hints)) {
2951                 ast_log(LOG_ERROR, "Unable to lock hints\n");
2952                 return -1;
2953         }
2954         AST_LIST_TRAVERSE(&hints, hint, list) {
2955                 watchers = 0;
2956                 for (watcher = hint->callbacks; watcher; watcher = watcher->next)
2957                         watchers++;
2958                 ast_cli(fd, "   %-20.20s: %-20.20s  State:%-15.15s Watchers %2d\n",
2959                         ast_get_extension_name(hint->exten), ast_get_extension_app(hint->exten),
2960                         ast_extension_state2str(hint->laststate), watchers);
2961                 num++;
2962         }
2963         ast_cli(fd, "----------------\n");
2964         ast_cli(fd, "- %d hints registered\n", num);
2965         AST_LIST_UNLOCK(&hints);
2966         return RESULT_SUCCESS;
2967 }
2968
2969 /*! \brief  handle_show_switches: CLI support for listing registred dial plan switches */
2970 static int handle_show_switches(int fd, int argc, char *argv[])
2971 {
2972         struct ast_switch *sw;
2973         if (!switches) {
2974                 ast_cli(fd, "There are no registered alternative switches\n");
2975                 return RESULT_SUCCESS;
2976         }
2977         /* ... we have applications ... */
2978         ast_cli(fd, "\n    -= Registered Asterisk Alternative Switches =-\n");
2979         if (ast_mutex_lock(&switchlock)) {
2980                 ast_log(LOG_ERROR, "Unable to lock switches\n");
2981                 return -1;
2982         }
2983         for (sw = switches; sw; sw = sw->next) {
2984                 ast_cli(fd, "%s: %s\n", sw->name, sw->description);
2985         }
2986         ast_mutex_unlock(&switchlock);
2987         return RESULT_SUCCESS;
2988 }
2989
2990 /*
2991  * 'show applications' CLI command implementation functions ...
2992  */
2993 static int handle_show_applications(int fd, int argc, char *argv[])
2994 {
2995         struct ast_app *a;
2996         int like = 0, describing = 0;
2997         int total_match = 0;    /* Number of matches in like clause */
2998         int total_apps = 0;     /* Number of apps registered */
2999         
3000         /* try to lock applications list ... */
3001         if (ast_mutex_lock(&applock)) {
3002                 ast_log(LOG_ERROR, "Unable to lock application list\n");
3003                 return -1;
3004         }
3005
3006         /* ... have we got at least one application (first)? no? */
3007         if (!apps) {
3008                 ast_cli(fd, "There are no registered applications\n");
3009                 ast_mutex_unlock(&applock);
3010                 return -1;
3011         }
3012
3013         /* show applications like <keyword> */
3014         if ((argc == 4) && (!strcmp(argv[2], "like"))) {
3015                 like = 1;
3016         } else if ((argc > 3) && (!strcmp(argv[2], "describing"))) {
3017                 describing = 1;
3018         }
3019
3020         /* show applications describing <keyword1> [<keyword2>] [...] */
3021         if ((!like) && (!describing)) {
3022                 ast_cli(fd, "    -= Registered Asterisk Applications =-\n");
3023         } else {
3024                 ast_cli(fd, "    -= Matching Asterisk Applications =-\n");
3025         }
3026
3027         /* ... go through all applications ... */
3028         for (a = apps; a; a = a->next) {
3029                 /* ... show informations about applications ... */
3030                 int printapp=0;
3031                 total_apps++;
3032                 if (like) {
3033                         if (strcasestr(a->name, argv[3])) {
3034                                 printapp = 1;
3035                                 total_match++;
3036                         }
3037                 } else if (describing) {
3038                         if (a->description) {
3039                                 /* Match all words on command line */
3040                                 int i;
3041                                 printapp = 1;
3042                                 for (i = 3; i < argc; i++) {
3043                                         if (!strcasestr(a->description, argv[i])) {
3044                                                 printapp = 0;
3045                                         } else {
3046                                                 total_match++;
3047                                         }
3048                                 }
3049                         }
3050                 } else {
3051                         printapp = 1;
3052                 }
3053
3054                 if (printapp) {
3055                         ast_cli(fd,"  %20s: %s\n", a->name, a->synopsis ? a->synopsis : "<Synopsis not available>");
3056                 }
3057         }
3058         if ((!like) && (!describing)) {
3059                 ast_cli(fd, "    -= %d Applications Registered =-\n",total_apps);
3060         } else {
3061                 ast_cli(fd, "    -= %d Applications Matching =-\n",total_match);
3062         }
3063         
3064         /* ... unlock and return */
3065         ast_mutex_unlock(&applock);
3066
3067         return RESULT_SUCCESS;
3068 }
3069
3070 static char *complete_show_applications(const char *line, const char *word, int pos, int state)
3071 {
3072         int wordlen = strlen(word);
3073
3074         if (pos == 2) {
3075                 if (ast_strlen_zero(word)) {
3076                         switch (state) {
3077                         case 0:
3078                                 return strdup("like");
3079                         case 1:
3080                                 return strdup("describing");
3081                         default:
3082                                 return NULL;
3083                         }
3084                 } else if (! strncasecmp(word, "like", wordlen)) {
3085                         if (state == 0) {
3086                                 return strdup("like");
3087                         } else {
3088                                 return NULL;
3089                         }
3090                 } else if (! strncasecmp(word, "describing", wordlen)) {
3091                         if (state == 0) {
3092                                 return strdup("describing");
3093                         } else {
3094                                 return NULL;
3095                         }
3096                 }
3097         }
3098         return NULL;
3099 }
3100
3101 /*
3102  * 'show dialplan' CLI command implementation functions ...
3103  */
3104 static char *complete_show_dialplan_context(const char *line, const char *word, int pos,
3105         int state)
3106 {
3107         struct ast_context *c = NULL;
3108         char *ret = NULL;
3109         int which = 0;
3110         int wordlen;
3111
3112         /* we are do completion of [exten@]context on second position only */
3113         if (pos != 2)
3114                 return NULL;
3115
3116         /* try to lock contexts list ... */
3117         if (ast_lock_contexts()) {
3118                 ast_log(LOG_ERROR, "Unable to lock context list\n");
3119                 return NULL;
3120         }
3121
3122         wordlen = strlen(word);
3123
3124         /* ... walk through all contexts ... */
3125         while ( (c = ast_walk_contexts(c)) ) {
3126                 /* ... word matches context name? yes? ... */
3127                 if (!strncasecmp(word, ast_get_context_name(c), wordlen)) {
3128                         /* ... for serve? ... */
3129                         if (++which > state) {
3130                                 /* ... yes, serve this context name ... */
3131                                 ret = strdup(ast_get_context_name(c));
3132                                 break;
3133                         }
3134                 }
3135         }
3136
3137         /* ... unlock and return */
3138         ast_unlock_contexts();
3139         return ret;
3140 }
3141
3142 struct dialplan_counters {
3143         int total_context;
3144         int total_exten;
3145         int total_prio;
3146         int context_existence;
3147         int extension_existence;
3148 };
3149
3150 static int show_dialplan_helper(int fd, char *context, char *exten, struct dialplan_counters *dpc, struct ast_include *rinclude, int includecount, char *includes[])
3151 {
3152         struct ast_context *c = NULL;
3153         int res = 0, old_total_exten = dpc->total_exten;
3154
3155         /* try to lock contexts */
3156         if (ast_lock_contexts()) {
3157                 ast_log(LOG_WARNING, "Failed to lock contexts list\n");
3158                 return -1;
3159         }
3160
3161         /* walk all contexts ... */
3162         while ( (c = ast_walk_contexts(c)) ) {
3163                 /* show this context? */
3164                 if (!context ||
3165                         !strcmp(ast_get_context_name(c), context)) {
3166                         dpc->context_existence = 1;
3167
3168                         /* try to lock context before walking in ... */
3169                         if (!ast_lock_context(c)) {
3170                                 struct ast_exten *e;
3171                                 struct ast_include *i;
3172                                 struct ast_ignorepat *ip;
3173                                 struct ast_sw *sw;
3174                                 char buf[256], buf2[256];
3175                                 int context_info_printed = 0;
3176
3177                                 /* are we looking for exten too? if yes, we print context
3178                                  * if we our extension only
3179                                  */
3180                                 if (!exten) {
3181                                         dpc->total_context++;
3182                                         ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
3183                                                 ast_get_context_name(c), ast_get_context_registrar(c));
3184                                         context_info_printed = 1;
3185                                 }
3186
3187                                 /* walk extensions ... */
3188                                 for (e = ast_walk_context_extensions(c, NULL); e; e = ast_walk_context_extensions(c, e)) {
3189                                         struct ast_exten *p;
3190                                         int prio;
3191
3192                                         /* looking for extension? is this our extension? */
3193                                         if (exten &&
3194                                                 !ast_extension_match(ast_get_extension_name(e), exten))
3195                                         {
3196                                                 /* we are looking for extension and it's not our
3197                                                  * extension, so skip to next extension */
3198                                                 continue;
3199                                         }
3200
3201                                         dpc->extension_existence = 1;
3202
3203                                         /* may we print context info? */        
3204                                         if (!context_info_printed) {
3205                                                 dpc->total_context++;
3206                                                 if (rinclude) {
3207                                                         /* TODO Print more info about rinclude */
3208                                                         ast_cli(fd, "[ Included context '%s' created by '%s' ]\n",
3209                                                                 ast_get_context_name(c),
3210                                                                 ast_get_context_registrar(c));
3211                                                 } else {
3212                                                         ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
3213                                                                 ast_get_context_name(c),
3214                                                                 ast_get_context_registrar(c));
3215                                                 }
3216                                                 context_info_printed = 1;
3217                                         }
3218                                         dpc->total_prio++;
3219
3220                                         /* write extension name and first peer */       
3221                                         bzero(buf, sizeof(buf));                
3222                                         snprintf(buf, sizeof(buf), "'%s' =>",
3223                                                 ast_get_extension_name(e));
3224
3225                                         prio = ast_get_extension_priority(e);
3226                                         if (prio == PRIORITY_HINT) {
3227                                                 snprintf(buf2, sizeof(buf2),
3228                                                         "hint: %s",
3229                                                         ast_get_extension_app(e));
3230                                         } else {
3231                                                 snprintf(buf2, sizeof(buf2),
3232                                                         "%d. %s(%s)",
3233                                                         prio,
3234                                                         ast_get_extension_app(e),
3235                                                         (char *)ast_get_extension_app_data(e));
3236                                         }
3237
3238                                         ast_cli(fd, "  %-17s %-45s [%s]\n", buf, buf2,
3239                                                 ast_get_extension_registrar(e));
3240
3241                                         dpc->total_exten++;
3242                                         /* walk next extension peers */
3243                                         for (p=ast_walk_extension_priorities(e, e); p; p=ast_walk_extension_priorities(e, p)) {
3244                                                 dpc->total_prio++;
3245                                                 bzero((void *)buf2, sizeof(buf2));
3246                                                 bzero((void *)buf, sizeof(buf));
3247                                                 if (ast_get_extension_label(p))
3248                                                         snprintf(buf, sizeof(buf), "   [%s]", ast_get_extension_label(p));
3249                                                 prio = ast_get_extension_priority(p);
3250                                                 if (prio == PRIORITY_HINT) {
3251                                                         snprintf(buf2, sizeof(buf2),
3252                                                                 "hint: %s",
3253                                                                 ast_get_extension_app(p));
3254                                                 } else {
3255                                                         snprintf(buf2, sizeof(buf2),
3256                                                                 "%d. %s(%s)",
3257                                                                 prio,
3258                                                                 ast_get_extension_app(p),
3259                                                                 (char *)ast_get_extension_app_data(p));
3260                                                 }
3261
3262                                                 ast_cli(fd,"  %-17s %-45s [%s]\n",
3263                                                         buf, buf2,
3264                                                         ast_get_extension_registrar(p));
3265                                         }
3266                                 }
3267
3268                                 /* walk included and write info ... */
3269                                 for (i = ast_walk_context_includes(c, NULL); i; i = ast_walk_context_includes(c, i)) {
3270                                         bzero(buf, sizeof(buf));
3271                                         snprintf(buf, sizeof(buf), "'%s'",
3272                                                 ast_get_include_name(i));
3273                                         if (exten) {
3274                                                 /* Check all includes for the requested extension */
3275                                                 if (includecount >= AST_PBX_MAX_STACK) {
3276                                                         ast_log(LOG_NOTICE, "Maximum include depth exceeded!\n");
3277                                                 } else {
3278                                                         int dupe=0;
3279                                                         int x;
3280                                                         for (x=0;x<includecount;x++) {
3281                                                                 if (!strcasecmp(includes[x], ast_get_include_name(i))) {
3282                                                                         dupe++;
3283                                                                         break;
3284                                                                 }
3285                                                         }
3286                                                         if (!dupe) {
3287                                                                 includes[includecount] = (char *)ast_get_include_name(i);
3288                                                                 show_dialplan_helper(fd, (char *)ast_get_include_name(i), exten, dpc, i, includecount + 1, includes);
3289                                                         } else {
3290                                                                 ast_log(LOG_WARNING, "Avoiding circular include of %s within %s\n", ast_get_include_name(i), context);
3291                                                         }
3292                                                 }
3293                                         } else {
3294                                                 ast_cli(fd, "  Include =>        %-45s [%s]\n",
3295                                                         buf, ast_get_include_registrar(i));
3296                                         }
3297                                 }
3298
3299                                 /* walk ignore patterns and write info ... */
3300                                 for (ip = ast_walk_context_ignorepats(c, NULL); ip; ip = ast_walk_context_ignorepats(c, ip)) {
3301                                         const char *ipname = ast_get_ignorepat_name(ip);
3302                                         char ignorepat[AST_MAX_EXTENSION];
3303                                         snprintf(buf, sizeof(buf), "'%s'", ipname);
3304                                         snprintf(ignorepat, sizeof(ignorepat), "_%s.", ipname);
3305                                         if ((!exten) || ast_extension_match(ignorepat, exten)) {
3306                                                 ast_cli(fd, "  Ignore pattern => %-45s [%s]\n",
3307                                                         buf, ast_get_ignorepat_registrar(ip));
3308                                         }
3309                                 }
3310                                 if (!rinclude) {
3311                                         for (sw = ast_walk_context_switches(c, NULL); sw; sw = ast_walk_context_switches(c, sw)) {
3312                                                 snprintf(buf, sizeof(buf), "'%s/%s'",
3313                                                         ast_get_switch_name(sw),
3314                                                         ast_get_switch_data(sw));
3315                                                 ast_cli(fd, "  Alt. Switch =>    %-45s [%s]\n",
3316                                                         buf, ast_get_switch_registrar(sw));     
3317                                         }
3318                                 }
3319         
3320                                 ast_unlock_context(c);
3321
3322                                 /* if we print something in context, make an empty line */
3323                                 if (context_info_printed) ast_cli(fd, "\r\n");
3324                         }
3325                 }
3326         }
3327         ast_unlock_contexts();
3328
3329         if (dpc->total_exten == old_total_exten) {
3330                 /* Nothing new under the sun */
3331                 return -1;
3332         } else {
3333                 return res;
3334         }
3335 }
3336
3337 static int handle_show_dialplan(int fd, int argc, char *argv[])
3338 {
3339         char *exten = NULL, *context = NULL;
3340         /* Variables used for different counters */
3341         struct dialplan_counters counters;
3342         char *incstack[AST_PBX_MAX_STACK];
3343         memset(&counters, 0, sizeof(counters));
3344
3345         if (argc != 2 && argc != 3) 
3346                 return RESULT_SHOWUSAGE;
3347
3348         /* we obtain [exten@]context? if yes, split them ... */
3349         if (argc == 3) {
3350                 char *splitter = ast_strdupa(argv[2]);
3351                 /* is there a '@' character? */
3352                 if (splitter && strchr(argv[2], '@')) {
3353                         /* yes, split into exten & context ... */
3354                         exten   = strsep(&splitter, "@");
3355                         context = splitter;
3356
3357                         /* check for length and change to NULL if ast_strlen_zero() */
3358                         if (ast_strlen_zero(exten))
3359                                 exten = NULL;
3360                         if (ast_strlen_zero(context))
3361                                 context = NULL;
3362                         show_dialplan_helper(fd, context, exten, &counters, NULL, 0, incstack);
3363                 } else {
3364                         /* no '@' char, only context given */
3365                         context = argv[2];
3366                         if (ast_strlen_zero(context))
3367                                 context = NULL;
3368                         show_dialplan_helper(fd, context, exten, &counters, NULL, 0, incstack);
3369                 }
3370         } else {
3371                 /* Show complete dial plan */
3372                 show_dialplan_helper(fd, NULL, NULL, &counters, NULL, 0, incstack);
3373         }
3374
3375         /* check for input failure and throw some error messages */
3376         if (context && !counters.context_existence) {
3377                 ast_cli(fd, "There is no existence of '%s' context\n", context);
3378                 return RESULT_FAILURE;
3379         }
3380
3381         if (exten && !counters.extension_existence) {
3382                 if (context)
3383                         ast_cli(fd, "There is no existence of %s@%s extension\n",
3384                                 exten, context);
3385                 else
3386                         ast_cli(fd,
3387                                 "There is no existence of '%s' extension in all contexts\n",
3388                                 exten);
3389                 return RESULT_FAILURE;
3390         }
3391
3392         ast_cli(fd,"-= %d %s (%d %s) in %d %s. =-\n",
3393                                 counters.total_exten, counters.total_exten == 1 ? "extension" : "extensions",
3394                                 counters.total_prio, counters.total_prio == 1 ? "priority" : "priorities",
3395                                 counters.total_context, counters.total_context == 1 ? "context" : "contexts");
3396
3397         /* everything ok */
3398         return RESULT_SUCCESS;
3399 }
3400
3401 /*
3402  * CLI entries for upper commands ...
3403  */
3404 static struct ast_cli_entry pbx_cli[] = {
3405         { { "show", "applications", NULL }, handle_show_applications,
3406           "Shows registered dialplan applications", show_applications_help, complete_show_applications },
3407         { { "show", "functions", NULL }, handle_show_functions,
3408           "Shows registered dialplan functions", show_functions_help },
3409         { { "show" , "function", NULL }, handle_show_function,
3410           "Describe a specific dialplan function", show_function_help, complete_show_function },
3411         { { "show", "application", NULL }, handle_show_application,
3412           "Describe a specific dialplan application", show_application_help, complete_show_application },
3413         { { "show", "dialplan", NULL }, handle_show_dialplan,
3414           "Show dialplan", show_dialplan_help, complete_show_dialplan_context },
3415         { { "show", "switches", NULL }, handle_show_switches,
3416           "Show alternative switches", show_switches_help },
3417         { { "show", "hints", NULL }, handle_show_hints,
3418           "Show dialplan hints", show_hints_help },
3419 };
3420
3421 int ast_unregister_application(const char *app) 
3422 {
3423         struct ast_app *tmp, *tmpl = NULL;
3424         if (ast_mutex_lock(&applock)) {
3425                 ast_log(LOG_ERROR, "Unable to lock application list\n");
3426                 return -1;
3427         }
3428         for (tmp = apps; tmp; tmp = tmp->next) {
3429                 if (!strcasecmp(app, tmp->name)) {
3430                         if (tmpl)
3431                                 tmpl->next = tmp->next;
3432                         else
3433                                 apps = tmp->next;
3434                         if (option_verbose > 1)
3435                                 ast_verbose( VERBOSE_PREFIX_2 "Unregistered application '%s'\n", tmp->name);
3436                         free(tmp);
3437        &n