Fix features + astmm interaction (bug #4217)
[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                                 strncpy(pu->peername,peer->name,sizeof(pu->peername) - 1);
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                                 strncpy(pu->context, chan->macrocontext, sizeof(pu->context)-1);
302                         else
303                                 strncpy(pu->context, chan->context, sizeof(pu->context)-1);
304                         if (!ast_strlen_zero(chan->macroexten))
305                                 strncpy(pu->exten, chan->macroexten, sizeof(pu->exten)-1);
306                         else
307                                 strncpy(pu->exten, chan->exten, sizeof(pu->exten)-1);
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                 strncpy(chan->context, rchan->context, sizeof(chan->context) - 1);
391                 strncpy(chan->exten, rchan->exten, sizeof(chan->exten) - 1);
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;
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_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR");
469                 if (!touch_monitor)
470                         touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR");
471                 
472                 if (touch_monitor) {
473                         len = strlen(touch_monitor) + 50;
474                         args = alloca(len);
475                         snprintf(args, len, "WAV|auto-%ld-%s|m", time(NULL), touch_monitor);
476                 } else {
477                         caller_chan_id = ast_strdupa(caller_chan->cid.cid_num ? caller_chan->cid.cid_num : caller_chan->name);
478                         callee_chan_id = ast_strdupa(callee_chan->cid.cid_num ? callee_chan->cid.cid_num : callee_chan->name);
479                         len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50;
480                         args = alloca(len);
481                         snprintf(args, len, "WAV|auto-%ld-%s-%s|m", time(NULL), caller_chan_id, callee_chan_id);
482                 }
483
484                 for( x = 0; x < strlen(args); x++)
485                         if (args[x] == '/')
486                                 args[x] = '-';
487                 
488                 if (option_verbose > 3)
489                         ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to record call. filename: %s\n", code, args);
490
491                 pbx_exec(callee_chan, monitor_app, args, 1);
492                 
493                 return FEATURE_RETURN_SUCCESS;
494         }
495         
496         ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n");   
497         return -1;
498 }
499
500 static int builtin_disconnect(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
501 {
502         if (option_verbose > 3)
503                 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to disconnect call.\n", code);
504         return FEATURE_RETURN_HANGUP;
505 }
506
507 static int builtin_blindtransfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
508 {
509         struct ast_channel *transferer;
510         struct ast_channel *transferee;
511         char *transferer_real_context;
512         char newext[256];
513         int res;
514
515         if (sense == FEATURE_SENSE_PEER) {
516                 transferer = peer;
517                 transferee = chan;
518         } else {
519                 transferer = chan;
520                 transferee = peer;
521         }
522         if (!(transferer_real_context=pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT")) &&
523            !(transferer_real_context=pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT"))) {
524                 /* Use the non-macro context to transfer the call */
525                 if (!ast_strlen_zero(transferer->macrocontext))
526                         transferer_real_context = transferer->macrocontext;
527                 else
528                         transferer_real_context = transferer->context;
529         }
530         /* Start autoservice on chan while we talk
531            to the originator */
532         ast_indicate(transferee, AST_CONTROL_HOLD);
533         ast_autoservice_start(transferee);
534         ast_moh_start(transferee, NULL);
535
536         memset(newext, 0, sizeof(newext));
537         
538         /* Transfer */
539         if ((res=ast_streamfile(transferer, "pbx-transfer", transferer->language))) {
540                 ast_moh_stop(transferee);
541                 ast_autoservice_stop(transferee);
542                 ast_indicate(transferee, AST_CONTROL_UNHOLD);
543                 return res;
544         }
545         if ((res=ast_waitstream(transferer, AST_DIGIT_ANY)) < 0) {
546                 ast_moh_stop(transferee);
547                 ast_autoservice_stop(transferee);
548                 ast_indicate(transferee, AST_CONTROL_UNHOLD);
549                 return res;
550         } else if (res > 0) {
551                 /* If they've typed a digit already, handle it */
552                 newext[0] = (char) res;
553         }
554
555         ast_stopstream(transferer);
556         res = ast_app_dtget(transferer, transferer_real_context, newext, sizeof(newext), 100, transferdigittimeout);
557         if (res < 0) {
558                 ast_moh_stop(transferee);
559                 ast_autoservice_stop(transferee);
560                 ast_indicate(transferee, AST_CONTROL_UNHOLD);
561                 return res;
562         }
563         if (!strcmp(newext, ast_parking_ext())) {
564                 ast_moh_stop(transferee);
565
566                 res = ast_autoservice_stop(transferee);
567                 ast_indicate(transferee, AST_CONTROL_UNHOLD);
568                 if (res)
569                         res = -1;
570                 else if (!ast_park_call(transferee, transferer, 0, NULL)) {
571                         /* We return non-zero, but tell the PBX not to hang the channel when
572                            the thread dies -- We have to be careful now though.  We are responsible for 
573                            hanging up the channel, else it will never be hung up! */
574
575                         if (transferer==peer)
576                                 res=AST_PBX_KEEPALIVE;
577                         else
578                                 res=AST_PBX_NO_HANGUP_PEER;
579                         return res;
580                 } else {
581                         ast_log(LOG_WARNING, "Unable to park call %s\n", transferee->name);
582                 }
583                 /* XXX Maybe we should have another message here instead of invalid extension XXX */
584         } else if (ast_exists_extension(transferee, transferer_real_context, newext, 1, transferer->cid.cid_num)) {
585                 pbx_builtin_setvar_helper(peer, "BLINDTRANSFER", chan->name);
586                 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", peer->name);
587                 ast_moh_stop(transferee);
588                 res=ast_autoservice_stop(transferee);
589                 ast_indicate(transferee, AST_CONTROL_UNHOLD);
590                 if (!transferee->pbx) {
591                         /* Doh!  Use our handy async_goto functions */
592                         if (option_verbose > 2) 
593                                 ast_verbose(VERBOSE_PREFIX_3 "Transferring %s to '%s' (context %s) priority 1\n"
594                                                                 ,transferee->name, newext, transferer_real_context);
595                         if (ast_async_goto(transferee, transferer_real_context, newext, 1))
596                                 ast_log(LOG_WARNING, "Async goto failed :-(\n");
597                         res = -1;
598                 } else {
599                         /* Set the channel's new extension, since it exists, using transferer context */
600                         strncpy(transferee->exten, newext, sizeof(transferee->exten)-1);
601                         strncpy(transferee->context, transferer_real_context, sizeof(transferee->context)-1);
602                         transferee->priority = 0;
603                 }
604                 check_goto_on_transfer(transferer);
605                 return res;
606         } else {
607                 if (option_verbose > 2) 
608                         ast_verbose(VERBOSE_PREFIX_3 "Unable to find extension '%s' in context '%s'\n", newext, transferer_real_context);
609         }
610         if (!ast_strlen_zero(xferfailsound))
611                 res = ast_streamfile(transferer, xferfailsound, transferee->language);
612         else
613                 res = 0;
614         if (res) {
615                 ast_moh_stop(transferee);
616                 ast_autoservice_stop(transferee);
617                 ast_indicate(transferee, AST_CONTROL_UNHOLD);
618                 return res;
619         }
620         res = ast_waitstream(transferer, AST_DIGIT_ANY);
621         ast_stopstream(transferer);
622         ast_moh_stop(transferee);
623         res = ast_autoservice_stop(transferee);
624         ast_indicate(transferee, AST_CONTROL_UNHOLD);
625         if (res) {
626                 if (option_verbose > 1)
627                         ast_verbose(VERBOSE_PREFIX_2 "Hungup during autoservice stop on '%s'\n", transferee->name);
628                 return res;
629         }
630         return FEATURE_RETURN_SUCCESS;
631 }
632
633 static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
634 {
635         struct ast_channel *transferer;
636         struct ast_channel *transferee;
637         struct ast_channel *newchan, *xferchan=NULL;
638         int outstate=0;
639         struct ast_bridge_config bconfig;
640         char *transferer_real_context;
641         char xferto[256],dialstr[265];
642         char *cid_num;
643         char *cid_name;
644         int res;
645         struct ast_frame *f = NULL;
646         struct ast_bridge_thread_obj *tobj;
647
648         ast_log(LOG_DEBUG, "Executing Attended Transfer %s, %s (sense=%d) XXX\n", chan->name, peer->name, sense);
649         if (sense == FEATURE_SENSE_PEER) {
650                 transferer = peer;
651                 transferee = chan;
652         } else {
653                 transferer = chan;
654                 transferee = peer;
655         }
656         if (!(transferer_real_context=pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT")) &&
657            !(transferer_real_context=pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT"))) {
658                 /* Use the non-macro context to transfer the call */
659                 if (!ast_strlen_zero(transferer->macrocontext))
660                         transferer_real_context = transferer->macrocontext;
661                 else
662                         transferer_real_context = transferer->context;
663         }
664         /* Start autoservice on chan while we talk
665            to the originator */
666         ast_indicate(transferee, AST_CONTROL_HOLD);
667         ast_autoservice_start(transferee);
668         ast_moh_start(transferee, NULL);
669         memset(xferto, 0, sizeof(xferto));
670         /* Transfer */
671         if ((res=ast_streamfile(transferer, "pbx-transfer", transferer->language))) {
672                 ast_moh_stop(transferee);
673                 ast_autoservice_stop(transferee);
674                 ast_indicate(transferee, AST_CONTROL_UNHOLD);
675                 return res;
676         }
677         if ((res=ast_waitstream(transferer, AST_DIGIT_ANY)) < 0) {
678                 ast_moh_stop(transferee);
679                 ast_autoservice_stop(transferee);
680                 ast_indicate(transferee, AST_CONTROL_UNHOLD);
681                 return res;
682         } else if(res > 0) {
683                 /* If they've typed a digit already, handle it */
684                 xferto[0] = (char) res;
685         }
686         if ((ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout))) {
687                 cid_num = transferer->cid.cid_num;
688                 cid_name = transferer->cid.cid_name;
689                 if (ast_exists_extension(transferer, transferer_real_context,xferto, 1, cid_num)) {
690                         snprintf(dialstr, sizeof(dialstr), "%s@%s/n", xferto, transferer_real_context);
691                         if ((newchan = ast_request_and_dial("Local", ast_best_codec(transferer->nativeformats), dialstr,30000, &outstate, cid_num, cid_name))) {
692                                 res = ast_channel_make_compatible(transferer, newchan);
693                                 if (res < 0) {
694                                         ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", transferer->name, newchan->name);
695                                         ast_hangup(newchan);
696                                         return -1;
697                                 }
698                                 memset(&bconfig,0,sizeof(struct ast_bridge_config));
699                                 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
700                                 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
701                                 res = ast_bridge_call(transferer,newchan,&bconfig);
702                                 if (newchan->_softhangup || newchan->_state != AST_STATE_UP) {
703                                         ast_hangup(newchan);
704                                         if (f) {
705                                                 ast_frfree(f);
706                                                 f = NULL;
707                                         }
708                                         if (!ast_strlen_zero(xfersound) && !ast_streamfile(transferer, xfersound, transferer->language)) {
709                                                 if (ast_waitstream(transferer, "") < 0) {
710                                                         ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
711                                                 }
712                                         }
713                                         ast_moh_stop(transferee);
714                                         ast_autoservice_stop(transferee);
715                                         ast_indicate(transferee, AST_CONTROL_UNHOLD);
716                                         transferer->_softhangup = 0;
717                                         return FEATURE_RETURN_SUCCESS;
718                                 }
719                                 
720                                 res = ast_channel_make_compatible(transferee, newchan);
721                                 if (res < 0) {
722                                         ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", transferee->name, newchan->name);
723                                         ast_hangup(newchan);
724                                         return -1;
725                                 }
726                                 
727                                 
728                                 ast_moh_stop(transferee);
729                                 
730                                 if ((ast_autoservice_stop(transferee) < 0)
731                                    ||(ast_waitfordigit(transferee,100) < 0)
732                                    || (ast_waitfordigit(newchan,100) < 0) 
733                                    || ast_check_hangup(transferee) 
734                                    || ast_check_hangup(newchan)) {
735                                         ast_hangup(newchan);
736                                         res = -1;
737                                         return -1;
738                                 }
739
740                                 if ((xferchan = ast_channel_alloc(0))) {
741                                         snprintf(xferchan->name, sizeof (xferchan->name), "Transfered/%s",transferee->name);
742                                         /* Make formats okay */
743                                         xferchan->readformat = transferee->readformat;
744                                         xferchan->writeformat = transferee->writeformat;
745                                         ast_channel_masquerade(xferchan, transferee);
746                                         ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority);
747                                         xferchan->_state = AST_STATE_UP;
748                                         ast_clear_flag(xferchan, AST_FLAGS_ALL);        
749                                         xferchan->_softhangup = 0;
750
751                                         if ((f = ast_read(xferchan))) {
752                                                 ast_frfree(f);
753                                                 f = NULL;
754                                         }
755                                         
756                                 } else {
757                                         ast_hangup(newchan);
758                                         return -1;
759                                 }
760
761                                 newchan->_state = AST_STATE_UP;
762                                 ast_clear_flag(newchan, AST_FLAGS_ALL); 
763                                 newchan->_softhangup = 0;
764
765                                 tobj = malloc(sizeof(struct ast_bridge_thread_obj));
766                                 if (tobj) {
767                                         memset(tobj,0,sizeof(struct ast_bridge_thread_obj));
768                                         tobj->chan = xferchan;
769                                         tobj->peer = newchan;
770                                         tobj->bconfig = *config;
771         
772                                         if (!ast_strlen_zero(xfersound) && !ast_streamfile(newchan, xfersound, newchan->language)) {
773                                                 if (ast_waitstream(newchan, "") < 0) {
774                                                         ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
775                                                 }
776                                         }
777                                         ast_bridge_call_thread_launch(tobj);
778                                 } else {
779                                         ast_log(LOG_WARNING, "Out of memory!\n");
780                                         ast_hangup(xferchan);
781                                         ast_hangup(newchan);
782                                 }
783                                 return -1;
784                                 
785                         } else {
786                                 ast_log(LOG_WARNING, "Unable to create channel Local/%s do you have chan_local?\n",dialstr);
787                                 ast_moh_stop(transferee);
788                                 ast_autoservice_stop(transferee);
789                                 ast_indicate(transferee, AST_CONTROL_UNHOLD);
790                                 if (!ast_strlen_zero(xferfailsound)) {
791                                         res = ast_streamfile(transferer, xferfailsound, transferer->language);
792                                         if (!res && (ast_waitstream(transferer, "") < 0)) {
793                                                 return -1;
794                                         }
795                                 }
796                                 return -1;
797                         }
798                 } else {
799                         ast_log(LOG_WARNING, "Extension %s does not exist in context %s\n",xferto,transferer_real_context);
800                         ast_moh_stop(transferee);
801                         ast_autoservice_stop(transferee);
802                         ast_indicate(transferee, AST_CONTROL_UNHOLD);
803                         res = ast_streamfile(transferer, "beeperr", transferer->language);
804                         if (!res && (ast_waitstream(transferer, "") < 0)) {
805                                 return -1;
806                         }
807                 }
808         }  else {
809                 ast_log(LOG_WARNING, "Did not read data.\n");
810                 res = ast_streamfile(transferer, "beeperr", transferer->language);
811                 if (ast_waitstream(transferer, "") < 0) {
812                         return -1;
813                 }
814         }
815         ast_moh_stop(transferee);
816         ast_autoservice_stop(transferee);
817         ast_indicate(transferee, AST_CONTROL_UNHOLD);
818
819         return FEATURE_RETURN_SUCCESS;
820 }
821
822 struct ast_call_feature {
823         int feature_mask;
824         char *fname;
825         char *sname;
826         char exten[FEATURE_MAX_LEN];
827         char default_exten[FEATURE_MAX_LEN];
828         int (*operation)(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense);
829         unsigned int flags;
830 };
831
832 /* add atxfer and automon as undefined so you can only use em if you configure them */
833 #define FEATURES_COUNT (sizeof(builtin_features) / sizeof(builtin_features[0]))
834 struct ast_call_feature builtin_features[] = 
835 {
836         { AST_FEATURE_REDIRECT, "Blind Transfer", "blindxfer", "#", "#", builtin_blindtransfer, AST_FEATURE_FLAG_NEEDSDTMF },
837         { AST_FEATURE_REDIRECT, "Attended Transfer", "atxfer", "", "", builtin_atxfer, AST_FEATURE_FLAG_NEEDSDTMF },
838         { AST_FEATURE_AUTOMON, "One Touch Monitor", "automon", "", "", builtin_automonitor, AST_FEATURE_FLAG_NEEDSDTMF },
839         { AST_FEATURE_DISCONNECT, "Disconnect Call", "disconnect", "*", "*", builtin_disconnect, AST_FEATURE_FLAG_NEEDSDTMF },
840 };
841
842 static void unmap_features(void)
843 {
844         int x;
845         for (x=0;x<FEATURES_COUNT;x++)
846                 strcpy(builtin_features[x].exten, builtin_features[x].default_exten);
847 }
848
849 static int remap_feature(const char *name, const char *value)
850 {
851         int x;
852         int res = -1;
853         for (x=0;x<FEATURES_COUNT;x++) {
854                 if (!strcasecmp(name, builtin_features[x].sname)) {
855                         strncpy(builtin_features[x].exten, value, sizeof(builtin_features[x].exten) - 1);
856                         if (option_verbose > 1)
857                                 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);
858                         res = 0;
859                 } else if (!strcmp(value, builtin_features[x].exten)) 
860                         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);
861         }
862         return res;
863 }
864
865 static int ast_feature_interpret(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
866 {
867         int x;
868         struct ast_flags features;
869         int res = FEATURE_RETURN_PASSDIGITS;
870
871         if (sense == FEATURE_SENSE_CHAN)
872                 ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);   
873         else
874                 ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL);   
875         ast_log(LOG_DEBUG, "Feature interpret: chan=%s, peer=%s, sense=%d, features=%d\n", chan->name, peer->name, sense, features.flags);
876         for (x=0;x<FEATURES_COUNT;x++) {
877                 if ((ast_test_flag(&features, builtin_features[x].feature_mask)) &&
878                     !ast_strlen_zero(builtin_features[x].exten)) {
879                         /* Feature is up for consideration */
880                         if (!strcmp(builtin_features[x].exten, code)) {
881                                 res = builtin_features[x].operation(chan, peer, config, code, sense);
882                                 break;
883                         } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) {
884                                 if (res == FEATURE_RETURN_PASSDIGITS)
885                                         res = FEATURE_RETURN_STOREDIGITS;
886                         }
887                 }
888         }
889         return res;
890 }
891
892 static void set_config_flags(struct ast_bridge_config *config)
893 {
894         int x;
895         ast_clear_flag(config, AST_FLAGS_ALL);  
896         for (x=0;x<FEATURES_COUNT;x++) {
897                 if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask)) {
898                         if (ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF))
899                                 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
900                 }
901                 if (ast_test_flag(&(config->features_callee), 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_1);
904                 }
905         }
906 }
907
908 int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast_bridge_config *config)
909 {
910         /* Copy voice back and forth between the two channels.  Give the peer
911            the ability to transfer calls with '#<extension' syntax. */
912         struct ast_frame *f;
913         struct ast_channel *who;
914         char chan_featurecode[FEATURE_MAX_LEN + 1]="";
915         char peer_featurecode[FEATURE_MAX_LEN + 1]="";
916         int res;
917         int diff;
918         int hasfeatures=0;
919         int hadfeatures=0;
920         struct ast_option_header *aoh;
921         struct timeval start, end;
922         struct ast_bridge_config backup_config;
923         int allowdisconnect_in,allowdisconnect_out,allowredirect_in,allowredirect_out;
924         char *monitor_exec;
925
926         memset(&backup_config, 0, sizeof(backup_config));
927
928         if (chan && peer) {
929                 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
930                 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
931         } else if (chan)
932                 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
933
934         if (monitor_ok) {
935                 if (!monitor_app) { 
936                         if (!(monitor_app = pbx_findapp("Monitor")))
937                                 monitor_ok=0;
938                 }
939                 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 
940                         pbx_exec(chan, monitor_app, monitor_exec, 1);
941                 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
942                         pbx_exec(peer, monitor_app, monitor_exec, 1);
943         }
944         
945         allowdisconnect_in = ast_test_flag(&(config->features_callee), AST_FEATURE_DISCONNECT);
946         allowdisconnect_out = ast_test_flag(&(config->features_caller), AST_FEATURE_DISCONNECT);
947         allowredirect_in = ast_test_flag(&(config->features_callee), AST_FEATURE_REDIRECT);
948         allowredirect_out = ast_test_flag(&(config->features_caller), AST_FEATURE_REDIRECT);
949         set_config_flags(config);
950         config->firstpass = 1;
951
952         /* Answer if need be */
953         if (ast_answer(chan))
954                 return -1;
955         peer->appl = "Bridged Call";
956         peer->data = chan->name;
957         /* copy the userfield from the B-leg to A-leg if applicable */
958         if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) {
959                 char tmp[256];
960                 if (!ast_strlen_zero(chan->cdr->userfield)) {
961                         snprintf(tmp, sizeof(tmp), "%s;%s",chan->cdr->userfield, peer->cdr->userfield);
962                         ast_cdr_appenduserfield(chan, tmp);
963                 } else
964                         ast_cdr_setuserfield(chan, peer->cdr->userfield);
965                 /* free the peer's cdr without ast_cdr_free complaining */
966                 free(peer->cdr);
967                 peer->cdr = NULL;
968         }
969         for (;;) {
970                 if (config->timelimit)
971                         gettimeofday(&start, NULL);
972                 res = ast_channel_bridge(chan,peer,config,&f, &who);
973                 if (config->timelimit) {
974                         /* Update time limit for next pass */
975                         gettimeofday(&end, NULL);
976                         diff = (end.tv_sec - start.tv_sec) * 1000;
977                         diff += (end.tv_usec - start.tv_usec) / 1000;
978                         config->timelimit -= diff;
979                         if (hasfeatures) {
980                                 /* Running on backup config, meaning a feature might be being
981                                    activated, but that's no excuse to keep things going 
982                                    indefinitely! */
983                                 if (backup_config.timelimit && ((backup_config.timelimit -= diff) <= 0)) {
984                                         ast_log(LOG_DEBUG, "Timed out, realtime this time!\n");
985                                         config->timelimit = 0;
986                                         who = chan;
987                                         if (f)
988                                                 ast_frfree(f);
989                                         f = NULL;
990                                         res = 0;
991                                 } else if (config->timelimit <= 0) {
992                                         /* Not *really* out of time, just out of time for
993                                            digits to come in for features. */
994                                         ast_log(LOG_DEBUG, "Timed out for feature!\n");
995                                         if (!ast_strlen_zero(peer_featurecode)) {
996                                                 ast_dtmf_stream(chan, peer, peer_featurecode, 0);
997                                                 memset(peer_featurecode, 0, sizeof(peer_featurecode));
998                                         }
999                                         if (!ast_strlen_zero(chan_featurecode)) {
1000                                                 ast_dtmf_stream(peer, chan, chan_featurecode, 0);
1001                                                 memset(chan_featurecode, 0, sizeof(chan_featurecode));
1002                                         }
1003                                         if (f)
1004                                                 ast_frfree(f);
1005                                         hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
1006                                         if (!hasfeatures) {
1007                                                 /* Restore original (possibly time modified) bridge config */
1008                                                 memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
1009                                                 memset(&backup_config, 0, sizeof(backup_config));
1010                                         }
1011                                         hadfeatures = hasfeatures;
1012                                         /* Continue as we were */
1013                                         continue;
1014                                 }
1015                         } else {
1016                                 if (config->timelimit <=0) {
1017                                         /* We ran out of time */
1018                                         config->timelimit = 0;
1019                                         who = chan;
1020                                         if (f)
1021                                                 ast_frfree(f);
1022                                         f = NULL;
1023                                         res = 0;
1024                                 }
1025                         }
1026                 }
1027                 if (res < 0) {
1028                         ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
1029                         return -1;
1030                 }
1031                 
1032                 if (!f || ((f->frametype == AST_FRAME_CONTROL) && ((f->subclass == AST_CONTROL_HANGUP) || (f->subclass == AST_CONTROL_BUSY) || 
1033                         (f->subclass == AST_CONTROL_CONGESTION)))) {
1034                                 res = -1;
1035                                 break;
1036                 }
1037                 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_RINGING)) {
1038                         if (who == chan)
1039                                 ast_indicate(peer, AST_CONTROL_RINGING);
1040                         else
1041                                 ast_indicate(chan, AST_CONTROL_RINGING);
1042                 }
1043                 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == -1)) {
1044                         if (who == chan)
1045                                 ast_indicate(peer, -1);
1046                         else
1047                                 ast_indicate(chan, -1);
1048                 }
1049                 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_FLASH)) {
1050                         if (who == chan)
1051                                 ast_indicate(peer, AST_CONTROL_FLASH);
1052                         else
1053                                 ast_indicate(chan, AST_CONTROL_FLASH);
1054                 }
1055                 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_OPTION)) {
1056                         aoh = f->data;
1057                         /* Forward option Requests */
1058                         if (aoh && (aoh->flag == AST_OPTION_FLAG_REQUEST)) {
1059                                 if (who == chan)
1060                                         ast_channel_setoption(peer, ntohs(aoh->option), aoh->data, f->datalen - sizeof(struct ast_option_header), 0);
1061                                 else
1062                                         ast_channel_setoption(chan, ntohs(aoh->option), aoh->data, f->datalen - sizeof(struct ast_option_header), 0);
1063                         }
1064                 }
1065                 /* check for '*', if we find it it's time to disconnect */
1066                 if (f && (f->frametype == AST_FRAME_DTMF)) {
1067                         char *featurecode;
1068                         int sense;
1069                         struct ast_channel *other;
1070                         hadfeatures = hasfeatures;
1071                         /* This cannot overrun because the longest feature is one shorter than our buffer */
1072                         if (who == chan) {
1073                                 other = peer;
1074                                 sense = FEATURE_SENSE_CHAN;
1075                                 featurecode = chan_featurecode;
1076                         } else  {
1077                                 other = chan;
1078                                 sense = FEATURE_SENSE_PEER;
1079                                 featurecode = peer_featurecode;
1080                         }
1081                         featurecode[strlen(featurecode)] = f->subclass;
1082                         config->timelimit = backup_config.timelimit;
1083                         res = ast_feature_interpret(chan, peer, config, featurecode, sense);
1084                         switch(res) {
1085                         case FEATURE_RETURN_PASSDIGITS:
1086                                 ast_dtmf_stream(other, who, featurecode, 0);
1087                                 /* Fall through */
1088                         case FEATURE_RETURN_SUCCESS:
1089                                 memset(featurecode, 0, sizeof(chan_featurecode));
1090                                 break;
1091                         }
1092                         if (res >= FEATURE_RETURN_PASSDIGITS) {
1093                                 res = 0;
1094                         } else {
1095                                 ast_frfree(f);
1096                                 break;
1097                         }
1098                         hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
1099                         if (hadfeatures && !hasfeatures) {
1100                                 /* Restore backup */
1101                                 memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
1102                                 memset(&backup_config, 0, sizeof(struct ast_bridge_config));
1103                         } else if (hasfeatures) {
1104                                 if (!hadfeatures) {
1105                                         /* Backup configuration */
1106                                         memcpy(&backup_config, config, sizeof(struct ast_bridge_config));
1107                                         /* Setup temporary config options */
1108                                         config->play_warning = 0;
1109                                         ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
1110                                         ast_clear_flag(&(config->features_callee),AST_FEATURE_PLAY_WARNING);
1111                                         config->warning_freq = 0;
1112                                         config->warning_sound = NULL;
1113                                         config->end_sound = NULL;
1114                                         config->start_sound = NULL;
1115                                         config->firstpass = 0;
1116                                 }
1117                                 config->timelimit = featuredigittimeout;
1118                                 ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->timelimit);
1119                         }
1120                 }
1121                 if (f)
1122                         ast_frfree(f);
1123         }
1124         return res;
1125 }
1126
1127 static void *do_parking_thread(void *ignore)
1128 {
1129         int ms, tms, max;
1130         struct parkeduser *pu, *pl, *pt = NULL;
1131         struct timeval tv;
1132         struct ast_frame *f;
1133         char exten[AST_MAX_EXTENSION];
1134         char *peername,*cp;
1135         char returnexten[AST_MAX_EXTENSION];
1136         struct ast_context *con;
1137         int x;
1138         fd_set rfds, efds;
1139         fd_set nrfds, nefds;
1140         FD_ZERO(&rfds);
1141         FD_ZERO(&efds);
1142
1143         for (;;) {
1144                 ms = -1;
1145                 max = -1;
1146                 ast_mutex_lock(&parking_lock);
1147                 pl = NULL;
1148                 pu = parkinglot;
1149                 FD_ZERO(&nrfds);
1150                 FD_ZERO(&nefds);
1151                 while(pu) {
1152                         if (pu->notquiteyet) {
1153                                 /* Pretend this one isn't here yet */
1154                                 pl = pu;
1155                                 pu = pu->next;
1156                                 continue;
1157                         }
1158                         gettimeofday(&tv, NULL);
1159                         tms = (tv.tv_sec - pu->start.tv_sec) * 1000 + (tv.tv_usec - pu->start.tv_usec) / 1000;
1160                         if (tms > pu->parkingtime) {
1161                                 /* Stop music on hold */
1162                                 ast_moh_stop(pu->chan);
1163                                 ast_indicate(pu->chan, AST_CONTROL_UNHOLD);
1164                                 /* Get chan, exten from derived kludge */
1165                                 if (pu->peername[0]) {
1166                                         peername = ast_strdupa(pu->peername);
1167                                         cp = strrchr(peername, '-');
1168                                         if (cp) 
1169                                                 *cp = 0;
1170                                         con = ast_context_find(parking_con_dial);
1171                                         if (!con) {
1172                                                 con = ast_context_create(NULL, parking_con_dial, registrar);
1173                                                 if (!con) {
1174                                                         ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial);
1175                                                 }
1176                                         }
1177                                         if (con) {
1178                                                 snprintf(returnexten, sizeof(returnexten), "%s||t", peername);
1179                                                 ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(returnexten), FREE, registrar);
1180                                         }
1181                                         strncpy(pu->chan->exten, peername, sizeof(pu->chan->exten) - 1);
1182                                         strncpy(pu->chan->context, parking_con_dial, sizeof(pu->chan->context) - 1);
1183                                         pu->chan->priority = 1;
1184
1185                                 } else {
1186                                         /* They've been waiting too long, send them back to where they came.  Theoretically they
1187                                            should have their original extensions and such, but we copy to be on the safe side */
1188                                         strncpy(pu->chan->exten, pu->exten, sizeof(pu->chan->exten)-1);
1189                                         strncpy(pu->chan->context, pu->context, sizeof(pu->chan->context)-1);
1190                                         pu->chan->priority = pu->priority;
1191                                 }
1192
1193                                 manager_event(EVENT_FLAG_CALL, "ParkedCallTimeOut",
1194                                         "Exten: %d\r\n"
1195                                         "Channel: %s\r\n"
1196                                         "CallerID: %s\r\n"
1197                                         "CallerIDName: %s\r\n\r\n"
1198                                         ,pu->parkingnum, pu->chan->name
1199                                         ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
1200                                         ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
1201                                         );
1202
1203                                 if (option_verbose > 1) 
1204                                         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);
1205                                 /* Start up the PBX, or hang them up */
1206                                 if (ast_pbx_start(pu->chan))  {
1207                                         ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", pu->chan->name);
1208                                         ast_hangup(pu->chan);
1209                                 }
1210                                 /* And take them out of the parking lot */
1211                                 if (pl) 
1212                                         pl->next = pu->next;
1213                                 else
1214                                         parkinglot = pu->next;
1215                                 pt = pu;
1216                                 pu = pu->next;
1217                                 con = ast_context_find(parking_con);
1218                                 if (con) {
1219                                         snprintf(exten, sizeof(exten), "%d", pt->parkingnum);
1220                                         if (ast_context_remove_extension2(con, exten, 1, NULL))
1221                                                 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
1222                                 } else
1223                                         ast_log(LOG_WARNING, "Whoa, no parking context?\n");
1224                                 free(pt);
1225                         } else {
1226                                 for (x=0; x<AST_MAX_FDS; x++) {
1227                                         if ((pu->chan->fds[x] > -1) && (FD_ISSET(pu->chan->fds[x], &rfds) || FD_ISSET(pu->chan->fds[x], &efds))) {
1228                                                 if (FD_ISSET(pu->chan->fds[x], &efds))
1229                                                         ast_set_flag(pu->chan, AST_FLAG_EXCEPTION);
1230                                                 else
1231                                                         ast_clear_flag(pu->chan, AST_FLAG_EXCEPTION);
1232                                                 pu->chan->fdno = x;
1233                                                 /* See if they need servicing */
1234                                                 f = ast_read(pu->chan);
1235                                                 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass ==  AST_CONTROL_HANGUP))) {
1236
1237                                                         manager_event(EVENT_FLAG_CALL, "ParkedCallGiveUp",
1238                                                                 "Exten: %d\r\n"
1239                                                                 "Channel: %s\r\n"
1240                                                                 "CallerID: %s\r\n"
1241                                                                 "CallerIDName: %s\r\n\r\n"
1242                                                                 ,pu->parkingnum, pu->chan->name
1243                                                                 ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
1244                                                                 ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
1245                                                                 );
1246
1247                                                         /* There's a problem, hang them up*/
1248                                                         if (option_verbose > 1) 
1249                                                                 ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being parked\n", pu->chan->name);
1250                                                         ast_hangup(pu->chan);
1251                                                         /* And take them out of the parking lot */
1252                                                         if (pl) 
1253                                                                 pl->next = pu->next;
1254                                                         else
1255                                                                 parkinglot = pu->next;
1256                                                         pt = pu;
1257                                                         pu = pu->next;
1258                                                         con = ast_context_find(parking_con);
1259                                                         if (con) {
1260                                                                 snprintf(exten, sizeof(exten), "%d", pt->parkingnum);
1261                                                                 if (ast_context_remove_extension2(con, exten, 1, NULL))
1262                                                                         ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
1263                                                         } else
1264                                                                 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
1265                                                         free(pt);
1266                                                         break;
1267                                                 } else {
1268                                                         /* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
1269                                                         ast_frfree(f);
1270                                                         if (pu->moh_trys < 3 && !pu->chan->generatordata) {
1271                                                                 ast_log(LOG_DEBUG, "MOH on parked call stopped by outside source.  Restarting.\n");
1272                                                                 ast_moh_start(pu->chan, NULL);
1273                                                                 pu->moh_trys++;
1274                                                         }
1275                                                         goto std;       /* XXX Ick: jumping into an else statement??? XXX */
1276                                                 }
1277                                         }
1278                                 }
1279                                 if (x >= AST_MAX_FDS) {
1280 std:                                    for (x=0; x<AST_MAX_FDS; x++) {
1281                                                 /* Keep this one for next one */
1282                                                 if (pu->chan->fds[x] > -1) {
1283                                                         FD_SET(pu->chan->fds[x], &nrfds);
1284                                                         FD_SET(pu->chan->fds[x], &nefds);
1285                                                         if (pu->chan->fds[x] > max)
1286                                                                 max = pu->chan->fds[x];
1287                                                 }
1288                                         }
1289                                         /* Keep track of our longest wait */
1290                                         if ((tms < ms) || (ms < 0))
1291                                                 ms = tms;
1292                                         pl = pu;
1293                                         pu = pu->next;
1294                                 }
1295                         }
1296                 }
1297                 ast_mutex_unlock(&parking_lock);
1298                 rfds = nrfds;
1299                 efds = nefds;
1300                 tv.tv_sec = ms / 1000;
1301                 tv.tv_usec = (ms % 1000) * 1000;
1302                 /* Wait for something to happen */
1303                 ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL);
1304                 pthread_testcancel();
1305         }
1306         return NULL;    /* Never reached */
1307 }
1308
1309 static int park_call_exec(struct ast_channel *chan, void *data)
1310 {
1311         /* Data is unused at the moment but could contain a parking
1312            lot context eventually */
1313         int res=0;
1314         struct localuser *u;
1315         LOCAL_USER_ADD(u);
1316         /* Setup the exten/priority to be s/1 since we don't know
1317            where this call should return */
1318         strcpy(chan->exten, "s");
1319         chan->priority = 1;
1320         if (chan->_state != AST_STATE_UP)
1321                 res = ast_answer(chan);
1322         if (!res)
1323                 res = ast_safe_sleep(chan, 1000);
1324         if (!res)
1325                 res = ast_park_call(chan, chan, 0, NULL);
1326         LOCAL_USER_REMOVE(u);
1327         if (!res)
1328                 res = AST_PBX_KEEPALIVE;
1329         return res;
1330 }
1331
1332 static int park_exec(struct ast_channel *chan, void *data)
1333 {
1334         int res=0;
1335         struct localuser *u;
1336         struct ast_channel *peer=NULL;
1337         struct parkeduser *pu, *pl=NULL;
1338         char exten[AST_MAX_EXTENSION];
1339         struct ast_context *con;
1340         int park;
1341         int dres;
1342         struct ast_bridge_config config;
1343
1344         if (!data) {
1345                 ast_log(LOG_WARNING, "Park requires an argument (extension number)\n");
1346                 return -1;
1347         }
1348         LOCAL_USER_ADD(u);
1349         park = atoi((char *)data);
1350         ast_mutex_lock(&parking_lock);
1351         pu = parkinglot;
1352         while(pu) {
1353                 if (pu->parkingnum == park) {
1354                         if (pl)
1355                                 pl->next = pu->next;
1356                         else
1357                                 parkinglot = pu->next;
1358                         break;
1359                 }
1360                 pl = pu;
1361                 pu = pu->next;
1362         }
1363         ast_mutex_unlock(&parking_lock);
1364         if (pu) {
1365                 peer = pu->chan;
1366                 con = ast_context_find(parking_con);
1367                 if (con) {
1368                         snprintf(exten, sizeof(exten), "%d", pu->parkingnum);
1369                         if (ast_context_remove_extension2(con, exten, 1, NULL))
1370                                 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
1371                 } else
1372                         ast_log(LOG_WARNING, "Whoa, no parking context?\n");
1373
1374                 manager_event(EVENT_FLAG_CALL, "UnParkedCall",
1375                         "Exten: %d\r\n"
1376                         "Channel: %s\r\n"
1377                         "From: %s\r\n"
1378                         "CallerID: %s\r\n"
1379                         "CallerIDName: %s\r\n\r\n"
1380                         ,pu->parkingnum, pu->chan->name, chan->name
1381                         ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
1382                         ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
1383                         );
1384
1385                 free(pu);
1386         }
1387         /* JK02: it helps to answer the channel if not already up */
1388         if (chan->_state != AST_STATE_UP) {
1389                 ast_answer(chan);
1390         }
1391
1392         if (peer) {
1393                 /* Play a courtesy beep in the calling channel to prefix the bridge connecting */       
1394                 if (!ast_strlen_zero(courtesytone)) {
1395                         if (!ast_streamfile(chan, courtesytone, chan->language)) {
1396                                 if (ast_waitstream(chan, "") < 0) {
1397                                         ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
1398                                         ast_hangup(peer);
1399                                         return -1;
1400                                 }
1401                         }
1402                 }
1403  
1404                 ast_moh_stop(peer);
1405                 ast_indicate(peer, AST_CONTROL_UNHOLD);
1406                 res = ast_channel_make_compatible(chan, peer);
1407                 if (res < 0) {
1408                         ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
1409                         ast_hangup(peer);
1410                         return -1;
1411                 }
1412                 /* This runs sorta backwards, since we give the incoming channel control, as if it
1413                    were the person called. */
1414                 if (option_verbose > 2) 
1415                         ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to parked call %d\n", chan->name, park);
1416
1417                 memset(&config,0,sizeof(struct ast_bridge_config));
1418                 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
1419                 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
1420                 config.timelimit = 0;
1421                 config.play_warning = 0;
1422                 config.warning_freq = 0;
1423                 config.warning_sound=NULL;
1424                 res = ast_bridge_call(chan,peer,&config);
1425
1426                 /* Simulate the PBX hanging up */
1427                 if (res != AST_PBX_NO_HANGUP_PEER)
1428                         ast_hangup(peer);
1429                 return res;
1430         } else {
1431                 /* XXX Play a message XXX */
1432                 dres = ast_streamfile(chan, "pbx-invalidpark", chan->language);
1433                 if (!dres)
1434                         dres = ast_waitstream(chan, "");
1435                  else {
1436                         ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
1437                         dres = 0;
1438                 }
1439                 if (option_verbose > 2) 
1440                         ast_verbose(VERBOSE_PREFIX_3 "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park);
1441                 res = -1;
1442         }
1443         LOCAL_USER_REMOVE(u);
1444         return res;
1445 }
1446
1447 static int handle_showfeatures(int fd, int argc, char *argv[])
1448 {
1449         int i;
1450         int fcount;
1451         char format[] = "%-25s %-7s %-7s\n";
1452
1453         ast_cli(fd, format, "Feature", "Default", "Current");
1454         ast_cli(fd, format, "-------", "-------", "-------");
1455
1456         ast_cli(fd, format, "Pickup", "*8", ast_pickup_ext());          /* default hardcoded above, so we'll hardcode it here */
1457
1458         fcount = sizeof(builtin_features) / sizeof(builtin_features[0]);
1459
1460         for (i = 0; i < fcount; i++)
1461         {
1462                 ast_cli(fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
1463         }
1464
1465         return RESULT_SUCCESS;
1466 }
1467
1468 static char showfeatures_help[] =
1469 "Usage: show features\n"
1470 "       Lists currently configured features.\n";
1471
1472 static struct ast_cli_entry showfeatures =
1473 { { "show", "features", NULL }, handle_showfeatures, "Lists configured features", showfeatures_help };
1474
1475 static int handle_parkedcalls(int fd, int argc, char *argv[])
1476 {
1477         struct parkeduser *cur;
1478         int numparked = 0;
1479
1480         ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
1481                 , "Context", "Extension", "Pri", "Timeout");
1482
1483         ast_mutex_lock(&parking_lock);
1484
1485         cur = parkinglot;
1486         while(cur) {
1487                 ast_cli(fd, "%4d %25s (%-15s %-12s %-4d) %6lds\n"
1488                         ,cur->parkingnum, cur->chan->name, cur->context, cur->exten
1489                         ,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL));
1490
1491                 cur = cur->next;
1492                 numparked++;
1493         }
1494         ast_cli(fd, "%d parked call(s).\n",numparked);
1495
1496         ast_mutex_unlock(&parking_lock);
1497
1498         return RESULT_SUCCESS;
1499 }
1500
1501 static char showparked_help[] =
1502 "Usage: show parkedcalls\n"
1503 "       Lists currently parked calls.\n";
1504
1505 static struct ast_cli_entry showparked =
1506 { { "show", "parkedcalls", NULL }, handle_parkedcalls, "Lists parked calls", showparked_help };
1507 /* Dump lot status */
1508 static int manager_parking_status( struct mansession *s, struct message *m )
1509 {
1510         struct parkeduser *cur;
1511         char *id = astman_get_header(m,"ActionID");
1512         char idText[256] = "";
1513
1514         if (id && !ast_strlen_zero(id))
1515                 snprintf(idText,256,"ActionID: %s\r\n",id);
1516
1517         astman_send_ack(s, m, "Parked calls will follow");
1518
1519         ast_mutex_lock(&parking_lock);
1520
1521         cur=parkinglot;
1522         while(cur) {
1523                         ast_mutex_lock(&s->lock);
1524                 ast_cli(s->fd, "Event: ParkedCall\r\n"
1525                         "Exten: %d\r\n"
1526                         "Channel: %s\r\n"
1527                         "Timeout: %ld\r\n"
1528                         "CallerID: %s\r\n"
1529                         "CallerIDName: %s\r\n"
1530                         "%s"
1531                         "\r\n"
1532                         ,cur->parkingnum, cur->chan->name
1533                         ,(long)cur->start.tv_sec + (long)(cur->parkingtime/1000) - (long)time(NULL)
1534                         ,(cur->chan->cid.cid_num ? cur->chan->cid.cid_num : "")
1535                         ,(cur->chan->cid.cid_name ? cur->chan->cid.cid_name : "")
1536                         ,idText);
1537                         ast_mutex_unlock(&s->lock);
1538
1539             cur = cur->next;
1540         }
1541
1542         ast_cli(s->fd,
1543         "Event: ParkedCallsComplete\r\n"
1544         "%s"
1545         "\r\n",idText);
1546
1547         ast_mutex_unlock(&parking_lock);
1548
1549         return RESULT_SUCCESS;
1550 }
1551
1552
1553 static int load_config(void) 
1554 {
1555         int start = 0, end = 0;
1556         struct ast_context *con = NULL;
1557         struct ast_config *cfg = NULL;
1558         struct ast_variable *var = NULL;
1559         
1560         transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
1561         featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
1562
1563         cfg = ast_config_load("features.conf");
1564         if (!cfg) {
1565                 cfg = ast_config_load("parking.conf");
1566                 if (cfg)
1567                         ast_log(LOG_NOTICE, "parking.conf is deprecated in favor of 'features.conf'.  Please rename it.\n");
1568         }
1569         if (cfg) {
1570                 var = ast_variable_browse(cfg, "general");
1571                 while(var) {
1572                         if (!strcasecmp(var->name, "parkext")) {
1573                                 strncpy(parking_ext, var->value, sizeof(parking_ext) - 1);
1574                         } else if (!strcasecmp(var->name, "context")) {
1575                                 strncpy(parking_con, var->value, sizeof(parking_con) - 1);
1576                         } else if (!strcasecmp(var->name, "parkingtime")) {
1577                                 if ((sscanf(var->value, "%d", &parkingtime) != 1) || (parkingtime < 1)) {
1578                                         ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value);
1579                                         parkingtime = DEFAULT_PARK_TIME;
1580                                 } else
1581                                         parkingtime = parkingtime * 1000;
1582                         } else if (!strcasecmp(var->name, "parkpos")) {
1583                                 if (sscanf(var->value, "%d-%d", &start, &end) != 2) {
1584                                         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);
1585                                 } else {
1586                                         parking_start = start;
1587                                         parking_stop = end;
1588                                 }
1589                         } else if (!strcasecmp(var->name, "findslot")) {
1590                                 parkfindnext = (!strcasecmp(var->value, "next"));
1591                         } else if (!strcasecmp(var->name, "adsipark")) {
1592                                 adsipark = ast_true(var->value);
1593                         } else if (!strcasecmp(var->name, "transferdigittimeout")) {
1594                                 if ((sscanf(var->value, "%d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) {
1595                                         ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value);
1596                                         transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
1597                                 } else
1598                                         transferdigittimeout = transferdigittimeout * 1000;
1599                         } else if (!strcasecmp(var->name, "featuredigittimeout")) {
1600                                 if ((sscanf(var->value, "%d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) {
1601                                         ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value);
1602                                         featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
1603                                 }
1604                         } else if (!strcasecmp(var->name, "courtesytone")) {
1605                                 strncpy(courtesytone, var->value, sizeof(courtesytone) - 1);
1606                         } else if (!strcasecmp(var->name, "xfersound")) {
1607                                 strncpy(xfersound, var->value, sizeof(xfersound) - 1);
1608                         } else if (!strcasecmp(var->name, "xferfailsound")) {
1609                                 strncpy(xferfailsound, var->value, sizeof(xferfailsound) - 1);
1610                         } else if (!strcasecmp(var->name, "pickupexten")) {
1611                                 strncpy(pickup_ext, var->value, sizeof(pickup_ext) - 1);
1612                         }
1613                         var = var->next;
1614                 }
1615                 unmap_features();
1616                 var = ast_variable_browse(cfg, "featuremap");
1617                 while(var) {
1618                         if (remap_feature(var->name, var->value))
1619                                 ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name);
1620                         var = var->next;
1621                 }
1622                 ast_config_destroy(cfg);
1623         }
1624         
1625         if (con)
1626                 ast_context_remove_extension2(con, ast_parking_ext(), 1, registrar);
1627         
1628         if (!(con = ast_context_find(parking_con))) {
1629                 if (!(con = ast_context_create(NULL, parking_con, registrar))) {
1630                         ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
1631                         return -1;
1632                 }
1633         }
1634         return ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, strdup(""), FREE, registrar);
1635 }
1636
1637 int reload(void) {
1638         return load_config();
1639 }
1640
1641 int load_module(void)
1642 {
1643         int res;
1644         if ((res = load_config()))
1645                 return res;
1646         ast_cli_register(&showparked);
1647         ast_cli_register(&showfeatures);
1648         ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
1649         res = ast_register_application(parkedcall, park_exec, synopsis, descrip);
1650         if (!res)
1651                 res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2);
1652         if (!res) {
1653                 ast_manager_register( "ParkedCalls", 0, manager_parking_status, "List parked calls" );
1654         }
1655         return res;
1656 }
1657
1658 int ast_pickup_call(struct ast_channel *chan)
1659 {
1660         struct ast_channel *cur;
1661         int res = -1;
1662         cur = ast_channel_walk_locked(NULL);
1663         while(cur) {
1664                 if (!cur->pbx && 
1665                         (cur != chan) &&
1666                         (chan->pickupgroup & cur->callgroup) &&
1667                         ((cur->_state == AST_STATE_RINGING) ||
1668                          (cur->_state == AST_STATE_RING))) {
1669                                 break;
1670                 }
1671                 ast_mutex_unlock(&cur->lock);
1672                 cur = ast_channel_walk_locked(cur);
1673         }
1674         if (cur) {
1675                 if (option_debug)
1676                         ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
1677                 res = ast_answer(chan);
1678                 if (res)
1679                         ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
1680                 res = ast_queue_control(chan, AST_CONTROL_ANSWER);
1681                 if (res)
1682                         ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
1683                 res = ast_channel_masquerade(cur, chan);
1684                 if (res)
1685                         ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name);           /* Done */
1686                 ast_mutex_unlock(&cur->lock);
1687         } else  {
1688                 if (option_debug)
1689                         ast_log(LOG_DEBUG, "No call pickup possible...\n");
1690         }
1691         return res;
1692 }
1693
1694 int unload_module(void)
1695 {
1696         STANDARD_HANGUP_LOCALUSERS;
1697
1698         ast_manager_unregister( "ParkedCalls" );
1699         ast_cli_unregister(&showfeatures);
1700         ast_cli_unregister(&showparked);
1701         ast_unregister_application(parkcall);
1702         return ast_unregister_application(parkedcall);
1703 }
1704
1705 char *description(void)
1706 {
1707         return "Call Parking Resource";
1708 }
1709
1710 int usecount(void)
1711 {
1712         /* Never allow parking to be unloaded because it will
1713            unresolve needed symbols in the dialer */
1714 #if 0
1715         int res;
1716         STANDARD_USECOUNT(res);
1717         return res;
1718 #else
1719         return 1;
1720 #endif
1721 }
1722
1723 char *key()
1724 {
1725         return ASTERISK_GPL_KEY;
1726 }