2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2006, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
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.
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.
21 * \brief Routines implementing call features as call pickup, parking and transfer
23 * \author Mark Spencer <markster@digium.com>
34 #include <sys/signal.h>
35 #include <netinet/in.h>
39 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
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"
61 #ifdef __AST_DEBUG_MALLOC
62 static void FREE(void *ptr)
70 #define DEFAULT_PARK_TIME 45000
71 #define DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000
72 #define DEFAULT_FEATURE_DIGIT_TIMEOUT 500
74 #define AST_MAX_WATCHERS 256
76 static char *parkedcall = "ParkedCall";
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 */
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 */
91 static int parking_offset;
92 static int parkfindnext;
96 static int transferdigittimeout;
97 static int featuredigittimeout;
99 static char *registrar = "res_features"; /*!< Registrar for operations */
101 /* module and CLI command definitions */
102 static char *synopsis = "Answer a parked call";
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"
110 static char *parkcall = "Park";
112 static char *synopsis2 = "Park yourself";
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"
121 static struct ast_app *monitor_app = NULL;
122 static int monitor_ok = 1;
125 struct ast_channel *chan;
126 struct timeval start;
128 /* Where to go if our parking time expires */
129 char context[AST_MAX_CONTEXT];
130 char exten[AST_MAX_EXTENSION];
135 unsigned char moh_trys;
136 struct parkeduser *next;
139 static struct parkeduser *parkinglot;
141 AST_MUTEX_DEFINE_STATIC(parking_lock);
143 static pthread_t parking_thread;
147 char *ast_parking_ext(void)
152 char *ast_pickup_ext(void)
157 struct ast_bridge_thread_obj
159 struct ast_bridge_config bconfig;
160 struct ast_channel *chan;
161 struct ast_channel *peer;
164 static void check_goto_on_transfer(struct ast_channel *chan)
166 struct ast_channel *xferchan;
167 const char *val = pbx_builtin_getvar_helper(chan, "GOTO_ON_BLINDXFR");
168 char *x, *goto_on_transfer;
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++)
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))) {
187 ast_pbx_start(xferchan);
189 ast_hangup(xferchan);
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);
197 static void *ast_bridge_call_thread(void *data)
199 struct ast_bridge_thread_obj *tobj = data;
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);
209 if (tobj->peer->cdr) {
210 ast_cdr_reset(tobj->peer->cdr, NULL);
211 ast_cdr_setdestchan(tobj->peer->cdr, tobj->chan->name);
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;
223 static void ast_bridge_call_thread_launch(void *data)
227 struct sched_param sched;
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);
239 static int adsi_announce_park(struct ast_channel *chan, int parkingnum)
242 int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT};
244 char *message[5] = {NULL, NULL, NULL, NULL, NULL};
246 snprintf(tmp, sizeof(tmp), "Parked on %d", parkingnum);
248 res = adsi_load_session(chan, NULL, 0, 1);
252 return adsi_print(chan, message, justify, 1);
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)
260 struct parkeduser *pu, *cur;
261 int i,x,parking_range;
262 char exten[AST_MAX_EXTENSION];
263 struct ast_context *con;
265 if (!(pu = ast_calloc(1, sizeof(*pu)))) {
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;
274 if (cur->parkingnum == x)
282 if (!(i < parking_range)) {
283 ast_log(LOG_WARNING, "No more parking spaces\n");
285 ast_mutex_unlock(&parking_lock);
289 parking_offset = x - parking_start + 1;
290 chan->appl = "Parked Call";
294 /* Start music on hold */
296 ast_indicate(pu->chan, AST_CONTROL_HOLD);
297 ast_moh_start(pu->chan, NULL);
299 pu->start = ast_tvnow();
302 pu->parkingtime = timeout;
304 pu->parkingtime = parkingtime;
308 ast_copy_string(pu->peername, peer->name, sizeof(pu->peername));
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));
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));
319 ast_copy_string(pu->exten, chan->exten, sizeof(pu->exten));
320 if (chan->macropriority)
321 pu->priority = chan->macropriority;
323 pu->priority = chan->priority;
324 pu->next = parkinglot;
326 /* If parking a channel directly, don't quiet yet get parking running on it */
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));
335 manager_event(EVENT_FLAG_CALL, "ParkedCall",
341 "CallerIDName: %s\r\n"
342 ,pu->parkingnum, pu->chan->name, 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>")
349 if (adsipark && adsi_available(peer)) {
350 adsi_announce_park(peer, pu->parkingnum);
352 if (adsipark && adsi_available(peer)) {
353 adsi_unload_session(peer);
356 con = ast_context_find(parking_con);
358 con = ast_context_create(NULL, parking_con, registrar);
360 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
364 snprintf(exten, sizeof(exten), "%d", x);
365 ast_add_extension2(con, 1, exten, 1, NULL, NULL, parkedcall, strdup(exten), FREE, registrar);
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);
373 pthread_kill(parking_thread, SIGURG);
378 int ast_masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout)
380 struct ast_channel *chan;
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);
388 /* Make formats okay */
389 chan->readformat = rchan->readformat;
390 chan->writeformat = rchan->writeformat;
391 ast_channel_masquerade(chan, rchan);
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;
398 /* Make the masq execute */
402 ast_park_call(chan, peer, timeout, extout);
404 ast_log(LOG_WARNING, "Unable to create parked channel\n");
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
419 #define FEATURE_SENSE_CHAN (1 << 0)
420 #define FEATURE_SENSE_PEER (1 << 1)
423 static int builtin_automonitor(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
425 char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL;
428 struct ast_channel *caller_chan = NULL, *callee_chan = NULL;
440 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
445 if (!(monitor_app = pbx_findapp("Monitor"))) {
447 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
451 if (!ast_strlen_zero(courtesytone)) {
452 if (ast_autoservice_start(callee_chan))
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);
461 if (ast_autoservice_stop(callee_chan))
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;
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");
477 touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT");
480 touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR");
483 len = strlen(touch_monitor) + 50;
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);
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;
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);
498 for( x = 0; x < strlen(args); x++)
502 if (option_verbose > 3)
503 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to record call. filename: %s\n", code, args);
505 pbx_exec(callee_chan, monitor_app, args, 1);
506 pbx_builtin_setvar_helper(callee_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
507 pbx_builtin_setvar_helper(caller_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
509 return FEATURE_RETURN_SUCCESS;
512 ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n");
516 static int builtin_disconnect(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
518 if (option_verbose > 3)
519 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to disconnect call.\n", code);
520 return FEATURE_RETURN_HANGUP;
523 static int builtin_blindtransfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
525 struct ast_channel *transferer;
526 struct ast_channel *transferee;
527 const char *transferer_real_context;
531 if (sense == FEATURE_SENSE_PEER) {
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;
544 transferer_real_context = transferer->context;
546 /* Start autoservice on chan while we talk
548 ast_indicate(transferee, AST_CONTROL_HOLD);
549 ast_autoservice_start(transferee);
550 ast_moh_start(transferee, NULL);
552 memset(newext, 0, sizeof(newext));
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);
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);
566 } else if (res > 0) {
567 /* If they've typed a digit already, handle it */
568 newext[0] = (char) res;
571 ast_stopstream(transferer);
572 res = ast_app_dtget(transferer, transferer_real_context, newext, sizeof(newext), 100, transferdigittimeout);
574 ast_moh_stop(transferee);
575 ast_autoservice_stop(transferee);
576 ast_indicate(transferee, AST_CONTROL_UNHOLD);
579 if (!strcmp(newext, ast_parking_ext())) {
580 ast_moh_stop(transferee);
582 res = ast_autoservice_stop(transferee);
583 ast_indicate(transferee, AST_CONTROL_UNHOLD);
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! */
591 if (transferer == peer)
592 res = AST_PBX_KEEPALIVE;
594 res = AST_PBX_NO_HANGUP_PEER;
597 ast_log(LOG_WARNING, "Unable to park call %s\n", transferee->name);
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");
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;
620 check_goto_on_transfer(transferer);
623 if (option_verbose > 2)
624 ast_verbose(VERBOSE_PREFIX_3 "Unable to find extension '%s' in context '%s'\n", newext, transferer_real_context);
626 if (!ast_strlen_zero(xferfailsound))
627 res = ast_streamfile(transferer, xferfailsound, transferee->language);
631 ast_moh_stop(transferee);
632 ast_autoservice_stop(transferee);
633 ast_indicate(transferee, AST_CONTROL_UNHOLD);
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);
642 if (option_verbose > 1)
643 ast_verbose(VERBOSE_PREFIX_2 "Hungup during autoservice stop on '%s'\n", transferee->name);
646 return FEATURE_RETURN_SUCCESS;
649 static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
651 struct ast_channel *transferer;
652 struct ast_channel *transferee;
653 struct ast_channel *newchan, *xferchan=NULL;
655 struct ast_bridge_config bconfig;
656 const char *transferer_real_context;
657 char xferto[256],dialstr[265];
661 struct ast_frame *f = NULL;
662 struct ast_bridge_thread_obj *tobj;
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) {
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;
678 transferer_real_context = transferer->context;
680 /* Start autoservice on chan while we talk
682 ast_indicate(transferee, AST_CONTROL_HOLD);
683 ast_autoservice_start(transferee);
684 ast_moh_start(transferee, NULL);
685 memset(xferto, 0, sizeof(xferto));
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);
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);
699 /* If they've typed a digit already, handle it */
700 xferto[0] = (char) res;
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);
710 res = ast_channel_make_compatible(transferer, newchan);
712 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", transferer->name, newchan->name);
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) {
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");
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;
738 res = ast_channel_make_compatible(transferee, newchan);
740 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", transferee->name, newchan->name);
746 ast_moh_stop(transferee);
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)) {
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;
769 if ((f = ast_read(xferchan))) {
779 newchan->_state = AST_STATE_UP;
780 ast_clear_flag(newchan, AST_FLAGS_ALL);
781 newchan->_softhangup = 0;
783 if ((tobj = ast_calloc(1, sizeof(*tobj)))) {
784 tobj->chan = xferchan;
785 tobj->peer = newchan;
786 tobj->bconfig = *config;
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");
793 ast_bridge_call_thread_launch(tobj);
795 ast_hangup(xferchan);
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)) {
811 return FEATURE_RETURN_SUCCESS;
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)) {
824 ast_log(LOG_WARNING, "Did not read data.\n");
825 res = ast_streamfile(transferer, "beeperr", transferer->language);
826 if (ast_waitstream(transferer, "") < 0) {
830 ast_moh_stop(transferee);
831 ast_autoservice_stop(transferee);
832 ast_indicate(transferee, AST_CONTROL_UNHOLD);
834 return FEATURE_RETURN_SUCCESS;
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]))
841 struct ast_call_feature builtin_features[] =
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 },
850 static AST_LIST_HEAD(feature_list,ast_call_feature) feature_list;
852 /*! \brief register new feature into feature_list*/
853 void ast_register_feature(struct ast_call_feature *feature)
856 ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
860 AST_LIST_LOCK(&feature_list);
861 AST_LIST_INSERT_HEAD(&feature_list,feature,feature_entry);
862 AST_LIST_UNLOCK(&feature_list);
864 if (option_verbose >= 2)
865 ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname);
868 /*! \brief unregister feature from feature_list */
869 void ast_unregister_feature(struct ast_call_feature *feature)
871 if (!feature) return;
873 AST_LIST_LOCK(&feature_list);
874 AST_LIST_REMOVE(&feature_list,feature,feature_entry);
875 AST_LIST_UNLOCK(&feature_list);
879 static void ast_unregister_features(void)
881 struct ast_call_feature *feature;
883 AST_LIST_LOCK(&feature_list);
884 while ((feature = AST_LIST_REMOVE_HEAD(&feature_list,feature_entry)))
886 AST_LIST_UNLOCK(&feature_list);
889 /*! \brief find a feature by name */
890 static struct ast_call_feature *find_feature(char *name)
892 struct ast_call_feature *tmp;
894 AST_LIST_LOCK(&feature_list);
895 AST_LIST_TRAVERSE(&feature_list, tmp, feature_entry) {
896 if (!strcasecmp(tmp->sname, name))
899 AST_LIST_UNLOCK(&feature_list);
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)
908 struct ast_call_feature *feature;
911 AST_LIST_LOCK(&feature_list);
912 AST_LIST_TRAVERSE(&feature_list,feature,feature_entry) {
913 if (!strcasecmp(feature->exten,code)) break;
915 AST_LIST_UNLOCK(&feature_list);
917 if (!feature) { /* shouldn't ever happen! */
918 ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n");
922 app = pbx_findapp(feature->app);
924 struct ast_channel *work = chan;
925 if (ast_test_flag(feature, AST_FEATURE_FLAG_CALLEE))
927 res = pbx_exec(work, app, feature->app_args, 1);
931 ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app);
935 return FEATURE_RETURN_SUCCESS;
938 static void unmap_features(void)
941 for (x = 0; x < FEATURES_COUNT; x++)
942 strcpy(builtin_features[x].exten, builtin_features[x].default_exten);
945 static int remap_feature(const char *name, const char *value)
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);
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);
961 static int ast_feature_interpret(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
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");
969 if (sense == FEATURE_SENSE_CHAN)
970 ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);
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);
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);
982 } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) {
983 if (res == FEATURE_RETURN_PASSDIGITS)
984 res = FEATURE_RETURN_STOREDIGITS;
990 if (!ast_strlen_zero(dynamic_features)) {
991 char *tmp = ast_strdupa(dynamic_features);
997 while ((tok = strsep(&tmp, "#")) != NULL) {
998 feature = find_feature(tok);
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);
1007 } else if (!strncmp(feature->exten, code, strlen(code))) {
1008 res = FEATURE_RETURN_STOREDIGITS;
1017 static void set_config_flags(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
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);
1027 if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask))
1028 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
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");
1035 if (dynamic_features) {
1036 char *tmp = ast_strdupa(dynamic_features);
1038 struct ast_call_feature *feature;
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);
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)
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;
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;
1077 char *disconnect_code = NULL, *dialed_code = NULL;
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"))
1085 disconnect_code = builtin_features[x].exten;
1086 len = strlen(disconnect_code) + 1;
1087 dialed_code = alloca(len);
1088 memset(dialed_code, 0, len);
1092 started = ast_tvnow();
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);
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*/
1106 if (!active_channel) {
1110 if (chan && (chan == active_channel)){
1112 if (f == NULL) { /*doh! where'd he go?*/
1113 state = AST_CONTROL_HANGUP;
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;
1129 } else if (f->subclass == AST_CONTROL_ANSWER) {
1130 /* This is what we are hoping for */
1131 state = f->subclass;
1137 ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass);
1139 /* else who cares */
1142 } else if (caller && (active_channel == caller)) {
1143 f = ast_read(caller);
1144 if (f == NULL) { /*doh! where'd he go?*/
1145 if (caller->_softhangup && !chan->_softhangup) {
1146 /* make this a blind transfer */
1150 state = AST_CONTROL_HANGUP;
1155 if (f->frametype == AST_FRAME_DTMF) {
1156 dialed_code[x++] = f->subclass;
1157 dialed_code[x] = '\0';
1158 if (strlen(dialed_code) == len) {
1160 } else if (x && strncmp(dialed_code, disconnect_code, x)) {
1162 dialed_code[x] = '\0';
1164 if (*dialed_code && !strcmp(dialed_code, disconnect_code)) {
1165 /* Caller Canceled the call */
1166 state = AST_CONTROL_UNHOLD;
1178 ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data);
1180 ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
1182 case AST_CAUSE_BUSY:
1183 state = AST_CONTROL_BUSY;
1185 case AST_CAUSE_CONGESTION:
1186 state = AST_CONTROL_CONGESTION;
1191 ast_indicate(caller, -1);
1192 if (chan && ready) {
1193 if (chan->_state == AST_STATE_UP)
1194 state = AST_CONTROL_ANSWER;
1207 if (chan && res <= 0) {
1208 if (chan->cdr || (chan->cdr = ast_cdr_alloc())) {
1210 ast_cdr_init(chan->cdr, chan);
1211 snprintf(tmp, 256, "%s/%s", type, (char *)data);
1212 ast_cdr_setapp(chan->cdr,"Dial",tmp);
1213 ast_cdr_update(chan);
1214 ast_cdr_start(chan->cdr);
1215 ast_cdr_end(chan->cdr);
1216 /* If the cause wasn't handled properly */
1217 if (ast_cdr_disposition(chan->cdr,chan->hangupcause))
1218 ast_cdr_failed(chan->cdr);
1220 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
1227 int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast_bridge_config *config)
1229 /* Copy voice back and forth between the two channels. Give the peer
1230 the ability to transfer calls with '#<extension' syntax. */
1231 struct ast_frame *f;
1232 struct ast_channel *who;
1233 char chan_featurecode[FEATURE_MAX_LEN + 1]="";
1234 char peer_featurecode[FEATURE_MAX_LEN + 1]="";
1239 struct ast_option_header *aoh;
1240 struct timeval start = { 0 , 0 };
1241 struct ast_bridge_config backup_config;
1243 memset(&backup_config, 0, sizeof(backup_config));
1245 config->start_time = ast_tvnow();
1248 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
1249 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
1251 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
1254 const char *monitor_exec;
1255 struct ast_channel *src = NULL;
1257 if (!(monitor_app = pbx_findapp("Monitor")))
1260 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR")))
1262 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
1264 if (monitor_app && src) {
1265 char *tmp = ast_strdupa(monitor_exec);
1267 pbx_exec(src, monitor_app, tmp, 1);
1269 ast_log(LOG_ERROR, "Monitor failed: out of memory\n");
1274 set_config_flags(chan, peer, config);
1275 config->firstpass = 1;
1277 /* Answer if need be */
1278 if (ast_answer(chan))
1280 peer->appl = "Bridged Call";
1281 peer->data = (char *) chan->name;
1283 /* copy the userfield from the B-leg to A-leg if applicable */
1284 if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) {
1286 if (!ast_strlen_zero(chan->cdr->userfield)) {
1287 snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield);
1288 ast_cdr_appenduserfield(chan, tmp);
1290 ast_cdr_setuserfield(chan, peer->cdr->userfield);
1291 /* free the peer's cdr without ast_cdr_free complaining */
1296 if (config->feature_timer)
1297 start = ast_tvnow();
1299 res = ast_channel_bridge(chan, peer, config, &f, &who);
1301 if (config->feature_timer) {
1302 /* Update time limit for next pass */
1303 diff = ast_tvdiff_ms(ast_tvnow(), start);
1304 config->feature_timer -= diff;
1306 /* Running on backup config, meaning a feature might be being
1307 activated, but that's no excuse to keep things going
1309 if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) {
1310 ast_log(LOG_DEBUG, "Timed out, realtime this time!\n");
1311 config->feature_timer = 0;
1317 } else if (config->feature_timer <= 0) {
1318 /* Not *really* out of time, just out of time for
1319 digits to come in for features. */
1320 ast_log(LOG_DEBUG, "Timed out for feature!\n");
1321 if (!ast_strlen_zero(peer_featurecode)) {
1322 ast_dtmf_stream(chan, peer, peer_featurecode, 0);
1323 memset(peer_featurecode, 0, sizeof(peer_featurecode));
1325 if (!ast_strlen_zero(chan_featurecode)) {
1326 ast_dtmf_stream(peer, chan, chan_featurecode, 0);
1327 memset(chan_featurecode, 0, sizeof(chan_featurecode));
1331 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
1333 /* Restore original (possibly time modified) bridge config */
1334 memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
1335 memset(&backup_config, 0, sizeof(backup_config));
1337 hadfeatures = hasfeatures;
1338 /* Continue as we were */
1342 if (config->feature_timer <=0) {
1343 /* We ran out of time */
1344 config->feature_timer = 0;
1354 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
1358 if (!f || ((f->frametype == AST_FRAME_CONTROL) && ((f->subclass == AST_CONTROL_HANGUP) || (f->subclass == AST_CONTROL_BUSY) ||
1359 (f->subclass == AST_CONTROL_CONGESTION)))) {
1363 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_RINGING)) {
1365 ast_indicate(peer, AST_CONTROL_RINGING);
1367 ast_indicate(chan, AST_CONTROL_RINGING);
1369 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == -1)) {
1371 ast_indicate(peer, -1);
1373 ast_indicate(chan, -1);
1375 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_FLASH)) {
1377 ast_indicate(peer, AST_CONTROL_FLASH);
1379 ast_indicate(chan, AST_CONTROL_FLASH);
1381 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_OPTION)) {
1383 /* Forward option Requests */
1384 if (aoh && (aoh->flag == AST_OPTION_FLAG_REQUEST)) {
1386 ast_channel_setoption(peer, ntohs(aoh->option), aoh->data, f->datalen - sizeof(struct ast_option_header), 0);
1388 ast_channel_setoption(chan, ntohs(aoh->option), aoh->data, f->datalen - sizeof(struct ast_option_header), 0);
1391 /* check for '*', if we find it it's time to disconnect */
1392 if (f && (f->frametype == AST_FRAME_DTMF)) {
1395 struct ast_channel *other;
1397 hadfeatures = hasfeatures;
1398 /* This cannot overrun because the longest feature is one shorter than our buffer */
1401 sense = FEATURE_SENSE_CHAN;
1402 featurecode = chan_featurecode;
1405 sense = FEATURE_SENSE_PEER;
1406 featurecode = peer_featurecode;
1408 featurecode[strlen(featurecode)] = f->subclass;
1409 config->feature_timer = backup_config.feature_timer;
1410 res = ast_feature_interpret(chan, peer, config, featurecode, sense);
1412 case FEATURE_RETURN_PASSDIGITS:
1413 ast_dtmf_stream(other, who, featurecode, 0);
1415 case FEATURE_RETURN_SUCCESS:
1416 memset(featurecode, 0, sizeof(chan_featurecode));
1419 if (res >= FEATURE_RETURN_PASSDIGITS) {
1425 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
1426 if (hadfeatures && !hasfeatures) {
1427 /* Restore backup */
1428 memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
1429 memset(&backup_config, 0, sizeof(struct ast_bridge_config));
1430 } else if (hasfeatures) {
1432 /* Backup configuration */
1433 memcpy(&backup_config, config, sizeof(struct ast_bridge_config));
1434 /* Setup temporary config options */
1435 config->play_warning = 0;
1436 ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
1437 ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
1438 config->warning_freq = 0;
1439 config->warning_sound = NULL;
1440 config->end_sound = NULL;
1441 config->start_sound = NULL;
1442 config->firstpass = 0;
1444 config->feature_timer = featuredigittimeout;
1445 ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->feature_timer);
1454 static void *do_parking_thread(void *ignore)
1457 struct parkeduser *pu, *pl, *pt = NULL;
1459 struct ast_frame *f;
1460 char exten[AST_MAX_EXTENSION];
1462 char returnexten[AST_MAX_EXTENSION];
1463 struct ast_context *con;
1466 fd_set nrfds, nefds;
1473 ast_mutex_lock(&parking_lock);
1479 if (pu->notquiteyet) {
1480 /* Pretend this one isn't here yet */
1485 tms = ast_tvdiff_ms(ast_tvnow(), pu->start);
1486 if (tms > pu->parkingtime) {
1487 /* Stop music on hold */
1488 ast_moh_stop(pu->chan);
1489 ast_indicate(pu->chan, AST_CONTROL_UNHOLD);
1490 /* Get chan, exten from derived kludge */
1491 if (pu->peername[0]) {
1492 peername = ast_strdupa(pu->peername);
1493 cp = strrchr(peername, '-');
1496 con = ast_context_find(parking_con_dial);
1498 con = ast_context_create(NULL, parking_con_dial, registrar);
1500 ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial);
1504 snprintf(returnexten, sizeof(returnexten), "%s||t", peername);
1505 ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(returnexten), FREE, registrar);
1507 ast_copy_string(pu->chan->exten, peername, sizeof(pu->chan->exten));
1508 ast_copy_string(pu->chan->context, parking_con_dial, sizeof(pu->chan->context));
1509 pu->chan->priority = 1;
1512 /* They've been waiting too long, send them back to where they came. Theoretically they
1513 should have their original extensions and such, but we copy to be on the safe side */
1514 ast_copy_string(pu->chan->exten, pu->exten, sizeof(pu->chan->exten));
1515 ast_copy_string(pu->chan->context, pu->context, sizeof(pu->chan->context));
1516 pu->chan->priority = pu->priority;
1519 manager_event(EVENT_FLAG_CALL, "ParkedCallTimeOut",
1523 "CallerIDName: %s\r\n"
1524 ,pu->parkingnum, pu->chan->name
1525 ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
1526 ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
1529 if (option_verbose > 1)
1530 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);
1531 /* Start up the PBX, or hang them up */
1532 if (ast_pbx_start(pu->chan)) {
1533 ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", pu->chan->name);
1534 ast_hangup(pu->chan);
1536 /* And take them out of the parking lot */
1538 pl->next = pu->next;
1540 parkinglot = pu->next;
1543 con = ast_context_find(parking_con);
1545 snprintf(exten, sizeof(exten), "%d", pt->parkingnum);
1546 if (ast_context_remove_extension2(con, exten, 1, NULL))
1547 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
1549 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
1552 for (x = 0; x < AST_MAX_FDS; x++) {
1553 if ((pu->chan->fds[x] > -1) && (FD_ISSET(pu->chan->fds[x], &rfds) || FD_ISSET(pu->chan->fds[x], &efds))) {
1554 if (FD_ISSET(pu->chan->fds[x], &efds))
1555 ast_set_flag(pu->chan, AST_FLAG_EXCEPTION);
1557 ast_clear_flag(pu->chan, AST_FLAG_EXCEPTION);
1559 /* See if they need servicing */
1560 f = ast_read(pu->chan);
1561 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
1564 manager_event(EVENT_FLAG_CALL, "ParkedCallGiveUp",
1568 "CallerIDName: %s\r\n"
1569 ,pu->parkingnum, pu->chan->name
1570 ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
1571 ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
1574 /* There's a problem, hang them up*/
1575 if (option_verbose > 1)
1576 ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being parked\n", pu->chan->name);
1577 ast_hangup(pu->chan);
1578 /* And take them out of the parking lot */
1580 pl->next = pu->next;
1582 parkinglot = pu->next;
1585 con = ast_context_find(parking_con);
1587 snprintf(exten, sizeof(exten), "%d", pt->parkingnum);
1588 if (ast_context_remove_extension2(con, exten, 1, NULL))
1589 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
1591 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
1595 /* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
1597 if (pu->moh_trys < 3 && !pu->chan->generatordata) {
1598 ast_log(LOG_DEBUG, "MOH on parked call stopped by outside source. Restarting.\n");
1599 ast_moh_start(pu->chan, NULL);
1602 goto std; /* XXX Ick: jumping into an else statement??? XXX */
1606 if (x >= AST_MAX_FDS) {
1607 std: for (x=0; x<AST_MAX_FDS; x++) {
1608 /* Keep this one for next one */
1609 if (pu->chan->fds[x] > -1) {
1610 FD_SET(pu->chan->fds[x], &nrfds);
1611 FD_SET(pu->chan->fds[x], &nefds);
1612 if (pu->chan->fds[x] > max)
1613 max = pu->chan->fds[x];
1616 /* Keep track of our longest wait */
1617 if ((tms < ms) || (ms < 0))
1624 ast_mutex_unlock(&parking_lock);
1627 tv = ast_samp2tv(ms, 1000);
1628 /* Wait for something to happen */
1629 ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL);
1630 pthread_testcancel();
1632 return NULL; /* Never reached */
1635 static int park_call_exec(struct ast_channel *chan, void *data)
1637 /* Data is unused at the moment but could contain a parking
1638 lot context eventually */
1640 struct localuser *u;
1642 /* Setup the exten/priority to be s/1 since we don't know
1643 where this call should return */
1644 strcpy(chan->exten, "s");
1646 if (chan->_state != AST_STATE_UP)
1647 res = ast_answer(chan);
1649 res = ast_safe_sleep(chan, 1000);
1651 res = ast_park_call(chan, chan, 0, NULL);
1652 LOCAL_USER_REMOVE(u);
1654 res = AST_PBX_KEEPALIVE;
1658 static int park_exec(struct ast_channel *chan, void *data)
1661 struct localuser *u;
1662 struct ast_channel *peer=NULL;
1663 struct parkeduser *pu, *pl=NULL;
1664 char exten[AST_MAX_EXTENSION];
1665 struct ast_context *con;
1668 struct ast_bridge_config config;
1671 ast_log(LOG_WARNING, "Park requires an argument (extension number)\n");
1675 park = atoi((char *)data);
1676 ast_mutex_lock(&parking_lock);
1679 if (pu->parkingnum == park) {
1681 pl->next = pu->next;
1683 parkinglot = pu->next;
1689 ast_mutex_unlock(&parking_lock);
1692 con = ast_context_find(parking_con);
1694 snprintf(exten, sizeof(exten), "%d", pu->parkingnum);
1695 if (ast_context_remove_extension2(con, exten, 1, NULL))
1696 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
1698 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
1700 manager_event(EVENT_FLAG_CALL, "UnParkedCall",
1705 "CallerIDName: %s\r\n"
1706 ,pu->parkingnum, pu->chan->name, chan->name
1707 ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
1708 ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
1713 /* JK02: it helps to answer the channel if not already up */
1714 if (chan->_state != AST_STATE_UP) {
1719 /* Play a courtesy to the source(s) configured to prefix the bridge connecting */
1721 if (!ast_strlen_zero(courtesytone)) {
1722 if (parkedplay == 0) {
1723 if (!ast_streamfile(chan, courtesytone, chan->language)) {
1724 if (ast_waitstream(chan, "") < 0) {
1725 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
1731 ast_indicate(peer, AST_CONTROL_UNHOLD);
1734 ast_indicate(peer, AST_CONTROL_UNHOLD);
1735 if (parkedplay == 2) {
1736 if (!ast_streamfile(chan, courtesytone, chan->language) && !ast_streamfile(peer, courtesytone, chan->language)) {
1737 res = ast_waitstream(chan, "");
1739 res = ast_waitstream(peer, "");
1741 ast_log(LOG_WARNING, "Failed to play courtesy tones!\n");
1746 } else if (parkedplay == 1) {
1747 if (!ast_streamfile(peer, courtesytone, chan->language)) {
1748 if (ast_waitstream(peer, "") < 0) {
1749 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
1758 res = ast_channel_make_compatible(chan, peer);
1760 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
1764 /* This runs sorta backwards, since we give the incoming channel control, as if it
1765 were the person called. */
1766 if (option_verbose > 2)
1767 ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to parked call %d\n", chan->name, park);
1769 memset(&config, 0, sizeof(struct ast_bridge_config));
1770 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
1771 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
1772 config.timelimit = 0;
1773 config.play_warning = 0;
1774 config.warning_freq = 0;
1775 config.warning_sound=NULL;
1776 res = ast_bridge_call(chan, peer, &config);
1778 /* Simulate the PBX hanging up */
1779 if (res != AST_PBX_NO_HANGUP_PEER)
1783 /* XXX Play a message XXX */
1784 dres = ast_streamfile(chan, "pbx-invalidpark", chan->language);
1786 dres = ast_waitstream(chan, "");
1788 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
1791 if (option_verbose > 2)
1792 ast_verbose(VERBOSE_PREFIX_3 "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park);
1795 LOCAL_USER_REMOVE(u);
1799 static int handle_showfeatures(int fd, int argc, char *argv[])
1803 struct ast_call_feature *feature;
1804 char format[] = "%-25s %-7s %-7s\n";
1806 ast_cli(fd, format, "Builtin Feature", "Default", "Current");
1807 ast_cli(fd, format, "---------------", "-------", "-------");
1809 ast_cli(fd, format, "Pickup", "*8", ast_pickup_ext()); /* default hardcoded above, so we'll hardcode it here */
1811 fcount = sizeof(builtin_features) / sizeof(builtin_features[0]);
1813 for (i = 0; i < fcount; i++)
1815 ast_cli(fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
1818 ast_cli(fd, format, "Dynamic Feature", "Default", "Current");
1819 ast_cli(fd, format, "---------------", "-------", "-------");
1820 if (AST_LIST_EMPTY(&feature_list)) {
1821 ast_cli(fd, "(none)\n");
1824 AST_LIST_LOCK(&feature_list);
1825 AST_LIST_TRAVERSE(&feature_list, feature, feature_entry) {
1826 ast_cli(fd, format, feature->sname, "no def", feature->exten);
1828 AST_LIST_UNLOCK(&feature_list);
1830 ast_cli(fd, "\nCall parking\n");
1831 ast_cli(fd, "------------\n");
1832 ast_cli(fd,"%-20s: %s\n", "Parking extension", parking_ext);
1833 ast_cli(fd,"%-20s: %s\n", "Parking context", parking_con);
1834 ast_cli(fd,"%-20s: %d-%d\n", "Parked call extensions", parking_start, parking_stop);
1837 return RESULT_SUCCESS;
1840 static char showfeatures_help[] =
1841 "Usage: show features\n"
1842 " Lists currently configured features.\n";
1844 static struct ast_cli_entry showfeatures =
1845 { { "show", "features", NULL }, handle_showfeatures, "Lists configured features", showfeatures_help };
1847 static int handle_parkedcalls(int fd, int argc, char *argv[])
1849 struct parkeduser *cur;
1852 ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
1853 , "Context", "Extension", "Pri", "Timeout");
1855 ast_mutex_lock(&parking_lock);
1859 ast_cli(fd, "%4d %25s (%-15s %-12s %-4d) %6lds\n"
1860 ,cur->parkingnum, cur->chan->name, cur->context, cur->exten
1861 ,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL));
1866 ast_cli(fd, "%d parked call%s.\n", numparked, (numparked != 1) ? "s" : "");
1868 ast_mutex_unlock(&parking_lock);
1870 return RESULT_SUCCESS;
1873 static char showparked_help[] =
1874 "Usage: show parkedcalls\n"
1875 " Lists currently parked calls.\n";
1877 static struct ast_cli_entry showparked =
1878 { { "show", "parkedcalls", NULL }, handle_parkedcalls, "Lists parked calls", showparked_help };
1880 /*! \brief Dump lot status */
1881 static int manager_parking_status( struct mansession *s, struct message *m )
1883 struct parkeduser *cur;
1884 char *id = astman_get_header(m,"ActionID");
1885 char idText[256] = "";
1887 if (!ast_strlen_zero(id))
1888 snprintf(idText,256,"ActionID: %s\r\n",id);
1890 astman_send_ack(s, m, "Parked calls will follow");
1892 ast_mutex_lock(&parking_lock);
1896 ast_cli(s->fd, "Event: ParkedCall\r\n"
1902 "CallerIDName: %s\r\n"
1905 ,cur->parkingnum, cur->chan->name, cur->peername
1906 ,(long)cur->start.tv_sec + (long)(cur->parkingtime/1000) - (long)time(NULL)
1907 ,(cur->chan->cid.cid_num ? cur->chan->cid.cid_num : "")
1908 ,(cur->chan->cid.cid_name ? cur->chan->cid.cid_name : "")
1915 "Event: ParkedCallsComplete\r\n"
1919 ast_mutex_unlock(&parking_lock);
1921 return RESULT_SUCCESS;
1924 static char mandescr_park[] =
1925 "Description: Park a channel.\n"
1926 "Variables: (Names marked with * are required)\n"
1927 " *Channel: Channel name to park\n"
1928 " *Channel2: Channel to announce park info to (and return to if timeout)\n"
1929 " Timeout: Number of milliseconds to wait before callback.\n";
1931 static int manager_park(struct mansession *s, struct message *m)
1933 char *channel = astman_get_header(m, "Channel");
1934 char *channel2 = astman_get_header(m, "Channel2");
1935 char *timeout = astman_get_header(m, "Timeout");
1940 struct ast_channel *ch1, *ch2;
1942 if (ast_strlen_zero(channel)) {
1943 astman_send_error(s, m, "Channel not specified");
1947 if (ast_strlen_zero(channel2)) {
1948 astman_send_error(s, m, "Channel2 not specified");
1952 ch1 = ast_get_channel_by_name_locked(channel);
1954 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel);
1955 astman_send_error(s, m, buf);
1959 ch2 = ast_get_channel_by_name_locked(channel2);
1961 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2);
1962 astman_send_error(s, m, buf);
1963 ast_mutex_unlock(&ch1->lock);
1967 if (!ast_strlen_zero(timeout)) {
1968 sscanf(timeout, "%d", &to);
1971 res = ast_masq_park_call(ch1, ch2, to, &parkExt);
1973 ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT);
1974 astman_send_ack(s, m, "Park successful");
1976 astman_send_error(s, m, "Park failure");
1979 ast_mutex_unlock(&ch1->lock);
1980 ast_mutex_unlock(&ch2->lock);
1986 int ast_pickup_call(struct ast_channel *chan)
1988 struct ast_channel *cur = NULL;
1991 while ( (cur = ast_channel_walk_locked(cur)) != NULL) {
1994 (chan->pickupgroup & cur->callgroup) &&
1995 ((cur->_state == AST_STATE_RINGING) ||
1996 (cur->_state == AST_STATE_RING))) {
1999 ast_mutex_unlock(&cur->lock);
2003 ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
2004 res = ast_answer(chan);
2006 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
2007 res = ast_queue_control(chan, AST_CONTROL_ANSWER);
2009 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
2010 res = ast_channel_masquerade(cur, chan);
2012 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name); /* Done */
2013 ast_mutex_unlock(&cur->lock);
2016 ast_log(LOG_DEBUG, "No call pickup possible...\n");
2021 static int load_config(void)
2023 int start = 0, end = 0;
2024 struct ast_context *con = NULL;
2025 struct ast_config *cfg = NULL;
2026 struct ast_variable *var = NULL;
2027 char old_parking_ext[AST_MAX_EXTENSION];
2028 char old_parking_con[AST_MAX_EXTENSION] = "";
2030 if (!ast_strlen_zero(parking_con)) {
2031 strcpy(old_parking_ext, parking_ext);
2032 strcpy(old_parking_con, parking_con);
2035 /* Reset to defaults */
2036 strcpy(parking_con, "parkedcalls");
2037 strcpy(parking_con_dial, "park-dial");
2038 strcpy(parking_ext, "700");
2039 strcpy(pickup_ext, "*8");
2040 courtesytone[0] = '\0';
2041 strcpy(xfersound, "beep");
2042 strcpy(xferfailsound, "pbx-invalid");
2043 parking_start = 701;
2047 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
2048 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
2050 cfg = ast_config_load("features.conf");
2052 var = ast_variable_browse(cfg, "general");
2054 if (!strcasecmp(var->name, "parkext")) {
2055 ast_copy_string(parking_ext, var->value, sizeof(parking_ext));
2056 } else if (!strcasecmp(var->name, "context")) {
2057 ast_copy_string(parking_con, var->value, sizeof(parking_con));
2058 } else if (!strcasecmp(var->name, "parkingtime")) {
2059 if ((sscanf(var->value, "%d", &parkingtime) != 1) || (parkingtime < 1)) {
2060 ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value);
2061 parkingtime = DEFAULT_PARK_TIME;
2063 parkingtime = parkingtime * 1000;
2064 } else if (!strcasecmp(var->name, "parkpos")) {
2065 if (sscanf(var->value, "%d-%d", &start, &end) != 2) {
2066 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);
2068 parking_start = start;
2071 } else if (!strcasecmp(var->name, "findslot")) {
2072 parkfindnext = (!strcasecmp(var->value, "next"));
2073 } else if (!strcasecmp(var->name, "adsipark")) {
2074 adsipark = ast_true(var->value);
2075 } else if (!strcasecmp(var->name, "transferdigittimeout")) {
2076 if ((sscanf(var->value, "%d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) {
2077 ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value);
2078 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
2080 transferdigittimeout = transferdigittimeout * 1000;
2081 } else if (!strcasecmp(var->name, "featuredigittimeout")) {
2082 if ((sscanf(var->value, "%d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) {
2083 ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value);
2084 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
2086 } else if (!strcasecmp(var->name, "courtesytone")) {
2087 ast_copy_string(courtesytone, var->value, sizeof(courtesytone));
2088 } else if (!strcasecmp(var->name, "parkedplay")) {
2089 if (!strcasecmp(var->value, "both"))
2091 else if (!strcasecmp(var->value, "parked"))
2095 } else if (!strcasecmp(var->name, "xfersound")) {
2096 ast_copy_string(xfersound, var->value, sizeof(xfersound));
2097 } else if (!strcasecmp(var->name, "xferfailsound")) {
2098 ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound));
2099 } else if (!strcasecmp(var->name, "pickupexten")) {
2100 ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext));
2106 var = ast_variable_browse(cfg, "featuremap");
2108 if (remap_feature(var->name, var->value))
2109 ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name);
2113 /* Map a key combination to an application*/
2114 ast_unregister_features();
2115 var = ast_variable_browse(cfg, "applicationmap");
2117 char *tmp_val=strdup(var->value);
2118 char *exten, *party=NULL, *app=NULL, *app_args=NULL;
2121 ast_log(LOG_ERROR, "res_features: strdup failed");
2126 exten=strsep(&tmp_val,",");
2127 if (exten) party=strsep(&tmp_val,",");
2128 if (party) app=strsep(&tmp_val,",");
2130 if (app) app_args=strsep(&tmp_val,",");
2132 if (!(app && strlen(app)) || !(exten && strlen(exten)) || !(party && strlen(party)) || !(var->name && strlen(var->name))) {
2133 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);
2140 struct ast_call_feature *feature;
2143 if (!(feature = find_feature(var->name))) {
2146 if (!(feature = ast_calloc(1, sizeof(*feature)))) {
2153 ast_copy_string(feature->sname,var->name,FEATURE_SNAME_LEN);
2154 ast_copy_string(feature->app,app,FEATURE_APP_LEN);
2155 ast_copy_string(feature->exten, exten,FEATURE_EXTEN_LEN);
2159 ast_copy_string(feature->app_args,app_args,FEATURE_APP_ARGS_LEN);
2161 ast_copy_string(feature->exten, exten,sizeof(feature->exten));
2162 feature->operation=feature_exec_app;
2163 ast_set_flag(feature,AST_FEATURE_FLAG_NEEDSDTMF);
2165 if (!strcasecmp(party,"caller"))
2166 ast_set_flag(feature,AST_FEATURE_FLAG_CALLER);
2167 else if (!strcasecmp(party, "callee"))
2168 ast_set_flag(feature,AST_FEATURE_FLAG_CALLEE);
2170 ast_log(LOG_NOTICE, "Invalid party specification for feature '%s', must be caller, or callee\n", var->name);
2175 ast_register_feature(feature);
2177 if (option_verbose >=1) ast_verbose(VERBOSE_PREFIX_2 "Mapping Feature '%s' to app '%s' with code '%s'\n", var->name, app, exten);
2182 ast_config_destroy(cfg);
2184 /* Remove the old parking extension */
2185 if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con))) {
2186 ast_context_remove_extension2(con, old_parking_ext, 1, registrar);
2187 ast_log(LOG_DEBUG, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con);
2190 if (!(con = ast_context_find(parking_con))) {
2191 if (!(con = ast_context_create(NULL, parking_con, registrar))) {
2192 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
2196 return ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, strdup(""), FREE, registrar);
2200 return load_config();
2203 int load_module(void)
2207 AST_LIST_HEAD_INIT(&feature_list);
2208 memset(parking_ext, 0, sizeof(parking_ext));
2209 memset(parking_con, 0, sizeof(parking_con));
2211 if ((res = load_config()))
2213 ast_cli_register(&showparked);
2214 ast_cli_register(&showfeatures);
2215 ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
2216 res = ast_register_application(parkedcall, park_exec, synopsis, descrip);
2218 res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2);
2220 ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls" );
2221 ast_manager_register2("Park", EVENT_FLAG_CALL, manager_park,
2222 "Park a channel", mandescr_park);
2228 int unload_module(void)
2230 STANDARD_HANGUP_LOCALUSERS;
2232 ast_manager_unregister("ParkedCalls");
2233 ast_manager_unregister("Park");
2234 ast_cli_unregister(&showfeatures);
2235 ast_cli_unregister(&showparked);
2236 ast_unregister_application(parkcall);
2237 return ast_unregister_application(parkedcall);
2240 char *description(void)
2242 return "Call Features Resource";
2247 /* Never allow parking to be unloaded because it will
2248 unresolve needed symbols in the dialer */
2251 STANDARD_USECOUNT(res);
2260 return ASTERISK_GPL_KEY;