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