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