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