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