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