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