Version 0.1.1 from FTP
[asterisk/asterisk.git] / pbx.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Core PBX routines.
5  * 
6  * Copyright (C) 1999, Adtran Inc. and Linux Support Services, LLC
7  *
8  * Mark Spencer <markster@linux-support.net>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  */
13
14 #include <pthread.h>
15 #include <asterisk/pbx.h>
16 #include <asterisk/channel.h>
17 #include <asterisk/options.h>
18 #include <asterisk/logger.h>
19 #include <asterisk/file.h>
20 #include <string.h>
21 #include <unistd.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <setjmp.h>
25 #include <ctype.h>
26
27
28 /*
29  * I M P O R T A N T :
30  *
31  *              The speed of extension handling will likely be among the most important
32  * aspects of this PBX.  The switching scheme as it exists right now isn't
33  * terribly bad (it's O(N+M), where N is the # of extensions and M is the avg #
34  * of priorities, but a constant search time here would be great ;-) 
35  *
36  */
37
38
39 struct ast_context;
40
41 struct ast_pbx {
42         int dtimeout;                                   /* Timeout between digits (seconds) */
43         int rtimeout;                                   /* Timeout for response (seconds) */
44 };
45
46 /* An extension */
47 struct ast_exten {
48         char exten[AST_MAX_EXTENSION];
49         int priority;
50         /* An extension */
51         struct ast_context *parent;
52         /* Application to execute */
53         char app[AST_MAX_EXTENSION];
54         /* Data to use */
55         void *data;
56         /* Data destructor */
57         void (*datad)(void *);
58         /* Next highest priority with our extension */
59         struct ast_exten *peer;
60         /* Extension with a greater ID */
61         struct ast_exten *next;
62 };
63
64 /* An extension context */
65 struct ast_context {
66         /* Name of the context */
67         char name[AST_MAX_EXTENSION];
68         /* A lock to prevent multiple threads from clobbering the context */
69         pthread_mutex_t lock;
70         /* The root of the list of extensions */
71         struct ast_exten *root;
72         /* Link them together */
73         struct ast_context *next;
74 };
75
76
77 /* An application */
78 struct ast_app {
79         /* Name of the application */
80         char name[AST_MAX_APP];
81         int (*execute)(struct ast_channel *chan, void *data);
82         struct ast_app *next;
83 };
84
85 static int pbx_builtin_answer(struct ast_channel *, void *);
86 static int pbx_builtin_goto(struct ast_channel *, void *);
87 static int pbx_builtin_hangup(struct ast_channel *, void *);
88 static int pbx_builtin_background(struct ast_channel *, void *);
89 static int pbx_builtin_dtimeout(struct ast_channel *, void *);
90 static int pbx_builtin_rtimeout(struct ast_channel *, void *);
91 static int pbx_builtin_wait(struct ast_channel *, void *);
92
93 static struct pbx_builtin {
94         char name[AST_MAX_APP];
95         int (*execute)(struct ast_channel *chan, void *data);
96 } builtins[] = 
97 {
98         /* These applications are built into the PBX core and do not
99            need separate modules */
100         { "Answer", pbx_builtin_answer },
101         { "Goto", pbx_builtin_goto },
102         { "Hangup", pbx_builtin_hangup },
103         { "DigitTimeout", pbx_builtin_dtimeout },
104         { "ResponseTimeout", pbx_builtin_rtimeout },
105         { "BackGround", pbx_builtin_background },
106         { "Wait", pbx_builtin_wait },
107 };
108
109 /* Lock for the application list */
110 static pthread_mutex_t applock = PTHREAD_MUTEX_INITIALIZER;
111 static struct ast_context *contexts = NULL;
112 /* Lock for the ast_context list */
113 static pthread_mutex_t conlock = PTHREAD_MUTEX_INITIALIZER;
114 static struct ast_app *apps = NULL;
115
116 static int pbx_exec(struct ast_channel *c, /* Channel */
117                                         int (*execute)(struct ast_channel *chan, void *data), 
118                                         void *data,                             /* Data for execution */
119                                         int newstack)                   /* Force stack increment */
120 {
121         /* This function is special.  It saves the stack so that no matter
122            how many times it is called, it returns to the same place */
123         int res;
124         int stack = c->stack;
125         if (newstack && stack > AST_CHANNEL_MAX_STACK - 2) {
126                 /* Don't allow us to go over the max number of stacks we
127                    permit saving. */
128                 ast_log(LOG_WARNING, "Stack overflow, cannot create another stack\n");
129                 return -1;
130         }
131         if (newstack && (res = setjmp(c->jmp[++c->stack]))) {
132                 /* Okay, here's where it gets weird.  If newstack is non-zero, 
133                    then we increase the stack increment, but setjmp is not going
134                    to return until longjmp is called -- when the application
135                    exec'd is finished running. */
136                 if (res == 1)
137                         res = 0;
138                 if (c->stack != stack + 1) 
139                         ast_log(LOG_WARNING, "Stack returned to an unexpected place!\n");
140                 else if (c->app[c->stack])
141                         ast_log(LOG_WARNING, "Application may have forgotten to free its memory\n");
142                 c->stack = stack;
143                 return res;
144         } else {
145                 res = execute(c, data);
146                 /* Any application that returns, we longjmp back, just in case. */
147                 if (c->stack != stack + 1)
148                         ast_log(LOG_WARNING, "Stack is not at expected value\n");
149                 longjmp(c->jmp[stack+1], res);
150                 /* Never returns */
151         }
152 }
153
154
155 #define HELPER_EXISTS 0
156 #define HELPER_SPAWN 1
157 #define HELPER_EXEC 2
158
159 static struct ast_app *pbx_findapp(char *app) 
160 {
161         struct ast_app *tmp;
162         if (pthread_mutex_lock(&applock)) {
163                 ast_log(LOG_WARNING, "Unable to obtain application lock\n");
164                 return NULL;
165         }
166         tmp = apps;
167         while(tmp) {
168                 if (!strcasecmp(tmp->name, app))
169                         break;
170                 tmp = tmp->next;
171         }
172         pthread_mutex_unlock(&applock);
173         return tmp;
174 }
175
176 static void pbx_destroy(struct ast_pbx *p)
177 {
178         free(p);
179 }
180
181 int extension_match(char *pattern, char *data)
182 {
183         int match;
184         /* If they're the same return */
185         if (!strcasecmp(pattern, data))
186                 return 1;
187         /* All patterns begin with _ */
188         if (pattern[0] != '_') 
189                 return 0;
190         /* Obviously must be the same length */
191         if (strlen(pattern) != strlen(data) + 1)
192                 return 0;
193         /* Start optimistic */
194         match=1;
195         pattern++;
196         while(match && *data && *pattern) {
197                 switch(toupper(*pattern)) {
198                 case 'N':
199                         if ((*data < '2') || (*data > '9'))
200                                 match=0;
201                         break;
202                 case 'X':
203                         if ((*data < '0') || (*data > '9'))
204                                 match = 0;
205                         break;
206                 default:
207                         if (*data != *pattern)
208                                 match =0;
209                 }
210                 data++;
211                 pattern++;
212         }
213         return match;
214 }
215
216 static int pbx_extension_helper(struct ast_channel *c, char *context, char *exten, int priority, int action) 
217 {
218         struct ast_context *tmp;
219         struct ast_exten *e;
220         struct ast_app *app;
221         int newstack = 0;
222         if (pthread_mutex_lock(&conlock)) {
223                 ast_log(LOG_WARNING, "Unable to obtain lock\n");
224                 if (action == HELPER_EXISTS)
225                         return 0;
226                 else
227                         return -1;
228         }
229         tmp = contexts;
230         while(tmp) {
231                 if (!strcasecmp(tmp->name, context)) {
232                         /* By locking tmp, not only can the state of its entries not
233                            change, but it cannot be destroyed either. */
234                         pthread_mutex_lock(&tmp->lock);
235                         /* But we can relieve the conlock, as tmp will not change */
236                         pthread_mutex_unlock(&conlock);
237                         e = tmp->root;
238                         while(e) {
239                                 if (extension_match(e->exten, exten)) {
240                                         while(e) {
241                                                 if (e->priority == priority) {
242                                                         pthread_mutex_unlock(&tmp->lock);
243                                                         /* We have a winner! Maybe there are some races
244                                                            in here though. XXX */
245                                                         switch(action) {
246                                                         case HELPER_EXISTS:
247                                                                 return -1;
248                                                         case HELPER_SPAWN:
249                                                                 newstack++;
250                                                                 /* Fall through */
251                                                         case HELPER_EXEC:
252                                                                 app = pbx_findapp(e->app);
253                                                                 if (app) {
254                                                                         strncpy(c->context, context, sizeof(c->context));
255                                                                         strncpy(c->exten, exten, sizeof(c->exten));
256                                                                         c->priority = priority;
257                                                                         if (option_debug)
258                                                                                 ast_log(LOG_DEBUG, "Launching '%s'\n", app->name);
259                                                                         else if (option_verbose > 2)
260                                                                                 ast_verbose( VERBOSE_PREFIX_3 "Executing %s(\"%s\", \"%s\") %s\n", 
261                                                                                                 app->name, c->name, (e->data ? (char *)e->data : NULL), (newstack ? "in new stack" : "in same stack"));
262                                                                         return pbx_exec(c, app->execute, e->data, newstack);
263                                                                 } else {
264                                                                         ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
265                                                                         return -1;
266                                                                 }
267                                                         default:
268                                                                 ast_log(LOG_WARNING, "Huh (%d)?\n", action);
269                                                         }
270                                                 }
271                                                 e = e->peer;
272                                         }
273                                         pthread_mutex_unlock(&tmp->lock);
274                                         if (action != HELPER_EXISTS) {
275                                                 ast_log(LOG_WARNING, "No such priority '%d' in '%s' in '%s'\n", priority, exten, context);
276                                                 return -1;
277                                         } else
278                                                 return 0;
279                                 }
280                                 e = e->next;
281                         }
282                         pthread_mutex_unlock(&tmp->lock);
283                         if (action != HELPER_EXISTS) {
284                                 ast_log(LOG_WARNING, "No such extension '%s' in '%s'\n", exten, context);
285                                 return -1;
286                         } else
287                                 return 0;
288                 }
289                 tmp = tmp->next;
290         }
291         pthread_mutex_unlock(&conlock);
292         if (action != HELPER_EXISTS) {
293                 ast_log(LOG_WARNING, "No such context '%s'\n", context);
294                 return -1;
295         } else
296                 return 0;
297 }
298 int ast_pbx_longest_extension(char *context) 
299 {
300         struct ast_context *tmp;
301         struct ast_exten *e;
302         int len = 0;
303         if (pthread_mutex_lock(&conlock)) {
304                 ast_log(LOG_WARNING, "Unable to obtain lock\n");
305                 return -1;
306         }
307         tmp = contexts;
308         while(tmp) {
309                 if (!strcasecmp(tmp->name, context)) {
310                         /* By locking tmp, not only can the state of its entries not
311                            change, but it cannot be destroyed either. */
312                         pthread_mutex_lock(&tmp->lock);
313                         /* But we can relieve the conlock, as tmp will not change */
314                         pthread_mutex_unlock(&conlock);
315                         e = tmp->root;
316                         while(e) {
317                                 if (strlen(e->exten) > len)
318                                         len = strlen(e->exten);
319                                 e = e->next;
320                         }
321                         pthread_mutex_unlock(&tmp->lock);
322                         return len;
323                 }
324                 tmp = tmp->next;
325         }
326         ast_log(LOG_WARNING, "No such context '%s'\n", context);
327         return -1;
328 }
329
330 int ast_exists_extension(struct ast_channel *c, char *context, char *exten, int priority) 
331 {
332         return pbx_extension_helper(c, context, exten, priority, HELPER_EXISTS);
333 }
334
335 int ast_spawn_extension(struct ast_channel *c, char *context, char *exten, int priority) 
336 {
337         return pbx_extension_helper(c, context, exten, priority, HELPER_SPAWN);
338 }
339
340 static void *pbx_thread(void *data)
341 {
342         /* Oh joyeous kernel, we're a new thread, with nothing to do but
343            answer this channel and get it going.  The setjmp stuff is fairly
344            confusing, but necessary to get smooth transitions between
345            the execution of different applications (without the use of
346            additional threads) */
347         struct ast_channel *c = data;
348         int firstpass = 1;
349         char digit;
350         char exten[256];
351         int pos;
352         int waittime;
353         if (option_debug)
354                 ast_log(LOG_DEBUG, "PBX_THREAD(%s)\n", c->name);
355         else if (option_verbose > 1)
356                 ast_verbose( VERBOSE_PREFIX_2 "Accepting call on '%s'\n", c->name);
357                 
358         
359         /* Start by trying whatever the channel is set to */
360         if (!ast_exists_extension(c, c->context, c->exten, c->priority)) {
361                 strncpy(c->context, "default", sizeof(c->context));
362                 strncpy(c->exten, "s", sizeof(c->exten));
363                 c->priority = 1;
364         }
365         for(;;) {
366                 memset(exten, 0, sizeof(exten));
367                 pos = 0;
368                 digit = 0;
369                 while(ast_exists_extension(c, c->context, c->exten, c->priority)) {
370                         if (ast_spawn_extension(c, c->context, c->exten, c->priority)) {
371                                 /* Something bad happened, or a hangup has been requested. */
372                                 if (option_debug)
373                                         ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
374                                 else if (option_verbose > 1)
375                                         ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
376                                 goto out;
377                         }
378                         /* If we're playing something in the background, wait for it to finish or for a digit */
379                         if (c->stream) {
380                                 digit = ast_waitstream(c, AST_DIGIT_ANY);
381                                 ast_stopstream(c);
382                                 /* Hang up if something goes wrong */
383                                 if (digit < 0)
384                                         goto out;
385                                 else if (digit) {
386                                         ast_stopstream(c);
387                                         exten[pos++] = digit;
388                                         break;
389                                 }
390                         }
391                         firstpass = 0;
392                         c->priority++;
393                 }
394                 /* Done, wait for an extension */
395                 if (digit)
396                         waittime = c->pbx->dtimeout;
397                 else
398                         waittime = c->pbx->rtimeout;
399                 while(!ast_exists_extension(c, c->context, exten, 1) && (
400                        strlen(exten) < ast_pbx_longest_extension(c->context))) {
401                         /* As long as we're willing to wait, and as long as it's not defined, 
402                            keep reading digits until we can't possibly get a right answer anymore.  */
403                         digit = ast_waitfordigit(c, waittime * 1000);
404                         if (!digit)
405                                 /* No entry */
406                                 break;
407                         if (digit < 0)
408                                 /* Error, maybe a  hangup */
409                                 goto out;
410                         exten[pos++] = digit;
411                         waittime = c->pbx->dtimeout;
412                 }
413                 if (ast_exists_extension(c, c->context, exten, 1)) {
414                         /* Prepare the next cycle */
415                         strncpy(c->exten, exten, sizeof(c->exten));
416                         c->priority = 1;
417                 } else {
418                         /* No such extension */
419                         if (strlen(exten)) {
420                                 /* An invalid extension */
421                                 if (ast_exists_extension(c, c->context, "i", 1)) {
422                                         if (option_verbose > 2)
423                                                 ast_verbose( VERBOSE_PREFIX_3 "Invalid extension '%s' in context '%s' on %s\n", exten, c->context, c->name);
424                                         strncpy(c->exten, "i", sizeof(c->exten));
425                                         c->priority = 1;
426                                 } else {
427                                         ast_log(LOG_WARNING, "Invalid extension, but no rule 'i' in context '%s'\n", c->context);
428                                         goto out;
429                                 }
430                         } else {
431                                 /* A simple timeout */
432                                 if (ast_exists_extension(c, c->context, "t", 1)) {
433                                         if (option_verbose > 2)
434                                                 ast_verbose( VERBOSE_PREFIX_3 "Timeout on %s\n", c->name);
435                                         strncpy(c->exten, "t", sizeof(c->exten));
436                                         c->priority = 1;
437                                 } else {
438                                         ast_log(LOG_WARNING, "Timeout, but no rule 't' in context '%s'\n", c->context);
439                                         goto out;
440                                 }
441                         }       
442                 }
443         }
444         if (firstpass) 
445                 ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", c->name);
446 out:
447         pbx_destroy(c->pbx);
448         c->pbx = NULL;
449         ast_hangup(c);
450         pthread_exit(NULL);
451         
452 }
453
454 int ast_pbx_start(struct ast_channel *c)
455 {
456         pthread_t t;
457         if (!c) {
458                 ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
459                 return -1;
460         }
461         if (c->pbx)
462                 ast_log(LOG_WARNING, "%s already has PBX structure??\n");
463         c->pbx = malloc(sizeof(struct ast_pbx));
464         if (!c->pbx) {
465                 ast_log(LOG_WARNING, "Out of memory\n");
466                 return -1;
467         }
468         memset(c->pbx, 0, sizeof(struct ast_pbx));
469         /* Start a new thread, and get something handling this channel. */
470         if (pthread_create(&t, NULL, pbx_thread, c)) {
471                 ast_log(LOG_WARNING, "Failed to create new channel thread\n");
472                 return -1;
473         }
474         return 0;
475 }
476 #if 0
477 int ast_remove_extension(struct ast_context *con, char *extension, int priority)
478 {
479         /* XXX Implement me XXX */
480         return -1;
481 }
482 #endif
483 int ast_register_application(char *app, int (*execute)(struct ast_channel *, void *))
484 {
485         struct ast_app *tmp;
486         if (pthread_mutex_lock(&applock)) {
487                 ast_log(LOG_ERROR, "Unable to lock application list\n");
488                 return -1;
489         }
490         tmp = apps;
491         while(tmp) {
492                 if (!strcasecmp(app, tmp->name)) {
493                         ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
494                         pthread_mutex_unlock(&applock);
495                         return -1;
496                 }
497                 tmp = tmp->next;
498         }
499         tmp = malloc(sizeof(struct ast_app));
500         if (tmp) {
501                 strncpy(tmp->name, app, sizeof(tmp->name));
502                 tmp->execute = execute;
503                 tmp->next = apps;
504                 apps = tmp;
505         } else {
506                 ast_log(LOG_WARNING, "Out of memory\n");
507                 pthread_mutex_unlock(&applock);
508                 return -1;
509         }
510         if (option_verbose > 1)
511                 ast_verbose( VERBOSE_PREFIX_2 "Registered application '%s'\n", tmp->name);
512         pthread_mutex_unlock(&applock);
513         return 0;
514 }
515
516 int ast_unregister_application(char *app) {
517         struct ast_app *tmp, *tmpl = NULL;
518         if (pthread_mutex_lock(&applock)) {
519                 ast_log(LOG_ERROR, "Unable to lock application list\n");
520                 return -1;
521         }
522         tmp = apps;
523         while(tmp) {
524                 if (!strcasecmp(app, tmp->name)) {
525                         if (tmpl)
526                                 tmpl->next = tmp->next;
527                         else
528                                 apps = tmp->next;
529                         if (option_verbose > 1)
530                                 ast_verbose( VERBOSE_PREFIX_2 "Unregistered application '%s'\n", tmp->name);
531                         pthread_mutex_unlock(&applock);
532                         return 0;
533                 }
534                 tmpl = tmp;
535                 tmp = tmp->next;
536         }
537         pthread_mutex_unlock(&applock);
538         return -1;
539 }
540
541 struct ast_context *ast_context_create(char *name)
542 {
543         struct ast_context *tmp;
544         
545         pthread_mutex_lock(&conlock);
546         tmp = contexts;
547         while(tmp) {
548                 if (!strcasecmp(tmp->name, name)) {
549                         pthread_mutex_unlock(&conlock);
550                         ast_log(LOG_WARNING, "Tried to register context '%s', already in use\n", name);
551                         return NULL;
552                 }
553                 tmp = tmp->next;
554         }
555         tmp = malloc(sizeof(struct ast_context));
556         if (tmp) {
557                 pthread_mutex_init(&tmp->lock, NULL);
558                 strncpy(tmp->name, name, sizeof(tmp->name));
559                 tmp->root = NULL;
560                 tmp->next = contexts;
561                 contexts = tmp;
562                 if (option_debug)
563                         ast_log(LOG_DEBUG, "Registered context '%s'\n", tmp->name);
564                 else if (option_verbose > 2)
565                         ast_verbose( VERBOSE_PREFIX_3 "Registered extension context '%s'\n", tmp->name);
566         } else
567                 ast_log(LOG_WARNING, "Out of memory\n");
568         
569         pthread_mutex_unlock(&conlock);
570         return tmp;
571 }
572
573 int ast_add_extension2(struct ast_context *con,
574                                           int replace, char *extension, int priority,
575                                           char *application, void *data, void (*datad)(void *))
576 {
577
578 #define LOG {   if (option_debug) \
579                 ast_log(LOG_DEBUG, "Added extension '%s' priority %d to %s\n", tmp->exten, tmp->priority, con->name); \
580         else if (option_verbose > 2) \
581                 ast_verbose( VERBOSE_PREFIX_3 "Added extension '%s' priority %d to %s\n", tmp->exten, tmp->priority, con->name); \
582                 }
583
584         /*
585          * This is a fairly complex routine.  Different extensions are kept
586          * in order by the extension number.  Then, extensions of different
587          * priorities (same extension) are kept in a list, according to the
588          * peer pointer.
589          */
590         struct ast_exten *tmp, *e, *el = NULL, *ep = NULL;
591         int res;
592         /* Be optimistic:  Build the extension structure first */
593         tmp = malloc(sizeof(struct ast_exten));
594         if (tmp) {
595                 strncpy(tmp->exten, extension, sizeof(tmp->exten));
596                 tmp->priority = priority;
597                 strncpy(tmp->app, application, sizeof(tmp->app));
598                 tmp->data = data;
599                 tmp->datad = datad;
600                 tmp->peer = NULL;
601                 tmp->next =  NULL;
602         } else {
603                 ast_log(LOG_WARNING, "Out of memory\n");
604                 return -1;
605         }
606         if (pthread_mutex_lock(&con->lock)) {
607                 free(tmp);
608                 /* And properly destroy the data */
609                 datad(data);
610                 ast_log(LOG_WARNING, "Failed to lock context '%s'\n", con->name);
611                 return -1;
612         }
613         e = con->root;
614         while(e) {
615                 res= strcasecmp(e->exten, extension);
616                 if (res == 0) {
617                         /* We have an exact match, now we find where we are
618                            and be sure there's no duplicates */
619                         while(e) {
620                                 if (e->priority == tmp->priority) {
621                                         /* Can't have something exactly the same.  Is this a
622                                            replacement?  If so, replace, otherwise, bonk. */
623                                         if (replace) {
624                                                 if (ep) {
625                                                         /* We're in the peer list, insert ourselves */
626                                                         ep->peer = tmp;
627                                                         tmp->peer = e->peer;
628                                                 } else if (el) {
629                                                         /* We're the first extension. Take over e's functions */
630                                                         el->next = tmp;
631                                                         tmp->next = e->next;
632                                                         tmp->peer = e->peer;
633                                                 } else {
634                                                         /* We're the very first extension.  */
635                                                         con->root = tmp;
636                                                         tmp->next = e->next;
637                                                         tmp->peer = e->peer;
638                                                 }
639                                                 /* Destroy the old one */
640                                                 e->datad(e->data);
641                                                 free(e);
642                                                 pthread_mutex_unlock(&con->lock);
643                                                 /* And immediately return success. */
644                                                 LOG;
645                                                 return 0;
646                                         } else {
647                                                 ast_log(LOG_WARNING, "Unable to register extension '%s', priority %d in '%s', already in use\n", tmp->exten, tmp->priority, con->name);
648                                                 tmp->datad(tmp->data);
649                                                 free(tmp);
650                                                 pthread_mutex_unlock(&con->lock);
651                                                 return -1;
652                                         }
653                                 } else if (e->priority > tmp->priority) {
654                                         /* Slip ourselves in just before e */
655                                         if (ep) {
656                                                 /* Easy enough, we're just in the peer list */
657                                                 ep->peer = tmp;
658                                                 tmp->peer = e;
659                                         } else if (el) {
660                                                 /* We're the first extension in this peer list */
661                                                 el->next = tmp;
662                                                 tmp->next = e->next;
663                                                 e->next = NULL;
664                                                 tmp->peer = e;
665                                         } else {
666                                                 /* We're the very first extension altogether */
667                                                 tmp->next = con->root;
668                                                 /* Con->root must always exist or we couldn't get here */
669                                                 tmp->peer = con->root->peer;
670                                                 con->root = tmp;
671                                         }
672                                         pthread_mutex_unlock(&con->lock);
673                                         /* And immediately return success. */
674                                         LOG;
675                                         return 0;
676                                 }
677                                 ep = e;
678                                 e = e->peer;
679                         }
680                         /* If we make it here, then it's time for us to go at the very end.
681                            ep *must* be defined or we couldn't have gotten here. */
682                         ep->peer = tmp;
683                         pthread_mutex_unlock(&con->lock);
684                         /* And immediately return success. */
685                         LOG;
686                         return 0;
687                                 
688                 } else if (res > 0) {
689                         /* Insert ourselves just before 'e'.  We're the first extension of
690                            this kind */
691                         tmp->next = e;
692                         if (el) {
693                                 /* We're in the list somewhere */
694                                 el->next = tmp;
695                         } else {
696                                 /* We're at the top of the list */
697                                 con->root = tmp;
698                         }
699                         pthread_mutex_unlock(&con->lock);
700                         /* And immediately return success. */
701                         LOG;
702                         return 0;
703                 }                       
704                         
705                 el = e;
706                 e = e->next;
707         }
708         /* If we fall all the way through to here, then we need to be on the end. */
709         if (el)
710                 el->next = tmp;
711         else
712                 con->root = tmp;
713         pthread_mutex_unlock(&con->lock);
714         LOG;
715         return 0;       
716 }
717
718 void ast_context_destroy(struct ast_context *con)
719 {
720         struct ast_context *tmp, *tmpl=NULL;
721         pthread_mutex_lock(&conlock);
722         tmp = contexts;
723         while(tmp) {
724                 if (tmp == con) {
725                         /* Okay, let's lock the structure to be sure nobody else
726                            is searching through it. */
727                         if (pthread_mutex_lock(&tmp->lock)) {
728                                 ast_log(LOG_WARNING, "Unable to lock context lock\n");
729                                 return;
730                         }
731                         if (tmpl)
732                                 tmpl->next = tmp->next;
733                         else
734                                 contexts = tmp->next;
735                         /* Okay, now we're safe to let it go -- in a sense, we were
736                            ready to let it go as soon as we locked it. */
737                         pthread_mutex_unlock(&tmp->lock);
738                         free(tmp);
739                         pthread_mutex_unlock(&conlock);
740                         return;
741                 }
742                 tmpl = tmp;
743                 tmp = tmp->next;
744         }
745         pthread_mutex_unlock(&conlock);
746 }
747
748 int pbx_builtin_answer(struct ast_channel *chan, void *data)
749 {
750         if (chan->state != AST_STATE_RING) {
751                 ast_log(LOG_WARNING, "Ignoring answer request since line is not ringing\n");
752                 return 0;
753         } else
754                 return ast_answer(chan);
755 }
756
757 int pbx_builtin_hangup(struct ast_channel *chan, void *data)
758 {
759         /* Just return non-zero and it will hang up */
760         return -1;
761 }
762
763 int pbx_builtin_wait(struct ast_channel *chan, void *data)
764 {
765         /* Wait for "n" seconds */
766         if (data && atoi((char *)data))
767                 sleep(atoi((char *)data));
768         return 0;
769 }
770
771 int pbx_builtin_background(struct ast_channel *chan, void *data)
772 {
773         int res;
774         /* Stop anything playing */
775         ast_stopstream(chan);
776         /* Stream a file */
777         res = ast_streamfile(chan, (char *)data);
778         return res;
779 }
780
781 int pbx_builtin_rtimeout(struct ast_channel *chan, void *data)
782 {
783         /* Set the timeout for how long to wait between digits */
784         chan->pbx->rtimeout = atoi((char *)data);
785         if (option_verbose > 2)
786                 ast_verbose( VERBOSE_PREFIX_3 "Set Response Timeout to %d\n", chan->pbx->rtimeout);
787         return 0;
788 }
789
790 int pbx_builtin_dtimeout(struct ast_channel *chan, void *data)
791 {
792         /* Set the timeout for how long to wait between digits */
793         chan->pbx->dtimeout = atoi((char *)data);
794         if (option_verbose > 2)
795                 ast_verbose( VERBOSE_PREFIX_3 "Set Digit Timeout to %d\n", chan->pbx->dtimeout);
796         return 0;
797 }
798
799 int pbx_builtin_goto(struct ast_channel *chan, void *data)
800 {
801         char *s;
802         char *exten, *pri, *context;
803         if (!data) {
804                 ast_log(LOG_WARNING, "Goto requires an argument (optional context|optional extension|priority)\n");
805                 return -1;
806         }
807         s = strdup((void *) data);
808         context = strtok(s, "|");
809         exten = strtok(NULL, "|");
810         if (!exten) {
811                 /* Only a priority in this one */
812                 pri = context;
813                 exten = NULL;
814                 context = NULL;
815         } else {
816                 pri = strtok(NULL, "|");
817                 if (!pri) {
818                         /* Only an extension and priority in this one */
819                         pri = exten;
820                         exten = context;
821                         context = NULL;
822                 }
823         }
824         if (atoi(pri) < 0) {
825                 ast_log(LOG_WARNING, "Priority '%s' must be a number > 0\n", pri);
826                 free(s);
827                 return -1;
828         }
829         /* At this point we have a priority and maybe an extension and a context */
830         chan->priority = atoi(pri) - 1;
831         if (exten)
832                 strncpy(chan->exten, exten, sizeof(chan->exten));
833         if (context)
834                 strncpy(chan->context, context, sizeof(chan->context));
835         if (option_verbose > 2)
836                 ast_verbose( VERBOSE_PREFIX_3 "Goto (%s,%s,%d)\n", chan->context,chan->exten, chan->priority+1);
837         return 0;
838 }
839
840 int load_pbx(void)
841 {
842         int x;
843         /* Initialize the PBX */
844         if (option_verbose) {
845                 ast_verbose( "Asterisk PBX Core Initializing\n");
846                 ast_verbose( "Registering builtin applications:\n");
847         }
848         for (x=0;x<sizeof(builtins) / sizeof(struct pbx_builtin); x++) {
849                 if (option_verbose)
850                         ast_verbose( VERBOSE_PREFIX_1 "[%s]\n", builtins[x].name);
851                 if (ast_register_application(builtins[x].name, builtins[x].execute)) {
852                         ast_log(LOG_ERROR, "Unable to register builtin application '%s'\n", builtins[x].name);
853                         return -1;
854                 }
855         }
856         return 0;
857 }
858