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