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