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