a few cleanups from the last commit
[asterisk/asterisk.git] / res / res_features.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2006, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  *
21  * \brief Routines implementing call features as call pickup, parking and transfer
22  *
23  * \author Mark Spencer <markster@digium.com> 
24  */
25
26 #include <pthread.h>
27 #include <stdlib.h>
28 #include <errno.h>
29 #include <unistd.h>
30 #include <string.h>
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <sys/time.h>
34 #include <sys/signal.h>
35 #include <netinet/in.h>
36
37 #include "asterisk.h"
38
39 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
40
41 #include "asterisk/lock.h"
42 #include "asterisk/file.h"
43 #include "asterisk/logger.h"
44 #include "asterisk/channel.h"
45 #include "asterisk/pbx.h"
46 #include "asterisk/options.h"
47 #include "asterisk/causes.h"
48 #include "asterisk/module.h"
49 #include "asterisk/translate.h"
50 #include "asterisk/app.h"
51 #include "asterisk/say.h"
52 #include "asterisk/features.h"
53 #include "asterisk/musiconhold.h"
54 #include "asterisk/config.h"
55 #include "asterisk/cli.h"
56 #include "asterisk/manager.h"
57 #include "asterisk/utils.h"
58 #include "asterisk/adsi.h"
59 #include "asterisk/monitor.h"
60
61 #ifdef __AST_DEBUG_MALLOC
62 static void FREE(void *ptr)
63 {
64         free(ptr);
65 }
66 #else
67 #define FREE free
68 #endif
69
70 #define DEFAULT_PARK_TIME 45000
71 #define DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000
72 #define DEFAULT_FEATURE_DIGIT_TIMEOUT 500
73
74 #define AST_MAX_WATCHERS 256
75
76 static char *parkedcall = "ParkedCall";
77
78 static int parkingtime = DEFAULT_PARK_TIME;             /*!< No more than 45 seconds parked before you do something with them */
79 static char parking_con[AST_MAX_EXTENSION];             /*!< Context for which parking is made accessible */
80 static char parking_con_dial[AST_MAX_EXTENSION];        /*!< Context for dialback for parking (KLUDGE) */
81 static char parking_ext[AST_MAX_EXTENSION];             /*!< Extension you type to park the call */
82 static char pickup_ext[AST_MAX_EXTENSION];              /*!< Call pickup extension */
83 static int parking_start;                               /*!< First available extension for parking */
84 static int parking_stop;                                /*!< Last available extension for parking */
85
86 static char courtesytone[256];                          /*!< Courtesy tone */
87 static int parkedplay = 0;                              /*!< Who to play the courtesy tone to */
88 static char xfersound[256];                             /*!< Call transfer sound */
89 static char xferfailsound[256];                         /*!< Call transfer failure sound */
90
91 static int parking_offset;
92 static int parkfindnext;
93
94 static int adsipark;
95
96 static int transferdigittimeout;
97 static int featuredigittimeout;
98
99 static char *registrar = "res_features";                /*!< Registrar for operations */
100
101 /* module and CLI command definitions */
102 static char *synopsis = "Answer a parked call";
103
104 static char *descrip = "ParkedCall(exten):"
105 "Used to connect to a parked call.  This application is always\n"
106 "registered internally and does not need to be explicitly added\n"
107 "into the dialplan, although you should include the 'parkedcalls'\n"
108 "context.\n";
109
110 static char *parkcall = "Park";
111
112 static char *synopsis2 = "Park yourself";
113
114 static char *descrip2 = "Park(exten):"
115 "Used to park yourself (typically in combination with a supervised\n"
116 "transfer to know the parking space). This application is always\n"
117 "registered internally and does not need to be explicitly added\n"
118 "into the dialplan, although you should include the 'parkedcalls'\n"
119 "context.\n";
120
121 static struct ast_app *monitor_app = NULL;
122 static int monitor_ok = 1;
123
124 struct parkeduser {
125         struct ast_channel *chan;
126         struct timeval start;
127         int parkingnum;
128         /* Where to go if our parking time expires */
129         char context[AST_MAX_CONTEXT];
130         char exten[AST_MAX_EXTENSION];
131         int priority;
132         int parkingtime;
133         int notquiteyet;
134         char peername[1024];
135         unsigned char moh_trys;
136         struct parkeduser *next;
137 };
138
139 static struct parkeduser *parkinglot;
140
141 AST_MUTEX_DEFINE_STATIC(parking_lock);
142
143 static pthread_t parking_thread;
144
145 LOCAL_USER_DECL;
146
147 char *ast_parking_ext(void)
148 {
149         return parking_ext;
150 }
151
152 char *ast_pickup_ext(void)
153 {
154         return pickup_ext;
155 }
156
157 struct ast_bridge_thread_obj 
158 {
159         struct ast_bridge_config bconfig;
160         struct ast_channel *chan;
161         struct ast_channel *peer;
162 };
163
164 static void check_goto_on_transfer(struct ast_channel *chan) 
165 {
166         struct ast_channel *xferchan;
167         const char *val = pbx_builtin_getvar_helper(chan, "GOTO_ON_BLINDXFR");
168         char *x, *goto_on_transfer;
169         struct ast_frame *f;
170
171         if (!ast_strlen_zero(val) && (goto_on_transfer = ast_strdupa(val)) && (xferchan = ast_channel_alloc(0))) {
172                 for (x = goto_on_transfer; x && *x; x++)
173                         if (*x == '^')
174                                 *x = '|';
175                 ast_string_field_set(xferchan, name, chan->name);
176                 /* Make formats okay */
177                 xferchan->readformat = chan->readformat;
178                 xferchan->writeformat = chan->writeformat;
179                 ast_channel_masquerade(xferchan, chan);
180                 ast_parseable_goto(xferchan, goto_on_transfer);
181                 xferchan->_state = AST_STATE_UP;
182                 ast_clear_flag(xferchan, AST_FLAGS_ALL);        
183                 xferchan->_softhangup = 0;
184                 if ((f = ast_read(xferchan))) {
185                         ast_frfree(f);
186                         f = NULL;
187                         ast_pbx_start(xferchan);
188                 } else {
189                         ast_hangup(xferchan);
190                 }
191         }
192 }
193
194 static struct ast_channel *ast_feature_request_and_dial(struct ast_channel *caller, const char *type, int format, void *data, int timeout, int *outstate, const char *cid_num, const char *cid_name);
195
196
197 static void *ast_bridge_call_thread(void *data) 
198 {
199         struct ast_bridge_thread_obj *tobj = data;
200
201         tobj->chan->appl = "Transferred Call";
202         tobj->chan->data = (char *) tobj->peer->name;
203         tobj->peer->appl = "Transferred Call";
204         tobj->peer->data = (char *) tobj->chan->name;
205         if (tobj->chan->cdr) {
206                 ast_cdr_reset(tobj->chan->cdr, NULL);
207                 ast_cdr_setdestchan(tobj->chan->cdr, tobj->peer->name);
208         }
209         if (tobj->peer->cdr) {
210                 ast_cdr_reset(tobj->peer->cdr, NULL);
211                 ast_cdr_setdestchan(tobj->peer->cdr, tobj->chan->name);
212         }
213
214         ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig);
215         ast_hangup(tobj->chan);
216         ast_hangup(tobj->peer);
217         tobj->chan = tobj->peer = NULL;
218         free(tobj);
219         tobj=NULL;
220         return NULL;
221 }
222
223 static void ast_bridge_call_thread_launch(void *data) 
224 {
225         pthread_t thread;
226         pthread_attr_t attr;
227         struct sched_param sched;
228
229         pthread_attr_init(&attr);
230         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
231         ast_pthread_create(&thread, &attr,ast_bridge_call_thread, data);
232         pthread_attr_destroy(&attr);
233         memset(&sched, 0, sizeof(sched));
234         pthread_setschedparam(thread, SCHED_RR, &sched);
235 }
236
237
238
239 static int adsi_announce_park(struct ast_channel *chan, int parkingnum)
240 {
241         int res;
242         int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT};
243         char tmp[256];
244         char *message[5] = {NULL, NULL, NULL, NULL, NULL};
245
246         snprintf(tmp, sizeof(tmp), "Parked on %d", parkingnum);
247         message[0] = tmp;
248         res = adsi_load_session(chan, NULL, 0, 1);
249         if (res == -1) {
250                 return res;
251         }
252         return adsi_print(chan, message, justify, 1);
253 }
254
255 /*! \brief Park a call 
256         We put the user in the parking list, then wake up the parking thread to be sure it looks
257         after these channels too */
258 int ast_park_call(struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout)
259 {
260         struct parkeduser *pu, *cur;
261         int i,x,parking_range;
262         char exten[AST_MAX_EXTENSION];
263         struct ast_context *con;
264         
265         if (!(pu = ast_calloc(1, sizeof(*pu)))) {
266                 return -1;
267         }
268         ast_mutex_lock(&parking_lock);
269         parking_range = parking_stop - parking_start+1;
270         for (i = 0; i < parking_range; i++) {
271                 x = (i + parking_offset) % parking_range + parking_start;
272                 cur = parkinglot;
273                 while(cur) {
274                         if (cur->parkingnum == x) 
275                                 break;
276                         cur = cur->next;
277                 }
278                 if (!cur)
279                         break;
280         }
281
282         if (!(i < parking_range)) {
283                 ast_log(LOG_WARNING, "No more parking spaces\n");
284                 free(pu);
285                 ast_mutex_unlock(&parking_lock);
286                 return -1;
287         }
288         if (parkfindnext) 
289                 parking_offset = x - parking_start + 1;
290         chan->appl = "Parked Call";
291         chan->data = NULL; 
292
293         pu->chan = chan;
294         /* Start music on hold */
295         if (chan != peer) {
296                 ast_indicate(pu->chan, AST_CONTROL_HOLD);
297                 ast_moh_start(pu->chan, NULL);
298         }
299         pu->start = ast_tvnow();
300         pu->parkingnum = x;
301         if (timeout > 0)
302                 pu->parkingtime = timeout;
303         else
304                 pu->parkingtime = parkingtime;
305         if (extout)
306                 *extout = x;
307         if (peer) 
308                 ast_copy_string(pu->peername, peer->name, sizeof(pu->peername));
309
310         /* Remember what had been dialed, so that if the parking
311            expires, we try to come back to the same place */
312         if (!ast_strlen_zero(chan->macrocontext))
313                 ast_copy_string(pu->context, chan->macrocontext, sizeof(pu->context));
314         else
315                 ast_copy_string(pu->context, chan->context, sizeof(pu->context));
316         if (!ast_strlen_zero(chan->macroexten))
317                 ast_copy_string(pu->exten, chan->macroexten, sizeof(pu->exten));
318         else
319                 ast_copy_string(pu->exten, chan->exten, sizeof(pu->exten));
320         if (chan->macropriority)
321                 pu->priority = chan->macropriority;
322         else
323                 pu->priority = chan->priority;
324         pu->next = parkinglot;
325         parkinglot = pu;
326         /* If parking a channel directly, don't quiet yet get parking running on it */
327         if (peer == chan) 
328                 pu->notquiteyet = 1;
329         ast_mutex_unlock(&parking_lock);
330         /* Wake up the (presumably select()ing) thread */
331         pthread_kill(parking_thread, SIGURG);
332         if (option_verbose > 1) 
333                 ast_verbose(VERBOSE_PREFIX_2 "Parked %s on %d. Will timeout back to extension [%s] %s, %d in %d seconds\n", pu->chan->name, pu->parkingnum, pu->context, pu->exten, pu->priority, (pu->parkingtime/1000));
334
335         manager_event(EVENT_FLAG_CALL, "ParkedCall",
336                 "Exten: %d\r\n"
337                 "Channel: %s\r\n"
338                 "From: %s\r\n"
339                 "Timeout: %ld\r\n"
340                 "CallerID: %s\r\n"
341                 "CallerIDName: %s\r\n"
342                 ,pu->parkingnum, pu->chan->name, peer ? peer->name : ""
343                 ,(long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL)
344                 ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
345                 ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
346                 );
347
348         if (peer) {
349                 if (adsipark && adsi_available(peer)) {
350                         adsi_announce_park(peer, pu->parkingnum);
351                 }
352                 if (adsipark && adsi_available(peer)) {
353                         adsi_unload_session(peer);
354                 }
355         }
356         con = ast_context_find(parking_con);
357         if (!con) {
358                 con = ast_context_create(NULL, parking_con, registrar);
359                 if (!con) {
360                         ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
361                 }
362         }
363         if (con) {
364                 snprintf(exten, sizeof(exten), "%d", x);
365                 ast_add_extension2(con, 1, exten, 1, NULL, NULL, parkedcall, strdup(exten), FREE, registrar);
366         }
367         if (peer) 
368                 ast_say_digits(peer, pu->parkingnum, "", peer->language);
369         if (pu->notquiteyet) {
370                 /* Wake up parking thread if we're really done */
371                 ast_moh_start(pu->chan, NULL);
372                 pu->notquiteyet = 0;
373                 pthread_kill(parking_thread, SIGURG);
374         }
375         return 0;
376 }
377
378 int ast_masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout)
379 {
380         struct ast_channel *chan;
381         struct ast_frame *f;
382
383         /* Make a new, fake channel that we'll use to masquerade in the real one */
384         if ((chan = ast_channel_alloc(0))) {
385                 /* Let us keep track of the channel name */
386                 ast_string_field_build(chan, name, "Parked/%s",rchan->name);
387
388                 /* Make formats okay */
389                 chan->readformat = rchan->readformat;
390                 chan->writeformat = rchan->writeformat;
391                 ast_channel_masquerade(chan, rchan);
392
393                 /* Setup the extensions and such */
394                 ast_copy_string(chan->context, rchan->context, sizeof(chan->context));
395                 ast_copy_string(chan->exten, rchan->exten, sizeof(chan->exten));
396                 chan->priority = rchan->priority;
397
398                 /* Make the masq execute */
399                 f = ast_read(chan);
400                 if (f)
401                         ast_frfree(f);
402                 ast_park_call(chan, peer, timeout, extout);
403         } else {
404                 ast_log(LOG_WARNING, "Unable to create parked channel\n");
405                 return -1;
406         }
407         return 0;
408 }
409
410
411 #define FEATURE_RETURN_HANGUP           -1
412 #define FEATURE_RETURN_SUCCESSBREAK      0
413 #define FEATURE_RETURN_PBX_KEEPALIVE    AST_PBX_KEEPALIVE
414 #define FEATURE_RETURN_NO_HANGUP_PEER   AST_PBX_NO_HANGUP_PEER
415 #define FEATURE_RETURN_PASSDIGITS        21
416 #define FEATURE_RETURN_STOREDIGITS       22
417 #define FEATURE_RETURN_SUCCESS           23
418
419 #define FEATURE_SENSE_CHAN      (1 << 0)
420 #define FEATURE_SENSE_PEER      (1 << 1)
421
422
423 static int builtin_automonitor(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
424 {
425         char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL;
426         int x = 0;
427         size_t len;
428         struct ast_channel *caller_chan = NULL, *callee_chan = NULL;
429
430
431         if(sense == 2) {
432                 caller_chan = peer;
433                 callee_chan = chan;
434         } else {
435                 callee_chan = peer;
436                 caller_chan = chan;
437         }
438         
439         if (!monitor_ok) {
440                 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
441                 return -1;
442         }
443
444         if (!monitor_app) { 
445                 if (!(monitor_app = pbx_findapp("Monitor"))) {
446                         monitor_ok=0;
447                         ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
448                         return -1;
449                 }
450         }
451         if (!ast_strlen_zero(courtesytone)) {
452                 if (ast_autoservice_start(callee_chan))
453                         return -1;
454                 if (!ast_streamfile(caller_chan, courtesytone, caller_chan->language)) {
455                         if (ast_waitstream(caller_chan, "") < 0) {
456                                 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
457                                 ast_autoservice_stop(callee_chan);
458                                 return -1;
459                         }
460                 }
461                 if (ast_autoservice_stop(callee_chan))
462                         return -1;
463         }
464         
465         if (callee_chan->monitor) {
466                 if (option_verbose > 3)
467                         ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to stop recording call.\n", code);
468                 ast_monitor_stop(callee_chan, 1);
469                 return FEATURE_RETURN_SUCCESS;
470         }
471
472         if (caller_chan && callee_chan) {
473                 const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT");
474                 const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR");
475
476                 if (!touch_format)
477                         touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT");
478
479                 if (!touch_monitor)
480                         touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR");
481         
482                 if (touch_monitor) {
483                         len = strlen(touch_monitor) + 50;
484                         args = alloca(len);
485                         touch_filename = alloca(len);
486                         snprintf(touch_filename, len, "auto-%ld-%s", (long)time(NULL), touch_monitor);
487                         snprintf(args, len, "%s|%s|m", (touch_format) ? touch_format : "wav", touch_filename);
488                 } else {
489                         caller_chan_id = ast_strdupa(caller_chan->cid.cid_num ? caller_chan->cid.cid_num : caller_chan->name);
490                         callee_chan_id = ast_strdupa(callee_chan->cid.cid_num ? callee_chan->cid.cid_num : callee_chan->name);
491                         len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50;
492                         args = alloca(len);
493                         touch_filename = alloca(len);
494                         snprintf(touch_filename, len, "auto-%ld-%s-%s", (long)time(NULL), caller_chan_id, callee_chan_id);
495                         snprintf(args, len, "%s|%s|m", (touch_format) ? touch_format : "wav", touch_filename);
496                 }
497
498                 for( x = 0; x < strlen(args); x++)
499                         if (args[x] == '/')
500                                 args[x] = '-';
501                 
502                 if (option_verbose > 3)
503                         ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to record call. filename: %s\n", code, args);
504
505                 pbx_exec(callee_chan, monitor_app, args);
506                 pbx_builtin_setvar_helper(callee_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
507                 pbx_builtin_setvar_helper(caller_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
508         
509                 return FEATURE_RETURN_SUCCESS;
510         }
511         
512         ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n");   
513         return -1;
514 }
515
516 static int builtin_disconnect(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
517 {
518         if (option_verbose > 3)
519                 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to disconnect call.\n", code);
520         return FEATURE_RETURN_HANGUP;
521 }
522
523 static int builtin_blindtransfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
524 {
525         struct ast_channel *transferer;
526         struct ast_channel *transferee;
527         const char *transferer_real_context;
528         char newext[256];
529         int res;
530
531         if (sense == FEATURE_SENSE_PEER) {
532                 transferer = peer;
533                 transferee = chan;
534         } else {
535                 transferer = chan;
536                 transferee = peer;
537         }
538         if (!(transferer_real_context = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT")) &&
539            !(transferer_real_context = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT"))) {
540                 /* Use the non-macro context to transfer the call */
541                 if (!ast_strlen_zero(transferer->macrocontext))
542                         transferer_real_context = transferer->macrocontext;
543                 else
544                         transferer_real_context = transferer->context;
545         }
546         /* Start autoservice on chan while we talk
547            to the originator */
548         ast_indicate(transferee, AST_CONTROL_HOLD);
549         ast_autoservice_start(transferee);
550         ast_moh_start(transferee, NULL);
551
552         memset(newext, 0, sizeof(newext));
553         
554         /* Transfer */
555         if ((res=ast_streamfile(transferer, "pbx-transfer", transferer->language))) {
556                 ast_moh_stop(transferee);
557                 ast_autoservice_stop(transferee);
558                 ast_indicate(transferee, AST_CONTROL_UNHOLD);
559                 return res;
560         }
561         if ((res=ast_waitstream(transferer, AST_DIGIT_ANY)) < 0) {
562                 ast_moh_stop(transferee);
563                 ast_autoservice_stop(transferee);
564                 ast_indicate(transferee, AST_CONTROL_UNHOLD);
565                 return res;
566         } else if (res > 0) {
567                 /* If they've typed a digit already, handle it */
568                 newext[0] = (char) res;
569         }
570
571         ast_stopstream(transferer);
572         res = ast_app_dtget(transferer, transferer_real_context, newext, sizeof(newext), 100, transferdigittimeout);
573         if (res < 0) {
574                 ast_moh_stop(transferee);
575                 ast_autoservice_stop(transferee);
576                 ast_indicate(transferee, AST_CONTROL_UNHOLD);
577                 return res;
578         }
579         if (!strcmp(newext, ast_parking_ext())) {
580                 ast_moh_stop(transferee);
581
582                 res = ast_autoservice_stop(transferee);
583                 ast_indicate(transferee, AST_CONTROL_UNHOLD);
584                 if (res)
585                         res = -1;
586                 else if (!ast_park_call(transferee, transferer, 0, NULL)) {
587                         /* We return non-zero, but tell the PBX not to hang the channel when
588                            the thread dies -- We have to be careful now though.  We are responsible for 
589                            hanging up the channel, else it will never be hung up! */
590
591                         if (transferer == peer)
592                                 res = AST_PBX_KEEPALIVE;
593                         else
594                                 res = AST_PBX_NO_HANGUP_PEER;
595                         return res;
596                 } else {
597                         ast_log(LOG_WARNING, "Unable to park call %s\n", transferee->name);
598                 }
599                 /* XXX Maybe we should have another message here instead of invalid extension XXX */
600         } else if (ast_exists_extension(transferee, transferer_real_context, newext, 1, transferer->cid.cid_num)) {
601                 pbx_builtin_setvar_helper(peer, "BLINDTRANSFER", chan->name);
602                 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", peer->name);
603                 ast_moh_stop(transferee);
604                 res=ast_autoservice_stop(transferee);
605                 ast_indicate(transferee, AST_CONTROL_UNHOLD);
606                 if (!transferee->pbx) {
607                         /* Doh!  Use our handy async_goto functions */
608                         if (option_verbose > 2) 
609                                 ast_verbose(VERBOSE_PREFIX_3 "Transferring %s to '%s' (context %s) priority 1\n"
610                                                                 ,transferee->name, newext, transferer_real_context);
611                         if (ast_async_goto(transferee, transferer_real_context, newext, 1))
612                                 ast_log(LOG_WARNING, "Async goto failed :-(\n");
613                         res = -1;
614                 } else {
615                         /* Set the channel's new extension, since it exists, using transferer context */
616                         ast_copy_string(transferee->exten, newext, sizeof(transferee->exten));
617                         ast_copy_string(transferee->context, transferer_real_context, sizeof(transferee->context));
618                         transferee->priority = 0;
619                 }
620                 check_goto_on_transfer(transferer);
621                 return res;
622         } else {
623                 if (option_verbose > 2) 
624                         ast_verbose(VERBOSE_PREFIX_3 "Unable to find extension '%s' in context '%s'\n", newext, transferer_real_context);
625         }
626         if (!ast_strlen_zero(xferfailsound))
627                 res = ast_streamfile(transferer, xferfailsound, transferee->language);
628         else
629                 res = 0;
630         if (res) {
631                 ast_moh_stop(transferee);
632                 ast_autoservice_stop(transferee);
633                 ast_indicate(transferee, AST_CONTROL_UNHOLD);
634                 return res;
635         }
636         res = ast_waitstream(transferer, AST_DIGIT_ANY);
637         ast_stopstream(transferer);
638         ast_moh_stop(transferee);
639         res = ast_autoservice_stop(transferee);
640         ast_indicate(transferee, AST_CONTROL_UNHOLD);
641         if (res) {
642                 if (option_verbose > 1)
643                         ast_verbose(VERBOSE_PREFIX_2 "Hungup during autoservice stop on '%s'\n", transferee->name);
644                 return res;
645         }
646         return FEATURE_RETURN_SUCCESS;
647 }
648
649 static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
650 {
651         struct ast_channel *transferer;
652         struct ast_channel *transferee;
653         struct ast_channel *newchan, *xferchan=NULL;
654         int outstate=0;
655         struct ast_bridge_config bconfig;
656         const char *transferer_real_context;
657         char xferto[256],dialstr[265];
658         char *cid_num;
659         char *cid_name;
660         int res;
661         struct ast_frame *f = NULL;
662         struct ast_bridge_thread_obj *tobj;
663
664         ast_log(LOG_DEBUG, "Executing Attended Transfer %s, %s (sense=%d) XXX\n", chan->name, peer->name, sense);
665         if (sense == FEATURE_SENSE_PEER) {
666                 transferer = peer;
667                 transferee = chan;
668         } else {
669                 transferer = chan;
670                 transferee = peer;
671         }
672         if (!(transferer_real_context=pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT")) &&
673            !(transferer_real_context=pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT"))) {
674                 /* Use the non-macro context to transfer the call */
675                 if (!ast_strlen_zero(transferer->macrocontext))
676                         transferer_real_context = transferer->macrocontext;
677                 else
678                         transferer_real_context = transferer->context;
679         }
680         /* Start autoservice on chan while we talk
681            to the originator */
682         ast_indicate(transferee, AST_CONTROL_HOLD);
683         ast_autoservice_start(transferee);
684         ast_moh_start(transferee, NULL);
685         memset(xferto, 0, sizeof(xferto));
686         /* Transfer */
687         if ((res = ast_streamfile(transferer, "pbx-transfer", transferer->language))) {
688                 ast_moh_stop(transferee);
689                 ast_autoservice_stop(transferee);
690                 ast_indicate(transferee, AST_CONTROL_UNHOLD);
691                 return res;
692         }
693         if ((res=ast_waitstream(transferer, AST_DIGIT_ANY)) < 0) {
694                 ast_moh_stop(transferee);
695                 ast_autoservice_stop(transferee);
696                 ast_indicate(transferee, AST_CONTROL_UNHOLD);
697                 return res;
698         } else if(res > 0) {
699                 /* If they've typed a digit already, handle it */
700                 xferto[0] = (char) res;
701         }
702         if ((ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout))) {
703                 cid_num = transferer->cid.cid_num;
704                 cid_name = transferer->cid.cid_name;
705                 if (ast_exists_extension(transferer, transferer_real_context,xferto, 1, cid_num)) {
706                         snprintf(dialstr, sizeof(dialstr), "%s@%s/n", xferto, transferer_real_context);
707                         newchan = ast_feature_request_and_dial(transferer, "Local", ast_best_codec(transferer->nativeformats), dialstr, 15000, &outstate, cid_num, cid_name);
708                         ast_indicate(transferer, -1);
709                         if (newchan) {
710                                 res = ast_channel_make_compatible(transferer, newchan);
711                                 if (res < 0) {
712                                         ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", transferer->name, newchan->name);
713                                         ast_hangup(newchan);
714                                         return -1;
715                                 }
716                                 memset(&bconfig,0,sizeof(struct ast_bridge_config));
717                                 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
718                                 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
719                                 res = ast_bridge_call(transferer,newchan,&bconfig);
720                                 if (newchan->_softhangup || newchan->_state != AST_STATE_UP || !transferer->_softhangup) {
721                                         ast_hangup(newchan);
722                                         if (f) {
723                                                 ast_frfree(f);
724                                                 f = NULL;
725                                         }
726                                         if (!ast_strlen_zero(xfersound) && !ast_streamfile(transferer, xfersound, transferer->language)) {
727                                                 if (ast_waitstream(transferer, "") < 0) {
728                                                         ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
729                                                 }
730                                         }
731                                         ast_moh_stop(transferee);
732                                         ast_autoservice_stop(transferee);
733                                         ast_indicate(transferee, AST_CONTROL_UNHOLD);
734                                         transferer->_softhangup = 0;
735                                         return FEATURE_RETURN_SUCCESS;
736                                 }
737                                 
738                                 res = ast_channel_make_compatible(transferee, newchan);
739                                 if (res < 0) {
740                                         ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", transferee->name, newchan->name);
741                                         ast_hangup(newchan);
742                                         return -1;
743                                 }
744                                 
745                                 
746                                 ast_moh_stop(transferee);
747                                 
748                                 if ((ast_autoservice_stop(transferee) < 0)
749                                    || (ast_waitfordigit(transferee, 100) < 0)
750                                    || (ast_waitfordigit(newchan, 100) < 0) 
751                                    || ast_check_hangup(transferee) 
752                                    || ast_check_hangup(newchan)) {
753                                         ast_hangup(newchan);
754                                         res = -1;
755                                         return -1;
756                                 }
757
758                                 if ((xferchan = ast_channel_alloc(0))) {
759                                         ast_string_field_build(xferchan, name, "Transfered/%s", transferee->name);
760                                         /* Make formats okay */
761                                         xferchan->readformat = transferee->readformat;
762                                         xferchan->writeformat = transferee->writeformat;
763                                         ast_channel_masquerade(xferchan, transferee);
764                                         ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority);
765                                         xferchan->_state = AST_STATE_UP;
766                                         ast_clear_flag(xferchan, AST_FLAGS_ALL);        
767                                         xferchan->_softhangup = 0;
768
769                                         if ((f = ast_read(xferchan))) {
770                                                 ast_frfree(f);
771                                                 f = NULL;
772                                         }
773                                         
774                                 } else {
775                                         ast_hangup(newchan);
776                                         return -1;
777                                 }
778
779                                 newchan->_state = AST_STATE_UP;
780                                 ast_clear_flag(newchan, AST_FLAGS_ALL); 
781                                 newchan->_softhangup = 0;
782                                 
783                                 if ((tobj = ast_calloc(1, sizeof(*tobj)))) {
784                                         tobj->chan = xferchan;
785                                         tobj->peer = newchan;
786                                         tobj->bconfig = *config;
787         
788                                         if (!ast_strlen_zero(xfersound) && !ast_streamfile(newchan, xfersound, newchan->language)) {
789                                                 if (ast_waitstream(newchan, "") < 0) {
790                                                         ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
791                                                 }
792                                         }
793                                         ast_bridge_call_thread_launch(tobj);
794                                 } else {
795                                         ast_hangup(xferchan);
796                                         ast_hangup(newchan);
797                                 }
798                                 return -1;
799                                 
800                         } else {
801                                 ast_moh_stop(transferee);
802                                 ast_autoservice_stop(transferee);
803                                 ast_indicate(transferee, AST_CONTROL_UNHOLD);
804                                 /* any reason besides user requested cancel and busy triggers the failed sound */
805                                 if (outstate != AST_CONTROL_UNHOLD && outstate != AST_CONTROL_BUSY && !ast_strlen_zero(xferfailsound)) {
806                                         res = ast_streamfile(transferer, xferfailsound, transferer->language);
807                                         if (!res && (ast_waitstream(transferer, "") < 0)) {
808                                                 return -1;
809                                         }
810                                 }
811                                 return FEATURE_RETURN_SUCCESS;
812                         }
813                 } else {
814                         ast_log(LOG_WARNING, "Extension %s does not exist in context %s\n",xferto,transferer_real_context);
815                         ast_moh_stop(transferee);
816                         ast_autoservice_stop(transferee);
817                         ast_indicate(transferee, AST_CONTROL_UNHOLD);
818                         res = ast_streamfile(transferer, "beeperr", transferer->language);
819                         if (!res && (ast_waitstream(transferer, "") < 0)) {
820                                 return -1;
821                         }
822                 }
823         }  else {
824                 ast_log(LOG_WARNING, "Did not read data.\n");
825                 res = ast_streamfile(transferer, "beeperr", transferer->language);
826                 if (ast_waitstream(transferer, "") < 0) {
827                         return -1;
828                 }
829         }
830         ast_moh_stop(transferee);
831         ast_autoservice_stop(transferee);
832         ast_indicate(transferee, AST_CONTROL_UNHOLD);
833
834         return FEATURE_RETURN_SUCCESS;
835 }
836
837
838 /* add atxfer and automon as undefined so you can only use em if you configure them */
839 #define FEATURES_COUNT (sizeof(builtin_features) / sizeof(builtin_features[0]))
840
841 struct ast_call_feature builtin_features[] = 
842  {
843         { AST_FEATURE_REDIRECT, "Blind Transfer", "blindxfer", "#", "#", builtin_blindtransfer, AST_FEATURE_FLAG_NEEDSDTMF },
844         { AST_FEATURE_REDIRECT, "Attended Transfer", "atxfer", "", "", builtin_atxfer, AST_FEATURE_FLAG_NEEDSDTMF },
845         { AST_FEATURE_AUTOMON, "One Touch Monitor", "automon", "", "", builtin_automonitor, AST_FEATURE_FLAG_NEEDSDTMF },
846         { AST_FEATURE_DISCONNECT, "Disconnect Call", "disconnect", "*", "*", builtin_disconnect, AST_FEATURE_FLAG_NEEDSDTMF },
847 };
848
849
850 static AST_LIST_HEAD(feature_list,ast_call_feature) feature_list;
851
852 /*! \brief register new feature into feature_list*/
853 void ast_register_feature(struct ast_call_feature *feature)
854 {
855         if (!feature) {
856                 ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
857                 return;
858         }
859   
860         AST_LIST_LOCK(&feature_list);
861         AST_LIST_INSERT_HEAD(&feature_list,feature,feature_entry);
862         AST_LIST_UNLOCK(&feature_list);
863
864         if (option_verbose >= 2) 
865                 ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname);
866 }
867
868 /*! \brief unregister feature from feature_list */
869 void ast_unregister_feature(struct ast_call_feature *feature)
870 {
871         if (!feature) return;
872
873         AST_LIST_LOCK(&feature_list);
874         AST_LIST_REMOVE(&feature_list,feature,feature_entry);
875         AST_LIST_UNLOCK(&feature_list);
876         free(feature);
877 }
878
879 static void ast_unregister_features(void)
880 {
881         struct ast_call_feature *feature;
882
883         AST_LIST_LOCK(&feature_list);
884         while ((feature = AST_LIST_REMOVE_HEAD(&feature_list,feature_entry)))
885                 free(feature);
886         AST_LIST_UNLOCK(&feature_list);
887 }
888
889 /*! \brief find a feature by name */
890 static struct ast_call_feature *find_feature(char *name)
891 {
892         struct ast_call_feature *tmp;
893
894         AST_LIST_LOCK(&feature_list);
895         AST_LIST_TRAVERSE(&feature_list, tmp, feature_entry) {
896                 if (!strcasecmp(tmp->sname, name))
897                         break;
898         }
899         AST_LIST_UNLOCK(&feature_list);
900
901         return tmp;
902 }
903
904 /*! \brief exec an app by feature */
905 static int feature_exec_app(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
906 {
907         struct ast_app *app;
908         struct ast_call_feature *feature;
909         int res;
910
911         AST_LIST_LOCK(&feature_list);
912         AST_LIST_TRAVERSE(&feature_list,feature,feature_entry) {
913                 if (!strcasecmp(feature->exten,code)) break;
914         }
915         AST_LIST_UNLOCK(&feature_list);
916
917         if (!feature) { /* shouldn't ever happen! */
918                 ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n");
919                 return -1; 
920         }
921         
922         app = pbx_findapp(feature->app);
923         if (app) {
924                 struct ast_channel *work = chan;
925                 if (ast_test_flag(feature, AST_FEATURE_FLAG_CALLEE))
926                         work = peer;
927                 res = pbx_exec(work, app, feature->app_args);
928                 if (res < 0)
929                         return res; 
930         } else {
931                 ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app);
932                 return -2;
933         }
934         
935         return FEATURE_RETURN_SUCCESS;
936 }
937
938 static void unmap_features(void)
939 {
940         int x;
941         for (x = 0; x < FEATURES_COUNT; x++)
942                 strcpy(builtin_features[x].exten, builtin_features[x].default_exten);
943 }
944
945 static int remap_feature(const char *name, const char *value)
946 {
947         int x;
948         int res = -1;
949         for (x = 0; x < FEATURES_COUNT; x++) {
950                 if (!strcasecmp(name, builtin_features[x].sname)) {
951                         ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten));
952                         if (option_verbose > 1)
953                                 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);
954                         res = 0;
955                 } else if (!strcmp(value, builtin_features[x].exten)) 
956                         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);
957         }
958         return res;
959 }
960
961 static int ast_feature_interpret(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
962 {
963         int x;
964         struct ast_flags features;
965         int res = FEATURE_RETURN_PASSDIGITS;
966         struct ast_call_feature *feature;
967         const char *dynamic_features=pbx_builtin_getvar_helper(chan,"DYNAMIC_FEATURES");
968
969         if (sense == FEATURE_SENSE_CHAN)
970                 ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);   
971         else
972                 ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL);   
973         ast_log(LOG_DEBUG, "Feature interpret: chan=%s, peer=%s, sense=%d, features=%d\n", chan->name, peer->name, sense, features.flags);
974
975         for (x=0; x < FEATURES_COUNT; x++) {
976                 if ((ast_test_flag(&features, builtin_features[x].feature_mask)) &&
977                     !ast_strlen_zero(builtin_features[x].exten)) {
978                         /* Feature is up for consideration */
979                         if (!strcmp(builtin_features[x].exten, code)) {
980                                 res = builtin_features[x].operation(chan, peer, config, code, sense);
981                                 break;
982                         } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) {
983                                 if (res == FEATURE_RETURN_PASSDIGITS)
984                                         res = FEATURE_RETURN_STOREDIGITS;
985                         }
986                 }
987         }
988
989
990         if (!ast_strlen_zero(dynamic_features)) {
991                 char *tmp = ast_strdupa(dynamic_features);
992                 char *tok;
993
994                 if (!tmp)
995                         return res;
996                 
997                 while ((tok = strsep(&tmp, "#")) != NULL) {
998                         feature = find_feature(tok);
999                         
1000                         if (feature) {
1001                                 /* Feature is up for consideration */
1002                                 if (!strcmp(feature->exten, code)) {
1003                                         if (option_verbose > 2)
1004                                                 ast_verbose(VERBOSE_PREFIX_3 " Feature Found: %s exten: %s\n",feature->sname, tok);
1005                                         res = feature->operation(chan, peer, config, code, sense);
1006                                         break;
1007                                 } else if (!strncmp(feature->exten, code, strlen(code))) {
1008                                         res = FEATURE_RETURN_STOREDIGITS;
1009                                 }
1010                         }
1011                 }
1012         }
1013         
1014         return res;
1015 }
1016
1017 static void set_config_flags(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
1018 {
1019         int x;
1020         
1021         ast_clear_flag(config, AST_FLAGS_ALL);  
1022         for (x = 0; x < FEATURES_COUNT; x++) {
1023                 if (ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF)) {
1024                         if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask))
1025                                 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
1026
1027                         if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask))
1028                                 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
1029                 }
1030         }
1031         
1032         if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) {
1033                 const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
1034
1035                 if (dynamic_features) {
1036                         char *tmp = ast_strdupa(dynamic_features);
1037                         char *tok;
1038                         struct ast_call_feature *feature;
1039
1040                         if (!tmp) {
1041                                 return;
1042                         }
1043
1044                         /* while we have a feature */
1045                         while (NULL != (tok = strsep(&tmp, "#"))) {
1046                                 if ((feature = find_feature(tok))) {
1047                                         if (ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) {
1048                                                 if (ast_test_flag(feature, AST_FEATURE_FLAG_CALLER))
1049                                                         ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
1050                                                 if (ast_test_flag(feature, AST_FEATURE_FLAG_CALLEE))
1051                                                         ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
1052                                         }
1053                                 }
1054                         }
1055                 }
1056         }
1057 }
1058
1059
1060 static struct ast_channel *ast_feature_request_and_dial(struct ast_channel *caller, const char *type, int format, void *data, int timeout, int *outstate, const char *cid_num, const char *cid_name)
1061 {
1062         int state = 0;
1063         int cause = 0;
1064         int to;
1065         struct ast_channel *chan;
1066         struct ast_channel *monitor_chans[2];
1067         struct ast_channel *active_channel;
1068         struct ast_frame *f = NULL;
1069         int res = 0, ready = 0;
1070         
1071         if ((chan = ast_request(type, format, data, &cause))) {
1072                 ast_set_callerid(chan, cid_num, cid_name, cid_num);
1073                 ast_channel_inherit_variables(caller, chan);    
1074                 if (!ast_call(chan, data, timeout)) {
1075                         struct timeval started;
1076                         int x, len = 0;
1077                         char *disconnect_code = NULL, *dialed_code = NULL;
1078
1079                         ast_indicate(caller, AST_CONTROL_RINGING);
1080                         /* support dialing of the featuremap disconnect code while performing an attended tranfer */
1081                         for (x=0; x < FEATURES_COUNT; x++) {
1082                                 if (strcasecmp(builtin_features[x].sname, "disconnect"))
1083                                         continue;
1084
1085                                 disconnect_code = builtin_features[x].exten;
1086                                 len = strlen(disconnect_code) + 1;
1087                                 dialed_code = alloca(len);
1088                                 memset(dialed_code, 0, len);
1089                                 break;
1090                         }
1091                         x = 0;
1092                         started = ast_tvnow();
1093                         to = timeout;
1094                         while (!ast_check_hangup(caller) && timeout && (chan->_state != AST_STATE_UP)) {
1095                                 monitor_chans[0] = caller;
1096                                 monitor_chans[1] = chan;
1097                                 active_channel = ast_waitfor_n(monitor_chans, 2, &to);
1098
1099                                 /* see if the timeout has been violated */
1100                                 if(ast_tvdiff_ms(ast_tvnow(), started) > timeout) {
1101                                         state = AST_CONTROL_UNHOLD;
1102                                         ast_log(LOG_NOTICE, "We exceeded our AT-timeout\n");
1103                                         break; /*doh! timeout*/
1104                                 }
1105
1106                                 if (!active_channel) {
1107                                         continue;
1108                                 }
1109
1110                                 if (chan && (chan == active_channel)){
1111                                         f = ast_read(chan);
1112                                         if (f == NULL) { /*doh! where'd he go?*/
1113                                                 state = AST_CONTROL_HANGUP;
1114                                                 res = 0;
1115                                                 break;
1116                                         }
1117                                         
1118                                         if (f->frametype == AST_FRAME_CONTROL || f->frametype == AST_FRAME_DTMF || f->frametype == AST_FRAME_TEXT) {
1119                                                 if (f->subclass == AST_CONTROL_RINGING) {
1120                                                         state = f->subclass;
1121                                                         if (option_verbose > 2)
1122                                                                 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", chan->name);
1123                                                         ast_indicate(caller, AST_CONTROL_RINGING);
1124                                                 } else if ((f->subclass == AST_CONTROL_BUSY) || (f->subclass == AST_CONTROL_CONGESTION)) {
1125                                                         state = f->subclass;
1126                                                         if (option_verbose > 2)
1127                                                                 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", chan->name);
1128                                                         ast_indicate(caller, AST_CONTROL_BUSY);
1129                                                         ast_frfree(f);
1130                                                         f = NULL;
1131                                                         break;
1132                                                 } else if (f->subclass == AST_CONTROL_ANSWER) {
1133                                                         /* This is what we are hoping for */
1134                                                         state = f->subclass;
1135                                                         ast_frfree(f);
1136                                                         f = NULL;
1137                                                         ready=1;
1138                                                         break;
1139                                                 } else {
1140                                                         ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass);
1141                                                 }
1142                                                 /* else who cares */
1143                                         }
1144
1145                                 } else if (caller && (active_channel == caller)) {
1146                                         f = ast_read(caller);
1147                                         if (f == NULL) { /*doh! where'd he go?*/
1148                                                 if (caller->_softhangup && !chan->_softhangup) {
1149                                                         /* make this a blind transfer */
1150                                                         ready = 1;
1151                                                         break;
1152                                                 }
1153                                                 state = AST_CONTROL_HANGUP;
1154                                                 res = 0;
1155                                                 break;
1156                                         }
1157                                         
1158                                         if (f->frametype == AST_FRAME_DTMF) {
1159                                                 dialed_code[x++] = f->subclass;
1160                                                 dialed_code[x] = '\0';
1161                                                 if (strlen(dialed_code) == len) {
1162                                                         x = 0;
1163                                                 } else if (x && strncmp(dialed_code, disconnect_code, x)) {
1164                                                         x = 0;
1165                                                         dialed_code[x] = '\0';
1166                                                 }
1167                                                 if (*dialed_code && !strcmp(dialed_code, disconnect_code)) {
1168                                                         /* Caller Canceled the call */
1169                                                         state = AST_CONTROL_UNHOLD;
1170                                                         ast_frfree(f);
1171                                                         f = NULL;
1172                                                         break;
1173                                                 }
1174                                         }
1175                                 }
1176                                 if (f) {
1177                                         ast_frfree(f);
1178                                 }
1179                         }
1180                 } else
1181                         ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data);
1182         } else {
1183                 ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
1184                 switch(cause) {
1185                 case AST_CAUSE_BUSY:
1186                         state = AST_CONTROL_BUSY;
1187                         break;
1188                 case AST_CAUSE_CONGESTION:
1189                         state = AST_CONTROL_CONGESTION;
1190                         break;
1191                 }
1192         }
1193         
1194         ast_indicate(caller, -1);
1195         if (chan && ready) {
1196                 if (chan->_state == AST_STATE_UP) 
1197                         state = AST_CONTROL_ANSWER;
1198                 res = 0;
1199         } else if(chan) {
1200                 res = -1;
1201                 ast_hangup(chan);
1202                 chan = NULL;
1203         } else {
1204                 res = -1;
1205         }
1206         
1207         if (outstate)
1208                 *outstate = state;
1209
1210         if (chan && res <= 0) {
1211                 if (chan->cdr || (chan->cdr = ast_cdr_alloc())) {
1212                         char tmp[256];
1213                         ast_cdr_init(chan->cdr, chan);
1214                         snprintf(tmp, 256, "%s/%s", type, (char *)data);
1215                         ast_cdr_setapp(chan->cdr,"Dial",tmp);
1216                         ast_cdr_update(chan);
1217                         ast_cdr_start(chan->cdr);
1218                         ast_cdr_end(chan->cdr);
1219                         /* If the cause wasn't handled properly */
1220                         if (ast_cdr_disposition(chan->cdr,chan->hangupcause))
1221                                 ast_cdr_failed(chan->cdr);
1222                 } else {
1223                         ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
1224                 }
1225         }
1226         
1227         return chan;
1228 }
1229
1230 int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast_bridge_config *config)
1231 {
1232         /* Copy voice back and forth between the two channels.  Give the peer
1233            the ability to transfer calls with '#<extension' syntax. */
1234         struct ast_frame *f;
1235         struct ast_channel *who;
1236         char chan_featurecode[FEATURE_MAX_LEN + 1]="";
1237         char peer_featurecode[FEATURE_MAX_LEN + 1]="";
1238         int res;
1239         int diff;
1240         int hasfeatures=0;
1241         int hadfeatures=0;
1242         struct ast_option_header *aoh;
1243         struct timeval start = { 0 , 0 };
1244         struct ast_bridge_config backup_config;
1245
1246         memset(&backup_config, 0, sizeof(backup_config));
1247
1248         config->start_time = ast_tvnow();
1249
1250         if (chan && peer) {
1251                 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
1252                 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
1253         } else if (chan)
1254                 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
1255
1256         if (monitor_ok) {
1257                 const char *monitor_exec;
1258                 struct ast_channel *src = NULL;
1259                 if (!monitor_app) { 
1260                         if (!(monitor_app = pbx_findapp("Monitor")))
1261                                 monitor_ok=0;
1262                 }
1263                 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 
1264                         src = chan;
1265                 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
1266                         src = peer;
1267                 if (monitor_app && src) {
1268                         char *tmp = ast_strdupa(monitor_exec);
1269                         if (tmp) {
1270                                 pbx_exec(src, monitor_app, tmp);
1271                         } else {
1272                                 ast_log(LOG_ERROR, "Monitor failed: out of memory\n");
1273                         }
1274                 }
1275         }
1276         
1277         set_config_flags(chan, peer, config);
1278         config->firstpass = 1;
1279
1280         /* Answer if need be */
1281         if (ast_answer(chan))
1282                 return -1;
1283         peer->appl = "Bridged Call";
1284         peer->data = (char *) chan->name;
1285
1286         /* copy the userfield from the B-leg to A-leg if applicable */
1287         if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) {
1288                 char tmp[256];
1289                 if (!ast_strlen_zero(chan->cdr->userfield)) {
1290                         snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield);
1291                         ast_cdr_appenduserfield(chan, tmp);
1292                 } else
1293                         ast_cdr_setuserfield(chan, peer->cdr->userfield);
1294                 /* free the peer's cdr without ast_cdr_free complaining */
1295                 free(peer->cdr);
1296                 peer->cdr = NULL;
1297         }
1298         for (;;) {
1299                 if (config->feature_timer)
1300                         start = ast_tvnow();
1301
1302                 res = ast_channel_bridge(chan, peer, config, &f, &who);
1303
1304                 if (config->feature_timer) {
1305                         /* Update time limit for next pass */
1306                         diff = ast_tvdiff_ms(ast_tvnow(), start);
1307                         config->feature_timer -= diff;
1308                         if (hasfeatures) {
1309                                 /* Running on backup config, meaning a feature might be being
1310                                    activated, but that's no excuse to keep things going 
1311                                    indefinitely! */
1312                                 if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) {
1313                                         ast_log(LOG_DEBUG, "Timed out, realtime this time!\n");
1314                                         config->feature_timer = 0;
1315                                         who = chan;
1316                                         if (f)
1317                                                 ast_frfree(f);
1318                                         f = NULL;
1319                                         res = 0;
1320                                 } else if (config->feature_timer <= 0) {
1321                                         /* Not *really* out of time, just out of time for
1322                                            digits to come in for features. */
1323                                         ast_log(LOG_DEBUG, "Timed out for feature!\n");
1324                                         if (!ast_strlen_zero(peer_featurecode)) {
1325                                                 ast_dtmf_stream(chan, peer, peer_featurecode, 0);
1326                                                 memset(peer_featurecode, 0, sizeof(peer_featurecode));
1327                                         }
1328                                         if (!ast_strlen_zero(chan_featurecode)) {
1329                                                 ast_dtmf_stream(peer, chan, chan_featurecode, 0);
1330                                                 memset(chan_featurecode, 0, sizeof(chan_featurecode));
1331                                         }
1332                                         if (f)
1333                                                 ast_frfree(f);
1334                                         hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
1335                                         if (!hasfeatures) {
1336                                                 /* Restore original (possibly time modified) bridge config */
1337                                                 memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
1338                                                 memset(&backup_config, 0, sizeof(backup_config));
1339                                         }
1340                                         hadfeatures = hasfeatures;
1341                                         /* Continue as we were */
1342                                         continue;
1343                                 }
1344                         } else {
1345                                 if (config->feature_timer <=0) {
1346                                         /* We ran out of time */
1347                                         config->feature_timer = 0;
1348                                         who = chan;
1349                                         if (f)
1350                                                 ast_frfree(f);
1351                                         f = NULL;
1352                                         res = 0;
1353                                 }
1354                         }
1355                 }
1356                 if (res < 0) {
1357                         ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
1358                         return -1;
1359                 }
1360                 
1361                 if (!f || ((f->frametype == AST_FRAME_CONTROL) && ((f->subclass == AST_CONTROL_HANGUP) || (f->subclass == AST_CONTROL_BUSY) || 
1362                         (f->subclass == AST_CONTROL_CONGESTION)))) {
1363                                 res = -1;
1364                                 break;
1365                 }
1366                 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_RINGING)) {
1367                         if (who == chan)
1368                                 ast_indicate(peer, AST_CONTROL_RINGING);
1369                         else
1370                                 ast_indicate(chan, AST_CONTROL_RINGING);
1371                 }
1372                 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == -1)) {
1373                         if (who == chan)
1374                                 ast_indicate(peer, -1);
1375                         else
1376                                 ast_indicate(chan, -1);
1377                 }
1378                 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_FLASH)) {
1379                         if (who == chan)
1380                                 ast_indicate(peer, AST_CONTROL_FLASH);
1381                         else
1382                                 ast_indicate(chan, AST_CONTROL_FLASH);
1383                 }
1384                 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_OPTION)) {
1385                         aoh = f->data;
1386                         /* Forward option Requests */
1387                         if (aoh && (aoh->flag == AST_OPTION_FLAG_REQUEST)) {
1388                                 if (who == chan)
1389                                         ast_channel_setoption(peer, ntohs(aoh->option), aoh->data, f->datalen - sizeof(struct ast_option_header), 0);
1390                                 else
1391                                         ast_channel_setoption(chan, ntohs(aoh->option), aoh->data, f->datalen - sizeof(struct ast_option_header), 0);
1392                         }
1393                 }
1394                 /* check for '*', if we find it it's time to disconnect */
1395                 if (f && (f->frametype == AST_FRAME_DTMF)) {
1396                         char *featurecode;
1397                         int sense;
1398                         struct ast_channel *other;
1399
1400                         hadfeatures = hasfeatures;
1401                         /* This cannot overrun because the longest feature is one shorter than our buffer */
1402                         if (who == chan) {
1403                                 other = peer;
1404                                 sense = FEATURE_SENSE_CHAN;
1405                                 featurecode = chan_featurecode;
1406                         } else  {
1407                                 other = chan;
1408                                 sense = FEATURE_SENSE_PEER;
1409                                 featurecode = peer_featurecode;
1410                         }
1411                         featurecode[strlen(featurecode)] = f->subclass;
1412                         config->feature_timer = backup_config.feature_timer;
1413                         res = ast_feature_interpret(chan, peer, config, featurecode, sense);
1414                         switch(res) {
1415                         case FEATURE_RETURN_PASSDIGITS:
1416                                 ast_dtmf_stream(other, who, featurecode, 0);
1417                                 /* Fall through */
1418                         case FEATURE_RETURN_SUCCESS:
1419                                 memset(featurecode, 0, sizeof(chan_featurecode));
1420                                 break;
1421                         }
1422                         if (res >= FEATURE_RETURN_PASSDIGITS) {
1423                                 res = 0;
1424                         } else {
1425                                 ast_frfree(f);
1426                                 break;
1427                         }
1428                         hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
1429                         if (hadfeatures && !hasfeatures) {
1430                                 /* Restore backup */
1431                                 memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
1432                                 memset(&backup_config, 0, sizeof(struct ast_bridge_config));
1433                         } else if (hasfeatures) {
1434                                 if (!hadfeatures) {
1435                                         /* Backup configuration */
1436                                         memcpy(&backup_config, config, sizeof(struct ast_bridge_config));
1437                                         /* Setup temporary config options */
1438                                         config->play_warning = 0;
1439                                         ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
1440                                         ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
1441                                         config->warning_freq = 0;
1442                                         config->warning_sound = NULL;
1443                                         config->end_sound = NULL;
1444                                         config->start_sound = NULL;
1445                                         config->firstpass = 0;
1446                                 }
1447                                 config->feature_timer = featuredigittimeout;
1448                                 ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->feature_timer);
1449                         }
1450                 }
1451                 if (f)
1452                         ast_frfree(f);
1453         }
1454         return res;
1455 }
1456
1457 /*! \brief Take care of parked calls and unpark them if needed */
1458 static void *do_parking_thread(void *ignore)
1459 {
1460         int ms, tms, max;
1461         struct parkeduser *pu, *pl, *pt = NULL;
1462         struct timeval tv;
1463         struct ast_frame *f;
1464         char exten[AST_MAX_EXTENSION];
1465         char *peername,*cp;
1466         char returnexten[AST_MAX_EXTENSION];
1467         struct ast_context *con;
1468         int x;
1469         fd_set rfds, efds;
1470         fd_set nrfds, nefds;
1471         FD_ZERO(&rfds);
1472         FD_ZERO(&efds);
1473
1474         for (;;) {
1475                 ms = -1;
1476                 max = -1;
1477                 ast_mutex_lock(&parking_lock);
1478                 pl = NULL;
1479                 pu = parkinglot;
1480                 FD_ZERO(&nrfds);
1481                 FD_ZERO(&nefds);
1482                 while(pu) {
1483                         if (pu->notquiteyet) {
1484                                 /* Pretend this one isn't here yet */
1485                                 pl = pu;
1486                                 pu = pu->next;
1487                                 continue;
1488                         }
1489                         tms = ast_tvdiff_ms(ast_tvnow(), pu->start);
1490                         if (tms > pu->parkingtime) {
1491                                 /* Stop music on hold */
1492                                 ast_moh_stop(pu->chan);
1493                                 ast_indicate(pu->chan, AST_CONTROL_UNHOLD);
1494                                 /* Get chan, exten from derived kludge */
1495                                 if (pu->peername[0]) {
1496                                         peername = ast_strdupa(pu->peername);
1497                                         cp = strrchr(peername, '-');
1498                                         if (cp) 
1499                                                 *cp = 0;
1500                                         con = ast_context_find(parking_con_dial);
1501                                         if (!con) {
1502                                                 con = ast_context_create(NULL, parking_con_dial, registrar);
1503                                                 if (!con) {
1504                                                         ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial);
1505                                                 }
1506                                         }
1507                                         if (con) {
1508                                                 snprintf(returnexten, sizeof(returnexten), "%s||t", peername);
1509                                                 ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(returnexten), FREE, registrar);
1510                                         }
1511                                         ast_copy_string(pu->chan->exten, peername, sizeof(pu->chan->exten));
1512                                         ast_copy_string(pu->chan->context, parking_con_dial, sizeof(pu->chan->context));
1513                                         pu->chan->priority = 1;
1514
1515                                 } else {
1516                                         /* They've been waiting too long, send them back to where they came.  Theoretically they
1517                                            should have their original extensions and such, but we copy to be on the safe side */
1518                                         ast_copy_string(pu->chan->exten, pu->exten, sizeof(pu->chan->exten));
1519                                         ast_copy_string(pu->chan->context, pu->context, sizeof(pu->chan->context));
1520                                         pu->chan->priority = pu->priority;
1521                                 }
1522
1523                                 manager_event(EVENT_FLAG_CALL, "ParkedCallTimeOut",
1524                                         "Exten: %d\r\n"
1525                                         "Channel: %s\r\n"
1526                                         "CallerID: %s\r\n"
1527                                         "CallerIDName: %s\r\n"
1528                                         ,pu->parkingnum, pu->chan->name
1529                                         ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
1530                                         ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
1531                                         );
1532
1533                                 if (option_verbose > 1) 
1534                                         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);
1535                                 /* Start up the PBX, or hang them up */
1536                                 if (ast_pbx_start(pu->chan))  {
1537                                         ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", pu->chan->name);
1538                                         ast_hangup(pu->chan);
1539                                 }
1540                                 /* And take them out of the parking lot */
1541                                 if (pl) 
1542                                         pl->next = pu->next;
1543                                 else
1544                                         parkinglot = pu->next;
1545                                 pt = pu;
1546                                 pu = pu->next;
1547                                 con = ast_context_find(parking_con);
1548                                 if (con) {
1549                                         snprintf(exten, sizeof(exten), "%d", pt->parkingnum);
1550                                         if (ast_context_remove_extension2(con, exten, 1, NULL))
1551                                                 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
1552                                 } else
1553                                         ast_log(LOG_WARNING, "Whoa, no parking context?\n");
1554                                 free(pt);
1555                         } else {
1556                                 for (x = 0; x < AST_MAX_FDS; x++) {
1557                                         if ((pu->chan->fds[x] > -1) && (FD_ISSET(pu->chan->fds[x], &rfds) || FD_ISSET(pu->chan->fds[x], &efds))) {
1558                                                 if (FD_ISSET(pu->chan->fds[x], &efds))
1559                                                         ast_set_flag(pu->chan, AST_FLAG_EXCEPTION);
1560                                                 else
1561                                                         ast_clear_flag(pu->chan, AST_FLAG_EXCEPTION);
1562                                                 pu->chan->fdno = x;
1563                                                 /* See if they need servicing */
1564                                                 f = ast_read(pu->chan);
1565                                                 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass ==  AST_CONTROL_HANGUP))) {
1566                                                         if (f)
1567                                                                 ast_frfree(f);
1568                                                         manager_event(EVENT_FLAG_CALL, "ParkedCallGiveUp",
1569                                                                 "Exten: %d\r\n"
1570                                                                 "Channel: %s\r\n"
1571                                                                 "CallerID: %s\r\n"
1572                                                                 "CallerIDName: %s\r\n"
1573                                                                 ,pu->parkingnum, pu->chan->name
1574                                                                 ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
1575                                                                 ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
1576                                                                 );
1577
1578                                                         /* There's a problem, hang them up*/
1579                                                         if (option_verbose > 1) 
1580                                                                 ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being parked\n", pu->chan->name);
1581                                                         ast_hangup(pu->chan);
1582                                                         /* And take them out of the parking lot */
1583                                                         if (pl) 
1584                                                                 pl->next = pu->next;
1585                                                         else
1586                                                                 parkinglot = pu->next;
1587                                                         pt = pu;
1588                                                         pu = pu->next;
1589                                                         con = ast_context_find(parking_con);
1590                                                         if (con) {
1591                                                                 snprintf(exten, sizeof(exten), "%d", pt->parkingnum);
1592                                                                 if (ast_context_remove_extension2(con, exten, 1, NULL))
1593                                                                         ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
1594                                                         } else
1595                                                                 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
1596                                                         free(pt);
1597                                                         break;
1598                                                 } else {
1599                                                         /* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
1600                                                         ast_frfree(f);
1601                                                         if (pu->moh_trys < 3 && !pu->chan->generatordata) {
1602                                                                 ast_log(LOG_DEBUG, "MOH on parked call stopped by outside source.  Restarting.\n");
1603                                                                 ast_moh_start(pu->chan, NULL);
1604                                                                 pu->moh_trys++;
1605                                                         }
1606                                                         goto std;       /* XXX Ick: jumping into an else statement??? XXX */
1607                                                 }
1608                                         }
1609                                 }
1610                                 if (x >= AST_MAX_FDS) {
1611 std:                                    for (x=0; x<AST_MAX_FDS; x++) {
1612                                                 /* Keep this one for next one */
1613                                                 if (pu->chan->fds[x] > -1) {
1614                                                         FD_SET(pu->chan->fds[x], &nrfds);
1615                                                         FD_SET(pu->chan->fds[x], &nefds);
1616                                                         if (pu->chan->fds[x] > max)
1617                                                                 max = pu->chan->fds[x];
1618                                                 }
1619                                         }
1620                                         /* Keep track of our longest wait */
1621                                         if ((tms < ms) || (ms < 0))
1622                                                 ms = tms;
1623                                         pl = pu;
1624                                         pu = pu->next;
1625                                 }
1626                         }
1627                 }
1628                 ast_mutex_unlock(&parking_lock);
1629                 rfds = nrfds;
1630                 efds = nefds;
1631                 tv = ast_samp2tv(ms, 1000);
1632                 /* Wait for something to happen */
1633                 ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL);
1634                 pthread_testcancel();
1635         }
1636         return NULL;    /* Never reached */
1637 }
1638
1639 static int park_call_exec(struct ast_channel *chan, void *data)
1640 {
1641         /* Data is unused at the moment but could contain a parking
1642            lot context eventually */
1643         int res=0;
1644         struct localuser *u;
1645         LOCAL_USER_ADD(u);
1646         /* Setup the exten/priority to be s/1 since we don't know
1647            where this call should return */
1648         strcpy(chan->exten, "s");
1649         chan->priority = 1;
1650         if (chan->_state != AST_STATE_UP)
1651                 res = ast_answer(chan);
1652         if (!res)
1653                 res = ast_safe_sleep(chan, 1000);
1654         if (!res)
1655                 res = ast_park_call(chan, chan, 0, NULL);
1656         LOCAL_USER_REMOVE(u);
1657         if (!res)
1658                 res = AST_PBX_KEEPALIVE;
1659         return res;
1660 }
1661
1662 static int park_exec(struct ast_channel *chan, void *data)
1663 {
1664         int res=0;
1665         struct localuser *u;
1666         struct ast_channel *peer=NULL;
1667         struct parkeduser *pu, *pl=NULL;
1668         char exten[AST_MAX_EXTENSION];
1669         struct ast_context *con;
1670         int park;
1671         int dres;
1672         struct ast_bridge_config config;
1673
1674         if (!data) {
1675                 ast_log(LOG_WARNING, "Park requires an argument (extension number)\n");
1676                 return -1;
1677         }
1678         LOCAL_USER_ADD(u);
1679         park = atoi((char *)data);
1680         ast_mutex_lock(&parking_lock);
1681         pu = parkinglot;
1682         while(pu) {
1683                 if (pu->parkingnum == park) {
1684                         if (pl)
1685                                 pl->next = pu->next;
1686                         else
1687                                 parkinglot = pu->next;
1688                         break;
1689                 }
1690                 pl = pu;
1691                 pu = pu->next;
1692         }
1693         ast_mutex_unlock(&parking_lock);
1694         if (pu) {
1695                 peer = pu->chan;
1696                 con = ast_context_find(parking_con);
1697                 if (con) {
1698                         snprintf(exten, sizeof(exten), "%d", pu->parkingnum);
1699                         if (ast_context_remove_extension2(con, exten, 1, NULL))
1700                                 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
1701                 } else
1702                         ast_log(LOG_WARNING, "Whoa, no parking context?\n");
1703
1704                 manager_event(EVENT_FLAG_CALL, "UnParkedCall",
1705                         "Exten: %d\r\n"
1706                         "Channel: %s\r\n"
1707                         "From: %s\r\n"
1708                         "CallerID: %s\r\n"
1709                         "CallerIDName: %s\r\n"
1710                         ,pu->parkingnum, pu->chan->name, chan->name
1711                         ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
1712                         ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
1713                         );
1714
1715                 free(pu);
1716         }
1717         /* JK02: it helps to answer the channel if not already up */
1718         if (chan->_state != AST_STATE_UP) {
1719                 ast_answer(chan);
1720         }
1721
1722         if (peer) {
1723                 /* Play a courtesy to the source(s) configured to prefix the bridge connecting */
1724                 
1725                 if (!ast_strlen_zero(courtesytone)) {
1726                         if (parkedplay == 0) {
1727                                 if (!ast_streamfile(chan, courtesytone, chan->language)) {
1728                                         if (ast_waitstream(chan, "") < 0) {
1729                                                 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
1730                                                 ast_hangup(peer);
1731                                                 return -1;
1732                                         }
1733                                 }
1734                                 ast_moh_stop(peer);
1735                                 ast_indicate(peer, AST_CONTROL_UNHOLD);
1736                         } else {
1737                                 ast_moh_stop(peer);
1738                                 ast_indicate(peer, AST_CONTROL_UNHOLD);
1739                                 if (parkedplay == 2) {
1740                                         if (!ast_streamfile(chan, courtesytone, chan->language) && !ast_streamfile(peer, courtesytone, chan->language)) {
1741                                                 res = ast_waitstream(chan, "");
1742                                                 if (res >= 0)
1743                                                         res = ast_waitstream(peer, "");
1744                                                 if (res < 0) {
1745                                                         ast_log(LOG_WARNING, "Failed to play courtesy tones!\n");
1746                                                         ast_hangup(peer);
1747                                                         return -1;
1748                                                 }
1749                                         }
1750                                 } else if (parkedplay == 1) {
1751                                         if (!ast_streamfile(peer, courtesytone, chan->language)) {
1752                                                 if (ast_waitstream(peer, "") < 0) {
1753                                                         ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
1754                                                         ast_hangup(peer);
1755                                                         return -1;
1756                                                 }
1757                                         }
1758                                 }
1759                         }
1760                 }
1761  
1762                 res = ast_channel_make_compatible(chan, peer);
1763                 if (res < 0) {
1764                         ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
1765                         ast_hangup(peer);
1766                         return -1;
1767                 }
1768                 /* This runs sorta backwards, since we give the incoming channel control, as if it
1769                    were the person called. */
1770                 if (option_verbose > 2) 
1771                         ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to parked call %d\n", chan->name, park);
1772
1773                 memset(&config, 0, sizeof(struct ast_bridge_config));
1774                 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
1775                 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
1776                 config.timelimit = 0;
1777                 config.play_warning = 0;
1778                 config.warning_freq = 0;
1779                 config.warning_sound=NULL;
1780                 res = ast_bridge_call(chan, peer, &config);
1781
1782                 /* Simulate the PBX hanging up */
1783                 if (res != AST_PBX_NO_HANGUP_PEER)
1784                         ast_hangup(peer);
1785                 return res;
1786         } else {
1787                 /* XXX Play a message XXX */
1788                 dres = ast_streamfile(chan, "pbx-invalidpark", chan->language);
1789                 if (!dres)
1790                         dres = ast_waitstream(chan, "");
1791                 else {
1792                         ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
1793                         dres = 0;
1794                 }
1795                 if (option_verbose > 2) 
1796                         ast_verbose(VERBOSE_PREFIX_3 "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park);
1797                 res = -1;
1798         }
1799         LOCAL_USER_REMOVE(u);
1800         return res;
1801 }
1802
1803 static int handle_showfeatures(int fd, int argc, char *argv[])
1804 {
1805         int i;
1806         int fcount;
1807         struct ast_call_feature *feature;
1808         char format[] = "%-25s %-7s %-7s\n";
1809
1810         ast_cli(fd, format, "Builtin Feature", "Default", "Current");
1811         ast_cli(fd, format, "---------------", "-------", "-------");
1812
1813         ast_cli(fd, format, "Pickup", "*8", ast_pickup_ext());          /* default hardcoded above, so we'll hardcode it here */
1814
1815         fcount = sizeof(builtin_features) / sizeof(builtin_features[0]);
1816
1817         for (i = 0; i < fcount; i++)
1818         {
1819                 ast_cli(fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
1820         }
1821         ast_cli(fd, "\n");
1822         ast_cli(fd, format, "Dynamic Feature", "Default", "Current");
1823         ast_cli(fd, format, "---------------", "-------", "-------");
1824         if (AST_LIST_EMPTY(&feature_list)) {
1825                 ast_cli(fd, "(none)\n");
1826         }
1827         else {
1828                 AST_LIST_LOCK(&feature_list);
1829                 AST_LIST_TRAVERSE(&feature_list, feature, feature_entry) {
1830                         ast_cli(fd, format, feature->sname, "no def", feature->exten);  
1831                 }
1832                 AST_LIST_UNLOCK(&feature_list);
1833         }
1834         ast_cli(fd, "\nCall parking\n");
1835         ast_cli(fd, "------------\n");
1836         ast_cli(fd,"%-20s:      %s\n", "Parking extension", parking_ext);
1837         ast_cli(fd,"%-20s:      %s\n", "Parking context", parking_con);
1838         ast_cli(fd,"%-20s:      %d-%d\n", "Parked call extensions", parking_start, parking_stop);
1839         ast_cli(fd,"\n");
1840         
1841         return RESULT_SUCCESS;
1842 }
1843
1844 static char showfeatures_help[] =
1845 "Usage: show features\n"
1846 "       Lists currently configured features.\n";
1847
1848 static struct ast_cli_entry showfeatures =
1849 { { "show", "features", NULL }, handle_showfeatures, "Lists configured features", showfeatures_help };
1850
1851 static int handle_parkedcalls(int fd, int argc, char *argv[])
1852 {
1853         struct parkeduser *cur;
1854         int numparked = 0;
1855
1856         ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
1857                 , "Context", "Extension", "Pri", "Timeout");
1858
1859         ast_mutex_lock(&parking_lock);
1860
1861         cur = parkinglot;
1862         while(cur) {
1863                 ast_cli(fd, "%4d %25s (%-15s %-12s %-4d) %6lds\n"
1864                         ,cur->parkingnum, cur->chan->name, cur->context, cur->exten
1865                         ,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL));
1866
1867                 cur = cur->next;
1868                 numparked++;
1869         }
1870         ast_cli(fd, "%d parked call%s.\n", numparked, (numparked != 1) ? "s" : "");
1871
1872         ast_mutex_unlock(&parking_lock);
1873
1874         return RESULT_SUCCESS;
1875 }
1876
1877 static char showparked_help[] =
1878 "Usage: show parkedcalls\n"
1879 "       Lists currently parked calls.\n";
1880
1881 static struct ast_cli_entry showparked =
1882 { { "show", "parkedcalls", NULL }, handle_parkedcalls, "Lists parked calls", showparked_help };
1883
1884 /*! \brief Dump lot status */
1885 static int manager_parking_status( struct mansession *s, struct message *m )
1886 {
1887         struct parkeduser *cur;
1888         char *id = astman_get_header(m,"ActionID");
1889         char idText[256] = "";
1890
1891         if (!ast_strlen_zero(id))
1892                 snprintf(idText,256,"ActionID: %s\r\n",id);
1893
1894         astman_send_ack(s, m, "Parked calls will follow");
1895
1896         ast_mutex_lock(&parking_lock);
1897
1898         cur=parkinglot;
1899         while(cur) {
1900                         astman_append(s, "Event: ParkedCall\r\n"
1901                         "Exten: %d\r\n"
1902                         "Channel: %s\r\n"
1903                         "From: %s\r\n"
1904                         "Timeout: %ld\r\n"
1905                         "CallerID: %s\r\n"
1906                         "CallerIDName: %s\r\n"
1907                         "%s"
1908                         "\r\n"
1909                         ,cur->parkingnum, cur->chan->name, cur->peername
1910                         ,(long)cur->start.tv_sec + (long)(cur->parkingtime/1000) - (long)time(NULL)
1911                         ,(cur->chan->cid.cid_num ? cur->chan->cid.cid_num : "")
1912                         ,(cur->chan->cid.cid_name ? cur->chan->cid.cid_name : "")
1913                         ,idText);
1914
1915             cur = cur->next;
1916         }
1917
1918         astman_append(s,
1919         "Event: ParkedCallsComplete\r\n"
1920         "%s"
1921         "\r\n",idText);
1922
1923         ast_mutex_unlock(&parking_lock);
1924
1925         return RESULT_SUCCESS;
1926 }
1927
1928 static char mandescr_park[] =
1929 "Description: Park a channel.\n"
1930 "Variables: (Names marked with * are required)\n"
1931 "       *Channel: Channel name to park\n"
1932 "       *Channel2: Channel to announce park info to (and return to if timeout)\n"
1933 "       Timeout: Number of milliseconds to wait before callback.\n";  
1934
1935 static int manager_park(struct mansession *s, struct message *m)
1936 {
1937         char *channel = astman_get_header(m, "Channel");
1938         char *channel2 = astman_get_header(m, "Channel2");
1939         char *timeout = astman_get_header(m, "Timeout");
1940         char buf[BUFSIZ];
1941         int to = 0;
1942         int res = 0;
1943         int parkExt = 0;
1944         struct ast_channel *ch1, *ch2;
1945
1946         if (ast_strlen_zero(channel)) {
1947                 astman_send_error(s, m, "Channel not specified");
1948                 return 0;
1949         }
1950
1951         if (ast_strlen_zero(channel2)) {
1952                 astman_send_error(s, m, "Channel2 not specified");
1953                 return 0;
1954         }
1955
1956         ch1 = ast_get_channel_by_name_locked(channel);
1957         if (!ch1) {
1958                 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel);
1959                 astman_send_error(s, m, buf);
1960                 return 0;
1961         }
1962
1963         ch2 = ast_get_channel_by_name_locked(channel2);
1964         if (!ch2) {
1965                 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2);
1966                 astman_send_error(s, m, buf);
1967                 ast_mutex_unlock(&ch1->lock);
1968                 return 0;
1969         }
1970
1971         if (!ast_strlen_zero(timeout)) {
1972                 sscanf(timeout, "%d", &to);
1973         }
1974
1975         res = ast_masq_park_call(ch1, ch2, to, &parkExt);
1976         if (!res) {
1977                 ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT);
1978                 astman_send_ack(s, m, "Park successful");
1979         } else {
1980                 astman_send_error(s, m, "Park failure");
1981         }
1982
1983         ast_mutex_unlock(&ch1->lock);
1984         ast_mutex_unlock(&ch2->lock);
1985
1986         return 0;
1987 }
1988
1989
1990 int ast_pickup_call(struct ast_channel *chan)
1991 {
1992         struct ast_channel *cur = NULL;
1993         int res = -1;
1994
1995         while ( (cur = ast_channel_walk_locked(cur)) != NULL) {
1996                 if (!cur->pbx && 
1997                         (cur != chan) &&
1998                         (chan->pickupgroup & cur->callgroup) &&
1999                         ((cur->_state == AST_STATE_RINGING) ||
2000                          (cur->_state == AST_STATE_RING))) {
2001                                 break;
2002                 }
2003                 ast_mutex_unlock(&cur->lock);
2004         }
2005         if (cur) {
2006                 if (option_debug)
2007                         ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
2008                 res = ast_answer(chan);
2009                 if (res)
2010                         ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
2011                 res = ast_queue_control(chan, AST_CONTROL_ANSWER);
2012                 if (res)
2013                         ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
2014                 res = ast_channel_masquerade(cur, chan);
2015                 if (res)
2016                         ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name);           /* Done */
2017                 ast_mutex_unlock(&cur->lock);
2018         } else  {
2019                 if (option_debug)
2020                         ast_log(LOG_DEBUG, "No call pickup possible...\n");
2021         }
2022         return res;
2023 }
2024
2025 static int load_config(void) 
2026 {
2027         int start = 0, end = 0;
2028         struct ast_context *con = NULL;
2029         struct ast_config *cfg = NULL;
2030         struct ast_variable *var = NULL;
2031         char old_parking_ext[AST_MAX_EXTENSION];
2032         char old_parking_con[AST_MAX_EXTENSION] = "";
2033
2034         if (!ast_strlen_zero(parking_con)) {
2035                 strcpy(old_parking_ext, parking_ext);
2036                 strcpy(old_parking_con, parking_con);
2037         } 
2038
2039         /* Reset to defaults */
2040         strcpy(parking_con, "parkedcalls");
2041         strcpy(parking_con_dial, "park-dial");
2042         strcpy(parking_ext, "700");
2043         strcpy(pickup_ext, "*8");
2044         courtesytone[0] = '\0';
2045         strcpy(xfersound, "beep");
2046         strcpy(xferfailsound, "pbx-invalid");
2047         parking_start = 701;
2048         parking_stop = 750;
2049         parkfindnext = 0;
2050         adsipark = 0;
2051
2052         transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
2053         featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
2054
2055         cfg = ast_config_load("features.conf");
2056         if (cfg) {
2057                 var = ast_variable_browse(cfg, "general");
2058                 while(var) {
2059                         if (!strcasecmp(var->name, "parkext")) {
2060                                 ast_copy_string(parking_ext, var->value, sizeof(parking_ext));
2061                         } else if (!strcasecmp(var->name, "context")) {
2062                                 ast_copy_string(parking_con, var->value, sizeof(parking_con));
2063                         } else if (!strcasecmp(var->name, "parkingtime")) {
2064                                 if ((sscanf(var->value, "%d", &parkingtime) != 1) || (parkingtime < 1)) {
2065                                         ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value);
2066                                         parkingtime = DEFAULT_PARK_TIME;
2067                                 } else
2068                                         parkingtime = parkingtime * 1000;
2069                         } else if (!strcasecmp(var->name, "parkpos")) {
2070                                 if (sscanf(var->value, "%d-%d", &start, &end) != 2) {
2071                                         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);
2072                                 } else {
2073                                         parking_start = start;
2074                                         parking_stop = end;
2075                                 }
2076                         } else if (!strcasecmp(var->name, "findslot")) {
2077                                 parkfindnext = (!strcasecmp(var->value, "next"));
2078                         } else if (!strcasecmp(var->name, "adsipark")) {
2079                                 adsipark = ast_true(var->value);
2080                         } else if (!strcasecmp(var->name, "transferdigittimeout")) {
2081                                 if ((sscanf(var->value, "%d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) {
2082                                         ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value);
2083                                         transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
2084                                 } else
2085                                         transferdigittimeout = transferdigittimeout * 1000;
2086                         } else if (!strcasecmp(var->name, "featuredigittimeout")) {
2087                                 if ((sscanf(var->value, "%d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) {
2088                                         ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value);
2089                                         featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
2090                                 }
2091                         } else if (!strcasecmp(var->name, "courtesytone")) {
2092                                 ast_copy_string(courtesytone, var->value, sizeof(courtesytone));
2093                         }  else if (!strcasecmp(var->name, "parkedplay")) {
2094                                 if (!strcasecmp(var->value, "both"))
2095                                         parkedplay = 2;
2096                                 else if (!strcasecmp(var->value, "parked"))
2097                                         parkedplay = 1;
2098                                 else
2099                                         parkedplay = 0;
2100                         } else if (!strcasecmp(var->name, "xfersound")) {
2101                                 ast_copy_string(xfersound, var->value, sizeof(xfersound));
2102                         } else if (!strcasecmp(var->name, "xferfailsound")) {
2103                                 ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound));
2104                         } else if (!strcasecmp(var->name, "pickupexten")) {
2105                                 ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext));
2106                         }
2107                         var = var->next;
2108                 }
2109
2110                 unmap_features();
2111                 var = ast_variable_browse(cfg, "featuremap");
2112                 while(var) {
2113                         if (remap_feature(var->name, var->value))
2114                                 ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name);
2115                         var = var->next;
2116                 }
2117
2118                 /* Map a key combination to an application*/
2119                 ast_unregister_features();
2120                 var = ast_variable_browse(cfg, "applicationmap");
2121                 while(var) {
2122                         char *tmp_val=strdup(var->value);
2123                         char *exten, *party=NULL, *app=NULL, *app_args=NULL; 
2124
2125                         if (!tmp_val) { 
2126                                 ast_log(LOG_ERROR, "res_features: strdup failed");
2127                                 continue;
2128                         }
2129                         
2130
2131                         exten=strsep(&tmp_val,",");
2132                         if (exten) party=strsep(&tmp_val,",");
2133                         if (party) app=strsep(&tmp_val,",");
2134
2135                         if (app) app_args=strsep(&tmp_val,",");
2136
2137                         if (!(app && strlen(app)) || !(exten && strlen(exten)) || !(party && strlen(party)) || !(var->name && strlen(var->name))) {
2138                                 ast_log(LOG_NOTICE, "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n",app,exten,party,var->name);
2139                                 free(tmp_val);
2140                                 var = var->next;
2141                                 continue;
2142                         }
2143
2144                         {
2145                                 struct ast_call_feature *feature;
2146                                 int mallocd = 0;
2147                                 
2148                                 if (!(feature = find_feature(var->name))) {
2149                                         mallocd = 1;
2150                                         
2151                                         if (!(feature = ast_calloc(1, sizeof(*feature)))) {
2152                                                 free(tmp_val);
2153                                                 var = var->next;
2154                                                 continue;                                       
2155                                         }
2156                                 }
2157
2158                                 ast_copy_string(feature->sname,var->name,FEATURE_SNAME_LEN);
2159                                 ast_copy_string(feature->app,app,FEATURE_APP_LEN);
2160                                 ast_copy_string(feature->exten, exten,FEATURE_EXTEN_LEN);
2161                                 free(tmp_val);
2162                                 
2163                                 if (app_args) 
2164                                         ast_copy_string(feature->app_args,app_args,FEATURE_APP_ARGS_LEN);
2165                                 
2166                                 ast_copy_string(feature->exten, exten,sizeof(feature->exten));
2167                                 feature->operation=feature_exec_app;
2168                                 ast_set_flag(feature,AST_FEATURE_FLAG_NEEDSDTMF);
2169                                 
2170                                 if (!strcasecmp(party,"caller"))
2171                                         ast_set_flag(feature,AST_FEATURE_FLAG_CALLER);
2172                                 else if (!strcasecmp(party, "callee"))
2173                                         ast_set_flag(feature,AST_FEATURE_FLAG_CALLEE);
2174                                 else {
2175                                         ast_log(LOG_NOTICE, "Invalid party specification for feature '%s', must be caller, or callee\n", var->name);
2176                                         var = var->next;
2177                                         continue;
2178                                 }
2179
2180                                 ast_register_feature(feature);
2181                                 
2182                                 if (option_verbose >=1) ast_verbose(VERBOSE_PREFIX_2 "Mapping Feature '%s' to app '%s' with code '%s'\n", var->name, app, exten);  
2183                         }
2184                         var = var->next;
2185                 }        
2186         }
2187         ast_config_destroy(cfg);
2188
2189         /* Remove the old parking extension */
2190         if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con)))     {
2191                 ast_context_remove_extension2(con, old_parking_ext, 1, registrar);
2192                 ast_log(LOG_DEBUG, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con);
2193         }
2194         
2195         if (!(con = ast_context_find(parking_con))) {
2196                 if (!(con = ast_context_create(NULL, parking_con, registrar))) {
2197                         ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
2198                         return -1;
2199                 }
2200         }
2201         return ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, strdup(""), FREE, registrar);
2202 }
2203
2204 int reload(void) {
2205         return load_config();
2206 }
2207
2208 int load_module(void)
2209 {
2210         int res;
2211         
2212         AST_LIST_HEAD_INIT(&feature_list);
2213         memset(parking_ext, 0, sizeof(parking_ext));
2214         memset(parking_con, 0, sizeof(parking_con));
2215
2216         if ((res = load_config()))
2217                 return res;
2218         ast_cli_register(&showparked);
2219         ast_cli_register(&showfeatures);
2220         ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
2221         res = ast_register_application(parkedcall, park_exec, synopsis, descrip);
2222         if (!res)
2223                 res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2);
2224         if (!res) {
2225                 ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls" );
2226                 ast_manager_register2("Park", EVENT_FLAG_CALL, manager_park,
2227                         "Park a channel", mandescr_park); 
2228         }
2229         return res;
2230 }
2231
2232
2233 int unload_module(void)
2234 {
2235         STANDARD_HANGUP_LOCALUSERS;
2236
2237         ast_manager_unregister("ParkedCalls");
2238         ast_manager_unregister("Park");
2239         ast_cli_unregister(&showfeatures);
2240         ast_cli_unregister(&showparked);
2241         ast_unregister_application(parkcall);
2242         return ast_unregister_application(parkedcall);
2243 }
2244
2245 const char *description(void)
2246 {
2247         return "Call Features Resource";
2248 }
2249
2250 int usecount(void)
2251 {
2252         /* Never allow parking to be unloaded because it will
2253            unresolve needed symbols in the dialer */
2254 #if 0
2255         int res;
2256         STANDARD_USECOUNT(res);
2257         return res;
2258 #else
2259         return 1;
2260 #endif
2261 }
2262
2263 const char *key()
2264 {
2265         return ASTERISK_GPL_KEY;
2266 }