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