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