2765cc159113a35b5b2b39029c5663312a1dbf15
[asterisk/asterisk.git] / res / res_features.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Routines implementing call parking
5  * 
6  * Copyright (C) 1999 - 2005, Digium, Inc.
7  *
8  * Mark Spencer <markster@digium.com>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  */
13
14 #include <pthread.h>
15 #include <stdlib.h>
16 #include <errno.h>
17 #include <unistd.h>
18 #include <string.h>
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <sys/time.h>
22 #include <sys/signal.h>
23 #include <netinet/in.h>
24
25 #include "asterisk.h"
26
27 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
28
29 #include "asterisk/lock.h"
30 #include "asterisk/file.h"
31 #include "asterisk/logger.h"
32 #include "asterisk/channel.h"
33 #include "asterisk/pbx.h"
34 #include "asterisk/options.h"
35 #include "asterisk/module.h"
36 #include "asterisk/translate.h"
37 #include "asterisk/app.h"
38 #include "asterisk/say.h"
39 #include "asterisk/features.h"
40 #include "asterisk/musiconhold.h"
41 #include "asterisk/config.h"
42 #include "asterisk/cli.h"
43 #include "asterisk/manager.h"
44 #include "asterisk/utils.h"
45 #include "asterisk/adsi.h"
46
47 #ifdef __AST_DEBUG_MALLOC
48 static void FREE(void *ptr)
49 {
50         free(ptr);
51 }
52 #else
53 #define FREE free
54 #endif
55
56 #define DEFAULT_PARK_TIME 45000
57 #define DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000
58 #define DEFAULT_FEATURE_DIGIT_TIMEOUT 500
59
60 static char *parkedcall = "ParkedCall";
61
62 /* No more than 45 seconds parked before you do something with them */
63 static int parkingtime = DEFAULT_PARK_TIME;
64
65 /* Context for which parking is made accessible */
66 static char parking_con[AST_MAX_EXTENSION] = "parkedcalls";
67
68 /* Context for dialback for parking (KLUDGE) */
69 static char parking_con_dial[AST_MAX_EXTENSION] = "park-dial";
70
71 /* Extension you type to park the call */
72 static char parking_ext[AST_MAX_EXTENSION] = "700";
73
74 static char pickup_ext[AST_MAX_EXTENSION] = "*8";
75
76 /* Default sounds */
77 static char courtesytone[256] = "";
78 static char xfersound[256] = "beep";
79 static char xferfailsound[256] = "pbx-invalid";
80
81 /* First available extension for parking */
82 static int parking_start = 701;
83
84 /* Last available extension for parking */
85 static int parking_stop = 750;
86
87 static int parking_offset = 0;
88
89 static int parkfindnext = 0;
90
91 static int adsipark = 0;
92
93 static int transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
94 static int featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
95
96 /* Default courtesy tone played when party joins conference */
97
98 /* Registrar for operations */
99 static char *registrar = "res_features";
100
101 static char *synopsis = "Answer a parked call";
102
103 static char *descrip = "ParkedCall(exten):"
104 "Used to connect to a parked call.  This application is always\n"
105 "registered internally and does not need to be explicitly added\n"
106 "into the dialplan, although you should include the 'parkedcalls'\n"
107 "context.\n";
108
109 static char *parkcall = "Park";
110
111 static char *synopsis2 = "Park yourself";
112
113 static char *descrip2 = "Park(exten):"
114 "Used to park yourself (typically in combination with a supervised\n"
115 "transfer to know the parking space). This application is always\n"
116 "registered internally and does not need to be explicitly added\n"
117 "into the dialplan, although you should include the 'parkedcalls'\n"
118 "context.\n";
119
120 static struct ast_app *monitor_app=NULL;
121 static int monitor_ok=1;
122
123 struct parkeduser {
124         struct ast_channel *chan;
125         struct timeval start;
126         int parkingnum;
127         /* Where to go if our parking time expires */
128         char context[AST_MAX_EXTENSION];
129         char exten[AST_MAX_EXTENSION];
130         int priority;
131         int parkingtime;
132         int notquiteyet;
133         char peername[1024];
134         unsigned char moh_trys;
135         struct parkeduser *next;
136 };
137
138 static struct parkeduser *parkinglot;
139
140 AST_MUTEX_DEFINE_STATIC(parking_lock);
141
142 static pthread_t parking_thread;
143
144 STANDARD_LOCAL_USER;
145
146 LOCAL_USER_DECL;
147
148 char *ast_parking_ext(void)
149 {
150         return parking_ext;
151 }
152
153 char *ast_pickup_ext(void)
154 {
155         return pickup_ext;
156 }
157
158 struct ast_bridge_thread_obj 
159 {
160         struct ast_bridge_config bconfig;
161         struct ast_channel *chan;
162         struct ast_channel *peer;
163 };
164
165 static void check_goto_on_transfer(struct ast_channel *chan) 
166 {
167         struct ast_channel *xferchan;
168         char *goto_on_transfer;
169
170         goto_on_transfer = pbx_builtin_getvar_helper(chan, "GOTO_ON_BLINDXFR");
171
172         if (goto_on_transfer && !ast_strlen_zero(goto_on_transfer) && (xferchan = ast_channel_alloc(0))) {
173                 char *x;
174                 struct ast_frame *f;
175                 
176                 for (x = goto_on_transfer; x && *x; x++)
177                         if (*x == '^')
178                                 *x = '|';
179
180                 strcpy(xferchan->name, chan->name);
181                 /* Make formats okay */
182                 xferchan->readformat = chan->readformat;
183                 xferchan->writeformat = chan->writeformat;
184                 ast_channel_masquerade(xferchan, chan);
185                 ast_parseable_goto(xferchan, goto_on_transfer);
186                 xferchan->_state = AST_STATE_UP;
187                 ast_clear_flag(xferchan, AST_FLAGS_ALL);        
188                 xferchan->_softhangup = 0;
189                 if ((f = ast_read(xferchan))) {
190                         ast_frfree(f);
191                         f = NULL;
192                         ast_pbx_start(xferchan);
193                 } else {
194                         ast_hangup(xferchan);
195                 }
196         }
197 }
198
199 static void *ast_bridge_call_thread(void *data) 
200 {
201         struct ast_bridge_thread_obj *tobj = data;
202         tobj->chan->appl = "Transferred Call";
203         tobj->chan->data = tobj->peer->name;
204         tobj->peer->appl = "Transferred Call";
205         tobj->peer->data = tobj->chan->name;
206         if (tobj->chan->cdr) {
207                 ast_cdr_reset(tobj->chan->cdr,0);
208                 ast_cdr_setdestchan(tobj->chan->cdr, tobj->peer->name);
209         }
210         if (tobj->peer->cdr) {
211                 ast_cdr_reset(tobj->peer->cdr,0);
212                 ast_cdr_setdestchan(tobj->peer->cdr, tobj->chan->name);
213         }
214
215
216         ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig);
217         ast_hangup(tobj->chan);
218         ast_hangup(tobj->peer);
219         tobj->chan = tobj->peer = NULL;
220         free(tobj);
221         tobj=NULL;
222         return NULL;
223 }
224
225 static void ast_bridge_call_thread_launch(void *data) 
226 {
227         pthread_t thread;
228         pthread_attr_t attr;
229         int result;
230
231         result = pthread_attr_init(&attr);
232         pthread_attr_setschedpolicy(&attr, SCHED_RR);
233         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
234         result = ast_pthread_create(&thread, &attr,ast_bridge_call_thread, data);
235         result = pthread_attr_destroy(&attr);
236 }
237
238
239
240 static int adsi_announce_park(struct ast_channel *chan, int parkingnum)
241 {
242         int res;
243         int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT};
244         char tmp[256] = "";
245         char *message[5] = {NULL, NULL, NULL, NULL, NULL};
246
247         snprintf(tmp, sizeof(tmp), "Parked on %d", parkingnum);
248         message[0] = tmp;
249         res = adsi_load_session(chan, NULL, 0, 1);
250         if (res == -1) {
251                 return res;
252         }
253         return adsi_print(chan, message, justify, 1);
254 }
255
256 int ast_park_call(struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout)
257 {
258         /* We put the user in the parking list, then wake up the parking thread to be sure it looks
259            after these channels too */
260         struct parkeduser *pu, *cur;
261         int i,x,parking_range;
262         char exten[AST_MAX_EXTENSION];
263         struct ast_context *con;
264         pu = malloc(sizeof(struct parkeduser));
265         if (pu) {
266                 memset(pu,0,sizeof(struct parkeduser));
267                 ast_mutex_lock(&parking_lock);
268                 parking_range=parking_stop-parking_start+1;
269                 for (i=0;i<parking_range;i++) {
270                         x=(i+parking_offset)%parking_range + parking_start;
271                         cur = parkinglot;
272                         while(cur) {
273                                 if (cur->parkingnum == x) 
274                                         break;
275                                 cur = cur->next;
276                         }
277                         if (!cur)
278                                 break;
279                 }
280
281                 if (i < parking_range) {
282                         if (parkfindnext) parking_offset=x-parking_start+1;
283                         chan->appl = "Parked Call";
284                         chan->data = NULL; 
285
286                         pu->chan = chan;
287                         /* Start music on hold */
288                         if (chan != peer) {
289                                 ast_indicate(pu->chan, AST_CONTROL_HOLD);
290                                 ast_moh_start(pu->chan, NULL);
291                         }
292                         gettimeofday(&pu->start, NULL);
293                         pu->parkingnum = x;
294                         if (timeout > 0)
295                                 pu->parkingtime = timeout;
296                         else
297                                 pu->parkingtime = parkingtime;
298                         if (extout)
299                                 *extout = x;
300                         if (peer) {
301                                 ast_copy_string(pu->peername,peer->name,sizeof(pu->peername));
302                         }
303                         /* Remember what had been dialed, so that if the parking
304                            expires, we try to come back to the same place */
305                         if (!ast_strlen_zero(chan->macrocontext))
306                                 ast_copy_string(pu->context, chan->macrocontext, sizeof(pu->context));
307                         else
308                                 ast_copy_string(pu->context, chan->context, sizeof(pu->context));
309                         if (!ast_strlen_zero(chan->macroexten))
310                                 ast_copy_string(pu->exten, chan->macroexten, sizeof(pu->exten));
311                         else
312                                 ast_copy_string(pu->exten, chan->exten, sizeof(pu->exten));
313                         if (chan->macropriority)
314                                 pu->priority = chan->macropriority;
315                         else
316                                 pu->priority = chan->priority;
317                         pu->next = parkinglot;
318                         parkinglot = pu;
319                         /* If parking a channel directly, don't quiet yet get parking running on it */
320                         if (peer == chan) 
321                                 pu->notquiteyet = 1;
322                         ast_mutex_unlock(&parking_lock);
323                         /* Wake up the (presumably select()ing) thread */
324                         pthread_kill(parking_thread, SIGURG);
325                         if (option_verbose > 1) 
326                                 ast_verbose(VERBOSE_PREFIX_2 "Parked %s on %d. Will timeout back to %s,%s,%d in %d seconds\n", pu->chan->name, pu->parkingnum, pu->context, pu->exten, pu->priority, (pu->parkingtime/1000));
327
328                         manager_event(EVENT_FLAG_CALL, "ParkedCall",
329                                 "Exten: %d\r\n"
330                                 "Channel: %s\r\n"
331                                 "From: %s\r\n"
332                                 "Timeout: %ld\r\n"
333                                 "CallerID: %s\r\n"
334                                 "CallerIDName: %s\r\n\r\n"
335                                 ,pu->parkingnum, pu->chan->name, peer->name
336                                 ,(long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL)
337                                 ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
338                                 ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
339                                 );
340
341                         if (peer) {
342                                 if (adsipark && adsi_available(peer)) {
343                                         adsi_announce_park(peer, pu->parkingnum);
344                                 }
345                                 if (adsipark && adsi_available(peer)) {
346                                         adsi_unload_session(peer);
347                                 }
348                         }
349                         con = ast_context_find(parking_con);
350                         if (!con) {
351                                 con = ast_context_create(NULL,parking_con, registrar);
352                                 if (!con) {
353                                         ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
354                                 }
355                         }
356                         if (con) {
357                                 snprintf(exten, sizeof(exten), "%d", x);
358                                 ast_add_extension2(con, 1, exten, 1, NULL, NULL, parkedcall, strdup(exten), FREE, registrar);
359                         }
360                         if (peer) ast_say_digits(peer, pu->parkingnum, "", peer->language);
361                         if (pu->notquiteyet) {
362                                 /* Wake up parking thread if we're really done */
363                                 ast_moh_start(pu->chan, NULL);
364                                 pu->notquiteyet = 0;
365                                 pthread_kill(parking_thread, SIGURG);
366                         }
367                         return 0;
368                 } else {
369                         ast_log(LOG_WARNING, "No more parking spaces\n");
370                         free(pu);
371                         ast_mutex_unlock(&parking_lock);
372                         return -1;
373                 }
374         } else {
375                 ast_log(LOG_WARNING, "Out of memory\n");
376                 return -1;
377         }
378         return 0;
379 }
380
381 int ast_masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout)
382 {
383         struct ast_channel *chan;
384         struct ast_frame *f;
385         /* Make a new, fake channel that we'll use to masquerade in the real one */
386         chan = ast_channel_alloc(0);
387         if (chan) {
388                 /* Let us keep track of the channel name */
389                 snprintf(chan->name, sizeof (chan->name), "Parked/%s",rchan->name);
390                 /* Make formats okay */
391                 chan->readformat = rchan->readformat;
392                 chan->writeformat = rchan->writeformat;
393                 ast_channel_masquerade(chan, rchan);
394                 /* Setup the extensions and such */
395                 ast_copy_string(chan->context, rchan->context, sizeof(chan->context));
396                 ast_copy_string(chan->exten, rchan->exten, sizeof(chan->exten));
397                 chan->priority = rchan->priority;
398                 /* Make the masq execute */
399                 f = ast_read(chan);
400                 if (f)
401                         ast_frfree(f);
402                 ast_park_call(chan, peer, timeout, extout);
403         } else {
404                 ast_log(LOG_WARNING, "Unable to create parked channel\n");
405                 return -1;
406         }
407         return 0;
408 }
409
410
411 #define FEATURE_RETURN_HANGUP           -1
412 #define FEATURE_RETURN_SUCCESSBREAK      0
413 #define FEATURE_RETURN_PBX_KEEPALIVE    AST_PBX_KEEPALIVE
414 #define FEATURE_RETURN_NO_HANGUP_PEER   AST_PBX_NO_HANGUP_PEER
415 #define FEATURE_RETURN_PASSDIGITS        21
416 #define FEATURE_RETURN_STOREDIGITS       22
417 #define FEATURE_RETURN_SUCCESS           23
418
419 #define FEATURE_SENSE_CHAN      (1 << 0)
420 #define FEATURE_SENSE_PEER      (1 << 1)
421 #define FEATURE_MAX_LEN         11
422
423 static int builtin_automonitor(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
424 {
425         char *touch_monitor = NULL, *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_format = NULL;
426         int x = 0;
427         size_t len;
428         struct ast_channel *caller_chan = NULL, *callee_chan = NULL;
429
430
431         if(sense == 2) {
432                 caller_chan = peer;
433                 callee_chan = chan;
434         } else {
435                 callee_chan = peer;
436                 caller_chan = chan;
437         }
438         
439         if (!monitor_ok) {
440                 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
441                 return -1;
442         }
443
444         if (!monitor_app) { 
445                 if (!(monitor_app = pbx_findapp("Monitor"))) {
446                         monitor_ok=0;
447                         ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
448                         return -1;
449                 }
450         }
451         if (!ast_strlen_zero(courtesytone)) {
452                 if (ast_autoservice_start(callee_chan))
453                         return -1;
454                 if (!ast_streamfile(caller_chan, courtesytone, caller_chan->language)) {
455                         if (ast_waitstream(caller_chan, "") < 0) {
456                                 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
457                                 ast_autoservice_stop(callee_chan);
458                                 return -1;
459                         }
460                 }
461                 if (ast_autoservice_stop(callee_chan))
462                         return -1;
463         }
464         
465         if (callee_chan->monitor) {
466                 if (option_verbose > 3)
467                         ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to stop recording call.\n", code);
468                 ast_monitor_stop(callee_chan, 1);
469                 return FEATURE_RETURN_SUCCESS;
470         }
471
472         if (caller_chan && callee_chan) {
473                 touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT");
474                 if (!touch_format)
475                         touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT");
476
477                 touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR");
478                 if (!touch_monitor)
479                         touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR");
480                 
481                 if (touch_monitor) {
482                         len = strlen(touch_monitor) + 50;
483                         args = alloca(len);
484                         snprintf(args, len, "%s|auto-%ld-%s|m", (touch_format) ? touch_format : "wav", time(NULL), touch_monitor);
485                 } else {
486                         caller_chan_id = ast_strdupa(caller_chan->cid.cid_num ? caller_chan->cid.cid_num : caller_chan->name);
487                         callee_chan_id = ast_strdupa(callee_chan->cid.cid_num ? callee_chan->cid.cid_num : callee_chan->name);
488                         len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50;
489                         args = alloca(len);
490                         snprintf(args, len, "%s|auto-%ld-%s-%s|m", (touch_format) ? touch_format : "wav", time(NULL), caller_chan_id, callee_chan_id);
491                 }
492
493                 for( x = 0; x < strlen(args); x++)
494                         if (args[x] == '/')
495                                 args[x] = '-';
496                 
497                 if (option_verbose > 3)
498                         ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to record call. filename: %s\n", code, args);
499
500                 pbx_exec(callee_chan, monitor_app, args, 1);
501                 
502                 return FEATURE_RETURN_SUCCESS;
503         }
504         
505         ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n");   
506         return -1;
507 }
508
509 static int builtin_disconnect(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
510 {
511         if (option_verbose > 3)
512                 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to disconnect call.\n", code);
513         return FEATURE_RETURN_HANGUP;
514 }
515
516 static int builtin_blindtransfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
517 {
518         struct ast_channel *transferer;
519         struct ast_channel *transferee;
520         char *transferer_real_context;
521         char newext[256];
522         int res;
523
524         if (sense == FEATURE_SENSE_PEER) {
525                 transferer = peer;
526                 transferee = chan;
527         } else {
528                 transferer = chan;
529                 transferee = peer;
530         }
531         if (!(transferer_real_context=pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT")) &&
532            !(transferer_real_context=pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT"))) {
533                 /* Use the non-macro context to transfer the call */
534                 if (!ast_strlen_zero(transferer->macrocontext))
535                         transferer_real_context = transferer->macrocontext;
536                 else
537                         transferer_real_context = transferer->context;
538         }
539         /* Start autoservice on chan while we talk
540            to the originator */
541         ast_indicate(transferee, AST_CONTROL_HOLD);
542         ast_autoservice_start(transferee);
543         ast_moh_start(transferee, NULL);
544
545         memset(newext, 0, sizeof(newext));
546         
547         /* Transfer */
548         if ((res=ast_streamfile(transferer, "pbx-transfer", transferer->language))) {
549                 ast_moh_stop(transferee);
550                 ast_autoservice_stop(transferee);
551                 ast_indicate(transferee, AST_CONTROL_UNHOLD);
552                 return res;
553         }
554         if ((res=ast_waitstream(transferer, AST_DIGIT_ANY)) < 0) {
555                 ast_moh_stop(transferee);
556                 ast_autoservice_stop(transferee);
557                 ast_indicate(transferee, AST_CONTROL_UNHOLD);
558                 return res;
559         } else if (res > 0) {
560                 /* If they've typed a digit already, handle it */
561                 newext[0] = (char) res;
562         }
563
564         ast_stopstream(transferer);
565         res = ast_app_dtget(transferer, transferer_real_context, newext, sizeof(newext), 100, transferdigittimeout);
566         if (res < 0) {
567                 ast_moh_stop(transferee);
568                 ast_autoservice_stop(transferee);
569                 ast_indicate(transferee, AST_CONTROL_UNHOLD);
570                 return res;
571         }
572         if (!strcmp(newext, ast_parking_ext())) {
573                 ast_moh_stop(transferee);
574
575                 res = ast_autoservice_stop(transferee);
576                 ast_indicate(transferee, AST_CONTROL_UNHOLD);
577                 if (res)
578                         res = -1;
579                 else if (!ast_park_call(transferee, transferer, 0, NULL)) {
580                         /* We return non-zero, but tell the PBX not to hang the channel when
581                            the thread dies -- We have to be careful now though.  We are responsible for 
582                            hanging up the channel, else it will never be hung up! */
583
584                         if (transferer==peer)
585                                 res=AST_PBX_KEEPALIVE;
586                         else
587                                 res=AST_PBX_NO_HANGUP_PEER;
588                         return res;
589                 } else {
590                         ast_log(LOG_WARNING, "Unable to park call %s\n", transferee->name);
591                 }
592                 /* XXX Maybe we should have another message here instead of invalid extension XXX */
593         } else if (ast_exists_extension(transferee, transferer_real_context, newext, 1, transferer->cid.cid_num)) {
594                 pbx_builtin_setvar_helper(peer, "BLINDTRANSFER", chan->name);
595                 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", peer->name);
596                 ast_moh_stop(transferee);
597                 res=ast_autoservice_stop(transferee);
598                 ast_indicate(transferee, AST_CONTROL_UNHOLD);
599                 if (!transferee->pbx) {
600                         /* Doh!  Use our handy async_goto functions */
601                         if (option_verbose > 2) 
602                                 ast_verbose(VERBOSE_PREFIX_3 "Transferring %s to '%s' (context %s) priority 1\n"
603                                                                 ,transferee->name, newext, transferer_real_context);
604                         if (ast_async_goto(transferee, transferer_real_context, newext, 1))
605                                 ast_log(LOG_WARNING, "Async goto failed :-(\n");
606                         res = -1;
607                 } else {
608                         /* Set the channel's new extension, since it exists, using transferer context */
609                         ast_copy_string(transferee->exten, newext, sizeof(transferee->exten));
610                         ast_copy_string(transferee->context, transferer_real_context, sizeof(transferee->context));
611                         transferee->priority = 0;
612                 }
613                 check_goto_on_transfer(transferer);
614                 return res;
615         } else {
616                 if (option_verbose > 2) 
617                         ast_verbose(VERBOSE_PREFIX_3 "Unable to find extension '%s' in context '%s'\n", newext, transferer_real_context);
618         }
619         if (!ast_strlen_zero(xferfailsound))
620                 res = ast_streamfile(transferer, xferfailsound, transferee->language);
621         else
622                 res = 0;
623         if (res) {
624                 ast_moh_stop(transferee);
625                 ast_autoservice_stop(transferee);
626                 ast_indicate(transferee, AST_CONTROL_UNHOLD);
627                 return res;
628         }
629         res = ast_waitstream(transferer, AST_DIGIT_ANY);
630         ast_stopstream(transferer);
631         ast_moh_stop(transferee);
632         res = ast_autoservice_stop(transferee);
633         ast_indicate(transferee, AST_CONTROL_UNHOLD);
634         if (res) {
635                 if (option_verbose > 1)
636                         ast_verbose(VERBOSE_PREFIX_2 "Hungup during autoservice stop on '%s'\n", transferee->name);
637                 return res;
638         }
639         return FEATURE_RETURN_SUCCESS;
640 }
641
642 static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
643 {
644         struct ast_channel *transferer;
645         struct ast_channel *transferee;
646         struct ast_channel *newchan, *xferchan=NULL;
647         int outstate=0;
648         struct ast_bridge_config bconfig;
649         char *transferer_real_context;
650         char xferto[256],dialstr[265];
651         char *cid_num;
652         char *cid_name;
653         int res;
654         struct ast_frame *f = NULL;
655         struct ast_bridge_thread_obj *tobj;
656
657         ast_log(LOG_DEBUG, "Executing Attended Transfer %s, %s (sense=%d) XXX\n", chan->name, peer->name, sense);
658         if (sense == FEATURE_SENSE_PEER) {
659                 transferer = peer;
660                 transferee = chan;
661         } else {
662                 transferer = chan;
663                 transferee = peer;
664         }
665         if (!(transferer_real_context=pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT")) &&
666            !(transferer_real_context=pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT"))) {
667                 /* Use the non-macro context to transfer the call */
668                 if (!ast_strlen_zero(transferer->macrocontext))
669                         transferer_real_context = transferer->macrocontext;
670                 else
671                         transferer_real_context = transferer->context;
672         }
673         /* Start autoservice on chan while we talk
674            to the originator */
675         ast_indicate(transferee, AST_CONTROL_HOLD);
676         ast_autoservice_start(transferee);
677         ast_moh_start(transferee, NULL);
678         memset(xferto, 0, sizeof(xferto));
679         /* Transfer */
680         if ((res=ast_streamfile(transferer, "pbx-transfer", transferer->language))) {
681                 ast_moh_stop(transferee);
682                 ast_autoservice_stop(transferee);
683                 ast_indicate(transferee, AST_CONTROL_UNHOLD);
684                 return res;
685         }
686         if ((res=ast_waitstream(transferer, AST_DIGIT_ANY)) < 0) {
687                 ast_moh_stop(transferee);
688                 ast_autoservice_stop(transferee);
689                 ast_indicate(transferee, AST_CONTROL_UNHOLD);
690                 return res;
691         } else if(res > 0) {
692                 /* If they've typed a digit already, handle it */
693                 xferto[0] = (char) res;
694         }
695         if ((ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout))) {
696                 cid_num = transferer->cid.cid_num;
697                 cid_name = transferer->cid.cid_name;
698                 if (ast_exists_extension(transferer, transferer_real_context,xferto, 1, cid_num)) {
699                         snprintf(dialstr, sizeof(dialstr), "%s@%s/n", xferto, transferer_real_context);
700                         if ((newchan = ast_request_and_dial("Local", ast_best_codec(transferer->nativeformats), dialstr,30000, &outstate, cid_num, cid_name))) {
701                                 res = ast_channel_make_compatible(transferer, newchan);
702                                 if (res < 0) {
703                                         ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", transferer->name, newchan->name);
704                                         ast_hangup(newchan);
705                                         return -1;
706                                 }
707                                 memset(&bconfig,0,sizeof(struct ast_bridge_config));
708                                 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
709                                 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
710                                 res = ast_bridge_call(transferer,newchan,&bconfig);
711                                 if (newchan->_softhangup || newchan->_state != AST_STATE_UP) {
712                                         ast_hangup(newchan);
713                                         if (f) {
714                                                 ast_frfree(f);
715                                                 f = NULL;
716                                         }
717                                         if (!ast_strlen_zero(xfersound) && !ast_streamfile(transferer, xfersound, transferer->language)) {
718                                                 if (ast_waitstream(transferer, "") < 0) {
719                                                         ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
720                                                 }
721                                         }
722                                         ast_moh_stop(transferee);
723                                         ast_autoservice_stop(transferee);
724                                         ast_indicate(transferee, AST_CONTROL_UNHOLD);
725                                         transferer->_softhangup = 0;
726                                         return FEATURE_RETURN_SUCCESS;
727                                 }
728                                 
729                                 res = ast_channel_make_compatible(transferee, newchan);
730                                 if (res < 0) {
731                                         ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", transferee->name, newchan->name);
732                                         ast_hangup(newchan);
733                                         return -1;
734                                 }
735                                 
736                                 
737                                 ast_moh_stop(transferee);
738                                 
739                                 if ((ast_autoservice_stop(transferee) < 0)
740                                    ||(ast_waitfordigit(transferee,100) < 0)
741                                    || (ast_waitfordigit(newchan,100) < 0) 
742                                    || ast_check_hangup(transferee) 
743                                    || ast_check_hangup(newchan)) {
744                                         ast_hangup(newchan);
745                                         res = -1;
746                                         return -1;
747                                 }
748
749                                 if ((xferchan = ast_channel_alloc(0))) {
750                                         snprintf(xferchan->name, sizeof (xferchan->name), "Transfered/%s",transferee->name);
751                                         /* Make formats okay */
752                                         xferchan->readformat = transferee->readformat;
753                                         xferchan->writeformat = transferee->writeformat;
754                                         ast_channel_masquerade(xferchan, transferee);
755                                         ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority);
756                                         xferchan->_state = AST_STATE_UP;
757                                         ast_clear_flag(xferchan, AST_FLAGS_ALL);        
758                                         xferchan->_softhangup = 0;
759
760                                         if ((f = ast_read(xferchan))) {
761                                                 ast_frfree(f);
762                                                 f = NULL;
763                                         }
764                                         
765                                 } else {
766                                         ast_hangup(newchan);
767                                         return -1;
768                                 }
769
770                                 newchan->_state = AST_STATE_UP;
771                                 ast_clear_flag(newchan, AST_FLAGS_ALL); 
772                                 newchan->_softhangup = 0;
773
774                                 tobj = malloc(sizeof(struct ast_bridge_thread_obj));
775                                 if (tobj) {
776                                         memset(tobj,0,sizeof(struct ast_bridge_thread_obj));
777                                         tobj->chan = xferchan;
778                                         tobj->peer = newchan;
779                                         tobj->bconfig = *config;
780         
781                                         if (!ast_strlen_zero(xfersound) && !ast_streamfile(newchan, xfersound, newchan->language)) {
782                                                 if (ast_waitstream(newchan, "") < 0) {
783                                                         ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
784                                                 }
785                                         }
786                                         ast_bridge_call_thread_launch(tobj);
787                                 } else {
788                                         ast_log(LOG_WARNING, "Out of memory!\n");
789                                         ast_hangup(xferchan);
790                                         ast_hangup(newchan);
791                                 }
792                                 return -1;
793                                 
794                         } else {
795                                 ast_log(LOG_WARNING, "Unable to create channel Local/%s do you have chan_local?\n",dialstr);
796                                 ast_moh_stop(transferee);
797                                 ast_autoservice_stop(transferee);
798                                 ast_indicate(transferee, AST_CONTROL_UNHOLD);
799                                 if (!ast_strlen_zero(xferfailsound)) {
800                                         res = ast_streamfile(transferer, xferfailsound, transferer->language);
801                                         if (!res && (ast_waitstream(transferer, "") < 0)) {
802                                                 return -1;
803                                         }
804                                 }
805                                 return -1;
806                         }
807                 } else {
808                         ast_log(LOG_WARNING, "Extension %s does not exist in context %s\n",xferto,transferer_real_context);
809                         ast_moh_stop(transferee);
810                         ast_autoservice_stop(transferee);
811                         ast_indicate(transferee, AST_CONTROL_UNHOLD);
812                         res = ast_streamfile(transferer, "beeperr", transferer->language);
813                         if (!res && (ast_waitstream(transferer, "") < 0)) {
814                                 return -1;
815                         }
816                 }
817         }  else {
818                 ast_log(LOG_WARNING, "Did not read data.\n");
819                 res = ast_streamfile(transferer, "beeperr", transferer->language);
820                 if (ast_waitstream(transferer, "") < 0) {
821                         return -1;
822                 }
823         }
824         ast_moh_stop(transferee);
825         ast_autoservice_stop(transferee);
826         ast_indicate(transferee, AST_CONTROL_UNHOLD);
827
828         return FEATURE_RETURN_SUCCESS;
829 }
830
831 struct ast_call_feature {
832         int feature_mask;
833         char *fname;
834         char *sname;
835         char exten[FEATURE_MAX_LEN];
836         char default_exten[FEATURE_MAX_LEN];
837         int (*operation)(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense);
838         unsigned int flags;
839 };
840
841 /* add atxfer and automon as undefined so you can only use em if you configure them */
842 #define FEATURES_COUNT (sizeof(builtin_features) / sizeof(builtin_features[0]))
843 struct ast_call_feature builtin_features[] = 
844 {
845         { AST_FEATURE_REDIRECT, "Blind Transfer", "blindxfer", "#", "#", builtin_blindtransfer, AST_FEATURE_FLAG_NEEDSDTMF },
846         { AST_FEATURE_REDIRECT, "Attended Transfer", "atxfer", "", "", builtin_atxfer, AST_FEATURE_FLAG_NEEDSDTMF },
847         { AST_FEATURE_AUTOMON, "One Touch Monitor", "automon", "", "", builtin_automonitor, AST_FEATURE_FLAG_NEEDSDTMF },
848         { AST_FEATURE_DISCONNECT, "Disconnect Call", "disconnect", "*", "*", builtin_disconnect, AST_FEATURE_FLAG_NEEDSDTMF },
849 };
850
851 static void unmap_features(void)
852 {
853         int x;
854         for (x=0;x<FEATURES_COUNT;x++)
855                 strcpy(builtin_features[x].exten, builtin_features[x].default_exten);
856 }
857
858 static int remap_feature(const char *name, const char *value)
859 {
860         int x;
861         int res = -1;
862         for (x=0;x<FEATURES_COUNT;x++) {
863                 if (!strcasecmp(name, builtin_features[x].sname)) {
864                         ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten));
865                         if (option_verbose > 1)
866                                 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);
867                         res = 0;
868                 } else if (!strcmp(value, builtin_features[x].exten)) 
869                         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);
870         }
871         return res;
872 }
873
874 static int ast_feature_interpret(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
875 {
876         int x;
877         struct ast_flags features;
878         int res = FEATURE_RETURN_PASSDIGITS;
879
880         if (sense == FEATURE_SENSE_CHAN)
881                 ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);   
882         else
883                 ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL);   
884         ast_log(LOG_DEBUG, "Feature interpret: chan=%s, peer=%s, sense=%d, features=%d\n", chan->name, peer->name, sense, features.flags);
885         for (x=0;x<FEATURES_COUNT;x++) {
886                 if ((ast_test_flag(&features, builtin_features[x].feature_mask)) &&
887                     !ast_strlen_zero(builtin_features[x].exten)) {
888                         /* Feature is up for consideration */
889                         if (!strcmp(builtin_features[x].exten, code)) {
890                                 res = builtin_features[x].operation(chan, peer, config, code, sense);
891                                 break;
892                         } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) {
893                                 if (res == FEATURE_RETURN_PASSDIGITS)
894                                         res = FEATURE_RETURN_STOREDIGITS;
895                         }
896                 }
897         }
898         return res;
899 }
900
901 static void set_config_flags(struct ast_bridge_config *config)
902 {
903         int x;
904         ast_clear_flag(config, AST_FLAGS_ALL);  
905         for (x=0;x<FEATURES_COUNT;x++) {
906                 if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask)) {
907                         if (ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF))
908                                 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
909                 }
910                 if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask)) {
911                         if (ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF))
912                                 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
913                 }
914         }
915 }
916
917 int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast_bridge_config *config)
918 {
919         /* Copy voice back and forth between the two channels.  Give the peer
920            the ability to transfer calls with '#<extension' syntax. */
921         struct ast_frame *f;
922         struct ast_channel *who;
923         char chan_featurecode[FEATURE_MAX_LEN + 1]="";
924         char peer_featurecode[FEATURE_MAX_LEN + 1]="";
925         int res;
926         int diff;
927         int hasfeatures=0;
928         int hadfeatures=0;
929         struct ast_option_header *aoh;
930         struct timeval start, end;
931         struct ast_bridge_config backup_config;
932         int allowdisconnect_in,allowdisconnect_out,allowredirect_in,allowredirect_out;
933         char *monitor_exec;
934
935         memset(&backup_config, 0, sizeof(backup_config));
936
937         if (chan && peer) {
938                 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
939                 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
940         } else if (chan)
941                 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
942
943         if (monitor_ok) {
944                 if (!monitor_app) { 
945                         if (!(monitor_app = pbx_findapp("Monitor")))
946                                 monitor_ok=0;
947                 }
948                 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 
949                         pbx_exec(chan, monitor_app, monitor_exec, 1);
950                 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
951                         pbx_exec(peer, monitor_app, monitor_exec, 1);
952         }
953         
954         allowdisconnect_in = ast_test_flag(&(config->features_callee), AST_FEATURE_DISCONNECT);
955         allowdisconnect_out = ast_test_flag(&(config->features_caller), AST_FEATURE_DISCONNECT);
956         allowredirect_in = ast_test_flag(&(config->features_callee), AST_FEATURE_REDIRECT);
957         allowredirect_out = ast_test_flag(&(config->features_caller), AST_FEATURE_REDIRECT);
958         set_config_flags(config);
959         config->firstpass = 1;
960
961         /* Answer if need be */
962         if (ast_answer(chan))
963                 return -1;
964         peer->appl = "Bridged Call";
965         peer->data = chan->name;
966         /* copy the userfield from the B-leg to A-leg if applicable */
967         if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) {
968                 char tmp[256];
969                 if (!ast_strlen_zero(chan->cdr->userfield)) {
970                         snprintf(tmp, sizeof(tmp), "%s;%s",chan->cdr->userfield, peer->cdr->userfield);
971                         ast_cdr_appenduserfield(chan, tmp);
972                 } else
973                         ast_cdr_setuserfield(chan, peer->cdr->userfield);
974                 /* free the peer's cdr without ast_cdr_free complaining */
975                 free(peer->cdr);
976                 peer->cdr = NULL;
977         }
978         for (;;) {
979                 if (config->timelimit)
980                         gettimeofday(&start, NULL);
981                 res = ast_channel_bridge(chan,peer,config,&f, &who);
982                 if (config->timelimit) {
983                         /* Update time limit for next pass */
984                         gettimeofday(&end, NULL);
985                         diff = (end.tv_sec - start.tv_sec) * 1000;
986                         diff += (end.tv_usec - start.tv_usec) / 1000;
987                         config->timelimit -= diff;
988                         if (hasfeatures) {
989                                 /* Running on backup config, meaning a feature might be being
990                                    activated, but that's no excuse to keep things going 
991                                    indefinitely! */
992                                 if (backup_config.timelimit && ((backup_config.timelimit -= diff) <= 0)) {
993                                         ast_log(LOG_DEBUG, "Timed out, realtime this time!\n");
994                                         config->timelimit = 0;
995                                         who = chan;
996                                         if (f)
997                                                 ast_frfree(f);
998                                         f = NULL;
999                                         res = 0;
1000                                 } else if (config->timelimit <= 0) {
1001                                         /* Not *really* out of time, just out of time for
1002                                            digits to come in for features. */
1003                                         ast_log(LOG_DEBUG, "Timed out for feature!\n");
1004                                         if (!ast_strlen_zero(peer_featurecode)) {
1005                                                 ast_dtmf_stream(chan, peer, peer_featurecode, 0);
1006                                                 memset(peer_featurecode, 0, sizeof(peer_featurecode));
1007                                         }
1008                                         if (!ast_strlen_zero(chan_featurecode)) {
1009                                                 ast_dtmf_stream(peer, chan, chan_featurecode, 0);
1010                                                 memset(chan_featurecode, 0, sizeof(chan_featurecode));
1011                                         }
1012                                         if (f)
1013                                                 ast_frfree(f);
1014                                         hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
1015                                         if (!hasfeatures) {
1016                                                 /* Restore original (possibly time modified) bridge config */
1017                                                 memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
1018                                                 memset(&backup_config, 0, sizeof(backup_config));
1019                                         }
1020                                         hadfeatures = hasfeatures;
1021                                         /* Continue as we were */
1022                                         continue;
1023                                 }
1024                         } else {
1025                                 if (config->timelimit <=0) {
1026                                         /* We ran out of time */
1027                                         config->timelimit = 0;
1028                                         who = chan;
1029                                         if (f)
1030                                                 ast_frfree(f);
1031                                         f = NULL;
1032                                         res = 0;
1033                                 }
1034                         }
1035                 }
1036                 if (res < 0) {
1037                         ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
1038                         return -1;
1039                 }
1040                 
1041                 if (!f || ((f->frametype == AST_FRAME_CONTROL) && ((f->subclass == AST_CONTROL_HANGUP) || (f->subclass == AST_CONTROL_BUSY) || 
1042                         (f->subclass == AST_CONTROL_CONGESTION)))) {
1043                                 res = -1;
1044                                 break;
1045                 }
1046                 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_RINGING)) {
1047                         if (who == chan)
1048                                 ast_indicate(peer, AST_CONTROL_RINGING);
1049                         else
1050                                 ast_indicate(chan, AST_CONTROL_RINGING);
1051                 }
1052                 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == -1)) {
1053                         if (who == chan)
1054                                 ast_indicate(peer, -1);
1055                         else
1056                                 ast_indicate(chan, -1);
1057                 }
1058                 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_FLASH)) {
1059                         if (who == chan)
1060                                 ast_indicate(peer, AST_CONTROL_FLASH);
1061                         else
1062                                 ast_indicate(chan, AST_CONTROL_FLASH);
1063                 }
1064                 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_OPTION)) {
1065                         aoh = f->data;
1066                         /* Forward option Requests */
1067                         if (aoh && (aoh->flag == AST_OPTION_FLAG_REQUEST)) {
1068                                 if (who == chan)
1069                                         ast_channel_setoption(peer, ntohs(aoh->option), aoh->data, f->datalen - sizeof(struct ast_option_header), 0);
1070                                 else
1071                                         ast_channel_setoption(chan, ntohs(aoh->option), aoh->data, f->datalen - sizeof(struct ast_option_header), 0);
1072                         }
1073                 }
1074                 /* check for '*', if we find it it's time to disconnect */
1075                 if (f && (f->frametype == AST_FRAME_DTMF)) {
1076                         char *featurecode;
1077                         int sense;
1078                         struct ast_channel *other;
1079                         hadfeatures = hasfeatures;
1080                         /* This cannot overrun because the longest feature is one shorter than our buffer */
1081                         if (who == chan) {
1082                                 other = peer;
1083                                 sense = FEATURE_SENSE_CHAN;
1084                                 featurecode = chan_featurecode;
1085                         } else  {
1086                                 other = chan;
1087                                 sense = FEATURE_SENSE_PEER;
1088                                 featurecode = peer_featurecode;
1089                         }
1090                         featurecode[strlen(featurecode)] = f->subclass;
1091                         config->timelimit = backup_config.timelimit;
1092                         res = ast_feature_interpret(chan, peer, config, featurecode, sense);
1093                         switch(res) {
1094                         case FEATURE_RETURN_PASSDIGITS:
1095                                 ast_dtmf_stream(other, who, featurecode, 0);
1096                                 /* Fall through */
1097                         case FEATURE_RETURN_SUCCESS:
1098                                 memset(featurecode, 0, sizeof(chan_featurecode));
1099                                 break;
1100                         }
1101                         if (res >= FEATURE_RETURN_PASSDIGITS) {
1102                                 res = 0;
1103                         } else {
1104                                 ast_frfree(f);
1105                                 break;
1106                         }
1107                         hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
1108                         if (hadfeatures && !hasfeatures) {
1109                                 /* Restore backup */
1110                                 memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
1111                                 memset(&backup_config, 0, sizeof(struct ast_bridge_config));
1112                         } else if (hasfeatures) {
1113                                 if (!hadfeatures) {
1114                                         /* Backup configuration */
1115                                         memcpy(&backup_config, config, sizeof(struct ast_bridge_config));
1116                                         /* Setup temporary config options */
1117                                         config->play_warning = 0;
1118                                         ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
1119                                         ast_clear_flag(&(config->features_callee),AST_FEATURE_PLAY_WARNING);
1120                                         config->warning_freq = 0;
1121                                         config->warning_sound = NULL;
1122                                         config->end_sound = NULL;
1123                                         config->start_sound = NULL;
1124                                         config->firstpass = 0;
1125                                 }
1126                                 config->timelimit = featuredigittimeout;
1127                                 ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->timelimit);
1128                         }
1129                 }
1130                 if (f)
1131                         ast_frfree(f);
1132         }
1133         return res;
1134 }
1135
1136 static void *do_parking_thread(void *ignore)
1137 {
1138         int ms, tms, max;
1139         struct parkeduser *pu, *pl, *pt = NULL;
1140         struct timeval tv;
1141         struct ast_frame *f;
1142         char exten[AST_MAX_EXTENSION];
1143         char *peername,*cp;
1144         char returnexten[AST_MAX_EXTENSION];
1145         struct ast_context *con;
1146         int x;
1147         fd_set rfds, efds;
1148         fd_set nrfds, nefds;
1149         FD_ZERO(&rfds);
1150         FD_ZERO(&efds);
1151
1152         for (;;) {
1153                 ms = -1;
1154                 max = -1;
1155                 ast_mutex_lock(&parking_lock);
1156                 pl = NULL;
1157                 pu = parkinglot;
1158                 FD_ZERO(&nrfds);
1159                 FD_ZERO(&nefds);
1160                 while(pu) {
1161                         if (pu->notquiteyet) {
1162                                 /* Pretend this one isn't here yet */
1163                                 pl = pu;
1164                                 pu = pu->next;
1165                                 continue;
1166                         }
1167                         gettimeofday(&tv, NULL);
1168                         tms = (tv.tv_sec - pu->start.tv_sec) * 1000 + (tv.tv_usec - pu->start.tv_usec) / 1000;
1169                         if (tms > pu->parkingtime) {
1170                                 /* Stop music on hold */
1171                                 ast_moh_stop(pu->chan);
1172                                 ast_indicate(pu->chan, AST_CONTROL_UNHOLD);
1173                                 /* Get chan, exten from derived kludge */
1174                                 if (pu->peername[0]) {
1175                                         peername = ast_strdupa(pu->peername);
1176                                         cp = strrchr(peername, '-');
1177                                         if (cp) 
1178                                                 *cp = 0;
1179                                         con = ast_context_find(parking_con_dial);
1180                                         if (!con) {
1181                                                 con = ast_context_create(NULL, parking_con_dial, registrar);
1182                                                 if (!con) {
1183                                                         ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial);
1184                                                 }
1185                                         }
1186                                         if (con) {
1187                                                 snprintf(returnexten, sizeof(returnexten), "%s||t", peername);
1188                                                 ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(returnexten), FREE, registrar);
1189                                         }
1190                                         ast_copy_string(pu->chan->exten, peername, sizeof(pu->chan->exten));
1191                                         ast_copy_string(pu->chan->context, parking_con_dial, sizeof(pu->chan->context));
1192                                         pu->chan->priority = 1;
1193
1194                                 } else {
1195                                         /* They've been waiting too long, send them back to where they came.  Theoretically they
1196                                            should have their original extensions and such, but we copy to be on the safe side */
1197                                         ast_copy_string(pu->chan->exten, pu->exten, sizeof(pu->chan->exten));
1198                                         ast_copy_string(pu->chan->context, pu->context, sizeof(pu->chan->context));
1199                                         pu->chan->priority = pu->priority;
1200                                 }
1201
1202                                 manager_event(EVENT_FLAG_CALL, "ParkedCallTimeOut",
1203                                         "Exten: %d\r\n"
1204                                         "Channel: %s\r\n"
1205                                         "CallerID: %s\r\n"
1206                                         "CallerIDName: %s\r\n\r\n"
1207                                         ,pu->parkingnum, pu->chan->name
1208                                         ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
1209                                         ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
1210                                         );
1211
1212                                 if (option_verbose > 1) 
1213                                         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);
1214                                 /* Start up the PBX, or hang them up */
1215                                 if (ast_pbx_start(pu->chan))  {
1216                                         ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", pu->chan->name);
1217                                         ast_hangup(pu->chan);
1218                                 }
1219                                 /* And take them out of the parking lot */
1220                                 if (pl) 
1221                                         pl->next = pu->next;
1222                                 else
1223                                         parkinglot = pu->next;
1224                                 pt = pu;
1225                                 pu = pu->next;
1226                                 con = ast_context_find(parking_con);
1227                                 if (con) {
1228                                         snprintf(exten, sizeof(exten), "%d", pt->parkingnum);
1229                                         if (ast_context_remove_extension2(con, exten, 1, NULL))
1230                                                 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
1231                                 } else
1232                                         ast_log(LOG_WARNING, "Whoa, no parking context?\n");
1233                                 free(pt);
1234                         } else {
1235                                 for (x=0; x<AST_MAX_FDS; x++) {
1236                                         if ((pu->chan->fds[x] > -1) && (FD_ISSET(pu->chan->fds[x], &rfds) || FD_ISSET(pu->chan->fds[x], &efds))) {
1237                                                 if (FD_ISSET(pu->chan->fds[x], &efds))
1238                                                         ast_set_flag(pu->chan, AST_FLAG_EXCEPTION);
1239                                                 else
1240                                                         ast_clear_flag(pu->chan, AST_FLAG_EXCEPTION);
1241                                                 pu->chan->fdno = x;
1242                                                 /* See if they need servicing */
1243                                                 f = ast_read(pu->chan);
1244                                                 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass ==  AST_CONTROL_HANGUP))) {
1245
1246                                                         manager_event(EVENT_FLAG_CALL, "ParkedCallGiveUp",
1247                                                                 "Exten: %d\r\n"
1248                                                                 "Channel: %s\r\n"
1249                                                                 "CallerID: %s\r\n"
1250                                                                 "CallerIDName: %s\r\n\r\n"
1251                                                                 ,pu->parkingnum, pu->chan->name
1252                                                                 ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
1253                                                                 ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
1254                                                                 );
1255
1256                                                         /* There's a problem, hang them up*/
1257                                                         if (option_verbose > 1) 
1258                                                                 ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being parked\n", pu->chan->name);
1259                                                         ast_hangup(pu->chan);
1260                                                         /* And take them out of the parking lot */
1261                                                         if (pl) 
1262                                                                 pl->next = pu->next;
1263                                                         else
1264                                                                 parkinglot = pu->next;
1265                                                         pt = pu;
1266                                                         pu = pu->next;
1267                                                         con = ast_context_find(parking_con);
1268                                                         if (con) {
1269                                                                 snprintf(exten, sizeof(exten), "%d", pt->parkingnum);
1270                                                                 if (ast_context_remove_extension2(con, exten, 1, NULL))
1271                                                                         ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
1272                                                         } else
1273                                                                 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
1274                                                         free(pt);
1275                                                         break;
1276                                                 } else {
1277                                                         /* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
1278                                                         ast_frfree(f);
1279                                                         if (pu->moh_trys < 3 && !pu->chan->generatordata) {
1280                                                                 ast_log(LOG_DEBUG, "MOH on parked call stopped by outside source.  Restarting.\n");
1281                                                                 ast_moh_start(pu->chan, NULL);
1282                                                                 pu->moh_trys++;
1283                                                         }
1284                                                         goto std;       /* XXX Ick: jumping into an else statement??? XXX */
1285                                                 }
1286                                         }
1287                                 }
1288                                 if (x >= AST_MAX_FDS) {
1289 std:                                    for (x=0; x<AST_MAX_FDS; x++) {
1290                                                 /* Keep this one for next one */
1291                                                 if (pu->chan->fds[x] > -1) {
1292                                                         FD_SET(pu->chan->fds[x], &nrfds);
1293                                                         FD_SET(pu->chan->fds[x], &nefds);
1294                                                         if (pu->chan->fds[x] > max)
1295                                                                 max = pu->chan->fds[x];
1296                                                 }
1297                                         }
1298                                         /* Keep track of our longest wait */
1299                                         if ((tms < ms) || (ms < 0))
1300                                                 ms = tms;
1301                                         pl = pu;
1302                                         pu = pu->next;
1303                                 }
1304                         }
1305                 }
1306                 ast_mutex_unlock(&parking_lock);
1307                 rfds = nrfds;
1308                 efds = nefds;
1309                 tv.tv_sec = ms / 1000;
1310                 tv.tv_usec = (ms % 1000) * 1000;
1311                 /* Wait for something to happen */
1312                 ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL);
1313                 pthread_testcancel();
1314         }
1315         return NULL;    /* Never reached */
1316 }
1317
1318 static int park_call_exec(struct ast_channel *chan, void *data)
1319 {
1320         /* Data is unused at the moment but could contain a parking
1321            lot context eventually */
1322         int res=0;
1323         struct localuser *u;
1324         LOCAL_USER_ADD(u);
1325         /* Setup the exten/priority to be s/1 since we don't know
1326            where this call should return */
1327         strcpy(chan->exten, "s");
1328         chan->priority = 1;
1329         if (chan->_state != AST_STATE_UP)
1330                 res = ast_answer(chan);
1331         if (!res)
1332                 res = ast_safe_sleep(chan, 1000);
1333         if (!res)
1334                 res = ast_park_call(chan, chan, 0, NULL);
1335         LOCAL_USER_REMOVE(u);
1336         if (!res)
1337                 res = AST_PBX_KEEPALIVE;
1338         return res;
1339 }
1340
1341 static int park_exec(struct ast_channel *chan, void *data)
1342 {
1343         int res=0;
1344         struct localuser *u;
1345         struct ast_channel *peer=NULL;
1346         struct parkeduser *pu, *pl=NULL;
1347         char exten[AST_MAX_EXTENSION];
1348         struct ast_context *con;
1349         int park;
1350         int dres;
1351         struct ast_bridge_config config;
1352
1353         if (!data) {
1354                 ast_log(LOG_WARNING, "Park requires an argument (extension number)\n");
1355                 return -1;
1356         }
1357         LOCAL_USER_ADD(u);
1358         park = atoi((char *)data);
1359         ast_mutex_lock(&parking_lock);
1360         pu = parkinglot;
1361         while(pu) {
1362                 if (pu->parkingnum == park) {
1363                         if (pl)
1364                                 pl->next = pu->next;
1365                         else
1366                                 parkinglot = pu->next;
1367                         break;
1368                 }
1369                 pl = pu;
1370                 pu = pu->next;
1371         }
1372         ast_mutex_unlock(&parking_lock);
1373         if (pu) {
1374                 peer = pu->chan;
1375                 con = ast_context_find(parking_con);
1376                 if (con) {
1377                         snprintf(exten, sizeof(exten), "%d", pu->parkingnum);
1378                         if (ast_context_remove_extension2(con, exten, 1, NULL))
1379                                 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
1380                 } else
1381                         ast_log(LOG_WARNING, "Whoa, no parking context?\n");
1382
1383                 manager_event(EVENT_FLAG_CALL, "UnParkedCall",
1384                         "Exten: %d\r\n"
1385                         "Channel: %s\r\n"
1386                         "From: %s\r\n"
1387                         "CallerID: %s\r\n"
1388                         "CallerIDName: %s\r\n\r\n"
1389                         ,pu->parkingnum, pu->chan->name, chan->name
1390                         ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
1391                         ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
1392                         );
1393
1394                 free(pu);
1395         }
1396         /* JK02: it helps to answer the channel if not already up */
1397         if (chan->_state != AST_STATE_UP) {
1398                 ast_answer(chan);
1399         }
1400
1401         if (peer) {
1402                 /* Play a courtesy beep in the calling channel to prefix the bridge connecting */       
1403                 if (!ast_strlen_zero(courtesytone)) {
1404                         if (!ast_streamfile(chan, courtesytone, chan->language)) {
1405                                 if (ast_waitstream(chan, "") < 0) {
1406                                         ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
1407                                         ast_hangup(peer);
1408                                         return -1;
1409                                 }
1410                         }
1411                 }
1412  
1413                 ast_moh_stop(peer);
1414                 ast_indicate(peer, AST_CONTROL_UNHOLD);
1415                 res = ast_channel_make_compatible(chan, peer);
1416                 if (res < 0) {
1417                         ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
1418                         ast_hangup(peer);
1419                         return -1;
1420                 }
1421                 /* This runs sorta backwards, since we give the incoming channel control, as if it
1422                    were the person called. */
1423                 if (option_verbose > 2) 
1424                         ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to parked call %d\n", chan->name, park);
1425
1426                 memset(&config,0,sizeof(struct ast_bridge_config));
1427                 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
1428                 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
1429                 config.timelimit = 0;
1430                 config.play_warning = 0;
1431                 config.warning_freq = 0;
1432                 config.warning_sound=NULL;
1433                 res = ast_bridge_call(chan,peer,&config);
1434
1435                 /* Simulate the PBX hanging up */
1436                 if (res != AST_PBX_NO_HANGUP_PEER)
1437                         ast_hangup(peer);
1438                 return res;
1439         } else {
1440                 /* XXX Play a message XXX */
1441                 dres = ast_streamfile(chan, "pbx-invalidpark", chan->language);
1442                 if (!dres)
1443                         dres = ast_waitstream(chan, "");
1444                  else {
1445                         ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
1446                         dres = 0;
1447                 }
1448                 if (option_verbose > 2) 
1449                         ast_verbose(VERBOSE_PREFIX_3 "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park);
1450                 res = -1;
1451         }
1452         LOCAL_USER_REMOVE(u);
1453         return res;
1454 }
1455
1456 static int handle_showfeatures(int fd, int argc, char *argv[])
1457 {
1458         int i;
1459         int fcount;
1460         char format[] = "%-25s %-7s %-7s\n";
1461
1462         ast_cli(fd, format, "Feature", "Default", "Current");
1463         ast_cli(fd, format, "-------", "-------", "-------");
1464
1465         ast_cli(fd, format, "Pickup", "*8", ast_pickup_ext());          /* default hardcoded above, so we'll hardcode it here */
1466
1467         fcount = sizeof(builtin_features) / sizeof(builtin_features[0]);
1468
1469         for (i = 0; i < fcount; i++)
1470         {
1471                 ast_cli(fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
1472         }
1473
1474         return RESULT_SUCCESS;
1475 }
1476
1477 static char showfeatures_help[] =
1478 "Usage: show features\n"
1479 "       Lists currently configured features.\n";
1480
1481 static struct ast_cli_entry showfeatures =
1482 { { "show", "features", NULL }, handle_showfeatures, "Lists configured features", showfeatures_help };
1483
1484 static int handle_parkedcalls(int fd, int argc, char *argv[])
1485 {
1486         struct parkeduser *cur;
1487         int numparked = 0;
1488
1489         ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
1490                 , "Context", "Extension", "Pri", "Timeout");
1491
1492         ast_mutex_lock(&parking_lock);
1493
1494         cur = parkinglot;
1495         while(cur) {
1496                 ast_cli(fd, "%4d %25s (%-15s %-12s %-4d) %6lds\n"
1497                         ,cur->parkingnum, cur->chan->name, cur->context, cur->exten
1498                         ,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL));
1499
1500                 cur = cur->next;
1501                 numparked++;
1502         }
1503         ast_cli(fd, "%d parked call(s).\n",numparked);
1504
1505         ast_mutex_unlock(&parking_lock);
1506
1507         return RESULT_SUCCESS;
1508 }
1509
1510 static char showparked_help[] =
1511 "Usage: show parkedcalls\n"
1512 "       Lists currently parked calls.\n";
1513
1514 static struct ast_cli_entry showparked =
1515 { { "show", "parkedcalls", NULL }, handle_parkedcalls, "Lists parked calls", showparked_help };
1516 /* Dump lot status */
1517 static int manager_parking_status( struct mansession *s, struct message *m )
1518 {
1519         struct parkeduser *cur;
1520         char *id = astman_get_header(m,"ActionID");
1521         char idText[256] = "";
1522
1523         if (id && !ast_strlen_zero(id))
1524                 snprintf(idText,256,"ActionID: %s\r\n",id);
1525
1526         astman_send_ack(s, m, "Parked calls will follow");
1527
1528         ast_mutex_lock(&parking_lock);
1529
1530         cur=parkinglot;
1531         while(cur) {
1532                         ast_mutex_lock(&s->lock);
1533                 ast_cli(s->fd, "Event: ParkedCall\r\n"
1534                         "Exten: %d\r\n"
1535                         "Channel: %s\r\n"
1536                         "Timeout: %ld\r\n"
1537                         "CallerID: %s\r\n"
1538                         "CallerIDName: %s\r\n"
1539                         "%s"
1540                         "\r\n"
1541                         ,cur->parkingnum, cur->chan->name
1542                         ,(long)cur->start.tv_sec + (long)(cur->parkingtime/1000) - (long)time(NULL)
1543                         ,(cur->chan->cid.cid_num ? cur->chan->cid.cid_num : "")
1544                         ,(cur->chan->cid.cid_name ? cur->chan->cid.cid_name : "")
1545                         ,idText);
1546                         ast_mutex_unlock(&s->lock);
1547
1548             cur = cur->next;
1549         }
1550
1551         ast_cli(s->fd,
1552         "Event: ParkedCallsComplete\r\n"
1553         "%s"
1554         "\r\n",idText);
1555
1556         ast_mutex_unlock(&parking_lock);
1557
1558         return RESULT_SUCCESS;
1559 }
1560
1561
1562 static int load_config(void) 
1563 {
1564         int start = 0, end = 0;
1565         struct ast_context *con = NULL;
1566         struct ast_config *cfg = NULL;
1567         struct ast_variable *var = NULL;
1568         
1569         transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
1570         featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
1571
1572         cfg = ast_config_load("features.conf");
1573         if (!cfg) {
1574                 cfg = ast_config_load("parking.conf");
1575                 if (cfg)
1576                         ast_log(LOG_NOTICE, "parking.conf is deprecated in favor of 'features.conf'.  Please rename it.\n");
1577         }
1578         if (cfg) {
1579                 var = ast_variable_browse(cfg, "general");
1580                 while(var) {
1581                         if (!strcasecmp(var->name, "parkext")) {
1582                                 ast_copy_string(parking_ext, var->value, sizeof(parking_ext));
1583                         } else if (!strcasecmp(var->name, "context")) {
1584                                 ast_copy_string(parking_con, var->value, sizeof(parking_con));
1585                         } else if (!strcasecmp(var->name, "parkingtime")) {
1586                                 if ((sscanf(var->value, "%d", &parkingtime) != 1) || (parkingtime < 1)) {
1587                                         ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value);
1588                                         parkingtime = DEFAULT_PARK_TIME;
1589                                 } else
1590                                         parkingtime = parkingtime * 1000;
1591                         } else if (!strcasecmp(var->name, "parkpos")) {
1592                                 if (sscanf(var->value, "%d-%d", &start, &end) != 2) {
1593                                         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);
1594                                 } else {
1595                                         parking_start = start;
1596                                         parking_stop = end;
1597                                 }
1598                         } else if (!strcasecmp(var->name, "findslot")) {
1599                                 parkfindnext = (!strcasecmp(var->value, "next"));
1600                         } else if (!strcasecmp(var->name, "adsipark")) {
1601                                 adsipark = ast_true(var->value);
1602                         } else if (!strcasecmp(var->name, "transferdigittimeout")) {
1603                                 if ((sscanf(var->value, "%d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) {
1604                                         ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value);
1605                                         transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
1606                                 } else
1607                                         transferdigittimeout = transferdigittimeout * 1000;
1608                         } else if (!strcasecmp(var->name, "featuredigittimeout")) {
1609                                 if ((sscanf(var->value, "%d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) {
1610                                         ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value);
1611                                         featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
1612                                 }
1613                         } else if (!strcasecmp(var->name, "courtesytone")) {
1614                                 ast_copy_string(courtesytone, var->value, sizeof(courtesytone));
1615                         } else if (!strcasecmp(var->name, "xfersound")) {
1616                                 ast_copy_string(xfersound, var->value, sizeof(xfersound));
1617                         } else if (!strcasecmp(var->name, "xferfailsound")) {
1618                                 ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound));
1619                         } else if (!strcasecmp(var->name, "pickupexten")) {
1620                                 ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext));
1621                         }
1622                         var = var->next;
1623                 }
1624                 unmap_features();
1625                 var = ast_variable_browse(cfg, "featuremap");
1626                 while(var) {
1627                         if (remap_feature(var->name, var->value))
1628                                 ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name);
1629                         var = var->next;
1630                 }
1631                 ast_config_destroy(cfg);
1632         }
1633         
1634         if (con)
1635                 ast_context_remove_extension2(con, ast_parking_ext(), 1, registrar);
1636         
1637         if (!(con = ast_context_find(parking_con))) {
1638                 if (!(con = ast_context_create(NULL, parking_con, registrar))) {
1639                         ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
1640                         return -1;
1641                 }
1642         }
1643         return ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, strdup(""), FREE, registrar);
1644 }
1645
1646 int reload(void) {
1647         return load_config();
1648 }
1649
1650 int load_module(void)
1651 {
1652         int res;
1653         if ((res = load_config()))
1654                 return res;
1655         ast_cli_register(&showparked);
1656         ast_cli_register(&showfeatures);
1657         ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
1658         res = ast_register_application(parkedcall, park_exec, synopsis, descrip);
1659         if (!res)
1660                 res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2);
1661         if (!res) {
1662                 ast_manager_register( "ParkedCalls", 0, manager_parking_status, "List parked calls" );
1663         }
1664         return res;
1665 }
1666
1667 int ast_pickup_call(struct ast_channel *chan)
1668 {
1669         struct ast_channel *cur = NULL;
1670         int res = -1;
1671         while ( (cur = ast_channel_walk_locked(cur)) != NULL) {
1672                 if (!cur->pbx && 
1673                         (cur != chan) &&
1674                         (chan->pickupgroup & cur->callgroup) &&
1675                         ((cur->_state == AST_STATE_RINGING) ||
1676                          (cur->_state == AST_STATE_RING))) {
1677                                 break;
1678                 }
1679                 ast_mutex_unlock(&cur->lock);
1680         }
1681         if (cur) {
1682                 if (option_debug)
1683                         ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
1684                 res = ast_answer(chan);
1685                 if (res)
1686                         ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
1687                 res = ast_queue_control(chan, AST_CONTROL_ANSWER);
1688                 if (res)
1689                         ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
1690                 res = ast_channel_masquerade(cur, chan);
1691                 if (res)
1692                         ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name);           /* Done */
1693                 ast_mutex_unlock(&cur->lock);
1694         } else  {
1695                 if (option_debug)
1696                         ast_log(LOG_DEBUG, "No call pickup possible...\n");
1697         }
1698         return res;
1699 }
1700
1701 int unload_module(void)
1702 {
1703         STANDARD_HANGUP_LOCALUSERS;
1704
1705         ast_manager_unregister( "ParkedCalls" );
1706         ast_cli_unregister(&showfeatures);
1707         ast_cli_unregister(&showparked);
1708         ast_unregister_application(parkcall);
1709         return ast_unregister_application(parkedcall);
1710 }
1711
1712 char *description(void)
1713 {
1714         return "Call Parking Resource";
1715 }
1716
1717 int usecount(void)
1718 {
1719         /* Never allow parking to be unloaded because it will
1720            unresolve needed symbols in the dialer */
1721 #if 0
1722         int res;
1723         STANDARD_USECOUNT(res);
1724         return res;
1725 #else
1726         return 1;
1727 #endif
1728 }
1729
1730 char *key()
1731 {
1732         return ASTERISK_GPL_KEY;
1733 }