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