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