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():"
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 ? 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);
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);
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;
1126 if (option_verbose > 2)
1127 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", chan->name);
1128 ast_indicate(caller, AST_CONTROL_BUSY);
1132 } else if (f->subclass == AST_CONTROL_ANSWER) {
1133 /* This is what we are hoping for */
1134 state = f->subclass;
1140 ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass);
1142 /* else who cares */
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 */
1153 state = AST_CONTROL_HANGUP;
1158 if (f->frametype == AST_FRAME_DTMF) {
1159 dialed_code[x++] = f->subclass;
1160 dialed_code[x] = '\0';
1161 if (strlen(dialed_code) == len) {
1163 } else if (x && strncmp(dialed_code, disconnect_code, x)) {
1165 dialed_code[x] = '\0';
1167 if (*dialed_code && !strcmp(dialed_code, disconnect_code)) {
1168 /* Caller Canceled the call */
1169 state = AST_CONTROL_UNHOLD;
1181 ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data);
1183 ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
1185 case AST_CAUSE_BUSY:
1186 state = AST_CONTROL_BUSY;
1188 case AST_CAUSE_CONGESTION:
1189 state = AST_CONTROL_CONGESTION;
1194 ast_indicate(caller, -1);
1195 if (chan && ready) {
1196 if (chan->_state == AST_STATE_UP)
1197 state = AST_CONTROL_ANSWER;
1210 if (chan && res <= 0) {
1211 if (chan->cdr || (chan->cdr = ast_cdr_alloc())) {
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);
1223 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
1230 int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast_bridge_config *config)
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]="";
1242 struct ast_option_header *aoh;
1243 struct timeval start = { 0 , 0 };
1244 struct ast_bridge_config backup_config;
1246 memset(&backup_config, 0, sizeof(backup_config));
1248 config->start_time = ast_tvnow();
1251 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
1252 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
1254 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
1257 const char *monitor_exec;
1258 struct ast_channel *src = NULL;
1260 if (!(monitor_app = pbx_findapp("Monitor")))
1263 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR")))
1265 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
1267 if (monitor_app && src) {
1268 char *tmp = ast_strdupa(monitor_exec);
1270 pbx_exec(src, monitor_app, tmp);
1272 ast_log(LOG_ERROR, "Monitor failed: out of memory\n");
1277 set_config_flags(chan, peer, config);
1278 config->firstpass = 1;
1280 /* Answer if need be */
1281 if (ast_answer(chan))
1283 peer->appl = "Bridged Call";
1284 peer->data = (char *) chan->name;
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)) {
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);
1293 ast_cdr_setuserfield(chan, peer->cdr->userfield);
1294 /* free the peer's cdr without ast_cdr_free complaining */
1299 if (config->feature_timer)
1300 start = ast_tvnow();
1302 res = ast_channel_bridge(chan, peer, config, &f, &who);
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;
1309 /* Running on backup config, meaning a feature might be being
1310 activated, but that's no excuse to keep things going
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;
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));
1328 if (!ast_strlen_zero(chan_featurecode)) {
1329 ast_dtmf_stream(peer, chan, chan_featurecode, 0);
1330 memset(chan_featurecode, 0, sizeof(chan_featurecode));
1334 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
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));
1340 hadfeatures = hasfeatures;
1341 /* Continue as we were */
1345 if (config->feature_timer <=0) {
1346 /* We ran out of time */
1347 config->feature_timer = 0;
1357 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
1361 if (!f || ((f->frametype == AST_FRAME_CONTROL) && ((f->subclass == AST_CONTROL_HANGUP) || (f->subclass == AST_CONTROL_BUSY) ||
1362 (f->subclass == AST_CONTROL_CONGESTION)))) {
1366 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_RINGING)) {
1368 ast_indicate(peer, AST_CONTROL_RINGING);
1370 ast_indicate(chan, AST_CONTROL_RINGING);
1372 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == -1)) {
1374 ast_indicate(peer, -1);
1376 ast_indicate(chan, -1);
1378 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_FLASH)) {
1380 ast_indicate(peer, AST_CONTROL_FLASH);
1382 ast_indicate(chan, AST_CONTROL_FLASH);
1384 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_OPTION)) {
1386 /* Forward option Requests */
1387 if (aoh && (aoh->flag == AST_OPTION_FLAG_REQUEST)) {
1389 ast_channel_setoption(peer, ntohs(aoh->option), aoh->data, f->datalen - sizeof(struct ast_option_header), 0);
1391 ast_channel_setoption(chan, ntohs(aoh->option), aoh->data, f->datalen - sizeof(struct ast_option_header), 0);
1394 /* check for '*', if we find it it's time to disconnect */
1395 if (f && (f->frametype == AST_FRAME_DTMF)) {
1398 struct ast_channel *other;
1400 hadfeatures = hasfeatures;
1401 /* This cannot overrun because the longest feature is one shorter than our buffer */
1404 sense = FEATURE_SENSE_CHAN;
1405 featurecode = chan_featurecode;
1408 sense = FEATURE_SENSE_PEER;
1409 featurecode = peer_featurecode;
1411 featurecode[strlen(featurecode)] = f->subclass;
1412 config->feature_timer = backup_config.feature_timer;
1413 res = ast_feature_interpret(chan, peer, config, featurecode, sense);
1415 case FEATURE_RETURN_PASSDIGITS:
1416 ast_dtmf_stream(other, who, featurecode, 0);
1418 case FEATURE_RETURN_SUCCESS:
1419 memset(featurecode, 0, sizeof(chan_featurecode));
1422 if (res >= FEATURE_RETURN_PASSDIGITS) {
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) {
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;
1447 config->feature_timer = featuredigittimeout;
1448 ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->feature_timer);
1457 /*! \brief Take care of parked calls and unpark them if needed */
1458 static void *do_parking_thread(void *ignore)
1461 struct parkeduser *pu, *pl, *pt = NULL;
1463 struct ast_frame *f;
1464 char exten[AST_MAX_EXTENSION];
1466 char returnexten[AST_MAX_EXTENSION];
1467 struct ast_context *con;
1470 fd_set nrfds, nefds;
1477 ast_mutex_lock(&parking_lock);
1483 if (pu->notquiteyet) {
1484 /* Pretend this one isn't here yet */
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, '-');
1500 con = ast_context_find(parking_con_dial);
1502 con = ast_context_create(NULL, parking_con_dial, registrar);
1504 ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial);
1508 snprintf(returnexten, sizeof(returnexten), "%s||t", peername);
1509 ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(returnexten), FREE, registrar);
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;
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;
1523 manager_event(EVENT_FLAG_CALL, "ParkedCallTimeOut",
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>")
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);
1540 /* And take them out of the parking lot */
1542 pl->next = pu->next;
1544 parkinglot = pu->next;
1547 con = ast_context_find(parking_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");
1553 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
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);
1561 ast_clear_flag(pu->chan, AST_FLAG_EXCEPTION);
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))) {
1568 manager_event(EVENT_FLAG_CALL, "ParkedCallGiveUp",
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>")
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 */
1584 pl->next = pu->next;
1586 parkinglot = pu->next;
1589 con = ast_context_find(parking_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");
1595 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
1599 /* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
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);
1606 goto std; /* XXX Ick: jumping into an else statement??? XXX */
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];
1620 /* Keep track of our longest wait */
1621 if ((tms < ms) || (ms < 0))
1628 ast_mutex_unlock(&parking_lock);
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();
1636 return NULL; /* Never reached */
1639 static int park_call_exec(struct ast_channel *chan, void *data)
1641 /* Data is unused at the moment but could contain a parking
1642 lot context eventually */
1644 struct localuser *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");
1650 if (chan->_state != AST_STATE_UP)
1651 res = ast_answer(chan);
1653 res = ast_safe_sleep(chan, 1000);
1655 res = ast_park_call(chan, chan, 0, NULL);
1656 LOCAL_USER_REMOVE(u);
1658 res = AST_PBX_KEEPALIVE;
1662 static int park_exec(struct ast_channel *chan, void *data)
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;
1672 struct ast_bridge_config config;
1675 ast_log(LOG_WARNING, "Park requires an argument (extension number)\n");
1679 park = atoi((char *)data);
1680 ast_mutex_lock(&parking_lock);
1683 if (pu->parkingnum == park) {
1685 pl->next = pu->next;
1687 parkinglot = pu->next;
1693 ast_mutex_unlock(&parking_lock);
1696 con = ast_context_find(parking_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");
1702 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
1704 manager_event(EVENT_FLAG_CALL, "UnParkedCall",
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>")
1717 /* JK02: it helps to answer the channel if not already up */
1718 if (chan->_state != AST_STATE_UP) {
1723 /* Play a courtesy to the source(s) configured to prefix the bridge connecting */
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");
1735 ast_indicate(peer, AST_CONTROL_UNHOLD);
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, "");
1743 res = ast_waitstream(peer, "");
1745 ast_log(LOG_WARNING, "Failed to play courtesy tones!\n");
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");
1762 res = ast_channel_make_compatible(chan, peer);
1764 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
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);
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);
1782 /* Simulate the PBX hanging up */
1783 if (res != AST_PBX_NO_HANGUP_PEER)
1787 /* XXX Play a message XXX */
1788 dres = ast_streamfile(chan, "pbx-invalidpark", chan->language);
1790 dres = ast_waitstream(chan, "");
1792 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
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);
1799 LOCAL_USER_REMOVE(u);
1803 static int handle_showfeatures(int fd, int argc, char *argv[])
1807 struct ast_call_feature *feature;
1808 char format[] = "%-25s %-7s %-7s\n";
1810 ast_cli(fd, format, "Builtin Feature", "Default", "Current");
1811 ast_cli(fd, format, "---------------", "-------", "-------");
1813 ast_cli(fd, format, "Pickup", "*8", ast_pickup_ext()); /* default hardcoded above, so we'll hardcode it here */
1815 fcount = sizeof(builtin_features) / sizeof(builtin_features[0]);
1817 for (i = 0; i < fcount; i++)
1819 ast_cli(fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
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");
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);
1832 AST_LIST_UNLOCK(&feature_list);
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);
1841 return RESULT_SUCCESS;
1844 static char showfeatures_help[] =
1845 "Usage: show features\n"
1846 " Lists currently configured features.\n";
1848 static struct ast_cli_entry showfeatures =
1849 { { "show", "features", NULL }, handle_showfeatures, "Lists configured features", showfeatures_help };
1851 static int handle_parkedcalls(int fd, int argc, char *argv[])
1853 struct parkeduser *cur;
1856 ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
1857 , "Context", "Extension", "Pri", "Timeout");
1859 ast_mutex_lock(&parking_lock);
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));
1870 ast_cli(fd, "%d parked call%s.\n", numparked, (numparked != 1) ? "s" : "");
1872 ast_mutex_unlock(&parking_lock);
1874 return RESULT_SUCCESS;
1877 static char showparked_help[] =
1878 "Usage: show parkedcalls\n"
1879 " Lists currently parked calls.\n";
1881 static struct ast_cli_entry showparked =
1882 { { "show", "parkedcalls", NULL }, handle_parkedcalls, "Lists parked calls", showparked_help };
1884 /*! \brief Dump lot status */
1885 static int manager_parking_status( struct mansession *s, struct message *m )
1887 struct parkeduser *cur;
1888 char *id = astman_get_header(m,"ActionID");
1889 char idText[256] = "";
1891 if (!ast_strlen_zero(id))
1892 snprintf(idText,256,"ActionID: %s\r\n",id);
1894 astman_send_ack(s, m, "Parked calls will follow");
1896 ast_mutex_lock(&parking_lock);
1900 astman_append(s, "Event: ParkedCall\r\n"
1906 "CallerIDName: %s\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 : "")
1919 "Event: ParkedCallsComplete\r\n"
1923 ast_mutex_unlock(&parking_lock);
1925 return RESULT_SUCCESS;
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";
1935 static int manager_park(struct mansession *s, struct message *m)
1937 char *channel = astman_get_header(m, "Channel");
1938 char *channel2 = astman_get_header(m, "Channel2");
1939 char *timeout = astman_get_header(m, "Timeout");
1944 struct ast_channel *ch1, *ch2;
1946 if (ast_strlen_zero(channel)) {
1947 astman_send_error(s, m, "Channel not specified");
1951 if (ast_strlen_zero(channel2)) {
1952 astman_send_error(s, m, "Channel2 not specified");
1956 ch1 = ast_get_channel_by_name_locked(channel);
1958 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel);
1959 astman_send_error(s, m, buf);
1963 ch2 = ast_get_channel_by_name_locked(channel2);
1965 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2);
1966 astman_send_error(s, m, buf);
1967 ast_mutex_unlock(&ch1->lock);
1971 if (!ast_strlen_zero(timeout)) {
1972 sscanf(timeout, "%d", &to);
1975 res = ast_masq_park_call(ch1, ch2, to, &parkExt);
1977 ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT);
1978 astman_send_ack(s, m, "Park successful");
1980 astman_send_error(s, m, "Park failure");
1983 ast_mutex_unlock(&ch1->lock);
1984 ast_mutex_unlock(&ch2->lock);
1990 int ast_pickup_call(struct ast_channel *chan)
1992 struct ast_channel *cur = NULL;
1995 while ( (cur = ast_channel_walk_locked(cur)) != NULL) {
1998 (chan->pickupgroup & cur->callgroup) &&
1999 ((cur->_state == AST_STATE_RINGING) ||
2000 (cur->_state == AST_STATE_RING))) {
2003 ast_mutex_unlock(&cur->lock);
2007 ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
2008 res = ast_answer(chan);
2010 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
2011 res = ast_queue_control(chan, AST_CONTROL_ANSWER);
2013 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
2014 res = ast_channel_masquerade(cur, chan);
2016 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name); /* Done */
2017 ast_mutex_unlock(&cur->lock);
2020 ast_log(LOG_DEBUG, "No call pickup possible...\n");
2025 static int load_config(void)
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] = "";
2034 if (!ast_strlen_zero(parking_con)) {
2035 strcpy(old_parking_ext, parking_ext);
2036 strcpy(old_parking_con, parking_con);
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;
2052 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
2053 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
2055 cfg = ast_config_load("features.conf");
2057 var = ast_variable_browse(cfg, "general");
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;
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);
2073 parking_start = start;
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;
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;
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"))
2096 else if (!strcasecmp(var->value, "parked"))
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));
2111 var = ast_variable_browse(cfg, "featuremap");
2113 if (remap_feature(var->name, var->value))
2114 ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name);
2118 /* Map a key combination to an application*/
2119 ast_unregister_features();
2120 var = ast_variable_browse(cfg, "applicationmap");
2122 char *tmp_val=strdup(var->value);
2123 char *exten, *party=NULL, *app=NULL, *app_args=NULL;
2126 ast_log(LOG_ERROR, "res_features: strdup failed");
2131 exten=strsep(&tmp_val,",");
2132 if (exten) party=strsep(&tmp_val,",");
2133 if (party) app=strsep(&tmp_val,",");
2135 if (app) app_args=strsep(&tmp_val,",");
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);
2145 struct ast_call_feature *feature;
2148 if (!(feature = find_feature(var->name))) {
2151 if (!(feature = ast_calloc(1, sizeof(*feature)))) {
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);
2164 ast_copy_string(feature->app_args,app_args,FEATURE_APP_ARGS_LEN);
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);
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);
2175 ast_log(LOG_NOTICE, "Invalid party specification for feature '%s', must be caller, or callee\n", var->name);
2180 ast_register_feature(feature);
2182 if (option_verbose >=1) ast_verbose(VERBOSE_PREFIX_2 "Mapping Feature '%s' to app '%s' with code '%s'\n", var->name, app, exten);
2187 ast_config_destroy(cfg);
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);
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);
2201 return ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, strdup(""), FREE, registrar);
2205 return load_config();
2208 int load_module(void)
2212 AST_LIST_HEAD_INIT(&feature_list);
2213 memset(parking_ext, 0, sizeof(parking_ext));
2214 memset(parking_con, 0, sizeof(parking_con));
2216 if ((res = load_config()))
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);
2223 res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2);
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);
2233 int unload_module(void)
2235 STANDARD_HANGUP_LOCALUSERS;
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);
2245 const char *description(void)
2247 return "Call Features Resource";
2252 /* Never allow parking to be unloaded because it will
2253 unresolve needed symbols in the dialer */
2256 STANDARD_USECOUNT(res);
2265 return ASTERISK_GPL_KEY;