Keep track of timelimit across entries to ast_channel_bridge (bug #2222)
[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, Mark Spencer
7  *
8  * Mark Spencer <markster@linux-support.net>
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/say.h>
23 #include <asterisk/channel_pvt.h>
24 #include <asterisk/features.h>
25 #include <asterisk/musiconhold.h>
26 #include <asterisk/config.h>
27 #include <asterisk/cli.h>
28 #include <asterisk/manager.h>
29 #include <asterisk/utils.h>
30 #include <stdlib.h>
31 #include <errno.h>
32 #include <unistd.h>
33 #include <string.h>
34 #include <stdlib.h>
35 #include <stdio.h>
36 #include <sys/time.h>
37 #include <sys/signal.h>
38 #include <netinet/in.h>
39
40 #define DEFAULT_PARK_TIME 45000
41 #define DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000
42
43 static char *parkedcall = "ParkedCall";
44
45 /* No more than 45 seconds parked before you do something with them */
46 static int parkingtime = DEFAULT_PARK_TIME;
47
48 /* Context for which parking is made accessible */
49 static char parking_con[AST_MAX_EXTENSION] = "parkedcalls";
50
51 /* Extension you type to park the call */
52 static char parking_ext[AST_MAX_EXTENSION] = "700";
53
54 static char pickup_ext[AST_MAX_EXTENSION] = "*8";
55
56 /* First available extension for parking */
57 static int parking_start = 701;
58
59 /* Last available extension for parking */
60 static int parking_stop = 750;
61
62 static int transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
63
64 /* Registrar for operations */
65 static char *registrar = "res_features";
66
67 static char *synopsis = "Answer a parked call";
68
69 static char *descrip = "ParkedCall(exten):"
70 "Used to connect to a parked call.  This Application is always\n"
71 "registered internally and does not need to be explicitly added\n"
72 "into the dialplan, although you should include the 'parkedcalls'\n"
73 "context.\n";
74
75
76 static char *parkcall = "Park";
77
78 static char *synopsis2 = "Park yourself";
79
80 static char *descrip2 = "Park(exten):"
81 "Used to park yourself (typically in combination with a supervised\n"
82 "transfer to know the parking space.  This Application is always\n"
83 "registered internally and does not need to be explicitly added\n"
84 "into the dialplan, although you should include the 'parkedcalls'\n"
85 "context.\n";
86
87 struct parkeduser {
88         struct ast_channel *chan;
89         struct timeval start;
90         int parkingnum;
91         /* Where to go if our parking time expires */
92         char context[AST_MAX_EXTENSION];
93         char exten[AST_MAX_EXTENSION];
94         int priority;
95         int parkingtime;
96         int notquiteyet;
97         struct parkeduser *next;
98 };
99
100 static struct parkeduser *parkinglot;
101
102 AST_MUTEX_DEFINE_STATIC(parking_lock);
103
104 static pthread_t parking_thread;
105
106 STANDARD_LOCAL_USER;
107
108 LOCAL_USER_DECL;
109
110 char *ast_parking_ext(void)
111 {
112         return parking_ext;
113 }
114
115 char *ast_pickup_ext(void)
116 {
117         return pickup_ext;
118 }
119
120 int ast_park_call(struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout)
121 {
122         /* We put the user in the parking list, then wake up the parking thread to be sure it looks
123            after these channels too */
124         struct parkeduser *pu, *cur;
125         int x;
126         char exten[AST_MAX_EXTENSION];
127         struct ast_context *con;
128         pu = malloc(sizeof(struct parkeduser));
129         if (pu) {
130                 ast_mutex_lock(&parking_lock);
131                 for (x=parking_start;x<=parking_stop;x++) {
132                         cur = parkinglot;
133                         while(cur) {
134                                 if (cur->parkingnum == x) 
135                                         break;
136                                 cur = cur->next;
137                         }
138                         if (!cur)
139                                 break;
140                 }
141                 if (x <= parking_stop) {
142                         chan->appl = "Parked Call";
143                         chan->data = NULL; 
144
145                         pu->chan = chan;
146                         /* Start music on hold */
147                         if (chan != peer)
148                                 ast_moh_start(pu->chan, NULL);
149                         gettimeofday(&pu->start, NULL);
150                         pu->parkingnum = x;
151                         if (timeout > 0)
152                                 pu->parkingtime = timeout;
153                         else
154                                 pu->parkingtime = parkingtime;
155                         if (extout)
156                                 *extout = x;
157                         /* Remember what had been dialed, so that if the parking
158                            expires, we try to come back to the same place */
159                         if (strlen(chan->macrocontext))
160                                 strncpy(pu->context, chan->macrocontext, sizeof(pu->context)-1);
161                         else
162                                 strncpy(pu->context, chan->context, sizeof(pu->context)-1);
163                         if (strlen(chan->macroexten))
164                                 strncpy(pu->exten, chan->macroexten, sizeof(pu->exten)-1);
165                         else
166                                 strncpy(pu->exten, chan->exten, sizeof(pu->exten)-1);
167                         if (chan->macropriority)
168                                 pu->priority = chan->macropriority;
169                         else
170                                 pu->priority = chan->priority;
171                         pu->next = parkinglot;
172                         parkinglot = pu;
173                         /* If parking a channel directly, don't quiet yet get parking running on it */
174                         if (peer == chan)
175                                 pu->notquiteyet = 1;
176                         ast_mutex_unlock(&parking_lock);
177                         /* Wake up the (presumably select()ing) thread */
178                         pthread_kill(parking_thread, SIGURG);
179                         if (option_verbose > 1) 
180                                 ast_verbose(VERBOSE_PREFIX_2 "Parked %s on %d\n", pu->chan->name, pu->parkingnum);
181
182                         manager_event(EVENT_FLAG_CALL, "ParkedCall",
183                                 "Exten: %d\r\n"
184                                 "Channel: %s\r\n"
185                                 "From: %s\r\n"
186                                 "Timeout: %ld\r\n"
187                                 "CallerID: %s\r\n"
188                                 ,pu->parkingnum, pu->chan->name, peer->name
189                                 ,(long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL)
190                                 ,(pu->chan->callerid ? pu->chan->callerid : "")
191                                 );
192
193                         if (peer) {
194                                 ast_say_digits(peer, pu->parkingnum, "", peer->language);
195                                 if (pu->notquiteyet) {
196                                         /* Wake up parking thread if we're really done */
197                                         ast_moh_start(pu->chan, NULL);
198                                         pu->notquiteyet = 0;
199                                         pthread_kill(parking_thread, SIGURG);
200                                 }
201                         }
202                         con = ast_context_find(parking_con);
203                         if (!con) {
204                                 con = ast_context_create(NULL,parking_con, registrar);
205                                 if (!con) {
206                                         ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
207                                 }
208                         }
209                         if (con) {
210                                 snprintf(exten, sizeof(exten), "%d", x);
211                                 ast_add_extension2(con, 1, exten, 1, NULL, parkedcall, strdup(exten), free, registrar);
212                         }
213                         return 0;
214                 } else {
215                         ast_log(LOG_WARNING, "No more parking spaces\n");
216                         free(pu);
217                         ast_mutex_unlock(&parking_lock);
218                         return -1;
219                 }
220         } else {
221                 ast_log(LOG_WARNING, "Out of memory\n");
222                 return -1;
223         }
224         return 0;
225 }
226
227 int ast_masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout)
228 {
229         struct ast_channel *chan;
230         struct ast_frame *f;
231         /* Make a new, fake channel that we'll use to masquerade in the real one */
232         chan = ast_channel_alloc(0);
233         if (chan) {
234                 /* Let us keep track of the channel name */
235                 snprintf(chan->name, sizeof (chan->name), "Parked/%s",rchan->name);
236                 /* Make formats okay */
237                 chan->readformat = rchan->readformat;
238                 chan->writeformat = rchan->writeformat;
239                 ast_channel_masquerade(chan, rchan);
240                 /* Setup the extensions and such */
241                 strncpy(chan->context, rchan->context, sizeof(chan->context) - 1);
242                 strncpy(chan->exten, rchan->exten, sizeof(chan->exten) - 1);
243                 chan->priority = rchan->priority;
244                 /* Make the masq execute */
245                 f = ast_read(chan);
246                 if (f)
247                         ast_frfree(f);
248                 ast_park_call(chan, peer, timeout, extout);
249         } else {
250                 ast_log(LOG_WARNING, "Unable to create parked channel\n");
251                 return -1;
252         }
253         return 0;
254 }
255
256 int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast_bridge_config *config)
257 {
258         /* Copy voice back and forth between the two channels.  Give the peer
259            the ability to transfer calls with '#<extension' syntax. */
260         int len;
261         struct ast_frame *f;
262         struct ast_channel *who;
263         char newext[256], *ptr;
264         int res;
265         int diff;
266         struct ast_option_header *aoh;
267         struct ast_channel *transferer;
268         struct ast_channel *transferee;
269         struct timeval start, end;
270         char *transferer_real_context;
271         int allowdisconnect_in,allowdisconnect_out,allowredirect_in,allowredirect_out;
272
273         allowdisconnect_in = config->allowdisconnect_in;
274         allowdisconnect_out = config->allowdisconnect_out;
275         allowredirect_in = config->allowredirect_in;
276         allowredirect_out = config->allowredirect_out;
277
278         /* Answer if need be */
279         if (ast_answer(chan))
280                 return -1;
281         peer->appl = "Bridged Call";
282         peer->data = chan->name;
283         /* copy the userfield from the B-leg to A-leg if applicable */
284         if (chan->cdr && peer->cdr && strlen(peer->cdr->userfield)) {
285                 char tmp[256];
286                 if (strlen(chan->cdr->userfield)) {
287                         snprintf(tmp, sizeof(tmp), "%s;%s",chan->cdr->userfield, peer->cdr->userfield);
288                         ast_cdr_appenduserfield(chan, tmp);
289                 } else
290                         ast_cdr_setuserfield(chan, peer->cdr->userfield);
291                 /* free the peer's cdr without ast_cdr_free complaining */
292                 free(peer->cdr);
293                 peer->cdr = NULL;
294         }
295         for (;;) {
296                 if (config->timelimit)
297                         gettimeofday(&start, NULL);
298                 res = ast_channel_bridge(chan,peer,config,&f, &who);
299                 if (config->timelimit) {
300                         /* Update time limit for next pass */
301                         gettimeofday(&end, NULL);
302                         diff = (end.tv_sec - start.tv_sec) * 1000;
303                         diff += (end.tv_usec - start.tv_usec) / 1000;
304                         config->timelimit -= diff;
305                         if (config->timelimit <=0) {
306                                 /* We ran out of time */
307                                 config->timelimit = 0;
308                                 who = chan;
309                                 f = NULL;
310                                 res = 0;
311                         }
312                 }
313                 if (res < 0) {
314                         ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
315                         return -1;
316                 }
317                 
318                 if (!f || ((f->frametype == AST_FRAME_CONTROL) && ((f->subclass == AST_CONTROL_HANGUP) || (f->subclass == AST_CONTROL_BUSY) || 
319                         (f->subclass == AST_CONTROL_CONGESTION)))) {
320                                 res = -1;
321                                 break;
322                 }
323                 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_RINGING)) {
324                         if (who == chan)
325                                 ast_indicate(peer, AST_CONTROL_RINGING);
326                         else
327                                 ast_indicate(chan, AST_CONTROL_RINGING);
328                 }
329                 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == -1)) {
330                         if (who == chan)
331                                 ast_indicate(peer, -1);
332                         else
333                                 ast_indicate(chan, -1);
334                 }
335                 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_OPTION)) {
336                         aoh = f->data;
337                         /* Forward option Requests */
338                         if (aoh && (aoh->flag == AST_OPTION_FLAG_REQUEST)) {
339                                 if (who == chan)
340                                         ast_channel_setoption(peer, ntohs(aoh->option), aoh->data, f->datalen - sizeof(struct ast_option_header), 0);
341                                 else
342                                         ast_channel_setoption(chan, ntohs(aoh->option), aoh->data, f->datalen - sizeof(struct ast_option_header), 0);
343                         }
344                 }
345                 /* check for '*', if we find it it's time to disconnect */
346                 if (f && (f->frametype == AST_FRAME_DTMF) &&
347                         (((who == chan) && allowdisconnect_out) || ((who == peer) && allowdisconnect_in)) &&
348                         (f->subclass == '*')) {
349                         
350                         if (option_verbose > 3)
351                                 ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass);
352                         res = -1;
353                         break;
354                 }
355
356                 if ((f->frametype == AST_FRAME_DTMF) &&
357                         ((allowredirect_in && who == peer) || (allowredirect_out && who == chan)) &&
358                         (f->subclass == '#')) {
359                                 if(allowredirect_in &&  who == peer) {
360                                         transferer = peer;
361                                         transferee = chan;
362                                 }
363                                 else {
364                                         transferer = chan;
365                                         transferee = peer;
366                                 }
367                                 if(!(transferer_real_context=pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT")) &&
368                                    !(transferer_real_context=pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT"))) {
369                                         /* Use the non-macro context to transfer the call */
370                                         if(strlen(transferer->macrocontext))
371                                                 transferer_real_context=transferer->macrocontext;
372                                         else
373                                                 transferer_real_context=transferer->context;
374                                 }
375                                 /* Start autoservice on chan while we talk
376                                    to the originator */
377                                 ast_autoservice_start(transferee);
378                                 ast_moh_start(transferee, NULL);
379
380                                 memset(newext, 0, sizeof(newext));
381                                 ptr = newext;
382
383                                         /* Transfer */
384                                 if ((res=ast_streamfile(transferer, "pbx-transfer", transferer->language))) {
385                                         ast_moh_stop(transferee);
386                                         ast_autoservice_stop(transferee);
387                                         break;
388                                 }
389                                 if ((res=ast_waitstream(transferer, AST_DIGIT_ANY)) < 0) {
390                                         ast_moh_stop(transferee);
391                                         ast_autoservice_stop(transferee);
392                                         break;
393                                 }
394                                 ast_stopstream(transferer);
395                                 if (res > 0) {
396                                         /* If they've typed a digit already, handle it */
397                                         newext[0] = res;
398                                         ptr++;
399                                         len --;
400                                 }
401                                 res = 0;
402                                 while(strlen(newext) < sizeof(newext) - 1) {
403                                         res = ast_waitfordigit(transferer, transferdigittimeout);
404                                         if (res < 1) 
405                                                 break;
406                                         if (res == '#')
407                                                 break;
408                                         *(ptr++) = res;
409                                         if (!ast_matchmore_extension(transferer, transferer_real_context
410                                                                 , newext, 1, transferer->callerid)) {
411                                                 break;
412                                         }
413                                 }
414
415                                 if (res < 0) {
416                                         ast_moh_stop(transferee);
417                                         ast_autoservice_stop(transferee);
418                                         break;
419                                 }
420                                 if (!strcmp(newext, ast_parking_ext())) {
421                                         ast_moh_stop(transferee);
422
423                                         if (ast_autoservice_stop(transferee))
424                                                 res = -1;
425                                         else if (!ast_park_call(transferee, transferer, 0, NULL)) {
426                                                 /* We return non-zero, but tell the PBX not to hang the channel when
427                                                    the thread dies -- We have to be careful now though.  We are responsible for 
428                                                    hanging up the channel, else it will never be hung up! */
429
430                                                 if(transferer==peer)
431                                                         res=AST_PBX_KEEPALIVE;
432                                                 else
433                                                         res=AST_PBX_NO_HANGUP_PEER;
434                                                 break;
435                                         } else {
436                                                 ast_log(LOG_WARNING, "Unable to park call %s\n", transferee->name);
437                                         }
438                                         /* XXX Maybe we should have another message here instead of invalid extension XXX */
439                                 } else if (ast_exists_extension(transferee, transferer_real_context, newext, 1, transferer->callerid)) {
440                                         ast_moh_stop(transferee);
441                                         res=ast_autoservice_stop(transferee);
442                                         if (!transferee->pbx) {
443                                                 /* Doh!  Use our handy async_goto funcitons */
444                                                 if (option_verbose > 2) 
445                                                         ast_verbose(VERBOSE_PREFIX_3 "Transferring %s to '%s' (context %s) priority 1\n"
446                                                                 ,transferee->name, newext, transferer_real_context);
447                                                 if (ast_async_goto(transferee, transferer_real_context, newext, 1))
448                                                         ast_log(LOG_WARNING, "Async goto fialed :(\n");
449                                                 res = -1;
450                                         } else {
451                                                 /* Set the channel's new extension, since it exists, using transferer context */
452                                                 strncpy(transferee->exten, newext, sizeof(transferee->exten)-1);
453                                                 strncpy(transferee->context, transferer_real_context, sizeof(transferee->context)-1);
454                                                 transferee->priority = 0;
455                                                 ast_frfree(f);
456                                         }
457                                         break;
458                                 } else {
459                                         if (option_verbose > 2) 
460                                                 ast_verbose(VERBOSE_PREFIX_3 "Unable to find extension '%s' in context '%s'\n", newext, transferer_real_context);
461                                 }
462                                 res = ast_streamfile(transferer, "pbx-invalid", transferee->language);
463                                 if (res) {
464                                         ast_moh_stop(transferee);
465                                         ast_autoservice_stop(transferee);
466                                         break;
467                                 }
468                                 res = ast_waitstream(transferer, AST_DIGIT_ANY);
469                                 ast_stopstream(transferer);
470                                 ast_moh_stop(transferee);
471                                 res = ast_autoservice_stop(transferee);
472                                 if (res) {
473                                         if (option_verbose > 1)
474                                                 ast_verbose(VERBOSE_PREFIX_2 "Hungup during autoservice stop on '%s'\n", transferee->name);
475                                 }
476                         } else {
477             if (f && (f->frametype == AST_FRAME_DTMF)) {
478                   if (who == peer)
479                         ast_write(chan, f);
480                   else
481                         ast_write(peer, f);
482             }            
483 #if 1
484                                 ast_log(LOG_DEBUG, "Read from %s (%d,%d)\n", who->name, f->frametype, f->subclass);
485 #endif
486                         }
487          if (f)
488                ast_frfree(f);
489         }
490         return res;
491 }
492
493 static void *do_parking_thread(void *ignore)
494 {
495         int ms, tms, max;
496         struct parkeduser *pu, *pl, *pt = NULL;
497         struct timeval tv;
498         struct ast_frame *f;
499         char exten[AST_MAX_EXTENSION];
500         struct ast_context *con;
501         int x;
502         int gc=0;
503         fd_set rfds, efds;
504         fd_set nrfds, nefds;
505         FD_ZERO(&rfds);
506         FD_ZERO(&efds);
507         for (;;) {
508                 ms = -1;
509                 max = -1;
510                 ast_mutex_lock(&parking_lock);
511                 pl = NULL;
512                 pu = parkinglot;
513                 gettimeofday(&tv, NULL);
514                 FD_ZERO(&nrfds);
515                 FD_ZERO(&nefds);
516                 while(pu) {
517                         if (pu->notquiteyet) {
518                                 /* Pretend this one isn't here yet */
519                                 pl = pu;
520                                 pu = pu->next;
521                                 continue;
522                         }
523                         if (gc < 5 && !pu->chan->generator) {
524                                 gc++;
525                                 ast_moh_start(pu->chan,NULL);
526                         }
527                         tms = (tv.tv_sec - pu->start.tv_sec) * 1000 + (tv.tv_usec - pu->start.tv_usec) / 1000;
528                         if (tms > pu->parkingtime) {
529                                 /* They've been waiting too long, send them back to where they came.  Theoretically they
530                                    should have their original extensions and such, but we copy to be on the safe side */
531                                 strncpy(pu->chan->exten, pu->exten, sizeof(pu->chan->exten)-1);
532                                 strncpy(pu->chan->context, pu->context, sizeof(pu->chan->context)-1);
533                                 pu->chan->priority = pu->priority;
534                                 /* Stop music on hold */
535                                 ast_moh_stop(pu->chan);
536                                 /* Start up the PBX, or hang them up */
537                                 if (ast_pbx_start(pu->chan))  {
538                                         ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", pu->chan->name);
539                                         ast_hangup(pu->chan);
540                                 }
541                                 /* And take them out of the parking lot */
542                                 if (pl) 
543                                         pl->next = pu->next;
544                                 else
545                                         parkinglot = pu->next;
546                                 pt = pu;
547                                 pu = pu->next;
548                                 con = ast_context_find(parking_con);
549                                 if (con) {
550                                         snprintf(exten, sizeof(exten), "%d", pt->parkingnum);
551                                         if (ast_context_remove_extension2(con, exten, 1, NULL))
552                                                 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
553                                 } else
554                                         ast_log(LOG_WARNING, "Whoa, no parking context?\n");
555                                 free(pt);
556                         } else {
557                                 for (x=0;x<AST_MAX_FDS;x++) {
558                                         if ((pu->chan->fds[x] > -1) && (FD_ISSET(pu->chan->fds[x], &rfds) || FD_ISSET(pu->chan->fds[x], &efds))) {
559                                                 if (FD_ISSET(pu->chan->fds[x], &efds))
560                                                         pu->chan->exception = 1;
561                                                 pu->chan->fdno = x;
562                                                 /* See if they need servicing */
563                                                 f = ast_read(pu->chan);
564                                                 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass ==  AST_CONTROL_HANGUP))) {
565                                                         /* There's a problem, hang them up*/
566                                                         if (option_verbose > 1) 
567                                                                 ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being parked\n", pu->chan->name);
568                                                         ast_hangup(pu->chan);
569                                                         /* And take them out of the parking lot */
570                                                         if (pl) 
571                                                                 pl->next = pu->next;
572                                                         else
573                                                                 parkinglot = pu->next;
574                                                         pt = pu;
575                                                         pu = pu->next;
576                                                         con = ast_context_find(parking_con);
577                                                         if (con) {
578                                                                 snprintf(exten, sizeof(exten), "%d", pt->parkingnum);
579                                                                 if (ast_context_remove_extension2(con, exten, 1, NULL))
580                                                                         ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
581                                                         } else
582                                                                 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
583                                                         free(pt);
584                                                         break;
585                                                 } else {
586                                                         /* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
587                                                         ast_frfree(f);
588                                                         goto std;       /* XXX Ick: jumping into an else statement??? XXX */
589                                                 }
590                                         }
591                                 }
592                                 if (x >= AST_MAX_FDS) {
593 std:                                    for (x=0;x<AST_MAX_FDS;x++) {
594                                                 /* Keep this one for next one */
595                                                 if (pu->chan->fds[x] > -1) {
596                                                         FD_SET(pu->chan->fds[x], &nrfds);
597                                                         FD_SET(pu->chan->fds[x], &nefds);
598                                                         if (pu->chan->fds[x] > max)
599                                                                 max = pu->chan->fds[x];
600                                                 }
601                                         }
602                                         /* Keep track of our longest wait */
603                                         if ((tms < ms) || (ms < 0))
604                                                 ms = tms;
605                                         pl = pu;
606                                         pu = pu->next;
607                                 }
608                         }
609                 }
610                 ast_mutex_unlock(&parking_lock);
611                 rfds = nrfds;
612                 efds = nefds;
613                 tv.tv_sec = ms / 1000;
614                 tv.tv_usec = (ms % 1000) * 1000;
615                 /* Wait for something to happen */
616                 ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL);
617                 pthread_testcancel();
618         }
619         return NULL;    /* Never reached */
620 }
621
622 static int park_call_exec(struct ast_channel *chan, void *data)
623 {
624         /* Data is unused at the moment but could contain a parking
625            lot context eventually */
626         int res=0;
627         struct localuser *u;
628         LOCAL_USER_ADD(u);
629         /* Setup the exten/priority to be s/1 since we don't know
630            where this call should return */
631         strcpy(chan->exten, "s");
632         chan->priority = 1;
633         if (chan->_state != AST_STATE_UP)
634                 res = ast_answer(chan);
635         if (!res)
636                 res = ast_safe_sleep(chan, 1000);
637         if (!res)
638                 res = ast_park_call(chan, chan, 0, NULL);
639         LOCAL_USER_REMOVE(u);
640         if (!res)
641                 res = AST_PBX_KEEPALIVE;
642         return res;
643 }
644
645 static int park_exec(struct ast_channel *chan, void *data)
646 {
647         int res=0;
648         struct localuser *u;
649         struct ast_channel *peer=NULL;
650         struct parkeduser *pu, *pl=NULL;
651         char exten[AST_MAX_EXTENSION];
652         struct ast_context *con;
653         int park;
654         int dres;
655         struct ast_bridge_config config;
656
657         if (!data) {
658                 ast_log(LOG_WARNING, "Park requires an argument (extension number)\n");
659                 return -1;
660         }
661         LOCAL_USER_ADD(u);
662         park = atoi((char *)data);
663         ast_mutex_lock(&parking_lock);
664         pu = parkinglot;
665         while(pu) {
666                 if (pu->parkingnum == park) {
667                         if (pl)
668                                 pl->next = pu->next;
669                         else
670                                 parkinglot = pu->next;
671                         break;
672                 }
673                 pl = pu;
674                 pu = pu->next;
675         }
676         ast_mutex_unlock(&parking_lock);
677         if (pu) {
678                 peer = pu->chan;
679                 con = ast_context_find(parking_con);
680                 if (con) {
681                         snprintf(exten, sizeof(exten), "%d", pu->parkingnum);
682                         if (ast_context_remove_extension2(con, exten, 1, NULL))
683                                 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
684                 } else
685                         ast_log(LOG_WARNING, "Whoa, no parking context?\n");
686                 free(pu);
687         }
688         /* JK02: it helps to answer the channel if not already up */
689         if (chan->_state != AST_STATE_UP) {
690                 ast_answer(chan);
691         }
692
693         if (peer) {
694                 ast_moh_stop(peer);
695                 res = ast_channel_make_compatible(chan, peer);
696                 if (res < 0) {
697                         ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
698                         ast_hangup(peer);
699                         return -1;
700                 }
701                 /* This runs sorta backwards, since we give the incoming channel control, as if it
702                    were the person called. */
703                 if (option_verbose > 2) 
704                         ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to parked call %d\n", chan->name, park);
705
706                 memset(&config,0,sizeof(struct ast_bridge_config));
707                 config.allowredirect_in = 1;
708                 config.allowredirect_out = 1;
709                 config.allowdisconnect_out = 0;
710                 config.allowdisconnect_in = 0;
711                 config.timelimit = 0;
712                 config.play_warning = 0;
713                 config.warning_freq = 0;
714                 config.warning_sound=NULL;
715                 res = ast_bridge_call(chan,peer,&config);
716
717                 /* Simulate the PBX hanging up */
718                 if (res != AST_PBX_NO_HANGUP_PEER)
719                         ast_hangup(peer);
720                 return res;
721         } else {
722                 /* XXX Play a message XXX */
723           dres = ast_streamfile(chan, "pbx-invalidpark", chan->language);
724           if (!dres)
725             dres = ast_waitstream(chan, "");
726           else {
727             ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
728             dres = 0;
729           }
730                 if (option_verbose > 2) 
731                         ast_verbose(VERBOSE_PREFIX_3 "Channel %s tried to talk to non-existant parked call %d\n", chan->name, park);
732                 res = -1;
733         }
734         LOCAL_USER_REMOVE(u);
735         return res;
736 }
737
738 static int handle_parkedcalls(int fd, int argc, char *argv[])
739 {
740         struct parkeduser *cur;
741
742         ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
743                 , "Context", "Extension", "Pri", "Timeout");
744
745         ast_mutex_lock(&parking_lock);
746
747         cur=parkinglot;
748         while(cur) {
749                 ast_cli(fd, "%4d %25s (%-15s %-12s %-4d) %6lds\n"
750                         ,cur->parkingnum, cur->chan->name, cur->context, cur->exten
751                         ,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL));
752
753                 cur = cur->next;
754         }
755
756         ast_mutex_unlock(&parking_lock);
757
758         return RESULT_SUCCESS;
759 }
760
761 static char showparked_help[] =
762 "Usage: show parkedcalls\n"
763 "       Lists currently parked calls.\n";
764
765 static struct ast_cli_entry showparked =
766 { { "show", "parkedcalls", NULL }, handle_parkedcalls, "Lists parked calls", showparked_help };
767 /* Dump lot status */
768 static int manager_parking_status( struct mansession *s, struct message *m )
769 {
770         struct parkeduser *cur;
771         char *id = astman_get_header(m,"ActionID");
772         char idText[256] = "";
773
774         if (id && !ast_strlen_zero(id))
775                 snprintf(idText,256,"ActionID: %s\r\n",id);
776
777         astman_send_ack(s, m, "Parked calls will follow");
778
779         ast_mutex_lock(&parking_lock);
780
781         cur=parkinglot;
782         while(cur) {
783                 ast_cli(s->fd, "Event: ParkedCall\r\n"
784                         "Exten: %d\r\n"
785                         "Channel: %s\r\n"
786                         "Timeout: %ld\r\n"
787                         "CallerID: %s\r\n"
788                         "%s"
789                         "\r\n"
790                         ,cur->parkingnum, cur->chan->name
791                         ,(long)cur->start.tv_sec + (long)(cur->parkingtime/1000) - (long)time(NULL)
792                         ,(cur->chan->callerid ? cur->chan->callerid : "")
793                         ,idText);
794
795                 cur = cur->next;
796         }
797
798         ast_cli(s->fd,
799         "Event: ParkedCallsComplete\r\n"
800         "%s"
801         "\r\n",idText);
802
803         ast_mutex_unlock(&parking_lock);
804
805         return RESULT_SUCCESS;
806 }
807
808
809
810 int load_module(void)
811 {
812         int res;
813         int start, end;
814         struct ast_context *con;
815         struct ast_config *cfg;
816         struct ast_variable *var;
817
818         ast_cli_register(&showparked);
819
820         cfg = ast_load("features.conf");
821         if (!cfg) {
822                 cfg = ast_load("parking.conf");
823                 if (cfg)
824                         ast_log(LOG_NOTICE, "parking.conf is deprecated in favor of 'features.conf'.  Please rename it.\n");
825         }
826         if (cfg) {
827                 var = ast_variable_browse(cfg, "general");
828                 while(var) {
829                         if (!strcasecmp(var->name, "parkext")) {
830                                 strncpy(parking_ext, var->value, sizeof(parking_ext) - 1);
831                         } else if (!strcasecmp(var->name, "context")) {
832                                 strncpy(parking_con, var->value, sizeof(parking_con) - 1);
833                         } else if (!strcasecmp(var->name, "parkingtime")) {
834                                 if ((sscanf(var->value, "%d", &parkingtime) != 1) || (parkingtime < 1)) {
835                                         ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value);
836                                         parkingtime = DEFAULT_PARK_TIME;
837                                 } else
838                                         parkingtime = parkingtime * 1000;
839                         } else if (!strcasecmp(var->name, "parkpos")) {
840                                 if (sscanf(var->value, "%i-%i", &start, &end) != 2) {
841                                         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);
842                                 } else {
843                                         parking_start = start;
844                                         parking_stop = end;
845                                 }
846                         } else if(!strcasecmp(var->name, "transferdigittimeout")) {
847                                 if ((sscanf(var->value, "%d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) {
848                                         ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value);
849                                         transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
850                                 } else
851                                         transferdigittimeout = transferdigittimeout * 1000;
852                         }
853                         var = var->next;
854                 }
855                 ast_destroy(cfg);
856         }
857         con = ast_context_find(parking_con);
858         if (!con) {
859                 con = ast_context_create(NULL,parking_con, registrar);
860                 if (!con) {
861                         ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
862                         return -1;
863                 }
864         }
865         ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, parkcall, strdup(""),free, registrar);
866         pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
867         res = ast_register_application(parkedcall, park_exec, synopsis, descrip);
868         if (!res)
869                 res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2);
870         if (!res) {
871                 ast_manager_register( "ParkedCalls", 0, manager_parking_status, "List parked calls" );
872         }
873         return res;
874 }
875
876 int ast_pickup_call(struct ast_channel *chan)
877 {
878         struct ast_channel *cur;
879         int res = -1;
880         cur = ast_channel_walk_locked(NULL);
881         while(cur) {
882                 if (!cur->pbx && 
883                         (cur != chan) &&
884                         (chan->pickupgroup & cur->callgroup) &&
885                         ((cur->_state == AST_STATE_RINGING) ||
886                          (cur->_state == AST_STATE_RING))) {
887                                 break;
888                 }
889                 ast_mutex_unlock(&cur->lock);
890                 cur = ast_channel_walk_locked(cur);
891         }
892         if (cur) {
893                 ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
894                 res = ast_answer(chan);
895                 if (res)
896                         ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
897                 res = ast_queue_control(chan, AST_CONTROL_ANSWER);
898                 if (res)
899                         ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
900                 res = ast_channel_masquerade(cur, chan);
901                 if (res)
902                         ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name);           /* Done */
903                 ast_mutex_unlock(&cur->lock);
904         } else  {
905                 ast_log(LOG_DEBUG, "No call pickup possible...\n");
906         }
907         return res;
908 }
909
910 int unload_module(void)
911 {
912         STANDARD_HANGUP_LOCALUSERS;
913
914         ast_manager_unregister( "ParkedCalls" );
915         ast_cli_unregister(&showparked);
916         ast_unregister_application(parkcall);
917         return ast_unregister_application(parkedcall);
918 }
919
920 char *description(void)
921 {
922         return "Call Parking Resource";
923 }
924
925 int usecount(void)
926 {
927         /* Never allow parking to be unloaded because it will
928            unresolve needed symbols in the dialer */
929 #if 0
930         int res;
931         STANDARD_USECOUNT(res);
932         return res;
933 #else
934         return 1;
935 #endif
936 }
937
938 char *key()
939 {
940         return ASTERISK_GPL_KEY;
941 }