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