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