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