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