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