Pass through flash hook
[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                                 if (f)
362                                         ast_frfree(f);
363                                 f = NULL;
364                                 res = 0;
365                         }
366                 }
367                 if (res < 0) {
368                         ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
369                         return -1;
370                 }
371                 
372                 if (!f || ((f->frametype == AST_FRAME_CONTROL) && ((f->subclass == AST_CONTROL_HANGUP) || (f->subclass == AST_CONTROL_BUSY) || 
373                         (f->subclass == AST_CONTROL_CONGESTION)))) {
374                                 res = -1;
375                                 break;
376                 }
377                 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_RINGING)) {
378                         if (who == chan)
379                                 ast_indicate(peer, AST_CONTROL_RINGING);
380                         else
381                                 ast_indicate(chan, AST_CONTROL_RINGING);
382                 }
383                 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == -1)) {
384                         if (who == chan)
385                                 ast_indicate(peer, -1);
386                         else
387                                 ast_indicate(chan, -1);
388                 }
389                 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_FLASH)) {
390                         if (who == chan)
391                                 ast_indicate(peer, AST_CONTROL_FLASH);
392                         else
393                                 ast_indicate(chan, AST_CONTROL_FLASH);
394                 }
395                 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_OPTION)) {
396                         aoh = f->data;
397                         /* Forward option Requests */
398                         if (aoh && (aoh->flag == AST_OPTION_FLAG_REQUEST)) {
399                                 if (who == chan)
400                                         ast_channel_setoption(peer, ntohs(aoh->option), aoh->data, f->datalen - sizeof(struct ast_option_header), 0);
401                                 else
402                                         ast_channel_setoption(chan, ntohs(aoh->option), aoh->data, f->datalen - sizeof(struct ast_option_header), 0);
403                         }
404                 }
405                 /* check for '*', if we find it it's time to disconnect */
406                 if (f && (f->frametype == AST_FRAME_DTMF) &&
407                         (((who == chan) && allowdisconnect_out) || ((who == peer) && allowdisconnect_in)) &&
408                         (f->subclass == '*')) {
409                         
410                         if (option_verbose > 3)
411                                 ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass);
412                         res = -1;
413                         break;
414                 }
415
416                 if ((f->frametype == AST_FRAME_DTMF) &&
417                         ((allowredirect_in && who == peer) || (allowredirect_out && who == chan)) &&
418                         (f->subclass == '#')) {
419                                 if (allowredirect_in &&  who == peer) {
420                                         transferer = peer;
421                                         transferee = chan;
422                                 } else {
423                                         transferer = chan;
424                                         transferee = peer;
425                                 }
426                                 if (!(transferer_real_context=pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT")) &&
427                                    !(transferer_real_context=pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT"))) {
428                                         /* Use the non-macro context to transfer the call */
429                                         if (!ast_strlen_zero(transferer->macrocontext))
430                                                 transferer_real_context = transferer->macrocontext;
431                                         else
432                                                 transferer_real_context = transferer->context;
433                                 }
434                                 /* Start autoservice on chan while we talk
435                                    to the originator */
436                                 ast_autoservice_start(transferee);
437                                 ast_moh_start(transferee, NULL);
438
439                                 memset(newext, 0, sizeof(newext));
440                                 ptr = newext;
441
442                                         /* Transfer */
443                                 if ((res=ast_streamfile(transferer, "pbx-transfer", transferer->language))) {
444                                         ast_moh_stop(transferee);
445                                         ast_autoservice_stop(transferee);
446                                         break;
447                                 }
448                                 if ((res=ast_waitstream(transferer, AST_DIGIT_ANY)) < 0) {
449                                         ast_moh_stop(transferee);
450                                         ast_autoservice_stop(transferee);
451                                         break;
452                                 }
453                                 ast_stopstream(transferer);
454                                 if (res > 0) {
455                                         /* If they've typed a digit already, handle it */
456                                         newext[0] = res;
457                                         ptr++;
458                                         len --;
459                                 }
460                                 res = 0;
461                                 while (strlen(newext) < sizeof(newext) - 1) {
462                                         res = ast_waitfordigit(transferer, transferdigittimeout);
463                                         if (res < 1) 
464                                                 break;
465                                         if (res == '#')
466                                                 break;
467                                         *(ptr++) = res;
468                                         if (!ast_matchmore_extension(transferer, transferer_real_context
469                                                                 , newext, 1, transferer->cid.cid_num)) {
470                                                 break;
471                                         }
472                                 }
473
474                                 if (res < 0) {
475                                         ast_moh_stop(transferee);
476                                         ast_autoservice_stop(transferee);
477                                         break;
478                                 }
479                                 if (!strcmp(newext, ast_parking_ext())) {
480                                         ast_moh_stop(transferee);
481
482                                         if (ast_autoservice_stop(transferee))
483                                                 res = -1;
484                                         else if (!ast_park_call(transferee, transferer, 0, NULL)) {
485                                                 /* We return non-zero, but tell the PBX not to hang the channel when
486                                                    the thread dies -- We have to be careful now though.  We are responsible for 
487                                                    hanging up the channel, else it will never be hung up! */
488
489                                                 if (transferer==peer)
490                                                         res=AST_PBX_KEEPALIVE;
491                                                 else
492                                                         res=AST_PBX_NO_HANGUP_PEER;
493                                                 break;
494                                         } else {
495                                                 ast_log(LOG_WARNING, "Unable to park call %s\n", transferee->name);
496                                         }
497                                         /* XXX Maybe we should have another message here instead of invalid extension XXX */
498                                 } else if (ast_exists_extension(transferee, transferer_real_context, newext, 1, transferer->cid.cid_num)) {
499                                         pbx_builtin_setvar_helper(peer, "BLINDTRANSFER", chan->name);
500                                         pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", peer->name);
501                                         ast_moh_stop(transferee);
502                                         res=ast_autoservice_stop(transferee);
503                                         if (!transferee->pbx) {
504                                                 /* Doh!  Use our handy async_goto funcitons */
505                                                 if (option_verbose > 2) 
506                                                         ast_verbose(VERBOSE_PREFIX_3 "Transferring %s to '%s' (context %s) priority 1\n"
507                                                                 ,transferee->name, newext, transferer_real_context);
508                                                 if (ast_async_goto(transferee, transferer_real_context, newext, 1))
509                                                         ast_log(LOG_WARNING, "Async goto fialed :(\n");
510                                                 res = -1;
511                                         } else {
512                                                 /* Set the channel's new extension, since it exists, using transferer context */
513                                                 strncpy(transferee->exten, newext, sizeof(transferee->exten)-1);
514                                                 strncpy(transferee->context, transferer_real_context, sizeof(transferee->context)-1);
515                                                 transferee->priority = 0;
516                                                 ast_frfree(f);
517                                         }
518                                         break;
519                                 } else {
520                                         if (option_verbose > 2) 
521                                                 ast_verbose(VERBOSE_PREFIX_3 "Unable to find extension '%s' in context '%s'\n", newext, transferer_real_context);
522                                 }
523                                 res = ast_streamfile(transferer, "pbx-invalid", transferee->language);
524                                 if (res) {
525                                         ast_moh_stop(transferee);
526                                         ast_autoservice_stop(transferee);
527                                         break;
528                                 }
529                                 res = ast_waitstream(transferer, AST_DIGIT_ANY);
530                                 ast_stopstream(transferer);
531                                 ast_moh_stop(transferee);
532                                 res = ast_autoservice_stop(transferee);
533                                 if (res) {
534                                         if (option_verbose > 1)
535                                                 ast_verbose(VERBOSE_PREFIX_2 "Hungup during autoservice stop on '%s'\n", transferee->name);
536                                 }
537                         } else {
538             if (f && (f->frametype == AST_FRAME_DTMF)) {
539                   if (who == peer)
540                         ast_write(chan, f);
541                   else
542                         ast_write(peer, f);
543             }            
544 #if 1
545                                 ast_log(LOG_DEBUG, "Read from %s (%d,%d)\n", who->name, f->frametype, f->subclass);
546 #endif
547                         }
548          if (f)
549                ast_frfree(f);
550         }
551         return res;
552 }
553
554 static void *do_parking_thread(void *ignore)
555 {
556         int ms, tms, max;
557         struct parkeduser *pu, *pl, *pt = NULL;
558         struct timeval tv;
559         struct ast_frame *f;
560         char exten[AST_MAX_EXTENSION];
561         struct ast_context *con;
562         int x;
563         int gc=0;
564         fd_set rfds, efds;
565         fd_set nrfds, nefds;
566         FD_ZERO(&rfds);
567         FD_ZERO(&efds);
568         for (;;) {
569                 ms = -1;
570                 max = -1;
571                 ast_mutex_lock(&parking_lock);
572                 pl = NULL;
573                 pu = parkinglot;
574                 gettimeofday(&tv, NULL);
575                 FD_ZERO(&nrfds);
576                 FD_ZERO(&nefds);
577                 while(pu) {
578                         if (pu->notquiteyet) {
579                                 /* Pretend this one isn't here yet */
580                                 pl = pu;
581                                 pu = pu->next;
582                                 continue;
583                         }
584                         if (gc < 5 && !pu->chan->generator) {
585                                 gc++;
586                                 ast_moh_start(pu->chan,NULL);
587                         }
588                         tms = (tv.tv_sec - pu->start.tv_sec) * 1000 + (tv.tv_usec - pu->start.tv_usec) / 1000;
589                         if (tms > pu->parkingtime) {
590                                 /* They've been waiting too long, send them back to where they came.  Theoretically they
591                                    should have their original extensions and such, but we copy to be on the safe side */
592                                 strncpy(pu->chan->exten, pu->exten, sizeof(pu->chan->exten)-1);
593                                 strncpy(pu->chan->context, pu->context, sizeof(pu->chan->context)-1);
594                                 pu->chan->priority = pu->priority;
595                                 if (option_verbose > 1) 
596                                         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);
597                                 /* Stop music on hold */
598                                 ast_moh_stop(pu->chan);
599                                 /* Start up the PBX, or hang them up */
600                                 if (ast_pbx_start(pu->chan))  {
601                                         ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", pu->chan->name);
602                                         ast_hangup(pu->chan);
603                                 }
604                                 /* And take them out of the parking lot */
605                                 if (pl) 
606                                         pl->next = pu->next;
607                                 else
608                                         parkinglot = pu->next;
609                                 pt = pu;
610                                 pu = pu->next;
611                                 con = ast_context_find(parking_con);
612                                 if (con) {
613                                         snprintf(exten, sizeof(exten), "%d", pt->parkingnum);
614                                         if (ast_context_remove_extension2(con, exten, 1, NULL))
615                                                 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
616                                 } else
617                                         ast_log(LOG_WARNING, "Whoa, no parking context?\n");
618                                 free(pt);
619                         } else {
620                                 for (x=0;x<AST_MAX_FDS;x++) {
621                                         if ((pu->chan->fds[x] > -1) && (FD_ISSET(pu->chan->fds[x], &rfds) || FD_ISSET(pu->chan->fds[x], &efds))) {
622                                                 if (FD_ISSET(pu->chan->fds[x], &efds))
623                                                         pu->chan->exception = 1;
624                                                 pu->chan->fdno = x;
625                                                 /* See if they need servicing */
626                                                 f = ast_read(pu->chan);
627                                                 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass ==  AST_CONTROL_HANGUP))) {
628                                                         /* There's a problem, hang them up*/
629                                                         if (option_verbose > 1) 
630                                                                 ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being parked\n", pu->chan->name);
631                                                         ast_hangup(pu->chan);
632                                                         /* And take them out of the parking lot */
633                                                         if (pl) 
634                                                                 pl->next = pu->next;
635                                                         else
636                                                                 parkinglot = pu->next;
637                                                         pt = pu;
638                                                         pu = pu->next;
639                                                         con = ast_context_find(parking_con);
640                                                         if (con) {
641                                                                 snprintf(exten, sizeof(exten), "%d", pt->parkingnum);
642                                                                 if (ast_context_remove_extension2(con, exten, 1, NULL))
643                                                                         ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
644                                                         } else
645                                                                 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
646                                                         free(pt);
647                                                         break;
648                                                 } else {
649                                                         /* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
650                                                         ast_frfree(f);
651                                                         goto std;       /* XXX Ick: jumping into an else statement??? XXX */
652                                                 }
653                                         }
654                                 }
655                                 if (x >= AST_MAX_FDS) {
656 std:                                    for (x=0;x<AST_MAX_FDS;x++) {
657                                                 /* Keep this one for next one */
658                                                 if (pu->chan->fds[x] > -1) {
659                                                         FD_SET(pu->chan->fds[x], &nrfds);
660                                                         FD_SET(pu->chan->fds[x], &nefds);
661                                                         if (pu->chan->fds[x] > max)
662                                                                 max = pu->chan->fds[x];
663                                                 }
664                                         }
665                                         /* Keep track of our longest wait */
666                                         if ((tms < ms) || (ms < 0))
667                                                 ms = tms;
668                                         pl = pu;
669                                         pu = pu->next;
670                                 }
671                         }
672                 }
673                 ast_mutex_unlock(&parking_lock);
674                 rfds = nrfds;
675                 efds = nefds;
676                 tv.tv_sec = ms / 1000;
677                 tv.tv_usec = (ms % 1000) * 1000;
678                 /* Wait for something to happen */
679                 ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL);
680                 pthread_testcancel();
681         }
682         return NULL;    /* Never reached */
683 }
684
685 static int park_call_exec(struct ast_channel *chan, void *data)
686 {
687         /* Data is unused at the moment but could contain a parking
688            lot context eventually */
689         int res=0;
690         struct localuser *u;
691         LOCAL_USER_ADD(u);
692         /* Setup the exten/priority to be s/1 since we don't know
693            where this call should return */
694         strcpy(chan->exten, "s");
695         chan->priority = 1;
696         if (chan->_state != AST_STATE_UP)
697                 res = ast_answer(chan);
698         if (!res)
699                 res = ast_safe_sleep(chan, 1000);
700         if (!res)
701                 res = ast_park_call(chan, chan, 0, NULL);
702         LOCAL_USER_REMOVE(u);
703         if (!res)
704                 res = AST_PBX_KEEPALIVE;
705         return res;
706 }
707
708 static int park_exec(struct ast_channel *chan, void *data)
709 {
710         int res=0;
711         struct localuser *u;
712         struct ast_channel *peer=NULL;
713         struct parkeduser *pu, *pl=NULL;
714         char exten[AST_MAX_EXTENSION];
715         struct ast_context *con;
716         int park;
717         int dres;
718         struct ast_bridge_config config;
719
720         if (!data) {
721                 ast_log(LOG_WARNING, "Park requires an argument (extension number)\n");
722                 return -1;
723         }
724         LOCAL_USER_ADD(u);
725         park = atoi((char *)data);
726         ast_mutex_lock(&parking_lock);
727         pu = parkinglot;
728         while(pu) {
729                 if (pu->parkingnum == park) {
730                         if (pl)
731                                 pl->next = pu->next;
732                         else
733                                 parkinglot = pu->next;
734                         break;
735                 }
736                 pl = pu;
737                 pu = pu->next;
738         }
739         ast_mutex_unlock(&parking_lock);
740         if (pu) {
741                 peer = pu->chan;
742                 con = ast_context_find(parking_con);
743                 if (con) {
744                         snprintf(exten, sizeof(exten), "%d", pu->parkingnum);
745                         if (ast_context_remove_extension2(con, exten, 1, NULL))
746                                 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
747                 } else
748                         ast_log(LOG_WARNING, "Whoa, no parking context?\n");
749                 free(pu);
750         }
751         /* JK02: it helps to answer the channel if not already up */
752         if (chan->_state != AST_STATE_UP) {
753                 ast_answer(chan);
754         }
755
756         if (peer) {
757                 /* Play a courtesy beep in the calling channel to prefix the bridge connecting */       
758                 if (!ast_strlen_zero(courtesytone)) {
759                         if (!ast_streamfile(chan, courtesytone, chan->language)) {
760                                 if (ast_waitstream(chan, "") < 0) {
761                                         ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
762                                         ast_hangup(peer);
763                                         return -1;
764                                 }
765                         }
766                 }
767  
768                 ast_moh_stop(peer);
769                 res = ast_channel_make_compatible(chan, peer);
770                 if (res < 0) {
771                         ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
772                         ast_hangup(peer);
773                         return -1;
774                 }
775                 /* This runs sorta backwards, since we give the incoming channel control, as if it
776                    were the person called. */
777                 if (option_verbose > 2) 
778                         ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to parked call %d\n", chan->name, park);
779
780                 memset(&config,0,sizeof(struct ast_bridge_config));
781                 config.allowredirect_in = 1;
782                 config.allowredirect_out = 1;
783                 config.allowdisconnect_out = 0;
784                 config.allowdisconnect_in = 0;
785                 config.timelimit = 0;
786                 config.play_warning = 0;
787                 config.warning_freq = 0;
788                 config.warning_sound=NULL;
789                 res = ast_bridge_call(chan,peer,&config);
790
791                 /* Simulate the PBX hanging up */
792                 if (res != AST_PBX_NO_HANGUP_PEER)
793                         ast_hangup(peer);
794                 return res;
795         } else {
796                 /* XXX Play a message XXX */
797           dres = ast_streamfile(chan, "pbx-invalidpark", chan->language);
798           if (!dres)
799             dres = ast_waitstream(chan, "");
800           else {
801             ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
802             dres = 0;
803           }
804                 if (option_verbose > 2) 
805                         ast_verbose(VERBOSE_PREFIX_3 "Channel %s tried to talk to non-existant parked call %d\n", chan->name, park);
806                 res = -1;
807         }
808         LOCAL_USER_REMOVE(u);
809         return res;
810 }
811
812 static int handle_parkedcalls(int fd, int argc, char *argv[])
813 {
814         struct parkeduser *cur;
815
816         ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
817                 , "Context", "Extension", "Pri", "Timeout");
818
819         ast_mutex_lock(&parking_lock);
820
821         cur=parkinglot;
822         while(cur) {
823                 ast_cli(fd, "%4d %25s (%-15s %-12s %-4d) %6lds\n"
824                         ,cur->parkingnum, cur->chan->name, cur->context, cur->exten
825                         ,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL));
826
827                 cur = cur->next;
828         }
829
830         ast_mutex_unlock(&parking_lock);
831
832         return RESULT_SUCCESS;
833 }
834
835 static char showparked_help[] =
836 "Usage: show parkedcalls\n"
837 "       Lists currently parked calls.\n";
838
839 static struct ast_cli_entry showparked =
840 { { "show", "parkedcalls", NULL }, handle_parkedcalls, "Lists parked calls", showparked_help };
841 /* Dump lot status */
842 static int manager_parking_status( struct mansession *s, struct message *m )
843 {
844         struct parkeduser *cur;
845         char *id = astman_get_header(m,"ActionID");
846         char idText[256] = "";
847
848         if (id && !ast_strlen_zero(id))
849                 snprintf(idText,256,"ActionID: %s\r\n",id);
850
851         astman_send_ack(s, m, "Parked calls will follow");
852
853         ast_mutex_lock(&parking_lock);
854
855         cur=parkinglot;
856         while(cur) {
857                         ast_mutex_lock(&s->lock);
858                 ast_cli(s->fd, "Event: ParkedCall\r\n"
859                         "Exten: %d\r\n"
860                         "Channel: %s\r\n"
861                         "Timeout: %ld\r\n"
862                         "CallerID: %s\r\n"
863                         "CallerIDName: %s\r\n"
864                         "%s"
865                         "\r\n"
866                         ,cur->parkingnum, cur->chan->name
867                         ,(long)cur->start.tv_sec + (long)(cur->parkingtime/1000) - (long)time(NULL)
868                         ,(cur->chan->cid.cid_num ? cur->chan->cid.cid_num : "")
869                         ,(cur->chan->cid.cid_name ? cur->chan->cid.cid_name : "")
870                         ,idText);
871                         ast_mutex_unlock(&s->lock);
872
873             cur = cur->next;
874         }
875
876         ast_cli(s->fd,
877         "Event: ParkedCallsComplete\r\n"
878         "%s"
879         "\r\n",idText);
880
881         ast_mutex_unlock(&parking_lock);
882
883         return RESULT_SUCCESS;
884 }
885
886
887
888 int load_module(void)
889 {
890         int res;
891         int start, end;
892         struct ast_context *con;
893         struct ast_config *cfg;
894         struct ast_variable *var;
895
896         ast_cli_register(&showparked);
897
898         cfg = ast_load("features.conf");
899         if (!cfg) {
900                 cfg = ast_load("parking.conf");
901                 if (cfg)
902                         ast_log(LOG_NOTICE, "parking.conf is deprecated in favor of 'features.conf'.  Please rename it.\n");
903         }
904         if (cfg) {
905                 var = ast_variable_browse(cfg, "general");
906                 while(var) {
907                         if (!strcasecmp(var->name, "parkext")) {
908                                 strncpy(parking_ext, var->value, sizeof(parking_ext) - 1);
909                         } else if (!strcasecmp(var->name, "context")) {
910                                 strncpy(parking_con, var->value, sizeof(parking_con) - 1);
911                         } else if (!strcasecmp(var->name, "parkingtime")) {
912                                 if ((sscanf(var->value, "%d", &parkingtime) != 1) || (parkingtime < 1)) {
913                                         ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value);
914                                         parkingtime = DEFAULT_PARK_TIME;
915                                 } else
916                                         parkingtime = parkingtime * 1000;
917                         } else if (!strcasecmp(var->name, "parkpos")) {
918                                 if (sscanf(var->value, "%i-%i", &start, &end) != 2) {
919                                         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);
920                                 } else {
921                                         parking_start = start;
922                                         parking_stop = end;
923                                 }
924                         } else if (!strcasecmp(var->name, "adsipark")) {
925                                 adsipark = ast_true(var->value);
926                         } else if (!strcasecmp(var->name, "transferdigittimeout")) {
927                                 if ((sscanf(var->value, "%d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) {
928                                         ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value);
929                                         transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
930                                 } else
931                                         transferdigittimeout = transferdigittimeout * 1000;
932                         } else if (!strcasecmp(var->name, "courtesytone")) {
933                                 strncpy(courtesytone, var->value, sizeof(courtesytone) - 1);
934                         } else if (!strcasecmp(var->name, "pickupexten")) {
935                                 strncpy(pickup_ext, var->value, sizeof(pickup_ext) - 1);
936                         }
937                         var = var->next;
938                 }
939                 ast_destroy(cfg);
940         }
941         con = ast_context_find(parking_con);
942         if (!con) {
943                 con = ast_context_create(NULL,parking_con, registrar);
944                 if (!con) {
945                         ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
946                         return -1;
947                 }
948         }
949         ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, strdup(""),free, registrar);
950         ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
951         res = ast_register_application(parkedcall, park_exec, synopsis, descrip);
952         if (!res)
953                 res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2);
954         if (!res) {
955                 ast_manager_register( "ParkedCalls", 0, manager_parking_status, "List parked calls" );
956         }
957         return res;
958 }
959
960 int ast_pickup_call(struct ast_channel *chan)
961 {
962         struct ast_channel *cur;
963         int res = -1;
964         cur = ast_channel_walk_locked(NULL);
965         while(cur) {
966                 if (!cur->pbx && 
967                         (cur != chan) &&
968                         (chan->pickupgroup & cur->callgroup) &&
969                         ((cur->_state == AST_STATE_RINGING) ||
970                          (cur->_state == AST_STATE_RING))) {
971                                 break;
972                 }
973                 ast_mutex_unlock(&cur->lock);
974                 cur = ast_channel_walk_locked(cur);
975         }
976         if (cur) {
977                 ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
978                 res = ast_answer(chan);
979                 if (res)
980                         ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
981                 res = ast_queue_control(chan, AST_CONTROL_ANSWER);
982                 if (res)
983                         ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
984                 res = ast_channel_masquerade(cur, chan);
985                 if (res)
986                         ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name);           /* Done */
987                 ast_mutex_unlock(&cur->lock);
988         } else  {
989                 ast_log(LOG_DEBUG, "No call pickup possible...\n");
990         }
991         return res;
992 }
993
994 int unload_module(void)
995 {
996         STANDARD_HANGUP_LOCALUSERS;
997
998         ast_manager_unregister( "ParkedCalls" );
999         ast_cli_unregister(&showparked);
1000         ast_unregister_application(parkcall);
1001         return ast_unregister_application(parkedcall);
1002 }
1003
1004 char *description(void)
1005 {
1006         return "Call Parking Resource";
1007 }
1008
1009 int usecount(void)
1010 {
1011         /* Never allow parking to be unloaded because it will
1012            unresolve needed symbols in the dialer */
1013 #if 0
1014         int res;
1015         STANDARD_USECOUNT(res);
1016         return res;
1017 #else
1018         return 1;
1019 #endif
1020 }
1021
1022 char *key()
1023 {
1024         return ASTERISK_GPL_KEY;
1025 }