Bug 6304 - Add Park command to the manager interface
[asterisk/asterisk.git] / res / res_features.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 Routines implementing call features as call pickup, parking and transfer
22  *
23  * \author Mark Spencer <markster@digium.com> 
24  */
25
26 #include <pthread.h>
27 #include <stdlib.h>
28 #include <errno.h>
29 #include <unistd.h>
30 #include <string.h>
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <sys/time.h>
34 #include <sys/signal.h>
35 #include <netinet/in.h>
36
37 #include "asterisk.h"
38
39 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
40
41 #include "asterisk/lock.h"
42 #include "asterisk/file.h"
43 #include "asterisk/logger.h"
44 #include "asterisk/channel.h"
45 #include "asterisk/pbx.h"
46 #include "asterisk/options.h"
47 #include "asterisk/causes.h"
48 #include "asterisk/module.h"
49 #include "asterisk/translate.h"
50 #include "asterisk/app.h"
51 #include "asterisk/say.h"
52 #include "asterisk/features.h"
53 #include "asterisk/musiconhold.h"
54 #include "asterisk/config.h"
55 #include "asterisk/cli.h"
56 #include "asterisk/manager.h"
57 #include "asterisk/utils.h"
58 #include "asterisk/adsi.h"
59 #include "asterisk/monitor.h"
60
61 #ifdef __AST_DEBUG_MALLOC
62 static void FREE(void *ptr)
63 {
64         free(ptr);
65 }
66 #else
67 #define FREE free
68 #endif
69
70 #define DEFAULT_PARK_TIME 45000
71 #define DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000
72 #define DEFAULT_FEATURE_DIGIT_TIMEOUT 500
73
74 #define AST_MAX_WATCHERS 256
75
76 static char *parkedcall = "ParkedCall";
77
78 static int parkingtime = DEFAULT_PARK_TIME;             /*!< No more than 45 seconds parked before you do something with them */
79 static char parking_con[AST_MAX_EXTENSION];             /*!< Context for which parking is made accessible */
80 static char parking_con_dial[AST_MAX_EXTENSION];        /*!< Context for dialback for parking (KLUDGE) */
81 static char parking_ext[AST_MAX_EXTENSION];             /*!< Extension you type to park the call */
82 static char pickup_ext[AST_MAX_EXTENSION];              /*!< Call pickup extension */
83 static int parking_start;                               /*!< First available extension for parking */
84 static int parking_stop;                                /*!< Last available extension for parking */
85
86 static char courtesytone[256];                          /*!< Courtesy tone */
87 static int parkedplay = 0;                              /*!< Who to play the courtesy tone to */
88 static char xfersound[256];                             /*!< Call transfer sound */
89 static char xferfailsound[256];                         /*!< Call transfer failure sound */
90
91 static int parking_offset;
92 static int parkfindnext;
93
94 static int adsipark;
95
96 static int transferdigittimeout;
97 static int featuredigittimeout;
98
99 static char *registrar = "res_features";                /*!< Registrar for operations */
100
101 /* module and CLI command definitions */
102 static char *synopsis = "Answer a parked call";
103
104 static char *descrip = "ParkedCall(exten):"
105 "Used to connect to a parked call.  This application is always\n"
106 "registered internally and does not need to be explicitly added\n"
107 "into the dialplan, although you should include the 'parkedcalls'\n"
108 "context.\n";
109
110 static char *parkcall = "Park";
111
112 static char *synopsis2 = "Park yourself";
113
114 static char *descrip2 = "Park(exten):"
115 "Used to park yourself (typically in combination with a supervised\n"
116 "transfer to know the parking space). This application is always\n"
117 "registered internally and does not need to be explicitly added\n"
118 "into the dialplan, although you should include the 'parkedcalls'\n"
119 "context.\n";
120
121 static struct ast_app *monitor_app = NULL;
122 static int monitor_ok = 1;
123
124 struct parkeduser {
125         struct ast_channel *chan;
126         struct timeval start;
127         int parkingnum;
128         /* Where to go if our parking time expires */
129         char context[AST_MAX_CONTEXT];
130         char exten[AST_MAX_EXTENSION];
131         int priority;
132         int parkingtime;
133         int notquiteyet;
134         char peername[1024];
135         unsigned char moh_trys;
136         struct parkeduser *next;
137 };
138
139 static struct parkeduser *parkinglot;
140
141 AST_MUTEX_DEFINE_STATIC(parking_lock);
142
143 static pthread_t parking_thread;
144
145 LOCAL_USER_DECL;
146
147 char *ast_parking_ext(void)
148 {
149         return parking_ext;
150 }
151
152 char *ast_pickup_ext(void)
153 {
154         return pickup_ext;
155 }
156
157 struct ast_bridge_thread_obj 
158 {
159         struct ast_bridge_config bconfig;
160         struct ast_channel *chan;
161         struct ast_channel *peer;
162 };
163
164 static void check_goto_on_transfer(struct ast_channel *chan) 
165 {
166         struct ast_channel *xferchan;
167         const char *val = pbx_builtin_getvar_helper(chan, "GOTO_ON_BLINDXFR");
168         char *x, *goto_on_transfer;
169         struct ast_frame *f;
170
171         if (!ast_strlen_zero(val) && (goto_on_transfer = ast_strdupa(val)) && (xferchan = ast_channel_alloc(0))) {
172                 for (x = goto_on_transfer; x && *x; x++)
173                         if (*x == '^')
174                                 *x = '|';
175                 ast_string_field_set(xferchan, name, chan->name);
176                 /* Make formats okay */
177                 xferchan->readformat = chan->readformat;
178                 xferchan->writeformat = chan->writeformat;
179                 ast_channel_masquerade(xferchan, chan);
180                 ast_parseable_goto(xferchan, goto_on_transfer);
181                 xferchan->_state = AST_STATE_UP;
182                 ast_clear_flag(xferchan, AST_FLAGS_ALL);        
183                 xferchan->_softhangup = 0;
184                 if ((f = ast_read(xferchan))) {
185                         ast_frfree(f);
186                         f = NULL;
187                         ast_pbx_start(xferchan);
188                 } else {
189                         ast_hangup(xferchan);
190                 }
191         }
192 }
193
194 static struct ast_channel *ast_feature_request_and_dial(struct ast_channel *caller, const char *type, int format, void *data, int timeout, int *outstate, const char *cid_num, const char *cid_name);
195
196
197 static void *ast_bridge_call_thread(void *data) 
198 {
199         struct ast_bridge_thread_obj *tobj = data;
200
201         tobj->chan->appl = "Transferred Call";
202         tobj->chan->data = (char *) tobj->peer->name;
203         tobj->peer->appl = "Transferred Call";
204         tobj->peer->data = (char *) tobj->chan->name;
205         if (tobj->chan->cdr) {
206                 ast_cdr_reset(tobj->chan->cdr, NULL);
207                 ast_cdr_setdestchan(tobj->chan->cdr, tobj->peer->name);
208         }
209         if (tobj->peer->cdr) {
210                 ast_cdr_reset(tobj->peer->cdr, NULL);
211                 ast_cdr_setdestchan(tobj->peer->cdr, tobj->chan->name);
212         }
213
214         ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig);
215         ast_hangup(tobj->chan);
216         ast_hangup(tobj->peer);
217         tobj->chan = tobj->peer = NULL;
218         free(tobj);
219         tobj=NULL;
220         return NULL;
221 }
222
223 static void ast_bridge_call_thread_launch(void *data) 
224 {
225         pthread_t thread;
226         pthread_attr_t attr;
227         struct sched_param sched;
228
229         pthread_attr_init(&attr);
230         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
231         ast_pthread_create(&thread, &attr,ast_bridge_call_thread, data);
232         pthread_attr_destroy(&attr);
233         memset(&sched, 0, sizeof(sched));
234         pthread_setschedparam(thread, SCHED_RR, &sched);
235 }
236
237
238
239 static int adsi_announce_park(struct ast_channel *chan, int parkingnum)
240 {
241         int res;
242         int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT};
243         char tmp[256];
244         char *message[5] = {NULL, NULL, NULL, NULL, NULL};
245
246         snprintf(tmp, sizeof(tmp), "Parked on %d", parkingnum);
247         message[0] = tmp;
248         res = adsi_load_session(chan, NULL, 0, 1);
249         if (res == -1) {
250                 return res;
251         }
252         return adsi_print(chan, message, justify, 1);
253 }
254
255 /*! \brief Park a call 
256         We put the user in the parking list, then wake up the parking thread to be sure it looks
257         after these channels too */
258 int ast_park_call(struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout)
259 {
260         struct parkeduser *pu, *cur;
261         int i,x,parking_range;
262         char exten[AST_MAX_EXTENSION];
263         struct ast_context *con;
264         
265         if (!(pu = ast_calloc(1, sizeof(*pu)))) {
266                 return -1;
267         }
268         ast_mutex_lock(&parking_lock);
269         parking_range = parking_stop - parking_start+1;
270         for (i = 0; i < parking_range; i++) {
271                 x = (i + parking_offset) % parking_range + parking_start;
272                 cur = parkinglot;
273                 while(cur) {
274                         if (cur->parkingnum == x) 
275                                 break;
276                         cur = cur->next;
277                 }
278                 if (!cur)
279                         break;
280         }
281
282         if (!(i < parking_range)) {
283                 ast_log(LOG_WARNING, "No more parking spaces\n");
284                 free(pu);
285                 ast_mutex_unlock(&parking_lock);
286                 return -1;
287         }
288         if (parkfindnext) 
289                 parking_offset = x - parking_start + 1;
290         chan->appl = "Parked Call";
291         chan->data = NULL; 
292
293         pu->chan = chan;
294         /* Start music on hold */
295         if (chan != peer) {
296                 ast_indicate(pu->chan, AST_CONTROL_HOLD);
297                 ast_moh_start(pu->chan, NULL);
298         }
299         pu->start = ast_tvnow();
300         pu->parkingnum = x;
301         if (timeout > 0)
302                 pu->parkingtime = timeout;
303         else
304                 pu->parkingtime = parkingtime;
305         if (extout)
306                 *extout = x;
307         if (peer) 
308                 ast_copy_string(pu->peername, peer->name, sizeof(pu->peername));
309
310         /* Remember what had been dialed, so that if the parking
311            expires, we try to come back to the same place */
312         if (!ast_strlen_zero(chan->macrocontext))
313                 ast_copy_string(pu->context, chan->macrocontext, sizeof(pu->context));
314         else
315                 ast_copy_string(pu->context, chan->context, sizeof(pu->context));
316         if (!ast_strlen_zero(chan->macroexten))
317                 ast_copy_string(pu->exten, chan->macroexten, sizeof(pu->exten));
318         else
319                 ast_copy_string(pu->exten, chan->exten, sizeof(pu->exten));
320         if (chan->macropriority)
321                 pu->priority = chan->macropriority;
322         else
323                 pu->priority = chan->priority;
324         pu->next = parkinglot;
325         parkinglot = pu;
326         /* If parking a channel directly, don't quiet yet get parking running on it */
327         if (peer == chan) 
328                 pu->notquiteyet = 1;
329         ast_mutex_unlock(&parking_lock);
330         /* Wake up the (presumably select()ing) thread */
331         pthread_kill(parking_thread, SIGURG);
332         if (option_verbose > 1) 
333                 ast_verbose(VERBOSE_PREFIX_2 "Parked %s on %d. Will timeout back to extension [%s] %s, %d in %d seconds\n", pu->chan->name, pu->parkingnum, pu->context, pu->exten, pu->priority, (pu->parkingtime/1000));
334
335         manager_event(EVENT_FLAG_CALL, "ParkedCall",
336                 "Exten: %d\r\n"
337                 "Channel: %s\r\n"
338                 "From: %s\r\n"
339                 "Timeout: %ld\r\n"
340                 "CallerID: %s\r\n"
341                 "CallerIDName: %s\r\n"
342                 ,pu->parkingnum, pu->chan->name, peer->name
343                 ,(long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL)
344                 ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
345                 ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
346                 );
347
348         if (peer) {
349                 if (adsipark && adsi_available(peer)) {
350                         adsi_announce_park(peer, pu->parkingnum);
351                 }
352                 if (adsipark && adsi_available(peer)) {
353                         adsi_unload_session(peer);
354                 }
355         }
356         con = ast_context_find(parking_con);
357         if (!con) {
358                 con = ast_context_create(NULL, parking_con, registrar);
359                 if (!con) {
360                         ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
361                 }
362         }
363         if (con) {
364                 snprintf(exten, sizeof(exten), "%d", x);
365                 ast_add_extension2(con, 1, exten, 1, NULL, NULL, parkedcall, strdup(exten), FREE, registrar);
366         }
367         if (peer) 
368                 ast_say_digits(peer, pu->parkingnum, "", peer->language);
369         if (pu->notquiteyet) {
370                 /* Wake up parking thread if we're really done */
371                 ast_moh_start(pu->chan, NULL);
372                 pu->notquiteyet = 0;
373                 pthread_kill(parking_thread, SIGURG);
374         }
375         return 0;
376 }
377
378 int ast_masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout)
379 {
380         struct ast_channel *chan;
381         struct ast_frame *f;
382
383         /* Make a new, fake channel that we'll use to masquerade in the real one */
384         if ((chan = ast_channel_alloc(0))) {
385                 /* Let us keep track of the channel name */
386                 ast_string_field_build(chan, name, "Parked/%s",rchan->name);
387
388                 /* Make formats okay */
389                 chan->readformat = rchan->readformat;
390                 chan->writeformat = rchan->writeformat;
391                 ast_channel_masquerade(chan, rchan);
392
393                 /* Setup the extensions and such */
394                 ast_copy_string(chan->context, rchan->context, sizeof(chan->context));
395                 ast_copy_string(chan->exten, rchan->exten, sizeof(chan->exten));
396                 chan->priority = rchan->priority;
397
398                 /* Make the masq execute */
399                 f = ast_read(chan);
400                 if (f)
401                         ast_frfree(f);
402                 ast_park_call(chan, peer, timeout, extout);
403         } else {
404                 ast_log(LOG_WARNING, "Unable to create parked channel\n");
405                 return -1;
406         }
407         return 0;
408 }
409
410
411 #define FEATURE_RETURN_HANGUP           -1
412 #define FEATURE_RETURN_SUCCESSBREAK      0
413 #define FEATURE_RETURN_PBX_KEEPALIVE    AST_PBX_KEEPALIVE
414 #define FEATURE_RETURN_NO_HANGUP_PEER   AST_PBX_NO_HANGUP_PEER
415 #define FEATURE_RETURN_PASSDIGITS        21
416 #define FEATURE_RETURN_STOREDIGITS       22
417 #define FEATURE_RETURN_SUCCESS           23
418
419 #define FEATURE_SENSE_CHAN      (1 << 0)
420 #define FEATURE_SENSE_PEER      (1 << 1)
421
422
423 static int builtin_automonitor(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
424 {
425         char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL;
426         int x = 0;
427         size_t len;
428         struct ast_channel *caller_chan = NULL, *callee_chan = NULL;
429
430
431         if(sense == 2) {
432                 caller_chan = peer;
433                 callee_chan = chan;
434         } else {
435                 callee_chan = peer;
436                 caller_chan = chan;
437         }
438         
439         if (!monitor_ok) {
440                 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
441                 return -1;
442         }
443
444         if (!monitor_app) { 
445                 if (!(monitor_app = pbx_findapp("Monitor"))) {
446                         monitor_ok=0;
447                         ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
448                         return -1;
449                 }
450         }
451         if (!ast_strlen_zero(courtesytone)) {
452                 if (ast_autoservice_start(callee_chan))
453                         return -1;
454                 if (!ast_streamfile(caller_chan, courtesytone, caller_chan->language)) {
455                         if (ast_waitstream(caller_chan, "") < 0) {
456                                 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
457                                 ast_autoservice_stop(callee_chan);
458                                 return -1;
459                         }
460                 }
461                 if (ast_autoservice_stop(callee_chan))
462                         return -1;
463         }
464         
465         if (callee_chan->monitor) {
466                 if (option_verbose > 3)
467                         ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to stop recording call.\n", code);
468                 ast_monitor_stop(callee_chan, 1);
469                 return FEATURE_RETURN_SUCCESS;
470         }
471
472         if (caller_chan && callee_chan) {
473                 const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT");
474                 const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR");
475
476                 if (!touch_format)
477                         touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT");
478
479                 if (!touch_monitor)
480                         touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR");
481         
482                 if (touch_monitor) {
483                         len = strlen(touch_monitor) + 50;
484                         args = alloca(len);
485                         touch_filename = alloca(len);
486                         snprintf(touch_filename, len, "auto-%ld-%s", (long)time(NULL), touch_monitor);
487                         snprintf(args, len, "%s|%s|m", (touch_format) ? touch_format : "wav", touch_filename);
488                 } else {
489                         caller_chan_id = ast_strdupa(caller_chan->cid.cid_num ? caller_chan->cid.cid_num : caller_chan->name);
490                         callee_chan_id = ast_strdupa(callee_chan->cid.cid_num ? callee_chan->cid.cid_num : callee_chan->name);
491                         len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50;
492                         args = alloca(len);
493                         touch_filename = alloca(len);
494                         snprintf(touch_filename, len, "auto-%ld-%s-%s", (long)time(NULL), caller_chan_id, callee_chan_id);
495                         snprintf(args, len, "%s|%s|m", (touch_format) ? touch_format : "wav", touch_filename);
496                 }
497
498                 for( x = 0; x < strlen(args); x++)
499                         if (args[x] == '/')
500                                 args[x] = '-';
501                 
502                 if (option_verbose > 3)
503                         ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to record call. filename: %s\n", code, args);
504
505                 pbx_exec(callee_chan, monitor_app, args, 1);
506                 pbx_builtin_setvar_helper(callee_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
507                 pbx_builtin_setvar_helper(caller_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
508         
509                 return FEATURE_RETURN_SUCCESS;
510         }
511         
512         ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n");   
513         return -1;
514 }
515
516 static int builtin_disconnect(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
517 {
518         if (option_verbose > 3)
519                 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to disconnect call.\n", code);
520         return FEATURE_RETURN_HANGUP;
521 }
522
523 static int builtin_blindtransfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
524 {
525         struct ast_channel *transferer;
526         struct ast_channel *transferee;
527         const char *transferer_real_context;
528         char newext[256];
529         int res;
530
531         if (sense == FEATURE_SENSE_PEER) {
532                 transferer = peer;
533                 transferee = chan;
534         } else {
535                 transferer = chan;
536                 transferee = peer;
537         }
538         if (!(transferer_real_context = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT")) &&
539            !(transferer_real_context = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT"))) {
540                 /* Use the non-macro context to transfer the call */
541                 if (!ast_strlen_zero(transferer->macrocontext))
542                         transferer_real_context = transferer->macrocontext;
543                 else
544                         transferer_real_context = transferer->context;
545         }
546         /* Start autoservice on chan while we talk
547            to the originator */
548         ast_indicate(transferee, AST_CONTROL_HOLD);
549         ast_autoservice_start(transferee);
550         ast_moh_start(transferee, NULL);
551
552         memset(newext, 0, sizeof(newext));
553         
554         /* Transfer */
555         if ((res=ast_streamfile(transferer, "pbx-transfer", transferer->language))) {
556                 ast_moh_stop(transferee);
557                 ast_autoservice_stop(transferee);
558                 ast_indicate(transferee, AST_CONTROL_UNHOLD);
559                 return res;
560         }
561         if ((res=ast_waitstream(transferer, AST_DIGIT_ANY)) < 0) {
562                 ast_moh_stop(transferee);
563                 ast_autoservice_stop(transferee);
564                 ast_indicate(transferee, AST_CONTROL_UNHOLD);
565                 return res;
566         } else if (res > 0) {
567                 /* If they've typed a digit already, handle it */
568                 newext[0] = (char) res;
569         }
570
571         ast_stopstream(transferer);
572         res = ast_app_dtget(transferer, transferer_real_context, newext, sizeof(newext), 100, transferdigittimeout);
573         if (res < 0) {
574                 ast_moh_stop(transferee);
575                 ast_autoservice_stop(transferee);
576                 ast_indicate(transferee, AST_CONTROL_UNHOLD);
577                 return res;
578         }
579         if (!strcmp(newext, ast_parking_ext())) {
580                 ast_moh_stop(transferee);
581
582                 res = ast_autoservice_stop(transferee);
583                 ast_indicate(transferee, AST_CONTROL_UNHOLD);
584                 if (res)
585                         res = -1;
586                 else if (!ast_park_call(transferee, transferer, 0, NULL)) {
587                         /* We return non-zero, but tell the PBX not to hang the channel when
588                            the thread dies -- We have to be careful now though.  We are responsible for 
589                            hanging up the channel, else it will never be hung up! */
590
591                         if (transferer == peer)
592                                 res = AST_PBX_KEEPALIVE;
593                         else
594                                 res = AST_PBX_NO_HANGUP_PEER;
595                         return res;
596                 } else {
597                         ast_log(LOG_WARNING, "Unable to park call %s\n", transferee->name);
598                 }
599                 /* XXX Maybe we should have another message here instead of invalid extension XXX */
600         } else if (ast_exists_extension(transferee, transferer_real_context, newext, 1, transferer->cid.cid_num)) {
601                 pbx_builtin_setvar_helper(peer, "BLINDTRANSFER", chan->name);
602                 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", peer->name);
603                 ast_moh_stop(transferee);
604                 res=ast_autoservice_stop(transferee);
605                 ast_indicate(transferee, AST_CONTROL_UNHOLD);
606                 if (!transferee->pbx) {
607                         /* Doh!  Use our handy async_goto functions */
608                         if (option_verbose > 2) 
609                                 ast_verbose(VERBOSE_PREFIX_3 "Transferring %s to '%s' (context %s) priority 1\n"
610                                                                 ,transferee->name, newext, transferer_real_context);
611                         if (ast_async_goto(transferee, transferer_real_context, newext, 1))
612                                 ast_log(LOG_WARNING, "Async goto failed :-(\n");
613                         res = -1;
614                 } else {
615                         /* Set the channel's new extension, since it exists, using transferer context */
616                         ast_copy_string(transferee->exten, newext, sizeof(transferee->exten));
617                         ast_copy_string(transferee->context, transferer_real_context, sizeof(transferee->context));
618                         transferee->priority = 0;
619                 }
620                 check_goto_on_transfer(transferer);
621                 return res;
622         } else {
623                 if (option_verbose > 2) 
624                         ast_verbose(VERBOSE_PREFIX_3 "Unable to find extension '%s' in context '%s'\n", newext, transferer_real_context);
625         }
626         if (!ast_strlen_zero(xferfailsound))
627                 res = ast_streamfile(transferer, xferfailsound, transferee->language);
628         else
629                 res = 0;
630         if (res) {
631                 ast_moh_stop(transferee);
632                 ast_autoservice_stop(transferee);
633                 ast_indicate(transferee, AST_CONTROL_UNHOLD);
634                 return res;
635         }
636         res = ast_waitstream(transferer, AST_DIGIT_ANY);
637         ast_stopstream(transferer);
638         ast_moh_stop(transferee);
639         res = ast_autoservice_stop(transferee);
640         ast_indicate(transferee, AST_CONTROL_UNHOLD);
641         if (res) {
642                 if (option_verbose > 1)
643                         ast_verbose(VERBOSE_PREFIX_2 "Hungup during autoservice stop on '%s'\n", transferee->name);
644                 return res;
645         }
646         return FEATURE_RETURN_SUCCESS;
647 }
648
649 static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
650 {
651         struct ast_channel *transferer;
652         struct ast_channel *transferee;
653         struct ast_channel *newchan, *xferchan=NULL;
654         int outstate=0;
655         struct ast_bridge_config bconfig;
656         const char *transferer_real_context;
657         char xferto[256],dialstr[265];
658         char *cid_num;
659         char *cid_name;
660         int res;
661         struct ast_frame *f = NULL;
662         struct ast_bridge_thread_obj *tobj;
663
664         ast_log(LOG_DEBUG, "Executing Attended Transfer %s, %s (sense=%d) XXX\n", chan->name, peer->name, sense);
665         if (sense == FEATURE_SENSE_PEER) {
666                 transferer = peer;
667                 transferee = chan;
668         } else {
669                 transferer = chan;
670                 transferee = peer;
671         }
672         if (!(transferer_real_context=pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT")) &&
673            !(transferer_real_context=pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT"))) {
674                 /* Use the non-macro context to transfer the call */
675                 if (!ast_strlen_zero(transferer->macrocontext))
676                         transferer_real_context = transferer->macrocontext;
677                 else
678                         transferer_real_context = transferer->context;
679         }
680         /* Start autoservice on chan while we talk
681            to the originator */
682         ast_indicate(transferee, AST_CONTROL_HOLD);
683         ast_autoservice_start(transferee);
684         ast_moh_start(transferee, NULL);
685         memset(xferto, 0, sizeof(xferto));
686         /* Transfer */
687         if ((res = ast_streamfile(transferer, "pbx-transfer", transferer->language))) {
688                 ast_moh_stop(transferee);
689                 ast_autoservice_stop(transferee);
690                 ast_indicate(transferee, AST_CONTROL_UNHOLD);
691                 return res;
692         }
693         if ((res=ast_waitstream(transferer, AST_DIGIT_ANY)) < 0) {
694                 ast_moh_stop(transferee);
695                 ast_autoservice_stop(transferee);
696                 ast_indicate(transferee, AST_CONTROL_UNHOLD);
697                 return res;
698         } else if(res > 0) {
699                 /* If they've typed a digit already, handle it */
700                 xferto[0] = (char) res;
701         }
702         if ((ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout))) {
703                 cid_num = transferer->cid.cid_num;
704                 cid_name = transferer->cid.cid_name;
705                 if (ast_exists_extension(transferer, transferer_real_context,xferto, 1, cid_num)) {
706                         snprintf(dialstr, sizeof(dialstr), "%s@%s/n", xferto, transferer_real_context);
707                         newchan = ast_feature_request_and_dial(transferer, "Local", ast_best_codec(transferer->nativeformats), dialstr, 15000, &outstate, cid_num, cid_name);
708                         ast_indicate(transferer, -1);
709                         if (newchan) {
710                                 res = ast_channel_make_compatible(transferer, newchan);
711                                 if (res < 0) {
712                                         ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", transferer->name, newchan->name);
713                                         ast_hangup(newchan);
714                                         return -1;
715                                 }
716                                 memset(&bconfig,0,sizeof(struct ast_bridge_config));
717                                 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
718                                 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
719                                 res = ast_bridge_call(transferer,newchan,&bconfig);
720                                 if (newchan->_softhangup || newchan->_state != AST_STATE_UP || !transferer->_softhangup) {
721                                         ast_hangup(newchan);
722                                         if (f) {
723                                                 ast_frfree(f);
724                                                 f = NULL;
725                                         }
726                                         if (!ast_strlen_zero(xfersound) && !ast_streamfile(transferer, xfersound, transferer->language)) {
727                                                 if (ast_waitstream(transferer, "") < 0) {
728                                                         ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
729                                                 }
730                                         }
731                                         ast_moh_stop(transferee);
732                                         ast_autoservice_stop(transferee);
733                                         ast_indicate(transferee, AST_CONTROL_UNHOLD);
734                                         transferer->_softhangup = 0;
735                                         return FEATURE_RETURN_SUCCESS;
736                                 }
737                                 
738                                 res = ast_channel_make_compatible(transferee, newchan);
739                                 if (res < 0) {
740                                         ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", transferee->name, newchan->name);
741                                         ast_hangup(newchan);
742                                         return -1;
743                                 }
744                                 
745                                 
746                                 ast_moh_stop(transferee);
747                                 
748                                 if ((ast_autoservice_stop(transferee) < 0)
749                                    || (ast_waitfordigit(transferee, 100) < 0)
750                                    || (ast_waitfordigit(newchan, 100) < 0) 
751                                    || ast_check_hangup(transferee) 
752                                    || ast_check_hangup(newchan)) {
753                                         ast_hangup(newchan);
754                                         res = -1;
755                                         return -1;
756                                 }
757
758                                 if ((xferchan = ast_channel_alloc(0))) {
759                                         ast_string_field_build(xferchan, name, "Transfered/%s", transferee->name);
760                                         /* Make formats okay */
761                                         xferchan->readformat = transferee->readformat;
762                                         xferchan->writeformat = transferee->writeformat;
763                                         ast_channel_masquerade(xferchan, transferee);
764                                         ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority);
765                                         xferchan->_state = AST_STATE_UP;
766                                         ast_clear_flag(xferchan, AST_FLAGS_ALL);        
767                                         xferchan->_softhangup = 0;
768
769                                         if ((f = ast_read(xferchan))) {
770                                                 ast_frfree(f);
771                                                 f = NULL;
772                                         }
773                                         
774                                 } else {
775                                         ast_hangup(newchan);
776                                         return -1;
777                                 }
778
779                                 newchan->_state = AST_STATE_UP;
780                                 ast_clear_flag(newchan, AST_FLAGS_ALL); 
781                                 newchan->_softhangup = 0;
782                                 
783                                 if ((tobj = ast_calloc(1, sizeof(*tobj)))) {
784                                         tobj->chan = xferchan;
785                                         tobj->peer = newchan;
786                                         tobj->bconfig = *config;
787         
788                                         if (!ast_strlen_zero(xfersound) && !ast_streamfile(newchan, xfersound, newchan->language)) {
789                                                 if (ast_waitstream(newchan, "") < 0) {
790                                                         ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
791                                                 }
792                                         }
793                                         ast_bridge_call_thread_launch(tobj);
794                                 } else {
795                                         ast_hangup(xferchan);
796                                         ast_hangup(newchan);
797                                 }
798                                 return -1;
799                                 
800                         } else {
801                                 ast_moh_stop(transferee);
802                                 ast_autoservice_stop(transferee);
803                                 ast_indicate(transferee, AST_CONTROL_UNHOLD);
804                                 /* any reason besides user requested cancel and busy triggers the failed sound */
805                                 if (outstate != AST_CONTROL_UNHOLD && outstate != AST_CONTROL_BUSY && !ast_strlen_zero(xferfailsound)) {
806                                         res = ast_streamfile(transferer, xferfailsound, transferer->language);
807                                         if (!res && (ast_waitstream(transferer, "") < 0)) {
808                                                 return -1;
809                                         }
810                                 }
811                                 return FEATURE_RETURN_SUCCESS;
812                         }
813                 } else {
814                         ast_log(LOG_WARNING, "Extension %s does not exist in context %s\n",xferto,transferer_real_context);
815                         ast_moh_stop(transferee);
816                         ast_autoservice_stop(transferee);
817                         ast_indicate(transferee, AST_CONTROL_UNHOLD);
818                         res = ast_streamfile(transferer, "beeperr", transferer->language);
819                         if (!res && (ast_waitstream(transferer, "") < 0)) {
820                                 return -1;
821                         }
822                 }
823         }  else {
824                 ast_log(LOG_WARNING, "Did not read data.\n");
825                 res = ast_streamfile(transferer, "beeperr", transferer->language);
826                 if (ast_waitstream(transferer, "") < 0) {
827                         return -1;
828                 }
829         }
830         ast_moh_stop(transferee);
831         ast_autoservice_stop(transferee);
832         ast_indicate(transferee, AST_CONTROL_UNHOLD);
833
834         return FEATURE_RETURN_SUCCESS;
835 }
836
837
838 /* add atxfer and automon as undefined so you can only use em if you configure them */
839 #define FEATURES_COUNT (sizeof(builtin_features) / sizeof(builtin_features[0]))
840
841 struct ast_call_feature builtin_features[] = 
842  {
843         { AST_FEATURE_REDIRECT, "Blind Transfer", "blindxfer", "#", "#", builtin_blindtransfer, AST_FEATURE_FLAG_NEEDSDTMF },
844         { AST_FEATURE_REDIRECT, "Attended Transfer", "atxfer", "", "", builtin_atxfer, AST_FEATURE_FLAG_NEEDSDTMF },
845         { AST_FEATURE_AUTOMON, "One Touch Monitor", "automon", "", "", builtin_automonitor, AST_FEATURE_FLAG_NEEDSDTMF },
846         { AST_FEATURE_DISCONNECT, "Disconnect Call", "disconnect", "*", "*", builtin_disconnect, AST_FEATURE_FLAG_NEEDSDTMF },
847 };
848
849
850 static AST_LIST_HEAD(feature_list,ast_call_feature) feature_list;
851
852 /*! \brief register new feature into feature_list*/
853 void ast_register_feature(struct ast_call_feature *feature)
854 {
855         if (!feature) {
856                 ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
857                 return;
858         }
859   
860         AST_LIST_LOCK(&feature_list);
861         AST_LIST_INSERT_HEAD(&feature_list,feature,feature_entry);
862         AST_LIST_UNLOCK(&feature_list);
863
864         if (option_verbose >= 2) 
865                 ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname);
866 }
867
868 /*! \brief unregister feature from feature_list */
869 void ast_unregister_feature(struct ast_call_feature *feature)
870 {
871         if (!feature) return;
872
873         AST_LIST_LOCK(&feature_list);
874         AST_LIST_REMOVE(&feature_list,feature,feature_entry);
875         AST_LIST_UNLOCK(&feature_list);
876         free(feature);
877 }
878
879 static void ast_unregister_features(void)
880 {
881         struct ast_call_feature *feature;
882
883         AST_LIST_LOCK(&feature_list);
884         while ((feature = AST_LIST_REMOVE_HEAD(&feature_list,feature_entry)))
885                 free(feature);
886         AST_LIST_UNLOCK(&feature_list);
887 }
888
889 /*! \brief find a feature by name */
890 static struct ast_call_feature *find_feature(char *name)
891 {
892         struct ast_call_feature *tmp;
893
894         AST_LIST_LOCK(&feature_list);
895         AST_LIST_TRAVERSE(&feature_list, tmp, feature_entry) {
896                 if (!strcasecmp(tmp->sname, name))
897                         break;
898         }
899         AST_LIST_UNLOCK(&feature_list);
900
901         return tmp;
902 }
903
904 /*! \brief exec an app by feature */
905 static int feature_exec_app(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
906 {
907         struct ast_app *app;
908         struct ast_call_feature *feature;
909         int res;
910
911         AST_LIST_LOCK(&feature_list);
912         AST_LIST_TRAVERSE(&feature_list,feature,feature_entry) {
913                 if (!strcasecmp(feature->exten,code)) break;
914         }
915         AST_LIST_UNLOCK(&feature_list);
916
917         if (!feature) { /* shouldn't ever happen! */
918                 ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n");
919                 return -1; 
920         }
921         
922         app = pbx_findapp(feature->app);
923         if (app) {
924                 struct ast_channel *work = chan;
925                 if (ast_test_flag(feature, AST_FEATURE_FLAG_CALLEE))
926                         work = peer;
927                 res = pbx_exec(work, app, feature->app_args, 1);
928                 if (res < 0)
929                         return res; 
930         } else {
931                 ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app);
932                 return -2;
933         }
934         
935         return FEATURE_RETURN_SUCCESS;
936 }
937
938 static void unmap_features(void)
939 {
940         int x;
941         for (x = 0; x < FEATURES_COUNT; x++)
942                 strcpy(builtin_features[x].exten, builtin_features[x].default_exten);
943 }
944
945 static int remap_feature(const char *name, const char *value)
946 {
947         int x;
948         int res = -1;
949         for (x = 0; x < FEATURES_COUNT; x++) {
950                 if (!strcasecmp(name, builtin_features[x].sname)) {
951                         ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten));
952                         if (option_verbose > 1)
953                                 ast_verbose(VERBOSE_PREFIX_2 "Remapping feature %s (%s) to sequence '%s'\n", builtin_features[x].fname, builtin_features[x].sname, builtin_features[x].exten);
954                         res = 0;
955                 } else if (!strcmp(value, builtin_features[x].exten)) 
956                         ast_log(LOG_WARNING, "Sequence '%s' already mapped to function %s (%s) while assigning to %s\n", value, builtin_features[x].fname, builtin_features[x].sname, name);
957         }
958         return res;
959 }
960
961 static int ast_feature_interpret(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
962 {
963         int x;
964         struct ast_flags features;
965         int res = FEATURE_RETURN_PASSDIGITS;
966         struct ast_call_feature *feature;
967         const char *dynamic_features=pbx_builtin_getvar_helper(chan,"DYNAMIC_FEATURES");
968
969         if (sense == FEATURE_SENSE_CHAN)
970                 ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);   
971         else
972                 ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL);   
973         ast_log(LOG_DEBUG, "Feature interpret: chan=%s, peer=%s, sense=%d, features=%d\n", chan->name, peer->name, sense, features.flags);
974
975         for (x=0; x < FEATURES_COUNT; x++) {
976                 if ((ast_test_flag(&features, builtin_features[x].feature_mask)) &&
977                     !ast_strlen_zero(builtin_features[x].exten)) {
978                         /* Feature is up for consideration */
979                         if (!strcmp(builtin_features[x].exten, code)) {
980                                 res = builtin_features[x].operation(chan, peer, config, code, sense);
981                                 break;
982                         } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) {
983                                 if (res == FEATURE_RETURN_PASSDIGITS)
984                                         res = FEATURE_RETURN_STOREDIGITS;
985                         }
986                 }
987         }
988
989
990         if (!ast_strlen_zero(dynamic_features)) {
991                 char *tmp = ast_strdupa(dynamic_features);
992                 char *tok;
993
994                 if (!tmp)
995                         return res;
996                 
997                 while ((tok = strsep(&tmp, "#")) != NULL) {
998                         feature = find_feature(tok);
999                         
1000                         if (feature) {
1001                                 /* Feature is up for consideration */
1002                                 if (!strcmp(feature->exten, code)) {
1003                                         if (option_verbose > 2)
1004                                                 ast_verbose(VERBOSE_PREFIX_3 " Feature Found: %s exten: %s\n",feature->sname, tok);
1005                                         res = feature->operation(chan, peer, config, code, sense);
1006                                         break;
1007                                 } else if (!strncmp(feature->exten, code, strlen(code))) {
1008                                         res = FEATURE_RETURN_STOREDIGITS;
1009                                 }
1010                         }
1011                 }
1012         }
1013         
1014         return res;
1015 }
1016
1017 static void set_config_flags(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
1018 {
1019         int x;
1020         
1021         ast_clear_flag(config, AST_FLAGS_ALL);  
1022         for (x = 0; x < FEATURES_COUNT; x++) {
1023                 if (ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF)) {
1024                         if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask))
1025                                 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
1026
1027                         if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask))
1028                                 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
1029                 }
1030         }
1031         
1032         if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) {
1033                 const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
1034
1035                 if (dynamic_features) {
1036                         char *tmp = ast_strdupa(dynamic_features);
1037                         char *tok;
1038                         struct ast_call_feature *feature;
1039
1040                         if (!tmp) {
1041                                 return;
1042                         }
1043
1044                         /* while we have a feature */
1045                         while (NULL != (tok = strsep(&tmp, "#"))) {
1046                                 if ((feature = find_feature(tok))) {
1047                                         if (ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) {
1048                                                 if (ast_test_flag(feature, AST_FEATURE_FLAG_CALLER))
1049                                                         ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
1050                                                 if (ast_test_flag(feature, AST_FEATURE_FLAG_CALLEE))
1051                                                         ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
1052                                         }
1053                                 }
1054                         }
1055                 }
1056         }
1057 }
1058
1059
1060 static struct ast_channel *ast_feature_request_and_dial(struct ast_channel *caller, const char *type, int format, void *data, int timeout, int *outstate, const char *cid_num, const char *cid_name)
1061 {
1062         int state = 0;
1063         int cause = 0;
1064         int to;
1065         struct ast_channel *chan;
1066         struct ast_channel *monitor_chans[2];
1067         struct ast_channel *active_channel;
1068         struct ast_frame *f = NULL;
1069         int res = 0, ready = 0;
1070         
1071         if ((chan = ast_request(type, format, data, &cause))) {
1072                 ast_set_callerid(chan, cid_num, cid_name, cid_num);
1073                 ast_channel_inherit_variables(caller, chan);    
1074                 if (!ast_call(chan, data, timeout)) {
1075                         struct timeval started;
1076                         int x, len = 0;
1077                         char *disconnect_code = NULL, *dialed_code = NULL;
1078
1079                         ast_indicate(caller, AST_CONTROL_RINGING);
1080                         /* support dialing of the featuremap disconnect code while performing an attended tranfer */
1081                         for (x=0; x < FEATURES_COUNT; x++) {
1082                                 if (strcasecmp(builtin_features[x].sname, "disconnect"))
1083                                         continue;
1084
1085                                 disconnect_code = builtin_features[x].exten;
1086                                 len = strlen(disconnect_code) + 1;
1087                                 dialed_code = alloca(len);
1088                                 memset(dialed_code, 0, len);
1089                                 break;
1090                         }
1091                         x = 0;
1092                         started = ast_tvnow();
1093                         to = timeout;
1094                         while (!ast_check_hangup(caller) && timeout && (chan->_state != AST_STATE_UP)) {
1095                                 monitor_chans[0] = caller;
1096                                 monitor_chans[1] = chan;
1097                                 active_channel = ast_waitfor_n(monitor_chans, 2, &to);
1098
1099                                 /* see if the timeout has been violated */
1100                                 if(ast_tvdiff_ms(ast_tvnow(), started) > timeout) {
1101                                         state = AST_CONTROL_UNHOLD;
1102                                         ast_log(LOG_NOTICE, "We exceeded our AT-timeout\n");
1103                                         break; /*doh! timeout*/
1104                                 }
1105
1106                                 if (!active_channel) {
1107                                         continue;
1108                                 }
1109
1110                                 if (chan && (chan == active_channel)){
1111                                         f = ast_read(chan);
1112                                         if (f == NULL) { /*doh! where'd he go?*/
1113                                                 state = AST_CONTROL_HANGUP;
1114                                                 res = 0;
1115                                                 break;
1116                                         }
1117                                         
1118                                         if (f->frametype == AST_FRAME_CONTROL || f->frametype == AST_FRAME_DTMF || f->frametype == AST_FRAME_TEXT) {
1119                                                 if (f->subclass == AST_CONTROL_RINGING) {
1120                                                         state = f->subclass;
1121                                                         if (option_verbose > 2)
1122                                                                 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", chan->name);
1123                                                         ast_indicate(caller, AST_CONTROL_RINGING);
1124                                                 } else if ((f->subclass == AST_CONTROL_BUSY) || (f->subclass == AST_CONTROL_CONGESTION)) {
1125                                                         state = f->subclass;
1126                                                         ast_frfree(f);
1127                                                         f = NULL;
1128                                                         break;
1129                                                 } else if (f->subclass == AST_CONTROL_ANSWER) {
1130                                                         /* This is what we are hoping for */
1131                                                         state = f->subclass;
1132                                                         ast_frfree(f);
1133                                                         f = NULL;
1134                                                         ready=1;
1135                                                         break;
1136                                                 } else {
1137                                                         ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass);
1138                                                 }
1139                                                 /* else who cares */
1140                                         }
1141
1142                                 } else if (caller && (active_channel == caller)) {
1143                                         f = ast_read(caller);
1144                                         if (f == NULL) { /*doh! where'd he go?*/
1145                                                 if (caller->_softhangup && !chan->_softhangup) {
1146                                                         /* make this a blind transfer */
1147                                                         ready = 1;
1148                                                         break;
1149                                                 }
1150                                                 state = AST_CONTROL_HANGUP;
1151                                                 res = 0;
1152                                                 break;
1153                                         }
1154                                         
1155                                         if (f->frametype == AST_FRAME_DTMF) {
1156                                                 dialed_code[x++] = f->subclass;
1157                                                 dialed_code[x] = '\0';
1158                                                 if (strlen(dialed_code) == len) {
1159                                                         x = 0;
1160                                                 } else if (x && strncmp(dialed_code, disconnect_code, x)) {
1161                                                         x = 0;
1162                                                         dialed_code[x] = '\0';
1163                                                 }
1164                                                 if (*dialed_code && !strcmp(dialed_code, disconnect_code)) {
1165                                                         /* Caller Canceled the call */
1166                                                         state = AST_CONTROL_UNHOLD;
1167                                                         ast_frfree(f);
1168                                                         f = NULL;
1169                                                         break;
1170                                                 }
1171                                         }
1172                                 }
1173                                 if (f) {
1174                                         ast_frfree(f);
1175                                 }
1176                         }
1177                 } else
1178                         ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data);
1179         } else {
1180                 ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
1181                 switch(cause) {
1182                 case AST_CAUSE_BUSY:
1183                         state = AST_CONTROL_BUSY;
1184                         break;
1185                 case AST_CAUSE_CONGESTION:
1186                         state = AST_CONTROL_CONGESTION;
1187                         break;
1188                 }
1189         }
1190         
1191         ast_indicate(caller, -1);
1192         if (chan && ready) {
1193                 if (chan->_state == AST_STATE_UP) 
1194                         state = AST_CONTROL_ANSWER;
1195                 res = 0;
1196         } else if(chan) {
1197                 res = -1;
1198                 ast_hangup(chan);
1199                 chan = NULL;
1200         } else {
1201                 res = -1;
1202         }
1203         
1204         if (outstate)
1205                 *outstate = state;
1206
1207         if (chan && res <= 0) {
1208                 if (chan->cdr || (chan->cdr = ast_cdr_alloc())) {
1209                         char tmp[256];
1210                         ast_cdr_init(chan->cdr, chan);
1211                         snprintf(tmp, 256, "%s/%s", type, (char *)data);
1212                         ast_cdr_setapp(chan->cdr,"Dial",tmp);
1213                         ast_cdr_update(chan);
1214                         ast_cdr_start(chan->cdr);
1215                         ast_cdr_end(chan->cdr);
1216                         /* If the cause wasn't handled properly */
1217                         if (ast_cdr_disposition(chan->cdr,chan->hangupcause))
1218                                 ast_cdr_failed(chan->cdr);
1219                 } else {
1220                         ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
1221                 }
1222         }
1223         
1224         return chan;
1225 }
1226
1227 int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast_bridge_config *config)
1228 {
1229         /* Copy voice back and forth between the two channels.  Give the peer
1230            the ability to transfer calls with '#<extension' syntax. */
1231         struct ast_frame *f;
1232         struct ast_channel *who;
1233         char chan_featurecode[FEATURE_MAX_LEN + 1]="";
1234         char peer_featurecode[FEATURE_MAX_LEN + 1]="";
1235         int res;
1236         int diff;
1237         int hasfeatures=0;
1238         int hadfeatures=0;
1239         struct ast_option_header *aoh;
1240         struct timeval start = { 0 , 0 };
1241         struct ast_bridge_config backup_config;
1242
1243         memset(&backup_config, 0, sizeof(backup_config));
1244
1245         config->start_time = ast_tvnow();
1246
1247         if (chan && peer) {
1248                 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
1249                 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
1250         } else if (chan)
1251                 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
1252
1253         if (monitor_ok) {
1254                 const char *monitor_exec;
1255                 struct ast_channel *src = NULL;
1256                 if (!monitor_app) { 
1257                         if (!(monitor_app = pbx_findapp("Monitor")))
1258                                 monitor_ok=0;
1259                 }
1260                 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 
1261                         src = chan;
1262                 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
1263                         src = peer;
1264                 if (monitor_app && src) {
1265                         char *tmp = ast_strdupa(monitor_exec);
1266                         if (tmp) {
1267                                 pbx_exec(src, monitor_app, tmp, 1);
1268                         } else {
1269                                 ast_log(LOG_ERROR, "Monitor failed: out of memory\n");
1270                         }
1271                 }
1272         }
1273         
1274         set_config_flags(chan, peer, config);
1275         config->firstpass = 1;
1276
1277         /* Answer if need be */
1278         if (ast_answer(chan))
1279                 return -1;
1280         peer->appl = "Bridged Call";
1281         peer->data = (char *) chan->name;
1282
1283         /* copy the userfield from the B-leg to A-leg if applicable */
1284         if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) {
1285                 char tmp[256];
1286                 if (!ast_strlen_zero(chan->cdr->userfield)) {
1287                         snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield);
1288                         ast_cdr_appenduserfield(chan, tmp);
1289                 } else
1290                         ast_cdr_setuserfield(chan, peer->cdr->userfield);
1291                 /* free the peer's cdr without ast_cdr_free complaining */
1292                 free(peer->cdr);
1293                 peer->cdr = NULL;
1294         }
1295         for (;;) {
1296                 if (config->feature_timer)
1297                         start = ast_tvnow();
1298
1299                 res = ast_channel_bridge(chan, peer, config, &f, &who);
1300
1301                 if (config->feature_timer) {
1302                         /* Update time limit for next pass */
1303                         diff = ast_tvdiff_ms(ast_tvnow(), start);
1304                         config->feature_timer -= diff;
1305                         if (hasfeatures) {
1306                                 /* Running on backup config, meaning a feature might be being
1307                                    activated, but that's no excuse to keep things going 
1308                                    indefinitely! */
1309                                 if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) {
1310                                         ast_log(LOG_DEBUG, "Timed out, realtime this time!\n");
1311                                         config->feature_timer = 0;
1312                                         who = chan;
1313                                         if (f)
1314                                                 ast_frfree(f);
1315                                         f = NULL;
1316                                         res = 0;
1317                                 } else if (config->feature_timer <= 0) {
1318                                         /* Not *really* out of time, just out of time for
1319                                            digits to come in for features. */
1320                                         ast_log(LOG_DEBUG, "Timed out for feature!\n");
1321                                         if (!ast_strlen_zero(peer_featurecode)) {
1322                                                 ast_dtmf_stream(chan, peer, peer_featurecode, 0);
1323                                                 memset(peer_featurecode, 0, sizeof(peer_featurecode));
1324                                         }
1325                                         if (!ast_strlen_zero(chan_featurecode)) {
1326                                                 ast_dtmf_stream(peer, chan, chan_featurecode, 0);
1327                                                 memset(chan_featurecode, 0, sizeof(chan_featurecode));
1328                                         }
1329                                         if (f)
1330                                                 ast_frfree(f);
1331                                         hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
1332                                         if (!hasfeatures) {
1333                                                 /* Restore original (possibly time modified) bridge config */
1334                                                 memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
1335                                                 memset(&backup_config, 0, sizeof(backup_config));
1336                                         }
1337                                         hadfeatures = hasfeatures;
1338                                         /* Continue as we were */
1339                                         continue;
1340                                 }
1341                         } else {
1342                                 if (config->feature_timer <=0) {
1343                                         /* We ran out of time */
1344                                         config->feature_timer = 0;
1345                                         who = chan;
1346                                         if (f)
1347                                                 ast_frfree(f);
1348                                         f = NULL;
1349                                         res = 0;
1350                                 }
1351                         }
1352                 }
1353                 if (res < 0) {
1354                         ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
1355                         return -1;
1356                 }
1357                 
1358                 if (!f || ((f->frametype == AST_FRAME_CONTROL) && ((f->subclass == AST_CONTROL_HANGUP) || (f->subclass == AST_CONTROL_BUSY) || 
1359                         (f->subclass == AST_CONTROL_CONGESTION)))) {
1360                                 res = -1;
1361                                 break;
1362                 }
1363                 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_RINGING)) {
1364                         if (who == chan)
1365                                 ast_indicate(peer, AST_CONTROL_RINGING);
1366                         else
1367                                 ast_indicate(chan, AST_CONTROL_RINGING);
1368                 }
1369                 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == -1)) {
1370                         if (who == chan)
1371                                 ast_indicate(peer, -1);
1372                         else
1373                                 ast_indicate(chan, -1);
1374                 }
1375                 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_FLASH)) {
1376                         if (who == chan)
1377                                 ast_indicate(peer, AST_CONTROL_FLASH);
1378                         else
1379                                 ast_indicate(chan, AST_CONTROL_FLASH);
1380                 }
1381                 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_OPTION)) {
1382                         aoh = f->data;
1383                         /* Forward option Requests */
1384                         if (aoh && (aoh->flag == AST_OPTION_FLAG_REQUEST)) {
1385                                 if (who == chan)
1386                                         ast_channel_setoption(peer, ntohs(aoh->option), aoh->data, f->datalen - sizeof(struct ast_option_header), 0);
1387                                 else
1388                                         ast_channel_setoption(chan, ntohs(aoh->option), aoh->data, f->datalen - sizeof(struct ast_option_header), 0);
1389                         }
1390                 }
1391                 /* check for '*', if we find it it's time to disconnect */
1392                 if (f && (f->frametype == AST_FRAME_DTMF)) {
1393                         char *featurecode;
1394                         int sense;
1395                         struct ast_channel *other;
1396
1397                         hadfeatures = hasfeatures;
1398                         /* This cannot overrun because the longest feature is one shorter than our buffer */
1399                         if (who == chan) {
1400                                 other = peer;
1401                                 sense = FEATURE_SENSE_CHAN;
1402                                 featurecode = chan_featurecode;
1403                         } else  {
1404                                 other = chan;
1405                                 sense = FEATURE_SENSE_PEER;
1406                                 featurecode = peer_featurecode;
1407                         }
1408                         featurecode[strlen(featurecode)] = f->subclass;
1409                         config->feature_timer = backup_config.feature_timer;
1410                         res = ast_feature_interpret(chan, peer, config, featurecode, sense);
1411                         switch(res) {
1412                         case FEATURE_RETURN_PASSDIGITS:
1413                                 ast_dtmf_stream(other, who, featurecode, 0);
1414                                 /* Fall through */
1415                         case FEATURE_RETURN_SUCCESS:
1416                                 memset(featurecode, 0, sizeof(chan_featurecode));
1417                                 break;
1418                         }
1419                         if (res >= FEATURE_RETURN_PASSDIGITS) {
1420                                 res = 0;
1421                         } else {
1422                                 ast_frfree(f);
1423                                 break;
1424                         }
1425                         hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
1426                         if (hadfeatures && !hasfeatures) {
1427                                 /* Restore backup */
1428                                 memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
1429                                 memset(&backup_config, 0, sizeof(struct ast_bridge_config));
1430                         } else if (hasfeatures) {
1431                                 if (!hadfeatures) {
1432                                         /* Backup configuration */
1433                                         memcpy(&backup_config, config, sizeof(struct ast_bridge_config));
1434                                         /* Setup temporary config options */
1435                                         config->play_warning = 0;
1436                                         ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
1437                                         ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
1438                                         config->warning_freq = 0;
1439                                         config->warning_sound = NULL;
1440                                         config->end_sound = NULL;
1441                                         config->start_sound = NULL;
1442                                         config->firstpass = 0;
1443                                 }
1444                                 config->feature_timer = featuredigittimeout;
1445                                 ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->feature_timer);
1446                         }
1447                 }
1448                 if (f)
1449                         ast_frfree(f);
1450         }
1451         return res;
1452 }
1453
1454 static void *do_parking_thread(void *ignore)
1455 {
1456         int ms, tms, max;
1457         struct parkeduser *pu, *pl, *pt = NULL;
1458         struct timeval tv;
1459         struct ast_frame *f;
1460         char exten[AST_MAX_EXTENSION];
1461         char *peername,*cp;
1462         char returnexten[AST_MAX_EXTENSION];
1463         struct ast_context *con;
1464         int x;
1465         fd_set rfds, efds;
1466         fd_set nrfds, nefds;
1467         FD_ZERO(&rfds);
1468         FD_ZERO(&efds);
1469
1470         for (;;) {
1471                 ms = -1;
1472                 max = -1;
1473                 ast_mutex_lock(&parking_lock);
1474                 pl = NULL;
1475                 pu = parkinglot;
1476                 FD_ZERO(&nrfds);
1477                 FD_ZERO(&nefds);
1478                 while(pu) {
1479                         if (pu->notquiteyet) {
1480                                 /* Pretend this one isn't here yet */
1481                                 pl = pu;
1482                                 pu = pu->next;
1483                                 continue;
1484                         }
1485                         tms = ast_tvdiff_ms(ast_tvnow(), pu->start);
1486                         if (tms > pu->parkingtime) {
1487                                 /* Stop music on hold */
1488                                 ast_moh_stop(pu->chan);
1489                                 ast_indicate(pu->chan, AST_CONTROL_UNHOLD);
1490                                 /* Get chan, exten from derived kludge */
1491                                 if (pu->peername[0]) {
1492                                         peername = ast_strdupa(pu->peername);
1493                                         cp = strrchr(peername, '-');
1494                                         if (cp) 
1495                                                 *cp = 0;
1496                                         con = ast_context_find(parking_con_dial);
1497                                         if (!con) {
1498                                                 con = ast_context_create(NULL, parking_con_dial, registrar);
1499                                                 if (!con) {
1500                                                         ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial);
1501                                                 }
1502                                         }
1503                                         if (con) {
1504                                                 snprintf(returnexten, sizeof(returnexten), "%s||t", peername);
1505                                                 ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(returnexten), FREE, registrar);
1506                                         }
1507                                         ast_copy_string(pu->chan->exten, peername, sizeof(pu->chan->exten));
1508                                         ast_copy_string(pu->chan->context, parking_con_dial, sizeof(pu->chan->context));
1509                                         pu->chan->priority = 1;
1510
1511                                 } else {
1512                                         /* They've been waiting too long, send them back to where they came.  Theoretically they
1513                                            should have their original extensions and such, but we copy to be on the safe side */
1514                                         ast_copy_string(pu->chan->exten, pu->exten, sizeof(pu->chan->exten));
1515                                         ast_copy_string(pu->chan->context, pu->context, sizeof(pu->chan->context));
1516                                         pu->chan->priority = pu->priority;
1517                                 }
1518
1519                                 manager_event(EVENT_FLAG_CALL, "ParkedCallTimeOut",
1520                                         "Exten: %d\r\n"
1521                                         "Channel: %s\r\n"
1522                                         "CallerID: %s\r\n"
1523                                         "CallerIDName: %s\r\n"
1524                                         ,pu->parkingnum, pu->chan->name
1525                                         ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
1526                                         ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
1527                                         );
1528
1529                                 if (option_verbose > 1) 
1530                                         ast_verbose(VERBOSE_PREFIX_2 "Timeout for %s parked on %d. Returning to %s,%s,%d\n", pu->chan->name, pu->parkingnum, pu->chan->context, pu->chan->exten, pu->chan->priority);
1531                                 /* Start up the PBX, or hang them up */
1532                                 if (ast_pbx_start(pu->chan))  {
1533                                         ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", pu->chan->name);
1534                                         ast_hangup(pu->chan);
1535                                 }
1536                                 /* And take them out of the parking lot */
1537                                 if (pl) 
1538                                         pl->next = pu->next;
1539                                 else
1540                                         parkinglot = pu->next;
1541                                 pt = pu;
1542                                 pu = pu->next;
1543                                 con = ast_context_find(parking_con);
1544                                 if (con) {
1545                                         snprintf(exten, sizeof(exten), "%d", pt->parkingnum);
1546                                         if (ast_context_remove_extension2(con, exten, 1, NULL))
1547                                                 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
1548                                 } else
1549                                         ast_log(LOG_WARNING, "Whoa, no parking context?\n");
1550                                 free(pt);
1551                         } else {
1552                                 for (x = 0; x < AST_MAX_FDS; x++) {
1553                                         if ((pu->chan->fds[x] > -1) && (FD_ISSET(pu->chan->fds[x], &rfds) || FD_ISSET(pu->chan->fds[x], &efds))) {
1554                                                 if (FD_ISSET(pu->chan->fds[x], &efds))
1555                                                         ast_set_flag(pu->chan, AST_FLAG_EXCEPTION);
1556                                                 else
1557                                                         ast_clear_flag(pu->chan, AST_FLAG_EXCEPTION);
1558                                                 pu->chan->fdno = x;
1559                                                 /* See if they need servicing */
1560                                                 f = ast_read(pu->chan);
1561                                                 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass ==  AST_CONTROL_HANGUP))) {
1562                                                         if (f)
1563                                                                 ast_frfree(f);
1564                                                         manager_event(EVENT_FLAG_CALL, "ParkedCallGiveUp",
1565                                                                 "Exten: %d\r\n"
1566                                                                 "Channel: %s\r\n"
1567                                                                 "CallerID: %s\r\n"
1568                                                                 "CallerIDName: %s\r\n"
1569                                                                 ,pu->parkingnum, pu->chan->name
1570                                                                 ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
1571                                                                 ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
1572                                                                 );
1573
1574                                                         /* There's a problem, hang them up*/
1575                                                         if (option_verbose > 1) 
1576                                                                 ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being parked\n", pu->chan->name);
1577                                                         ast_hangup(pu->chan);
1578                                                         /* And take them out of the parking lot */
1579                                                         if (pl) 
1580                                                                 pl->next = pu->next;
1581                                                         else
1582                                                                 parkinglot = pu->next;
1583                                                         pt = pu;
1584                                                         pu = pu->next;
1585                                                         con = ast_context_find(parking_con);
1586                                                         if (con) {
1587                                                                 snprintf(exten, sizeof(exten), "%d", pt->parkingnum);
1588                                                                 if (ast_context_remove_extension2(con, exten, 1, NULL))
1589                                                                         ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
1590                                                         } else
1591                                                                 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
1592                                                         free(pt);
1593                                                         break;
1594                                                 } else {
1595                                                         /* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
1596                                                         ast_frfree(f);
1597                                                         if (pu->moh_trys < 3 && !pu->chan->generatordata) {
1598                                                                 ast_log(LOG_DEBUG, "MOH on parked call stopped by outside source.  Restarting.\n");
1599                                                                 ast_moh_start(pu->chan, NULL);
1600                                                                 pu->moh_trys++;
1601                                                         }
1602                                                         goto std;       /* XXX Ick: jumping into an else statement??? XXX */
1603                                                 }
1604                                         }
1605                                 }
1606                                 if (x >= AST_MAX_FDS) {
1607 std:                                    for (x=0; x<AST_MAX_FDS; x++) {
1608                                                 /* Keep this one for next one */
1609                                                 if (pu->chan->fds[x] > -1) {
1610                                                         FD_SET(pu->chan->fds[x], &nrfds);
1611                                                         FD_SET(pu->chan->fds[x], &nefds);
1612                                                         if (pu->chan->fds[x] > max)
1613                                                                 max = pu->chan->fds[x];
1614                                                 }
1615                                         }
1616                                         /* Keep track of our longest wait */
1617                                         if ((tms < ms) || (ms < 0))
1618                                                 ms = tms;
1619                                         pl = pu;
1620                                         pu = pu->next;
1621                                 }
1622                         }
1623                 }
1624                 ast_mutex_unlock(&parking_lock);
1625                 rfds = nrfds;
1626                 efds = nefds;
1627                 tv = ast_samp2tv(ms, 1000);
1628                 /* Wait for something to happen */
1629                 ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL);
1630                 pthread_testcancel();
1631         }
1632         return NULL;    /* Never reached */
1633 }
1634
1635 static int park_call_exec(struct ast_channel *chan, void *data)
1636 {
1637         /* Data is unused at the moment but could contain a parking
1638            lot context eventually */
1639         int res=0;
1640         struct localuser *u;
1641         LOCAL_USER_ADD(u);
1642         /* Setup the exten/priority to be s/1 since we don't know
1643            where this call should return */
1644         strcpy(chan->exten, "s");
1645         chan->priority = 1;
1646         if (chan->_state != AST_STATE_UP)
1647                 res = ast_answer(chan);
1648         if (!res)
1649                 res = ast_safe_sleep(chan, 1000);
1650         if (!res)
1651                 res = ast_park_call(chan, chan, 0, NULL);
1652         LOCAL_USER_REMOVE(u);
1653         if (!res)
1654                 res = AST_PBX_KEEPALIVE;
1655         return res;
1656 }
1657
1658 static int park_exec(struct ast_channel *chan, void *data)
1659 {
1660         int res=0;
1661         struct localuser *u;
1662         struct ast_channel *peer=NULL;
1663         struct parkeduser *pu, *pl=NULL;
1664         char exten[AST_MAX_EXTENSION];
1665         struct ast_context *con;
1666         int park;
1667         int dres;
1668         struct ast_bridge_config config;
1669
1670         if (!data) {
1671                 ast_log(LOG_WARNING, "Park requires an argument (extension number)\n");
1672                 return -1;
1673         }
1674         LOCAL_USER_ADD(u);
1675         park = atoi((char *)data);
1676         ast_mutex_lock(&parking_lock);
1677         pu = parkinglot;
1678         while(pu) {
1679                 if (pu->parkingnum == park) {
1680                         if (pl)
1681                                 pl->next = pu->next;
1682                         else
1683                                 parkinglot = pu->next;
1684                         break;
1685                 }
1686                 pl = pu;
1687                 pu = pu->next;
1688         }
1689         ast_mutex_unlock(&parking_lock);
1690         if (pu) {
1691                 peer = pu->chan;
1692                 con = ast_context_find(parking_con);
1693                 if (con) {
1694                         snprintf(exten, sizeof(exten), "%d", pu->parkingnum);
1695                         if (ast_context_remove_extension2(con, exten, 1, NULL))
1696                                 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
1697                 } else
1698                         ast_log(LOG_WARNING, "Whoa, no parking context?\n");
1699
1700                 manager_event(EVENT_FLAG_CALL, "UnParkedCall",
1701                         "Exten: %d\r\n"
1702                         "Channel: %s\r\n"
1703                         "From: %s\r\n"
1704                         "CallerID: %s\r\n"
1705                         "CallerIDName: %s\r\n"
1706                         ,pu->parkingnum, pu->chan->name, chan->name
1707                         ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
1708                         ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
1709                         );
1710
1711                 free(pu);
1712         }
1713         /* JK02: it helps to answer the channel if not already up */
1714         if (chan->_state != AST_STATE_UP) {
1715                 ast_answer(chan);
1716         }
1717
1718         if (peer) {
1719                 /* Play a courtesy to the source(s) configured to prefix the bridge connecting */
1720                 
1721                 if (!ast_strlen_zero(courtesytone)) {
1722                         if (parkedplay == 0) {
1723                                 if (!ast_streamfile(chan, courtesytone, chan->language)) {
1724                                         if (ast_waitstream(chan, "") < 0) {
1725                                                 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
1726                                                 ast_hangup(peer);
1727                                                 return -1;
1728                                         }
1729                                 }
1730                                 ast_moh_stop(peer);
1731                                 ast_indicate(peer, AST_CONTROL_UNHOLD);
1732                         } else {
1733                                 ast_moh_stop(peer);
1734                                 ast_indicate(peer, AST_CONTROL_UNHOLD);
1735                                 if (parkedplay == 2) {
1736                                         if (!ast_streamfile(chan, courtesytone, chan->language) && !ast_streamfile(peer, courtesytone, chan->language)) {
1737                                                 res = ast_waitstream(chan, "");
1738                                                 if (res >= 0)
1739                                                         res = ast_waitstream(peer, "");
1740                                                 if (res < 0) {
1741                                                         ast_log(LOG_WARNING, "Failed to play courtesy tones!\n");
1742                                                         ast_hangup(peer);
1743                                                         return -1;
1744                                                 }
1745                                         }
1746                                 } else if (parkedplay == 1) {
1747                                         if (!ast_streamfile(peer, courtesytone, chan->language)) {
1748                                                 if (ast_waitstream(peer, "") < 0) {
1749                                                         ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
1750                                                         ast_hangup(peer);
1751                                                         return -1;
1752                                                 }
1753                                         }
1754                                 }
1755                         }
1756                 }
1757  
1758                 res = ast_channel_make_compatible(chan, peer);
1759                 if (res < 0) {
1760                         ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
1761                         ast_hangup(peer);
1762                         return -1;
1763                 }
1764                 /* This runs sorta backwards, since we give the incoming channel control, as if it
1765                    were the person called. */
1766                 if (option_verbose > 2) 
1767                         ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to parked call %d\n", chan->name, park);
1768
1769                 memset(&config, 0, sizeof(struct ast_bridge_config));
1770                 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
1771                 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
1772                 config.timelimit = 0;
1773                 config.play_warning = 0;
1774                 config.warning_freq = 0;
1775                 config.warning_sound=NULL;
1776                 res = ast_bridge_call(chan, peer, &config);
1777
1778                 /* Simulate the PBX hanging up */
1779                 if (res != AST_PBX_NO_HANGUP_PEER)
1780                         ast_hangup(peer);
1781                 return res;
1782         } else {
1783                 /* XXX Play a message XXX */
1784                 dres = ast_streamfile(chan, "pbx-invalidpark", chan->language);
1785                 if (!dres)
1786                         dres = ast_waitstream(chan, "");
1787                 else {
1788                         ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
1789                         dres = 0;
1790                 }
1791                 if (option_verbose > 2) 
1792                         ast_verbose(VERBOSE_PREFIX_3 "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park);
1793                 res = -1;
1794         }
1795         LOCAL_USER_REMOVE(u);
1796         return res;
1797 }
1798
1799 static int handle_showfeatures(int fd, int argc, char *argv[])
1800 {
1801         int i;
1802         int fcount;
1803         struct ast_call_feature *feature;
1804         char format[] = "%-25s %-7s %-7s\n";
1805
1806         ast_cli(fd, format, "Builtin Feature", "Default", "Current");
1807         ast_cli(fd, format, "---------------", "-------", "-------");
1808
1809         ast_cli(fd, format, "Pickup", "*8", ast_pickup_ext());          /* default hardcoded above, so we'll hardcode it here */
1810
1811         fcount = sizeof(builtin_features) / sizeof(builtin_features[0]);
1812
1813         for (i = 0; i < fcount; i++)
1814         {
1815                 ast_cli(fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
1816         }
1817         ast_cli(fd, "\n");
1818         ast_cli(fd, format, "Dynamic Feature", "Default", "Current");
1819         ast_cli(fd, format, "---------------", "-------", "-------");
1820         if (AST_LIST_EMPTY(&feature_list)) {
1821                 ast_cli(fd, "(none)\n");
1822         }
1823         else {
1824                 AST_LIST_LOCK(&feature_list);
1825                 AST_LIST_TRAVERSE(&feature_list, feature, feature_entry) {
1826                         ast_cli(fd, format, feature->sname, "no def", feature->exten);  
1827                 }
1828                 AST_LIST_UNLOCK(&feature_list);
1829         }
1830         ast_cli(fd, "\nCall parking\n");
1831         ast_cli(fd, "------------\n");
1832         ast_cli(fd,"%-20s:      %s\n", "Parking extension", parking_ext);
1833         ast_cli(fd,"%-20s:      %s\n", "Parking context", parking_con);
1834         ast_cli(fd,"%-20s:      %d-%d\n", "Parked call extensions", parking_start, parking_stop);
1835         ast_cli(fd,"\n");
1836         
1837         return RESULT_SUCCESS;
1838 }
1839
1840 static char showfeatures_help[] =
1841 "Usage: show features\n"
1842 "       Lists currently configured features.\n";
1843
1844 static struct ast_cli_entry showfeatures =
1845 { { "show", "features", NULL }, handle_showfeatures, "Lists configured features", showfeatures_help };
1846
1847 static int handle_parkedcalls(int fd, int argc, char *argv[])
1848 {
1849         struct parkeduser *cur;
1850         int numparked = 0;
1851
1852         ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
1853                 , "Context", "Extension", "Pri", "Timeout");
1854
1855         ast_mutex_lock(&parking_lock);
1856
1857         cur = parkinglot;
1858         while(cur) {
1859                 ast_cli(fd, "%4d %25s (%-15s %-12s %-4d) %6lds\n"
1860                         ,cur->parkingnum, cur->chan->name, cur->context, cur->exten
1861                         ,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL));
1862
1863                 cur = cur->next;
1864                 numparked++;
1865         }
1866         ast_cli(fd, "%d parked call%s.\n", numparked, (numparked != 1) ? "s" : "");
1867
1868         ast_mutex_unlock(&parking_lock);
1869
1870         return RESULT_SUCCESS;
1871 }
1872
1873 static char showparked_help[] =
1874 "Usage: show parkedcalls\n"
1875 "       Lists currently parked calls.\n";
1876
1877 static struct ast_cli_entry showparked =
1878 { { "show", "parkedcalls", NULL }, handle_parkedcalls, "Lists parked calls", showparked_help };
1879
1880 /*! \brief Dump lot status */
1881 static int manager_parking_status( struct mansession *s, struct message *m )
1882 {
1883         struct parkeduser *cur;
1884         char *id = astman_get_header(m,"ActionID");
1885         char idText[256] = "";
1886
1887         if (!ast_strlen_zero(id))
1888                 snprintf(idText,256,"ActionID: %s\r\n",id);
1889
1890         astman_send_ack(s, m, "Parked calls will follow");
1891
1892         ast_mutex_lock(&parking_lock);
1893
1894         cur=parkinglot;
1895         while(cur) {
1896                         ast_cli(s->fd, "Event: ParkedCall\r\n"
1897                         "Exten: %d\r\n"
1898                         "Channel: %s\r\n"
1899                         "From: %s\r\n"
1900                         "Timeout: %ld\r\n"
1901                         "CallerID: %s\r\n"
1902                         "CallerIDName: %s\r\n"
1903                         "%s"
1904                         "\r\n"
1905                         ,cur->parkingnum, cur->chan->name, cur->peername
1906                         ,(long)cur->start.tv_sec + (long)(cur->parkingtime/1000) - (long)time(NULL)
1907                         ,(cur->chan->cid.cid_num ? cur->chan->cid.cid_num : "")
1908                         ,(cur->chan->cid.cid_name ? cur->chan->cid.cid_name : "")
1909                         ,idText);
1910
1911             cur = cur->next;
1912         }
1913
1914         ast_cli(s->fd,
1915         "Event: ParkedCallsComplete\r\n"
1916         "%s"
1917         "\r\n",idText);
1918
1919         ast_mutex_unlock(&parking_lock);
1920
1921         return RESULT_SUCCESS;
1922 }
1923
1924 static char mandescr_park[] =
1925 "Description: Park a channel.\n"
1926 "Variables: (Names marked with * are required)\n"
1927 "       *Channel: Channel name to park\n"
1928 "       *Channel2: Channel to announce park info to (and return to if timeout)\n"
1929 "       Timeout: Number of milliseconds to wait before callback.\n";  
1930
1931 static int manager_park(struct mansession *s, struct message *m)
1932 {
1933         char *channel = astman_get_header(m, "Channel");
1934         char *channel2 = astman_get_header(m, "Channel2");
1935         char *timeout = astman_get_header(m, "Timeout");
1936         char buf[BUFSIZ];
1937         int to = 0;
1938         int res = 0;
1939         int parkExt = 0;
1940         struct ast_channel *ch1, *ch2;
1941
1942         if (ast_strlen_zero(channel)) {
1943                 astman_send_error(s, m, "Channel not specified");
1944                 return 0;
1945         }
1946
1947         if (ast_strlen_zero(channel2)) {
1948                 astman_send_error(s, m, "Channel2 not specified");
1949                 return 0;
1950         }
1951
1952         ch1 = ast_get_channel_by_name_locked(channel);
1953         if (!ch1) {
1954                 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel);
1955                 astman_send_error(s, m, buf);
1956                 return 0;
1957         }
1958
1959         ch2 = ast_get_channel_by_name_locked(channel2);
1960         if (!ch2) {
1961                 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2);
1962                 astman_send_error(s, m, buf);
1963                 ast_mutex_unlock(&ch1->lock);
1964                 return 0;
1965         }
1966
1967         if (!ast_strlen_zero(timeout)) {
1968                 sscanf(timeout, "%d", &to);
1969         }
1970
1971         res = ast_masq_park_call(ch1, ch2, to, &parkExt);
1972         if (!res) {
1973                 ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT);
1974                 astman_send_ack(s, m, "Park successful");
1975         } else {
1976                 astman_send_error(s, m, "Park failure");
1977         }
1978
1979         ast_mutex_unlock(&ch1->lock);
1980         ast_mutex_unlock(&ch2->lock);
1981
1982         return 0;
1983 }
1984
1985
1986 int ast_pickup_call(struct ast_channel *chan)
1987 {
1988         struct ast_channel *cur = NULL;
1989         int res = -1;
1990
1991         while ( (cur = ast_channel_walk_locked(cur)) != NULL) {
1992                 if (!cur->pbx && 
1993                         (cur != chan) &&
1994                         (chan->pickupgroup & cur->callgroup) &&
1995                         ((cur->_state == AST_STATE_RINGING) ||
1996                          (cur->_state == AST_STATE_RING))) {
1997                                 break;
1998                 }
1999                 ast_mutex_unlock(&cur->lock);
2000         }
2001         if (cur) {
2002                 if (option_debug)
2003                         ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
2004                 res = ast_answer(chan);
2005                 if (res)
2006                         ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
2007                 res = ast_queue_control(chan, AST_CONTROL_ANSWER);
2008                 if (res)
2009                         ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
2010                 res = ast_channel_masquerade(cur, chan);
2011                 if (res)
2012                         ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name);           /* Done */
2013                 ast_mutex_unlock(&cur->lock);
2014         } else  {
2015                 if (option_debug)
2016                         ast_log(LOG_DEBUG, "No call pickup possible...\n");
2017         }
2018         return res;
2019 }
2020
2021 static int load_config(void) 
2022 {
2023         int start = 0, end = 0;
2024         struct ast_context *con = NULL;
2025         struct ast_config *cfg = NULL;
2026         struct ast_variable *var = NULL;
2027         char old_parking_ext[AST_MAX_EXTENSION];
2028         char old_parking_con[AST_MAX_EXTENSION] = "";
2029
2030         if (!ast_strlen_zero(parking_con)) {
2031                 strcpy(old_parking_ext, parking_ext);
2032                 strcpy(old_parking_con, parking_con);
2033         } 
2034
2035         /* Reset to defaults */
2036         strcpy(parking_con, "parkedcalls");
2037         strcpy(parking_con_dial, "park-dial");
2038         strcpy(parking_ext, "700");
2039         strcpy(pickup_ext, "*8");
2040         courtesytone[0] = '\0';
2041         strcpy(xfersound, "beep");
2042         strcpy(xferfailsound, "pbx-invalid");
2043         parking_start = 701;
2044         parking_stop = 750;
2045         parkfindnext = 0;
2046
2047         transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
2048         featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
2049
2050         cfg = ast_config_load("features.conf");
2051         if (cfg) {
2052                 var = ast_variable_browse(cfg, "general");
2053                 while(var) {
2054                         if (!strcasecmp(var->name, "parkext")) {
2055                                 ast_copy_string(parking_ext, var->value, sizeof(parking_ext));
2056                         } else if (!strcasecmp(var->name, "context")) {
2057                                 ast_copy_string(parking_con, var->value, sizeof(parking_con));
2058                         } else if (!strcasecmp(var->name, "parkingtime")) {
2059                                 if ((sscanf(var->value, "%d", &parkingtime) != 1) || (parkingtime < 1)) {
2060                                         ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value);
2061                                         parkingtime = DEFAULT_PARK_TIME;
2062                                 } else
2063                                         parkingtime = parkingtime * 1000;
2064                         } else if (!strcasecmp(var->name, "parkpos")) {
2065                                 if (sscanf(var->value, "%d-%d", &start, &end) != 2) {
2066                                         ast_log(LOG_WARNING, "Format for parking positions is a-b, where a and b are numbers at line %d of parking.conf\n", var->lineno);
2067                                 } else {
2068                                         parking_start = start;
2069                                         parking_stop = end;
2070                                 }
2071                         } else if (!strcasecmp(var->name, "findslot")) {
2072                                 parkfindnext = (!strcasecmp(var->value, "next"));
2073                         } else if (!strcasecmp(var->name, "adsipark")) {
2074                                 adsipark = ast_true(var->value);
2075                         } else if (!strcasecmp(var->name, "transferdigittimeout")) {
2076                                 if ((sscanf(var->value, "%d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) {
2077                                         ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value);
2078                                         transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
2079                                 } else
2080                                         transferdigittimeout = transferdigittimeout * 1000;
2081                         } else if (!strcasecmp(var->name, "featuredigittimeout")) {
2082                                 if ((sscanf(var->value, "%d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) {
2083                                         ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value);
2084                                         featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
2085                                 }
2086                         } else if (!strcasecmp(var->name, "courtesytone")) {
2087                                 ast_copy_string(courtesytone, var->value, sizeof(courtesytone));
2088                         }  else if (!strcasecmp(var->name, "parkedplay")) {
2089                                 if (!strcasecmp(var->value, "both"))
2090                                         parkedplay = 2;
2091                                 else if (!strcasecmp(var->value, "parked"))
2092                                         parkedplay = 1;
2093                                 else
2094                                         parkedplay = 0;
2095                         } else if (!strcasecmp(var->name, "xfersound")) {
2096                                 ast_copy_string(xfersound, var->value, sizeof(xfersound));
2097                         } else if (!strcasecmp(var->name, "xferfailsound")) {
2098                                 ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound));
2099                         } else if (!strcasecmp(var->name, "pickupexten")) {
2100                                 ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext));
2101                         }
2102                         var = var->next;
2103                 }
2104
2105                 unmap_features();
2106                 var = ast_variable_browse(cfg, "featuremap");
2107                 while(var) {
2108                         if (remap_feature(var->name, var->value))
2109                                 ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name);
2110                         var = var->next;
2111                 }
2112
2113                 /* Map a key combination to an application*/
2114                 ast_unregister_features();
2115                 var = ast_variable_browse(cfg, "applicationmap");
2116                 while(var) {
2117                         char *tmp_val=strdup(var->value);
2118                         char *exten, *party=NULL, *app=NULL, *app_args=NULL; 
2119
2120                         if (!tmp_val) { 
2121                                 ast_log(LOG_ERROR, "res_features: strdup failed");
2122                                 continue;
2123                         }
2124                         
2125
2126                         exten=strsep(&tmp_val,",");
2127                         if (exten) party=strsep(&tmp_val,",");
2128                         if (party) app=strsep(&tmp_val,",");
2129
2130                         if (app) app_args=strsep(&tmp_val,",");
2131
2132                         if (!(app && strlen(app)) || !(exten && strlen(exten)) || !(party && strlen(party)) || !(var->name && strlen(var->name))) {
2133                                 ast_log(LOG_NOTICE, "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n",app,exten,party,var->name);
2134                                 free(tmp_val);
2135                                 var = var->next;
2136                                 continue;
2137                         }
2138
2139                         {
2140                                 struct ast_call_feature *feature;
2141                                 int mallocd = 0;
2142                                 
2143                                 if (!(feature = find_feature(var->name))) {
2144                                         mallocd = 1;
2145                                         
2146                                         if (!(feature = ast_calloc(1, sizeof(*feature)))) {
2147                                                 free(tmp_val);
2148                                                 var = var->next;
2149                                                 continue;                                       
2150                                         }
2151                                 }
2152
2153                                 ast_copy_string(feature->sname,var->name,FEATURE_SNAME_LEN);
2154                                 ast_copy_string(feature->app,app,FEATURE_APP_LEN);
2155                                 ast_copy_string(feature->exten, exten,FEATURE_EXTEN_LEN);
2156                                 free(tmp_val);
2157                                 
2158                                 if (app_args) 
2159                                         ast_copy_string(feature->app_args,app_args,FEATURE_APP_ARGS_LEN);
2160                                 
2161                                 ast_copy_string(feature->exten, exten,sizeof(feature->exten));
2162                                 feature->operation=feature_exec_app;
2163                                 ast_set_flag(feature,AST_FEATURE_FLAG_NEEDSDTMF);
2164                                 
2165                                 if (!strcasecmp(party,"caller"))
2166                                         ast_set_flag(feature,AST_FEATURE_FLAG_CALLER);
2167                                 else if (!strcasecmp(party, "callee"))
2168                                         ast_set_flag(feature,AST_FEATURE_FLAG_CALLEE);
2169                                 else {
2170                                         ast_log(LOG_NOTICE, "Invalid party specification for feature '%s', must be caller, or callee\n", var->name);
2171                                         var = var->next;
2172                                         continue;
2173                                 }
2174
2175                                 ast_register_feature(feature);
2176                                 
2177                                 if (option_verbose >=1) ast_verbose(VERBOSE_PREFIX_2 "Mapping Feature '%s' to app '%s' with code '%s'\n", var->name, app, exten);  
2178                         }
2179                         var = var->next;
2180                 }        
2181         }
2182         ast_config_destroy(cfg);
2183
2184         /* Remove the old parking extension */
2185         if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con)))     {
2186                 ast_context_remove_extension2(con, old_parking_ext, 1, registrar);
2187                 ast_log(LOG_DEBUG, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con);
2188         }
2189         
2190         if (!(con = ast_context_find(parking_con))) {
2191                 if (!(con = ast_context_create(NULL, parking_con, registrar))) {
2192                         ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
2193                         return -1;
2194                 }
2195         }
2196         return ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, strdup(""), FREE, registrar);
2197 }
2198
2199 int reload(void) {
2200         return load_config();
2201 }
2202
2203 int load_module(void)
2204 {
2205         int res;
2206         
2207         AST_LIST_HEAD_INIT(&feature_list);
2208         memset(parking_ext, 0, sizeof(parking_ext));
2209         memset(parking_con, 0, sizeof(parking_con));
2210
2211         if ((res = load_config()))
2212                 return res;
2213         ast_cli_register(&showparked);
2214         ast_cli_register(&showfeatures);
2215         ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
2216         res = ast_register_application(parkedcall, park_exec, synopsis, descrip);
2217         if (!res)
2218                 res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2);
2219         if (!res) {
2220                 ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls" );
2221                 ast_manager_register2("Park", EVENT_FLAG_CALL, manager_park,
2222                         "Park a channel", mandescr_park); 
2223         }
2224         return res;
2225 }
2226
2227
2228 int unload_module(void)
2229 {
2230         STANDARD_HANGUP_LOCALUSERS;
2231
2232         ast_manager_unregister("ParkedCalls");
2233         ast_manager_unregister("Park");
2234         ast_cli_unregister(&showfeatures);
2235         ast_cli_unregister(&showparked);
2236         ast_unregister_application(parkcall);
2237         return ast_unregister_application(parkedcall);
2238 }
2239
2240 char *description(void)
2241 {
2242         return "Call Features Resource";
2243 }
2244
2245 int usecount(void)
2246 {
2247         /* Never allow parking to be unloaded because it will
2248            unresolve needed symbols in the dialer */
2249 #if 0
2250         int res;
2251         STANDARD_USECOUNT(res);
2252         return res;
2253 #else
2254         return 1;
2255 #endif
2256 }
2257
2258 char *key()
2259 {
2260         return ASTERISK_GPL_KEY;
2261 }