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