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