8b2ad415b81814e4931275c54e64783ce81e3a75
[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/app.h>
23 #include <asterisk/say.h>
24 #include <asterisk/channel_pvt.h>
25 #include <asterisk/features.h>
26 #include <asterisk/musiconhold.h>
27 #include <asterisk/config.h>
28 #include <asterisk/cli.h>
29 #include <asterisk/manager.h>
30 #include <asterisk/utils.h>
31 #include <asterisk/adsi.h>
32 #include <pthread.h>
33 #include <stdlib.h>
34 #include <errno.h>
35 #include <unistd.h>
36 #include <string.h>
37 #include <stdlib.h>
38 #include <stdio.h>
39 #include <sys/time.h>
40 #include <sys/signal.h>
41 #include <netinet/in.h>
42
43 #define DEFAULT_PARK_TIME 45000
44 #define DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000
45 #define DEFAULT_FEATURE_DIGIT_TIMEOUT 500
46
47 static char *parkedcall = "ParkedCall";
48
49 /* No more than 45 seconds parked before you do something with them */
50 static int parkingtime = DEFAULT_PARK_TIME;
51
52 /* Context for which parking is made accessible */
53 static char parking_con[AST_MAX_EXTENSION] = "parkedcalls";
54
55 /* Context for dialback for parking (KLUDGE) */
56 static char parking_con_dial[AST_MAX_EXTENSION] = "park-dial";
57
58 /* Extension you type to park the call */
59 static char parking_ext[AST_MAX_EXTENSION] = "700";
60
61 static char pickup_ext[AST_MAX_EXTENSION] = "*8";
62
63 /* Default sounds */
64 static char courtesytone[256] = "";
65 static char xfersound[256] = "beep";
66 static char xferfailsound[256] = "pbx-invalid";
67
68 /* First available extension for parking */
69 static int parking_start = 701;
70
71 /* Last available extension for parking */
72 static int parking_stop = 750;
73
74 static int adsipark = 0;
75
76 static int transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
77 static int featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
78
79 /* Default courtesy tone played when party joins conference */
80
81 /* Registrar for operations */
82 static char *registrar = "res_features";
83
84 static char *synopsis = "Answer a parked call";
85
86 static char *descrip = "ParkedCall(exten):"
87 "Used to connect to a parked call.  This application is always\n"
88 "registered internally and does not need to be explicitly added\n"
89 "into the dialplan, although you should include the 'parkedcalls'\n"
90 "context.\n";
91
92 static char *parkcall = "Park";
93
94 static char *synopsis2 = "Park yourself";
95
96 static char *descrip2 = "Park(exten):"
97 "Used to park yourself (typically in combination with a supervised\n"
98 "transfer to know the parking space). This application is always\n"
99 "registered internally and does not need to be explicitly added\n"
100 "into the dialplan, although you should include the 'parkedcalls'\n"
101 "context.\n";
102
103 static struct ast_app *monitor_app=NULL;
104 static int monitor_ok=1;
105
106 struct parkeduser {
107         struct ast_channel *chan;
108         struct timeval start;
109         int parkingnum;
110         /* Where to go if our parking time expires */
111         char context[AST_MAX_EXTENSION];
112         char exten[AST_MAX_EXTENSION];
113         int priority;
114         int parkingtime;
115         int notquiteyet;
116         char peername[1024];
117         struct parkeduser *next;
118 };
119
120 static struct parkeduser *parkinglot;
121
122 AST_MUTEX_DEFINE_STATIC(parking_lock);
123
124 static pthread_t parking_thread;
125
126 STANDARD_LOCAL_USER;
127
128 LOCAL_USER_DECL;
129
130 char *ast_parking_ext(void)
131 {
132         return parking_ext;
133 }
134
135 char *ast_pickup_ext(void)
136 {
137         return pickup_ext;
138 }
139
140 struct ast_bridge_thread_obj 
141 {
142         struct ast_bridge_config bconfig;
143         struct ast_channel *chan;
144         struct ast_channel *peer;
145 };
146
147 static void *ast_bridge_call_thread(void *data) 
148 {
149         struct ast_bridge_thread_obj *tobj = data;
150         tobj->chan->appl = "Transferred Call";
151         tobj->chan->data = tobj->peer->name;
152         tobj->peer->appl = "Transferred Call";
153         tobj->peer->data = tobj->chan->name;
154         if (tobj->chan->cdr) {
155                 ast_cdr_reset(tobj->chan->cdr,0);
156                 ast_cdr_setdestchan(tobj->chan->cdr, tobj->peer->name);
157         }
158         if (tobj->peer->cdr) {
159                 ast_cdr_reset(tobj->peer->cdr,0);
160                 ast_cdr_setdestchan(tobj->peer->cdr, tobj->chan->name);
161         }
162
163
164         ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig);
165         ast_hangup(tobj->chan);
166         ast_hangup(tobj->peer);
167         tobj->chan = tobj->peer = NULL;
168         free(tobj);
169         tobj=NULL;
170         return NULL;
171 }
172
173 static void ast_bridge_call_thread_launch(void *data) 
174 {
175         pthread_t thread;
176         pthread_attr_t attr;
177         int result;
178
179         result = pthread_attr_init(&attr);
180         pthread_attr_setschedpolicy(&attr, SCHED_RR);
181         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
182         result = ast_pthread_create(&thread, &attr,ast_bridge_call_thread, data);
183         result = pthread_attr_destroy(&attr);
184 }
185
186
187
188 static int adsi_announce_park(struct ast_channel *chan, int parkingnum)
189 {
190         int res;
191         int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT};
192         char tmp[256] = "";
193         char *message[5] = {NULL, NULL, NULL, NULL, NULL};
194
195         snprintf(tmp, sizeof(tmp), "Parked on %d", parkingnum);
196         message[0] = tmp;
197         res = adsi_load_session(chan, NULL, 0, 1);
198         if (res == -1) {
199                 return res;
200         }
201         return adsi_print(chan, message, justify, 1);
202 }
203
204 int ast_park_call(struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout)
205 {
206         /* We put the user in the parking list, then wake up the parking thread to be sure it looks
207            after these channels too */
208         struct parkeduser *pu, *cur;
209         int x;
210         char exten[AST_MAX_EXTENSION];
211         struct ast_context *con;
212         pu = malloc(sizeof(struct parkeduser));
213         if (pu) {
214                 memset(pu,0,sizeof(struct parkeduser));
215                 ast_mutex_lock(&parking_lock);
216                 for (x=parking_start;x<=parking_stop;x++) {
217                         cur = parkinglot;
218                         while(cur) {
219                                 if (cur->parkingnum == x) 
220                                         break;
221                                 cur = cur->next;
222                         }
223                         if (!cur)
224                                 break;
225                 }
226                 if (x <= parking_stop) {
227                         chan->appl = "Parked Call";
228                         chan->data = NULL; 
229
230                         pu->chan = chan;
231                         /* Start music on hold */
232                         if (chan != peer)
233                                 ast_moh_start(pu->chan, NULL);
234                         gettimeofday(&pu->start, NULL);
235                         pu->parkingnum = x;
236                         if (timeout > 0)
237                                 pu->parkingtime = timeout;
238                         else
239                                 pu->parkingtime = parkingtime;
240                         if (extout)
241                                 *extout = x;
242                         if (peer)
243                         {
244                                 strncpy(pu->peername,peer->name,sizeof(pu->peername) - 1);
245                         }
246                         /* Remember what had been dialed, so that if the parking
247                            expires, we try to come back to the same place */
248                         if (!ast_strlen_zero(chan->macrocontext))
249                                 strncpy(pu->context, chan->macrocontext, sizeof(pu->context)-1);
250                         else
251                                 strncpy(pu->context, chan->context, sizeof(pu->context)-1);
252                         if (!ast_strlen_zero(chan->macroexten))
253                                 strncpy(pu->exten, chan->macroexten, sizeof(pu->exten)-1);
254                         else
255                                 strncpy(pu->exten, chan->exten, sizeof(pu->exten)-1);
256                         if (chan->macropriority)
257                                 pu->priority = chan->macropriority;
258                         else
259                                 pu->priority = chan->priority;
260                         pu->next = parkinglot;
261                         parkinglot = pu;
262                         /* If parking a channel directly, don't quiet yet get parking running on it */
263                         if (peer == chan) 
264                                 pu->notquiteyet = 1;
265                         ast_mutex_unlock(&parking_lock);
266                         /* Wake up the (presumably select()ing) thread */
267                         pthread_kill(parking_thread, SIGURG);
268                         if (option_verbose > 1) 
269                                 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));
270
271                         manager_event(EVENT_FLAG_CALL, "ParkedCall",
272                                 "Exten: %d\r\n"
273                                 "Channel: %s\r\n"
274                                 "From: %s\r\n"
275                                 "Timeout: %ld\r\n"
276                                 "CallerID: %s\r\n"
277                                 "CallerIDName: %s\r\n\r\n"
278                                 ,pu->parkingnum, pu->chan->name, peer->name
279                                 ,(long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL)
280                                 ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "")
281                                 ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "")
282                                 );
283
284                         if (peer) {
285                                 if (adsipark && adsi_available(peer)) {
286                                         adsi_announce_park(peer, pu->parkingnum);
287                                 }
288                                 if (adsipark && adsi_available(peer)) {
289                                         adsi_unload_session(peer);
290                                 }
291                                 if (pu->notquiteyet) {
292                                         /* Wake up parking thread if we're really done */
293                                         ast_moh_start(pu->chan, NULL);
294                                         pu->notquiteyet = 0;
295                                         pthread_kill(parking_thread, SIGURG);
296                                 }
297                         }
298                         con = ast_context_find(parking_con);
299                         if (!con) {
300                                 con = ast_context_create(NULL,parking_con, registrar);
301                                 if (!con) {
302                                         ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
303                                 }
304                         }
305                         if (con) {
306                                 snprintf(exten, sizeof(exten), "%d", x);
307                                 ast_add_extension2(con, 1, exten, 1, NULL, NULL, parkedcall, strdup(exten), free, registrar);
308                         }
309                         if (peer) ast_say_digits(peer, pu->parkingnum, "", peer->language);
310                         return 0;
311                 } else {
312                         ast_log(LOG_WARNING, "No more parking spaces\n");
313                         free(pu);
314                         ast_mutex_unlock(&parking_lock);
315                         return -1;
316                 }
317         } else {
318                 ast_log(LOG_WARNING, "Out of memory\n");
319                 return -1;
320         }
321         return 0;
322 }
323
324 int ast_masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout)
325 {
326         struct ast_channel *chan;
327         struct ast_frame *f;
328         /* Make a new, fake channel that we'll use to masquerade in the real one */
329         chan = ast_channel_alloc(0);
330         if (chan) {
331                 /* Let us keep track of the channel name */
332                 snprintf(chan->name, sizeof (chan->name), "Parked/%s",rchan->name);
333                 /* Make formats okay */
334                 chan->readformat = rchan->readformat;
335                 chan->writeformat = rchan->writeformat;
336                 ast_channel_masquerade(chan, rchan);
337                 /* Setup the extensions and such */
338                 strncpy(chan->context, rchan->context, sizeof(chan->context) - 1);
339                 strncpy(chan->exten, rchan->exten, sizeof(chan->exten) - 1);
340                 chan->priority = rchan->priority;
341                 /* Make the masq execute */
342                 f = ast_read(chan);
343                 if (f)
344                         ast_frfree(f);
345                 ast_park_call(chan, peer, timeout, extout);
346         } else {
347                 ast_log(LOG_WARNING, "Unable to create parked channel\n");
348                 return -1;
349         }
350         return 0;
351 }
352
353
354 #define FEATURE_RETURN_HANGUP           -1
355 #define FEATURE_RETURN_SUCCESSBREAK      0
356 #define FEATURE_RETURN_PBX_KEEPALIVE    AST_PBX_KEEPALIVE
357 #define FEATURE_RETURN_NO_HANGUP_PEER   AST_PBX_NO_HANGUP_PEER
358 #define FEATURE_RETURN_PASSDIGITS        21
359 #define FEATURE_RETURN_STOREDIGITS       22
360 #define FEATURE_RETURN_SUCCESS           23
361
362 #define FEATURE_SENSE_CHAN      (1 << 0)
363 #define FEATURE_SENSE_PEER      (1 << 1)
364 #define FEATURE_MAX_LEN         11
365
366 static int builtin_automonitor(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
367 {
368         char *args;
369         if (option_verbose > 3)
370         ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to record call.\n", code);
371         if (monitor_ok) {
372                 if (!monitor_app) { 
373                         if (!(monitor_app = pbx_findapp("Monitor"))) {
374                                 monitor_ok=0;
375                                 return -1;
376                         }
377                 }
378                 /* Copy to local variable just in case one of the channels goes away */
379                 args = pbx_builtin_getvar_helper(chan, "TOUCH_MONITOR");
380                 if (!args)
381                         args = pbx_builtin_getvar_helper(peer, "TOUCH_MONITOR");
382                 if (!args)
383                         args = "WAV||m";
384
385                 pbx_exec(peer, monitor_app, args, 1);
386                 if (!ast_strlen_zero(courtesytone)) {
387                         if (ast_autoservice_start(peer))
388                                 return -1;
389                         if (!ast_streamfile(chan, courtesytone, chan->language)) {
390                                 if (ast_waitstream(chan, "") < 0) {
391                                         ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
392                                         ast_autoservice_stop(peer);
393                                         return -1;
394                                 }
395                         }
396                         if (ast_autoservice_stop(peer))
397                                 return -1;
398                 }
399                 return FEATURE_RETURN_SUCCESS;
400         }
401
402         return -1;
403 }
404
405 static int builtin_disconnect(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
406 {
407         if (option_verbose > 3)
408                 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to disconnect call.\n", code);
409         return FEATURE_RETURN_HANGUP;
410 }
411
412 static int builtin_blindtransfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
413 {
414         struct ast_channel *transferer;
415         struct ast_channel *transferee;
416         char *transferer_real_context;
417         char newext[256], *ptr;
418         int res;
419         int len;
420
421         if (sense == FEATURE_SENSE_PEER) {
422                 transferer = peer;
423                 transferee = chan;
424         } else {
425                 transferer = chan;
426                 transferee = peer;
427         }
428         if (!(transferer_real_context=pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT")) &&
429            !(transferer_real_context=pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT"))) {
430                 /* Use the non-macro context to transfer the call */
431                 if (!ast_strlen_zero(transferer->macrocontext))
432                         transferer_real_context = transferer->macrocontext;
433                 else
434                         transferer_real_context = transferer->context;
435         }
436         /* Start autoservice on chan while we talk
437            to the originator */
438         ast_autoservice_start(transferee);
439         ast_moh_start(transferee, NULL);
440
441         memset(newext, 0, sizeof(newext));
442         ptr = newext;
443
444         /* Transfer */
445         if ((res=ast_streamfile(transferer, "pbx-transfer", transferer->language))) {
446                 ast_moh_stop(transferee);
447                 ast_autoservice_stop(transferee);
448                 return res;
449         }
450         if ((res=ast_waitstream(transferer, AST_DIGIT_ANY)) < 0) {
451                 ast_moh_stop(transferee);
452                 ast_autoservice_stop(transferee);
453                 return res;
454         }
455         ast_stopstream(transferer);
456         if (res > 0) {
457                 /* If they've typed a digit already, handle it */
458                 newext[0] = res;
459                 ptr++;
460                 len--;
461         }
462
463         res = ast_app_dtget(transferer, transferer_real_context, newext, sizeof(newext), 100, transferdigittimeout);
464         if (res < 0) {
465                 ast_moh_stop(transferee);
466                 ast_autoservice_stop(transferee);
467                 return res;
468         }
469         if (!strcmp(newext, ast_parking_ext())) {
470                 ast_moh_stop(transferee);
471
472                 if (ast_autoservice_stop(transferee))
473                         res = -1;
474                 else if (!ast_park_call(transferee, transferer, 0, NULL)) {
475                         /* We return non-zero, but tell the PBX not to hang the channel when
476                            the thread dies -- We have to be careful now though.  We are responsible for 
477                            hanging up the channel, else it will never be hung up! */
478
479                         if (transferer==peer)
480                                 res=AST_PBX_KEEPALIVE;
481                         else
482                                 res=AST_PBX_NO_HANGUP_PEER;
483                         return res;
484                 } else {
485                         ast_log(LOG_WARNING, "Unable to park call %s\n", transferee->name);
486                 }
487                 /* XXX Maybe we should have another message here instead of invalid extension XXX */
488         } else if (ast_exists_extension(transferee, transferer_real_context, newext, 1, transferer->cid.cid_num)) {
489                 pbx_builtin_setvar_helper(peer, "BLINDTRANSFER", chan->name);
490                 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", peer->name);
491                 ast_moh_stop(transferee);
492                 res=ast_autoservice_stop(transferee);
493                 if (!transferee->pbx) {
494                         /* Doh!  Use our handy async_goto functions */
495                         if (option_verbose > 2) 
496                                 ast_verbose(VERBOSE_PREFIX_3 "Transferring %s to '%s' (context %s) priority 1\n"
497                                                                 ,transferee->name, newext, transferer_real_context);
498                         if (ast_async_goto(transferee, transferer_real_context, newext, 1))
499                                 ast_log(LOG_WARNING, "Async goto failed :-(\n");
500                         res = -1;
501                 } else {
502                         /* Set the channel's new extension, since it exists, using transferer context */
503                         strncpy(transferee->exten, newext, sizeof(transferee->exten)-1);
504                         strncpy(transferee->context, transferer_real_context, sizeof(transferee->context)-1);
505                         transferee->priority = 0;
506                 }
507                 return res;
508         } else {
509                 if (option_verbose > 2) 
510                         ast_verbose(VERBOSE_PREFIX_3 "Unable to find extension '%s' in context '%s'\n", newext, transferer_real_context);
511         }
512         if (!ast_strlen_zero(xferfailsound))
513                 res = ast_streamfile(transferer, xferfailsound, transferee->language);
514         else
515                 res = 0;
516         if (res) {
517                 ast_moh_stop(transferee);
518                 ast_autoservice_stop(transferee);
519                 return res;
520         }
521         res = ast_waitstream(transferer, AST_DIGIT_ANY);
522         ast_stopstream(transferer);
523         ast_moh_stop(transferee);
524         res = ast_autoservice_stop(transferee);
525         if (res) {
526                 if (option_verbose > 1)
527                         ast_verbose(VERBOSE_PREFIX_2 "Hungup during autoservice stop on '%s'\n", transferee->name);
528                 return res;
529         }
530         return FEATURE_RETURN_SUCCESS;
531 }
532
533 static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
534 {
535         struct ast_channel *transferer;
536         struct ast_channel *transferee;
537         struct ast_channel *newchan, *xferchan=NULL;
538         int outstate=0;
539         struct ast_bridge_config bconfig;
540         char *transferer_real_context;
541         char xferto[256],dialstr[265];
542         char *cid_num;
543         char *cid_name;
544         int res;
545         struct ast_frame *f = NULL;
546         struct ast_bridge_thread_obj *tobj;
547
548         ast_log(LOG_DEBUG, "Executing Attended Transfer %s, %s (sense=%d) XXX\n", chan->name, peer->name, sense);
549         if (sense == FEATURE_SENSE_PEER) {
550                 transferer = peer;
551                 transferee = chan;
552         } else {
553                 transferer = chan;
554                 transferee = peer;
555         }
556         if (!(transferer_real_context=pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT")) &&
557            !(transferer_real_context=pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT"))) {
558                 /* Use the non-macro context to transfer the call */
559                 if (!ast_strlen_zero(transferer->macrocontext))
560                         transferer_real_context = transferer->macrocontext;
561                 else
562                         transferer_real_context = transferer->context;
563         }
564         /* Start autoservice on chan while we talk
565            to the originator */
566         ast_autoservice_start(transferee);
567         ast_moh_start(transferee, NULL);
568
569         /* Transfer */
570         if ((res=ast_streamfile(transferer, "pbx-transfer", transferer->language))) {
571                 ast_moh_stop(transferee);
572                 ast_autoservice_stop(transferee);
573                 return res;
574         }
575         if ((res=ast_waitstream(transferer, AST_DIGIT_ANY)) < 0) {
576                 ast_moh_stop(transferee);
577                 ast_autoservice_stop(transferee);
578                 return res;
579         }
580         if((ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout))) {
581                 cid_num = transferer->cid.cid_num;
582                 cid_name = transferer->cid.cid_name;
583                 if (ast_exists_extension(transferer, transferer_real_context,xferto, 1, cid_num)) {
584                         snprintf(dialstr, sizeof(dialstr), "%s@%s/n", xferto, transferer_real_context);
585                         if((newchan = ast_request_and_dial("Local", ast_best_codec(transferer->nativeformats), dialstr,30000, &outstate, cid_num, cid_name))) {
586                                 res = ast_channel_make_compatible(transferer, newchan);
587                                 if (res < 0) {
588                                         ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", transferer->name, newchan->name);
589                                         ast_hangup(newchan);
590                                         return -1;
591                                 }
592                                 memset(&bconfig,0,sizeof(struct ast_bridge_config));
593                                 bconfig.features_caller |= AST_FEATURE_DISCONNECT;
594                                 bconfig.features_callee |= AST_FEATURE_DISCONNECT;
595                                 res = ast_bridge_call(transferer,newchan,&bconfig);
596                                 if(newchan->_softhangup || newchan->_state != AST_STATE_UP) {
597                                         ast_hangup(newchan);
598                                         if (f) {
599                                                 ast_frfree(f);
600                                                 f = NULL;
601                                         }
602                                         if (!ast_strlen_zero(xfersound) && !ast_streamfile(transferer, xfersound, transferer->language)) {
603                                                 if (ast_waitstream(transferer, "") < 0) {
604                                                         ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
605                                                 }
606                                         }
607                                         ast_moh_stop(transferee);
608                                         ast_autoservice_stop(transferee);
609                                         transferer->_softhangup = 0;
610                                         return FEATURE_RETURN_SUCCESS;
611                                 }
612                                 
613                                 res = ast_channel_make_compatible(transferee, newchan);
614                                 if (res < 0) {
615                                         ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", transferee->name, newchan->name);
616                                         ast_hangup(newchan);
617                                         return -1;
618                                 }
619                                 
620                                 
621                                 ast_moh_stop(transferee);
622                                 
623                                 if((ast_autoservice_stop(transferee) < 0)
624                                    ||(ast_waitfordigit(transferee,100) < 0)
625                                    || (ast_waitfordigit(newchan,100) < 0) 
626                                    || ast_check_hangup(transferee) 
627                                    || ast_check_hangup(newchan)) {
628                                         ast_hangup(newchan);
629                                         res = -1;
630                                         return -1;
631                                 }
632
633                                 if ((xferchan = ast_channel_alloc(0))) {
634                                         snprintf(xferchan->name, sizeof (xferchan->name), "Transfered/%s",transferee->name);
635                                         /* Make formats okay */
636                                         xferchan->readformat = transferee->readformat;
637                                         xferchan->writeformat = transferee->writeformat;
638                                         ast_channel_masquerade(xferchan, transferee);
639                                         ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority);
640                                         xferchan->_state = AST_STATE_UP;
641                                         xferchan->flags = 0;
642                                         xferchan->_softhangup = 0;
643
644                                         if((f = ast_read(xferchan))) {
645                                                 ast_frfree(f);
646                                                 f = NULL;
647                                         }
648                                         
649                                 } else {
650                                         ast_hangup(newchan);
651                                         return -1;
652                                 }
653
654                                 newchan->_state = AST_STATE_UP;
655                                 newchan->flags = 0;
656                                 newchan->_softhangup = 0;
657
658                                 tobj = malloc(sizeof(struct ast_bridge_thread_obj));
659                                 if (tobj) {
660                                         memset(tobj,0,sizeof(struct ast_bridge_thread_obj));
661                                         tobj->chan = xferchan;
662                                         tobj->peer = newchan;
663                                         tobj->bconfig = *config;
664         
665                                         if (!ast_strlen_zero(xfersound) && !ast_streamfile(newchan, xfersound, newchan->language)) {
666                                                 if (ast_waitstream(newchan, "") < 0) {
667                                                         ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
668                                                 }
669                                         }
670                                         ast_bridge_call_thread_launch(tobj);
671                                 } else {
672                                         ast_log(LOG_WARNING, "Out of memory!\n");
673                                         ast_hangup(xferchan);
674                                         ast_hangup(newchan);
675                                 }
676                                 return -1;
677                                 
678                         } else {
679                                 ast_log(LOG_WARNING, "Unable to create channel Local/%s do you have chan_local?\n",dialstr);
680                                 ast_moh_stop(transferee);
681                                 ast_autoservice_stop(transferee);
682                                 if (!ast_strlen_zero(xferfailsound)) {
683                                         res = ast_streamfile(transferer, xferfailsound, transferer->language);
684                                         if (!res && (ast_waitstream(transferer, "") < 0)) {
685                                                 return -1;
686                                         }
687                                 }
688                                 return -1;
689                         }
690                 } else {
691                         ast_log(LOG_WARNING, "Extension %s does not exist in context %s\n",xferto,transferer_real_context);
692                         ast_moh_stop(transferee);
693                         ast_autoservice_stop(transferee);
694                         res = ast_streamfile(transferer, "beeperr", transferer->language);
695                         if (!res && (ast_waitstream(transferer, "") < 0)) {
696                                 return -1;
697                         }
698                 }
699         }  else {
700                 ast_log(LOG_WARNING, "Did not read data.\n");
701                 res = ast_streamfile(transferer, "beeperr", transferer->language);
702                 if (ast_waitstream(transferer, "") < 0) {
703                         return -1;
704                 }
705         }
706         ast_moh_stop(transferee);
707         ast_autoservice_stop(transferee);
708
709
710         return FEATURE_RETURN_SUCCESS;
711 }
712
713 struct ast_call_feature {
714         int feature_mask;
715         char *fname;
716         char *sname;
717         char exten[FEATURE_MAX_LEN];
718         char default_exten[FEATURE_MAX_LEN];
719         int (*operation)(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense);
720         unsigned int flags;
721 };
722
723 /* add atxfer and automon as undefined so you can only use em if you configure them */
724 #define FEATURES_COUNT (sizeof(builtin_features) / sizeof(builtin_features[0]))
725 struct ast_call_feature builtin_features[] = 
726 {
727         { AST_FEATURE_REDIRECT, "Blind Transfer", "blindxfer", "#", "#", builtin_blindtransfer, AST_FEATURE_FLAG_NEEDSDTMF },
728         { AST_FEATURE_REDIRECT, "Attended Transfer", "atxfer", "", "", builtin_atxfer, AST_FEATURE_FLAG_NEEDSDTMF },
729         { AST_FEATURE_AUTOMON, "One Touch Monitor", "automon", "", "", builtin_automonitor, AST_FEATURE_FLAG_NEEDSDTMF },
730         { AST_FEATURE_DISCONNECT, "Disconnect Call", "disconnect", "*", "*", builtin_disconnect, AST_FEATURE_FLAG_NEEDSDTMF },
731 };
732
733 static void unmap_features(void)
734 {
735         int x;
736         for (x=0;x<FEATURES_COUNT;x++)
737                 strcpy(builtin_features[x].exten, builtin_features[x].default_exten);
738 }
739
740 static int remap_feature(const char *name, const char *value)
741 {
742         int x;
743         int res = -1;
744         for (x=0;x<FEATURES_COUNT;x++) {
745                 if (!strcasecmp(name, builtin_features[x].sname)) {
746                         strncpy(builtin_features[x].exten, value, sizeof(builtin_features[x].exten) - 1);
747                         if (option_verbose > 1)
748                                 ast_verbose(VERBOSE_PREFIX_2 "Remapping feature %s (%s) to sequence '%s'\n", builtin_features[x].fname, builtin_features[x].sname, builtin_features[x].exten);
749                         res = 0;
750                 } else if (!strcmp(value, builtin_features[x].exten)) 
751                         ast_log(LOG_WARNING, "Sequence '%s' already mapped to function %s (%s) while assigning to %s\n", value, builtin_features[x].fname, builtin_features[x].sname, name);
752         }
753         return res;
754 }
755
756 static int ast_feature_interpret(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
757 {
758         int x;
759         unsigned int features;
760         int res = FEATURE_RETURN_PASSDIGITS;
761
762         if (sense == FEATURE_SENSE_CHAN)
763                 features = config->features_caller;
764         else
765                 features = config->features_callee;
766         ast_log(LOG_DEBUG, "Feature interpret: chan=%s, peer=%s, sense=%d, features=%d\n", chan->name, peer->name, sense, features);
767         for (x=0;x<FEATURES_COUNT;x++) {
768                 if ((features & builtin_features[x].feature_mask) &&
769                     !ast_strlen_zero(builtin_features[x].exten)) {
770                         /* Feature is up for consideration */
771                         if (!strcmp(builtin_features[x].exten, code)) {
772                                 res = builtin_features[x].operation(chan, peer, config, code, sense);
773                                 break;
774                         } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) {
775                                 if (res == FEATURE_RETURN_PASSDIGITS)
776                                         res = FEATURE_RETURN_STOREDIGITS;
777                         }
778                 }
779         }
780         return res;
781 }
782
783 static void set_config_flags(struct ast_bridge_config *config)
784 {
785         int x;
786         config->flags = 0;
787         for (x=0;x<FEATURES_COUNT;x++) {
788                 if (config->features_caller & builtin_features[x].feature_mask) {
789                         if (builtin_features[x].flags & AST_FEATURE_FLAG_NEEDSDTMF)
790                                 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
791                 }
792                 if (config->features_callee & builtin_features[x].feature_mask) {
793                         if (builtin_features[x].flags & AST_FEATURE_FLAG_NEEDSDTMF)
794                                 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
795                 }
796         }
797 }
798
799 int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast_bridge_config *config)
800 {
801         /* Copy voice back and forth between the two channels.  Give the peer
802            the ability to transfer calls with '#<extension' syntax. */
803         struct ast_frame *f;
804         struct ast_channel *who;
805         char chan_featurecode[FEATURE_MAX_LEN + 1]="";
806         char peer_featurecode[FEATURE_MAX_LEN + 1]="";
807         int res;
808         int diff;
809         int hasfeatures=0;
810         int hadfeatures=0;
811         struct ast_option_header *aoh;
812         struct timeval start, end;
813         struct ast_bridge_config backup_config;
814         int allowdisconnect_in,allowdisconnect_out,allowredirect_in,allowredirect_out;
815         char *monitor_exec;
816
817         memset(&backup_config, 0, sizeof(backup_config));
818
819         if (chan && peer) {
820                 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
821                 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
822         } else if (chan)
823                 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
824
825         if (monitor_ok) {
826                 if (!monitor_app) { 
827                         if (!(monitor_app = pbx_findapp("Monitor")))
828                                 monitor_ok=0;
829                 }
830                 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 
831                         pbx_exec(chan, monitor_app, monitor_exec, 1);
832                 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
833                         pbx_exec(peer, monitor_app, monitor_exec, 1);
834         }
835         
836         allowdisconnect_in = (config->features_callee & AST_FEATURE_DISCONNECT);
837         allowdisconnect_out = (config->features_caller & AST_FEATURE_DISCONNECT);
838         allowredirect_in = (config->features_callee & AST_FEATURE_REDIRECT);
839         allowredirect_out = (config->features_caller & AST_FEATURE_REDIRECT);
840         set_config_flags(config);
841         config->firstpass = 1;
842
843         /* Answer if need be */
844         if (ast_answer(chan))
845                 return -1;
846         peer->appl = "Bridged Call";
847         peer->data = chan->name;
848         /* copy the userfield from the B-leg to A-leg if applicable */
849         if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) {
850                 char tmp[256];
851                 if (!ast_strlen_zero(chan->cdr->userfield)) {
852                         snprintf(tmp, sizeof(tmp), "%s;%s",chan->cdr->userfield, peer->cdr->userfield);
853                         ast_cdr_appenduserfield(chan, tmp);
854                 } else
855                         ast_cdr_setuserfield(chan, peer->cdr->userfield);
856                 /* free the peer's cdr without ast_cdr_free complaining */
857                 free(peer->cdr);
858                 peer->cdr = NULL;
859         }
860         for (;;) {
861                 if (config->timelimit)
862                         gettimeofday(&start, NULL);
863                 res = ast_channel_bridge(chan,peer,config,&f, &who);
864                 if (config->timelimit) {
865                         /* Update time limit for next pass */
866                         gettimeofday(&end, NULL);
867                         diff = (end.tv_sec - start.tv_sec) * 1000;
868                         diff += (end.tv_usec - start.tv_usec) / 1000;
869                         config->timelimit -= diff;
870                         if (hasfeatures) {
871                                 /* Running on backup config, meaning a feature might be being
872                                    activated, but that's no excuse to keep things going 
873                                    indefinitely! */
874                                 if (backup_config.timelimit && ((backup_config.timelimit -= diff) <= 0)) {
875                                         ast_log(LOG_DEBUG, "Timed out, realtime this time!\n");
876                                         config->timelimit = 0;
877                                         who = chan;
878                                         if (f)
879                                                 ast_frfree(f);
880                                         f = NULL;
881                                         res = 0;
882                                 } else if (config->timelimit <= 0) {
883                                         /* Not *really* out of time, just out of time for
884                                            digits to come in for features. */
885                                         ast_log(LOG_DEBUG, "Timed out for feature!\n");
886                                         if (!ast_strlen_zero(peer_featurecode)) {
887                                                 ast_dtmf_stream(chan, peer, peer_featurecode, 0);
888                                                 memset(peer_featurecode, 0, sizeof(peer_featurecode));
889                                         }
890                                         if (!ast_strlen_zero(chan_featurecode)) {
891                                                 ast_dtmf_stream(peer, chan, chan_featurecode, 0);
892                                                 memset(chan_featurecode, 0, sizeof(chan_featurecode));
893                                         }
894                                         if (f)
895                                                 ast_frfree(f);
896                                         hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
897                                         if (!hasfeatures) {
898                                                 /* Restore original (possibly time modified) bridge config */
899                                                 memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
900                                                 memset(&backup_config, 0, sizeof(backup_config));
901                                         }
902                                         hadfeatures = hasfeatures;
903                                         /* Continue as we were */
904                                         continue;
905                                 }
906                         } else {
907                                 if (config->timelimit <=0) {
908                                         /* We ran out of time */
909                                         config->timelimit = 0;
910                                         who = chan;
911                                         if (f)
912                                                 ast_frfree(f);
913                                         f = NULL;
914                                         res = 0;
915                                 }
916                         }
917                 }
918                 if (res < 0) {
919                         ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
920                         return -1;
921                 }
922                 
923                 if (!f || ((f->frametype == AST_FRAME_CONTROL) && ((f->subclass == AST_CONTROL_HANGUP) || (f->subclass == AST_CONTROL_BUSY) || 
924                         (f->subclass == AST_CONTROL_CONGESTION)))) {
925                                 res = -1;
926                                 break;
927                 }
928                 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_RINGING)) {
929                         if (who == chan)
930                                 ast_indicate(peer, AST_CONTROL_RINGING);
931                         else
932                                 ast_indicate(chan, AST_CONTROL_RINGING);
933                 }
934                 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == -1)) {
935                         if (who == chan)
936                                 ast_indicate(peer, -1);
937                         else
938                                 ast_indicate(chan, -1);
939                 }
940                 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_FLASH)) {
941                         if (who == chan)
942                                 ast_indicate(peer, AST_CONTROL_FLASH);
943                         else
944                                 ast_indicate(chan, AST_CONTROL_FLASH);
945                 }
946                 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_OPTION)) {
947                         aoh = f->data;
948                         /* Forward option Requests */
949                         if (aoh && (aoh->flag == AST_OPTION_FLAG_REQUEST)) {
950                                 if (who == chan)
951                                         ast_channel_setoption(peer, ntohs(aoh->option), aoh->data, f->datalen - sizeof(struct ast_option_header), 0);
952                                 else
953                                         ast_channel_setoption(chan, ntohs(aoh->option), aoh->data, f->datalen - sizeof(struct ast_option_header), 0);
954                         }
955                 }
956                 /* check for '*', if we find it it's time to disconnect */
957                 if (f && (f->frametype == AST_FRAME_DTMF)) {
958                         char *featurecode;
959                         int sense;
960                         struct ast_channel *other;
961                         hadfeatures = hasfeatures;
962                         /* This cannot overrun because the longest feature is one shorter than our buffer */
963                         if (who == chan) {
964                                 other = peer;
965                                 sense = FEATURE_SENSE_CHAN;
966                                 featurecode = chan_featurecode;
967                         } else  {
968                                 other = chan;
969                                 sense = FEATURE_SENSE_PEER;
970                                 featurecode = peer_featurecode;
971                         }
972                         featurecode[strlen(featurecode)] = f->subclass;
973                         config->timelimit = backup_config.timelimit;
974                         res = ast_feature_interpret(chan, peer, config, featurecode, sense);
975                         switch(res) {
976                         case FEATURE_RETURN_PASSDIGITS:
977                                 ast_dtmf_stream(other, who, featurecode, 0);
978                                 /* Fall through */
979                         case FEATURE_RETURN_SUCCESS:
980                                 memset(featurecode, 0, sizeof(chan_featurecode));
981                                 break;
982                         }
983                         if (res >= FEATURE_RETURN_PASSDIGITS) {
984                                 res = 0;
985                         } else {
986                                 ast_frfree(f);
987                                 break;
988                         }
989                         hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
990                         if (hadfeatures && !hasfeatures) {
991                                 /* Restore backup */
992                                 memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
993                                 memset(&backup_config, 0, sizeof(struct ast_bridge_config));
994                         } else if (hasfeatures) {
995                                 if (!hadfeatures) {
996                                         /* Backup configuration */
997                                         memcpy(&backup_config, config, sizeof(struct ast_bridge_config));
998                                         /* Setup temporary config options */
999                                         config->play_warning = 0;
1000                                         config->features_caller &= ~(AST_FEATURE_PLAY_WARNING);
1001                                         config->features_callee &= ~(AST_FEATURE_PLAY_WARNING);
1002                                         config->warning_freq = 0;
1003                                         config->warning_sound = NULL;
1004                                         config->end_sound = NULL;
1005                                         config->start_sound = NULL;
1006                                         config->firstpass = 0;
1007                                 }
1008                                 config->timelimit = featuredigittimeout;
1009                                 ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->timelimit);
1010                         }
1011                 }
1012                 if (f)
1013                         ast_frfree(f);
1014         }
1015         return res;
1016 }
1017
1018 static void *do_parking_thread(void *ignore)
1019 {
1020         int ms, tms, max;
1021         struct parkeduser *pu, *pl, *pt = NULL;
1022         struct timeval tv;
1023         struct ast_frame *f;
1024         char exten[AST_MAX_EXTENSION];
1025         char *peername,*cp;
1026         struct ast_context *con;
1027         int x;
1028         int gc=0;
1029         fd_set rfds, efds;
1030         fd_set nrfds, nefds;
1031         FD_ZERO(&rfds);
1032         FD_ZERO(&efds);
1033
1034         for (;;) {
1035                 ms = -1;
1036                 max = -1;
1037                 ast_mutex_lock(&parking_lock);
1038                 pl = NULL;
1039                 pu = parkinglot;
1040                 FD_ZERO(&nrfds);
1041                 FD_ZERO(&nefds);
1042                 while(pu) {
1043                         if (pu->notquiteyet) {
1044                                 /* Pretend this one isn't here yet */
1045                                 pl = pu;
1046                                 pu = pu->next;
1047                                 continue;
1048                         }
1049                         if (gc < 5 && !pu->chan->generator) {
1050                                 gc++;
1051                                 ast_moh_start(pu->chan,NULL);
1052                         }
1053                         gettimeofday(&tv, NULL);
1054                         tms = (tv.tv_sec - pu->start.tv_sec) * 1000 + (tv.tv_usec - pu->start.tv_usec) / 1000;
1055                         if (tms > pu->parkingtime) {
1056                                 /* Stop music on hold */
1057                                 ast_moh_stop(pu->chan);
1058                                 /* Get chan, exten from derived kludge */
1059                                 if (pu->peername[0]) {
1060                                         peername = ast_strdupa(pu->peername);
1061                                         cp = strrchr(peername, '-');
1062                                         if (cp) 
1063                                                 *cp = 0;
1064                                         con = ast_context_find(parking_con_dial);
1065                                         if (!con) {
1066                                                 con = ast_context_create(NULL, parking_con_dial, registrar);
1067                                                 if (!con) {
1068                                                         ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial);
1069                                                 }
1070                                         }
1071                                         if (con) {
1072                                                 ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(peername), free, registrar);
1073                                         }
1074                                         strncpy(pu->chan->exten, peername, sizeof(pu->chan->exten) - 1);
1075                                         strncpy(pu->chan->context, parking_con_dial, sizeof(pu->chan->context) - 1);
1076                                         pu->chan->priority = 1;
1077
1078                                 } else {
1079                                         /* They've been waiting too long, send them back to where they came.  Theoretically they
1080                                            should have their original extensions and such, but we copy to be on the safe side */
1081                                         strncpy(pu->chan->exten, pu->exten, sizeof(pu->chan->exten)-1);
1082                                         strncpy(pu->chan->context, pu->context, sizeof(pu->chan->context)-1);
1083                                         pu->chan->priority = pu->priority;
1084                                 }
1085                                 if (option_verbose > 1) 
1086                                         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);
1087                                 /* Start up the PBX, or hang them up */
1088                                 if (ast_pbx_start(pu->chan))  {
1089                                         ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", pu->chan->name);
1090                                         ast_hangup(pu->chan);
1091                                 }
1092                                 /* And take them out of the parking lot */
1093                                 if (pl) 
1094                                         pl->next = pu->next;
1095                                 else
1096                                         parkinglot = pu->next;
1097                                 pt = pu;
1098                                 pu = pu->next;
1099                                 con = ast_context_find(parking_con);
1100                                 if (con) {
1101                                         snprintf(exten, sizeof(exten), "%d", pt->parkingnum);
1102                                         if (ast_context_remove_extension2(con, exten, 1, NULL))
1103                                                 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
1104                                 } else
1105                                         ast_log(LOG_WARNING, "Whoa, no parking context?\n");
1106                                 free(pt);
1107                         } else {
1108                                 for (x=0; x<AST_MAX_FDS; x++) {
1109                                         if ((pu->chan->fds[x] > -1) && (FD_ISSET(pu->chan->fds[x], &rfds) || FD_ISSET(pu->chan->fds[x], &efds))) {
1110                                                 if (FD_ISSET(pu->chan->fds[x], &efds))
1111                                                         ast_set_flag(pu->chan, AST_FLAG_EXCEPTION);
1112                                                 else
1113                                                         ast_clear_flag(pu->chan, AST_FLAG_EXCEPTION);
1114                                                 pu->chan->fdno = x;
1115                                                 /* See if they need servicing */
1116                                                 f = ast_read(pu->chan);
1117                                                 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass ==  AST_CONTROL_HANGUP))) {
1118                                                         /* There's a problem, hang them up*/
1119                                                         if (option_verbose > 1) 
1120                                                                 ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being parked\n", pu->chan->name);
1121                                                         ast_hangup(pu->chan);
1122                                                         /* And take them out of the parking lot */
1123                                                         if (pl) 
1124                                                                 pl->next = pu->next;
1125                                                         else
1126                                                                 parkinglot = pu->next;
1127                                                         pt = pu;
1128                                                         pu = pu->next;
1129                                                         con = ast_context_find(parking_con);
1130                                                         if (con) {
1131                                                                 snprintf(exten, sizeof(exten), "%d", pt->parkingnum);
1132                                                                 if (ast_context_remove_extension2(con, exten, 1, NULL))
1133                                                                         ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
1134                                                         } else
1135                                                                 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
1136                                                         free(pt);
1137                                                         break;
1138                                                 } else {
1139                                                         /* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
1140                                                         ast_frfree(f);
1141                                                         goto std;       /* XXX Ick: jumping into an else statement??? XXX */
1142                                                 }
1143                                         }
1144                                 }
1145                                 if (x >= AST_MAX_FDS) {
1146 std:                                    for (x=0; x<AST_MAX_FDS; x++) {
1147                                                 /* Keep this one for next one */
1148                                                 if (pu->chan->fds[x] > -1) {
1149                                                         FD_SET(pu->chan->fds[x], &nrfds);
1150                                                         FD_SET(pu->chan->fds[x], &nefds);
1151                                                         if (pu->chan->fds[x] > max)
1152                                                                 max = pu->chan->fds[x];
1153                                                 }
1154                                         }
1155                                         /* Keep track of our longest wait */
1156                                         if ((tms < ms) || (ms < 0))
1157                                                 ms = tms;
1158                                         pl = pu;
1159                                         pu = pu->next;
1160                                 }
1161                         }
1162                 }
1163                 ast_mutex_unlock(&parking_lock);
1164                 rfds = nrfds;
1165                 efds = nefds;
1166                 tv.tv_sec = ms / 1000;
1167                 tv.tv_usec = (ms % 1000) * 1000;
1168                 /* Wait for something to happen */
1169                 ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL);
1170                 pthread_testcancel();
1171         }
1172         return NULL;    /* Never reached */
1173 }
1174
1175 static int park_call_exec(struct ast_channel *chan, void *data)
1176 {
1177         /* Data is unused at the moment but could contain a parking
1178            lot context eventually */
1179         int res=0;
1180         struct localuser *u;
1181         LOCAL_USER_ADD(u);
1182         /* Setup the exten/priority to be s/1 since we don't know
1183            where this call should return */
1184         strcpy(chan->exten, "s");
1185         chan->priority = 1;
1186         if (chan->_state != AST_STATE_UP)
1187                 res = ast_answer(chan);
1188         if (!res)
1189                 res = ast_safe_sleep(chan, 1000);
1190         if (!res)
1191                 res = ast_park_call(chan, chan, 0, NULL);
1192         LOCAL_USER_REMOVE(u);
1193         if (!res)
1194                 res = AST_PBX_KEEPALIVE;
1195         return res;
1196 }
1197
1198 static int park_exec(struct ast_channel *chan, void *data)
1199 {
1200         int res=0;
1201         struct localuser *u;
1202         struct ast_channel *peer=NULL;
1203         struct parkeduser *pu, *pl=NULL;
1204         char exten[AST_MAX_EXTENSION];
1205         struct ast_context *con;
1206         int park;
1207         int dres;
1208         struct ast_bridge_config config;
1209
1210         if (!data) {
1211                 ast_log(LOG_WARNING, "Park requires an argument (extension number)\n");
1212                 return -1;
1213         }
1214         LOCAL_USER_ADD(u);
1215         park = atoi((char *)data);
1216         ast_mutex_lock(&parking_lock);
1217         pu = parkinglot;
1218         while(pu) {
1219                 if (pu->parkingnum == park) {
1220                         if (pl)
1221                                 pl->next = pu->next;
1222                         else
1223                                 parkinglot = pu->next;
1224                         break;
1225                 }
1226                 pl = pu;
1227                 pu = pu->next;
1228         }
1229         ast_mutex_unlock(&parking_lock);
1230         if (pu) {
1231                 peer = pu->chan;
1232                 con = ast_context_find(parking_con);
1233                 if (con) {
1234                         snprintf(exten, sizeof(exten), "%d", pu->parkingnum);
1235                         if (ast_context_remove_extension2(con, exten, 1, NULL))
1236                                 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
1237                 } else
1238                         ast_log(LOG_WARNING, "Whoa, no parking context?\n");
1239                 free(pu);
1240         }
1241         /* JK02: it helps to answer the channel if not already up */
1242         if (chan->_state != AST_STATE_UP) {
1243                 ast_answer(chan);
1244         }
1245
1246         if (peer) {
1247                 /* Play a courtesy beep in the calling channel to prefix the bridge connecting */       
1248                 if (!ast_strlen_zero(courtesytone)) {
1249                         if (!ast_streamfile(chan, courtesytone, chan->language)) {
1250                                 if (ast_waitstream(chan, "") < 0) {
1251                                         ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
1252                                         ast_hangup(peer);
1253                                         return -1;
1254                                 }
1255                         }
1256                 }
1257  
1258                 ast_moh_stop(peer);
1259                 res = ast_channel_make_compatible(chan, peer);
1260                 if (res < 0) {
1261                         ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
1262                         ast_hangup(peer);
1263                         return -1;
1264                 }
1265                 /* This runs sorta backwards, since we give the incoming channel control, as if it
1266                    were the person called. */
1267                 if (option_verbose > 2) 
1268                         ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to parked call %d\n", chan->name, park);
1269
1270                 memset(&config,0,sizeof(struct ast_bridge_config));
1271                 config.features_callee |= AST_FEATURE_REDIRECT;
1272                 config.features_caller |= AST_FEATURE_REDIRECT;
1273                 config.timelimit = 0;
1274                 config.play_warning = 0;
1275                 config.warning_freq = 0;
1276                 config.warning_sound=NULL;
1277                 res = ast_bridge_call(chan,peer,&config);
1278
1279                 /* Simulate the PBX hanging up */
1280                 if (res != AST_PBX_NO_HANGUP_PEER)
1281                         ast_hangup(peer);
1282                 return res;
1283         } else {
1284                 /* XXX Play a message XXX */
1285                 dres = ast_streamfile(chan, "pbx-invalidpark", chan->language);
1286                 if (!dres)
1287                         dres = ast_waitstream(chan, "");
1288                  else {
1289                         ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
1290                         dres = 0;
1291                 }
1292                 if (option_verbose > 2) 
1293                         ast_verbose(VERBOSE_PREFIX_3 "Channel %s tried to talk to non-existant parked call %d\n", chan->name, park);
1294                 res = -1;
1295         }
1296         LOCAL_USER_REMOVE(u);
1297         return res;
1298 }
1299
1300 static int handle_parkedcalls(int fd, int argc, char *argv[])
1301 {
1302         struct parkeduser *cur;
1303
1304         ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
1305                 , "Context", "Extension", "Pri", "Timeout");
1306
1307         ast_mutex_lock(&parking_lock);
1308
1309         cur = parkinglot;
1310         while(cur) {
1311                 ast_cli(fd, "%4d %25s (%-15s %-12s %-4d) %6lds\n"
1312                         ,cur->parkingnum, cur->chan->name, cur->context, cur->exten
1313                         ,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL));
1314
1315                 cur = cur->next;
1316         }
1317
1318         ast_mutex_unlock(&parking_lock);
1319
1320         return RESULT_SUCCESS;
1321 }
1322
1323 static char showparked_help[] =
1324 "Usage: show parkedcalls\n"
1325 "       Lists currently parked calls.\n";
1326
1327 static struct ast_cli_entry showparked =
1328 { { "show", "parkedcalls", NULL }, handle_parkedcalls, "Lists parked calls", showparked_help };
1329 /* Dump lot status */
1330 static int manager_parking_status( struct mansession *s, struct message *m )
1331 {
1332         struct parkeduser *cur;
1333         char *id = astman_get_header(m,"ActionID");
1334         char idText[256] = "";
1335
1336         if (id && !ast_strlen_zero(id))
1337                 snprintf(idText,256,"ActionID: %s\r\n",id);
1338
1339         astman_send_ack(s, m, "Parked calls will follow");
1340
1341         ast_mutex_lock(&parking_lock);
1342
1343         cur=parkinglot;
1344         while(cur) {
1345                         ast_mutex_lock(&s->lock);
1346                 ast_cli(s->fd, "Event: ParkedCall\r\n"
1347                         "Exten: %d\r\n"
1348                         "Channel: %s\r\n"
1349                         "Timeout: %ld\r\n"
1350                         "CallerID: %s\r\n"
1351                         "CallerIDName: %s\r\n"
1352                         "%s"
1353                         "\r\n"
1354                         ,cur->parkingnum, cur->chan->name
1355                         ,(long)cur->start.tv_sec + (long)(cur->parkingtime/1000) - (long)time(NULL)
1356                         ,(cur->chan->cid.cid_num ? cur->chan->cid.cid_num : "")
1357                         ,(cur->chan->cid.cid_name ? cur->chan->cid.cid_name : "")
1358                         ,idText);
1359                         ast_mutex_unlock(&s->lock);
1360
1361             cur = cur->next;
1362         }
1363
1364         ast_cli(s->fd,
1365         "Event: ParkedCallsComplete\r\n"
1366         "%s"
1367         "\r\n",idText);
1368
1369         ast_mutex_unlock(&parking_lock);
1370
1371         return RESULT_SUCCESS;
1372 }
1373
1374
1375
1376 int load_module(void)
1377 {
1378         int res;
1379         int start, end;
1380         struct ast_context *con;
1381         struct ast_config *cfg;
1382         struct ast_variable *var;
1383
1384         transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
1385         featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
1386
1387         ast_cli_register(&showparked);
1388
1389         cfg = ast_load("features.conf");
1390         if (!cfg) {
1391                 cfg = ast_load("parking.conf");
1392                 if (cfg)
1393                         ast_log(LOG_NOTICE, "parking.conf is deprecated in favor of 'features.conf'.  Please rename it.\n");
1394         }
1395         if (cfg) {
1396                 var = ast_variable_browse(cfg, "general");
1397                 while(var) {
1398                         if (!strcasecmp(var->name, "parkext")) {
1399                                 strncpy(parking_ext, var->value, sizeof(parking_ext) - 1);
1400                         } else if (!strcasecmp(var->name, "context")) {
1401                                 strncpy(parking_con, var->value, sizeof(parking_con) - 1);
1402                         } else if (!strcasecmp(var->name, "parkingtime")) {
1403                                 if ((sscanf(var->value, "%d", &parkingtime) != 1) || (parkingtime < 1)) {
1404                                         ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value);
1405                                         parkingtime = DEFAULT_PARK_TIME;
1406                                 } else
1407                                         parkingtime = parkingtime * 1000;
1408                         } else if (!strcasecmp(var->name, "parkpos")) {
1409                                 if (sscanf(var->value, "%i-%i", &start, &end) != 2) {
1410                                         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);
1411                                 } else {
1412                                         parking_start = start;
1413                                         parking_stop = end;
1414                                 }
1415                         } else if (!strcasecmp(var->name, "adsipark")) {
1416                                 adsipark = ast_true(var->value);
1417                         } else if (!strcasecmp(var->name, "transferdigittimeout")) {
1418                                 if ((sscanf(var->value, "%d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) {
1419                                         ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value);
1420                                         transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
1421                                 } else
1422                                         transferdigittimeout = transferdigittimeout * 1000;
1423                         } else if (!strcasecmp(var->name, "featuredigittimeout")) {
1424                                 if ((sscanf(var->value, "%d", &featuredigittimeout) != 1) || (transferdigittimeout < 1)) {
1425                                         ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value);
1426                                         featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
1427                                 }
1428                         } else if (!strcasecmp(var->name, "courtesytone")) {
1429                                 strncpy(courtesytone, var->value, sizeof(courtesytone) - 1);
1430                         } else if (!strcasecmp(var->name, "xfersound")) {
1431                                 strncpy(xfersound, var->value, sizeof(xfersound) - 1);
1432                         } else if (!strcasecmp(var->name, "xferfailsound")) {
1433                                 strncpy(xferfailsound, var->value, sizeof(xferfailsound) - 1);
1434                         } else if (!strcasecmp(var->name, "pickupexten")) {
1435                                 strncpy(pickup_ext, var->value, sizeof(pickup_ext) - 1);
1436                         }
1437                         var = var->next;
1438                 }
1439                 unmap_features();
1440                 var = ast_variable_browse(cfg, "featuremap");
1441                 while(var) {
1442                         if (remap_feature(var->name, var->value))
1443                                 ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name);
1444                         var = var->next;
1445                 }
1446                 ast_destroy(cfg);
1447         }
1448         con = ast_context_find(parking_con);
1449         if (!con) {
1450                 con = ast_context_create(NULL,parking_con, registrar);
1451                 if (!con) {
1452                         ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
1453                         return -1;
1454                 }
1455         }
1456         ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, strdup(""),free, registrar);
1457         ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
1458         res = ast_register_application(parkedcall, park_exec, synopsis, descrip);
1459         if (!res)
1460                 res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2);
1461         if (!res) {
1462                 ast_manager_register( "ParkedCalls", 0, manager_parking_status, "List parked calls" );
1463         }
1464         return res;
1465 }
1466
1467 int ast_pickup_call(struct ast_channel *chan)
1468 {
1469         struct ast_channel *cur;
1470         int res = -1;
1471         cur = ast_channel_walk_locked(NULL);
1472         while(cur) {
1473                 if (!cur->pbx && 
1474                         (cur != chan) &&
1475                         (chan->pickupgroup & cur->callgroup) &&
1476                         ((cur->_state == AST_STATE_RINGING) ||
1477                          (cur->_state == AST_STATE_RING))) {
1478                                 break;
1479                 }
1480                 ast_mutex_unlock(&cur->lock);
1481                 cur = ast_channel_walk_locked(cur);
1482         }
1483         if (cur) {
1484                 if (option_debug)
1485                         ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
1486                 res = ast_answer(chan);
1487                 if (res)
1488                         ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
1489                 res = ast_queue_control(chan, AST_CONTROL_ANSWER);
1490                 if (res)
1491                         ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
1492                 res = ast_channel_masquerade(cur, chan);
1493                 if (res)
1494                         ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name);           /* Done */
1495                 ast_mutex_unlock(&cur->lock);
1496         } else  {
1497                 if (option_debug)
1498                         ast_log(LOG_DEBUG, "No call pickup possible...\n");
1499         }
1500         return res;
1501 }
1502
1503 int unload_module(void)
1504 {
1505         STANDARD_HANGUP_LOCALUSERS;
1506
1507         ast_manager_unregister( "ParkedCalls" );
1508         ast_cli_unregister(&showparked);
1509         ast_unregister_application(parkcall);
1510         return ast_unregister_application(parkedcall);
1511 }
1512
1513 char *description(void)
1514 {
1515         return "Call Parking Resource";
1516 }
1517
1518 int usecount(void)
1519 {
1520         /* Never allow parking to be unloaded because it will
1521            unresolve needed symbols in the dialer */
1522 #if 0
1523         int res;
1524         STANDARD_USECOUNT(res);
1525         return res;
1526 #else
1527         return 1;
1528 #endif
1529 }
1530
1531 char *key()
1532 {
1533         return ASTERISK_GPL_KEY;
1534 }