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