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); /* protects all static variables above */
143 static pthread_t parking_thread;
145 char *ast_parking_ext(void)
150 char *ast_pickup_ext(void)
155 struct ast_bridge_thread_obj
157 struct ast_bridge_config bconfig;
158 struct ast_channel *chan;
159 struct ast_channel *peer;
162 /* store context, priority and extension */
163 static void set_c_e_p(struct ast_channel *chan, const char *ctx, const char *ext, int pri)
165 ast_copy_string(chan->context, ctx, sizeof(chan->context));
166 ast_copy_string(chan->exten, ext, sizeof(chan->exten));
167 chan->priority = pri;
170 static void check_goto_on_transfer(struct ast_channel *chan)
172 struct ast_channel *xferchan;
173 const char *val = pbx_builtin_getvar_helper(chan, "GOTO_ON_BLINDXFR");
174 char *x, *goto_on_transfer;
177 if (!ast_strlen_zero(val) && (goto_on_transfer = ast_strdupa(val)) && (xferchan = ast_channel_alloc(0))) {
178 for (x = goto_on_transfer; x && *x; x++)
181 ast_string_field_set(xferchan, name, chan->name);
182 /* Make formats okay */
183 xferchan->readformat = chan->readformat;
184 xferchan->writeformat = chan->writeformat;
185 ast_channel_masquerade(xferchan, chan);
186 ast_parseable_goto(xferchan, goto_on_transfer);
187 xferchan->_state = AST_STATE_UP;
188 ast_clear_flag(xferchan, AST_FLAGS_ALL);
189 xferchan->_softhangup = 0;
190 if ((f = ast_read(xferchan))) {
193 ast_pbx_start(xferchan);
195 ast_hangup(xferchan);
200 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);
203 static void *ast_bridge_call_thread(void *data)
205 struct ast_bridge_thread_obj *tobj = data;
207 tobj->chan->appl = "Transferred Call";
208 tobj->chan->data = tobj->peer->name;
209 tobj->peer->appl = "Transferred Call";
210 tobj->peer->data = tobj->chan->name;
211 if (tobj->chan->cdr) {
212 ast_cdr_reset(tobj->chan->cdr, NULL);
213 ast_cdr_setdestchan(tobj->chan->cdr, tobj->peer->name);
215 if (tobj->peer->cdr) {
216 ast_cdr_reset(tobj->peer->cdr, NULL);
217 ast_cdr_setdestchan(tobj->peer->cdr, tobj->chan->name);
220 ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig);
221 ast_hangup(tobj->chan);
222 ast_hangup(tobj->peer);
223 bzero(tobj, sizeof(*tobj)); /* XXX for safety */
228 static void ast_bridge_call_thread_launch(void *data)
232 struct sched_param sched;
234 pthread_attr_init(&attr);
235 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
236 ast_pthread_create(&thread, &attr,ast_bridge_call_thread, data);
237 pthread_attr_destroy(&attr);
238 memset(&sched, 0, sizeof(sched));
239 pthread_setschedparam(thread, SCHED_RR, &sched);
244 static int adsi_announce_park(struct ast_channel *chan, int parkingnum)
247 int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT};
249 char *message[5] = {NULL, NULL, NULL, NULL, NULL};
251 snprintf(tmp, sizeof(tmp), "Parked on %d", parkingnum);
253 res = adsi_load_session(chan, NULL, 0, 1);
256 return adsi_print(chan, message, justify, 1);
259 /*! \brief Park a call
260 We put the user in the parking list, then wake up the parking thread to be sure it looks
261 after these channels too */
262 int ast_park_call(struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout)
264 struct parkeduser *pu, *cur;
265 int i,x,parking_range;
266 char exten[AST_MAX_EXTENSION];
267 struct ast_context *con;
269 if (!(pu = ast_calloc(1, sizeof(*pu)))) {
272 ast_mutex_lock(&parking_lock);
273 parking_range = parking_stop - parking_start+1;
274 for (i = 0; i < parking_range; i++) {
275 x = (i + parking_offset) % parking_range + parking_start;
278 if (cur->parkingnum == x)
286 if (!(i < parking_range)) {
287 ast_log(LOG_WARNING, "No more parking spaces\n");
289 ast_mutex_unlock(&parking_lock);
293 parking_offset = x - parking_start + 1;
294 chan->appl = "Parked Call";
298 /* Start music on hold */
300 ast_indicate(pu->chan, AST_CONTROL_HOLD);
301 ast_moh_start(pu->chan, NULL);
303 pu->start = ast_tvnow();
305 pu->parkingtime = (timeout > 0) ? timeout : parkingtime;
309 ast_copy_string(pu->peername, peer->name, sizeof(pu->peername));
311 /* Remember what had been dialed, so that if the parking
312 expires, we try to come back to the same place */
313 ast_copy_string(pu->context, S_OR(chan->macrocontext, chan->context), sizeof(pu->context));
314 ast_copy_string(pu->exten, S_OR(chan->macroexten, chan->exten), sizeof(pu->exten));
315 pu->priority = chan->macropriority ? chan->macropriority : chan->priority;
316 pu->next = parkinglot;
318 /* If parking a channel directly, don't quiet yet get parking running on it */
321 ast_mutex_unlock(&parking_lock);
322 /* Wake up the (presumably select()ing) thread */
323 pthread_kill(parking_thread, SIGURG);
324 if (option_verbose > 1)
325 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));
327 manager_event(EVENT_FLAG_CALL, "ParkedCall",
333 "CallerIDName: %s\r\n"
334 ,pu->parkingnum, pu->chan->name, peer ? peer->name : ""
335 ,(long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL)
336 ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
337 ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
341 if (adsipark && adsi_available(peer))
342 adsi_announce_park(peer, pu->parkingnum);
343 if (adsipark && adsi_available(peer))
344 adsi_unload_session(peer);
346 con = ast_context_find(parking_con);
348 con = ast_context_create(NULL, parking_con, registrar);
350 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
353 snprintf(exten, sizeof(exten), "%d", x);
354 ast_add_extension2(con, 1, exten, 1, NULL, NULL, parkedcall, strdup(exten), FREE, registrar);
357 ast_say_digits(peer, pu->parkingnum, "", peer->language);
358 if (pu->notquiteyet) {
359 /* Wake up parking thread if we're really done */
360 ast_moh_start(pu->chan, NULL);
362 pthread_kill(parking_thread, SIGURG);
367 int ast_masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout)
369 struct ast_channel *chan;
372 /* Make a new, fake channel that we'll use to masquerade in the real one */
373 if ((chan = ast_channel_alloc(0))) {
374 /* Let us keep track of the channel name */
375 ast_string_field_build(chan, name, "Parked/%s",rchan->name);
377 /* Make formats okay */
378 chan->readformat = rchan->readformat;
379 chan->writeformat = rchan->writeformat;
380 ast_channel_masquerade(chan, rchan);
382 /* Setup the extensions and such */
383 set_c_e_p(chan, rchan->context, rchan->exten, rchan->priority);
385 /* Make the masq execute */
389 ast_park_call(chan, peer, timeout, extout);
391 ast_log(LOG_WARNING, "Unable to create parked channel\n");
398 #define FEATURE_RETURN_HANGUP -1
399 #define FEATURE_RETURN_SUCCESSBREAK 0
400 #define FEATURE_RETURN_PBX_KEEPALIVE AST_PBX_KEEPALIVE
401 #define FEATURE_RETURN_NO_HANGUP_PEER AST_PBX_NO_HANGUP_PEER
402 #define FEATURE_RETURN_PASSDIGITS 21
403 #define FEATURE_RETURN_STOREDIGITS 22
404 #define FEATURE_RETURN_SUCCESS 23
406 #define FEATURE_SENSE_CHAN (1 << 0)
407 #define FEATURE_SENSE_PEER (1 << 1)
410 * if the file name is non-empty, try to play it.
411 * Return 0 if success, -1 if error, digit if interrupted by a digit.
412 * If digits == "" then we can simply check for non-zero.
414 * XXX there are probably many replicas of this function in the source tree,
415 * that should be merged.
417 static int stream_and_wait(struct ast_channel *chan, const char *file, const char *language, const char *digits)
420 if (!ast_strlen_zero(file)) {
421 res = ast_streamfile(chan, file, language);
423 res = ast_waitstream(chan, digits);
429 * set caller and callee according to the direction
431 static void set_peers(struct ast_channel **caller, struct ast_channel **callee,
432 struct ast_channel *peer, struct ast_channel *chan, int sense)
434 if (sense == FEATURE_SENSE_PEER) {
443 static int builtin_automonitor(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
445 char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL;
448 struct ast_channel *caller_chan = NULL, *callee_chan = NULL;
451 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
455 if (!monitor_app && !(monitor_app = pbx_findapp("Monitor"))) {
457 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
461 set_peers(&caller_chan, &callee_chan, peer, chan, sense);
463 if (!ast_strlen_zero(courtesytone)) {
464 if (ast_autoservice_start(callee_chan))
466 if (!ast_streamfile(caller_chan, courtesytone, caller_chan->language)) {
467 if (ast_waitstream(caller_chan, "") < 0) {
468 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
469 ast_autoservice_stop(callee_chan);
473 if (ast_autoservice_stop(callee_chan))
477 if (callee_chan->monitor) {
478 if (option_verbose > 3)
479 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to stop recording call.\n", code);
480 ast_monitor_stop(callee_chan, 1);
481 return FEATURE_RETURN_SUCCESS;
484 if (caller_chan && callee_chan) {
485 const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT");
486 const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR");
489 touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT");
492 touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR");
495 len = strlen(touch_monitor) + 50;
497 touch_filename = alloca(len);
498 snprintf(touch_filename, len, "auto-%ld-%s", (long)time(NULL), touch_monitor);
499 snprintf(args, len, "%s|%s|m", (touch_format) ? touch_format : "wav", touch_filename);
501 caller_chan_id = ast_strdupa(caller_chan->cid.cid_num ? caller_chan->cid.cid_num : caller_chan->name);
502 callee_chan_id = ast_strdupa(callee_chan->cid.cid_num ? callee_chan->cid.cid_num : callee_chan->name);
503 len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50;
505 touch_filename = alloca(len);
506 snprintf(touch_filename, len, "auto-%ld-%s-%s", (long)time(NULL), caller_chan_id, callee_chan_id);
507 snprintf(args, len, "%s|%s|m", (touch_format) ? touch_format : "wav", touch_filename);
510 for( x = 0; x < strlen(args); x++) {
515 if (option_verbose > 3)
516 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to record call. filename: %s\n", code, args);
518 pbx_exec(callee_chan, monitor_app, args);
519 pbx_builtin_setvar_helper(callee_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
520 pbx_builtin_setvar_helper(caller_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
522 return FEATURE_RETURN_SUCCESS;
525 ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n");
529 static int builtin_disconnect(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
531 if (option_verbose > 3)
532 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to disconnect call.\n", code);
533 return FEATURE_RETURN_HANGUP;
536 static int finishup(struct ast_channel *chan)
541 res = ast_autoservice_stop(chan);
542 ast_indicate(chan, AST_CONTROL_UNHOLD);
546 static const char *real_ctx(struct ast_channel *transferer, struct ast_channel *transferee)
548 const char *s = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT");
549 if (ast_strlen_zero(s))
550 s = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT");
551 if (ast_strlen_zero(s)) /* Use the non-macro context to transfer the call XXX ? */
552 s = transferer->macrocontext;
553 if (ast_strlen_zero(s))
554 s = transferer->context;
558 static int builtin_blindtransfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
560 struct ast_channel *transferer;
561 struct ast_channel *transferee;
562 const char *transferer_real_context;
566 set_peers(&transferer, &transferee, peer, chan, sense);
567 transferer_real_context = real_ctx(transferer, transferee);
568 /* Start autoservice on chan while we talk to the originator */
569 ast_indicate(transferee, AST_CONTROL_HOLD);
570 ast_autoservice_start(transferee);
571 ast_moh_start(transferee, NULL);
573 memset(xferto, 0, sizeof(xferto));
576 if ((res=ast_streamfile(transferer, "pbx-transfer", transferer->language))) {
577 ast_moh_stop(transferee);
578 ast_autoservice_stop(transferee);
579 ast_indicate(transferee, AST_CONTROL_UNHOLD);
582 if ((res=ast_waitstream(transferer, AST_DIGIT_ANY)) < 0) {
583 ast_moh_stop(transferee);
584 ast_autoservice_stop(transferee);
585 ast_indicate(transferee, AST_CONTROL_UNHOLD);
587 } else if (res > 0) {
588 /* If they've typed a digit already, handle it */
589 xferto[0] = (char) res;
592 ast_stopstream(transferer);
593 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
595 ast_moh_stop(transferee);
596 ast_autoservice_stop(transferee);
597 ast_indicate(transferee, AST_CONTROL_UNHOLD);
600 if (!strcmp(xferto, ast_parking_ext())) {
601 ast_moh_stop(transferee);
603 res = ast_autoservice_stop(transferee);
604 ast_indicate(transferee, AST_CONTROL_UNHOLD);
607 else if (!ast_park_call(transferee, transferer, 0, NULL)) {
608 /* We return non-zero, but tell the PBX not to hang the channel when
609 the thread dies -- We have to be careful now though. We are responsible for
610 hanging up the channel, else it will never be hung up! */
612 return (transferer == peer) ? AST_PBX_KEEPALIVE : AST_PBX_NO_HANGUP_PEER;
614 ast_log(LOG_WARNING, "Unable to park call %s\n", transferee->name);
616 /* XXX Maybe we should have another message here instead of invalid extension XXX */
617 } else if (ast_exists_extension(transferee, transferer_real_context, xferto, 1, transferer->cid.cid_num)) {
618 pbx_builtin_setvar_helper(peer, "BLINDTRANSFER", chan->name);
619 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", peer->name);
620 ast_moh_stop(transferee);
621 res=ast_autoservice_stop(transferee);
622 ast_indicate(transferee, AST_CONTROL_UNHOLD);
623 if (!transferee->pbx) {
624 /* Doh! Use our handy async_goto functions */
625 if (option_verbose > 2)
626 ast_verbose(VERBOSE_PREFIX_3 "Transferring %s to '%s' (context %s) priority 1\n"
627 ,transferee->name, xferto, transferer_real_context);
628 if (ast_async_goto(transferee, transferer_real_context, xferto, 1))
629 ast_log(LOG_WARNING, "Async goto failed :-(\n");
632 /* Set the channel's new extension, since it exists, using transferer context */
633 set_c_e_p(transferee, transferer_real_context, xferto, 0);
635 check_goto_on_transfer(transferer);
638 if (option_verbose > 2)
639 ast_verbose(VERBOSE_PREFIX_3 "Unable to find extension '%s' in context '%s'\n", xferto, transferer_real_context);
641 if (!ast_strlen_zero(xferfailsound))
642 res = ast_streamfile(transferer, xferfailsound, transferee->language);
646 ast_moh_stop(transferee);
647 ast_autoservice_stop(transferee);
648 ast_indicate(transferee, AST_CONTROL_UNHOLD);
651 res = ast_waitstream(transferer, AST_DIGIT_ANY);
652 ast_stopstream(transferer);
653 ast_moh_stop(transferee);
654 res = ast_autoservice_stop(transferee);
655 ast_indicate(transferee, AST_CONTROL_UNHOLD);
657 if (option_verbose > 1)
658 ast_verbose(VERBOSE_PREFIX_2 "Hungup during autoservice stop on '%s'\n", transferee->name);
661 return FEATURE_RETURN_SUCCESS;
664 static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
666 struct ast_channel *transferer;
667 struct ast_channel *transferee;
668 struct ast_channel *newchan, *xferchan=NULL;
670 struct ast_bridge_config bconfig;
671 const char *transferer_real_context;
672 char xferto[256],dialstr[265];
676 struct ast_frame *f = NULL;
677 struct ast_bridge_thread_obj *tobj;
679 ast_log(LOG_DEBUG, "Executing Attended Transfer %s, %s (sense=%d) XXX\n", chan->name, peer->name, sense);
680 set_peers(&transferer, &transferee, peer, chan, sense);
681 transferer_real_context = real_ctx(transferer, transferee);
682 /* Start autoservice on chan while we talk to the originator */
683 ast_indicate(transferee, AST_CONTROL_HOLD);
684 ast_autoservice_start(transferee);
685 ast_moh_start(transferee, NULL);
686 memset(xferto, 0, sizeof(xferto));
688 res = stream_and_wait(transferer, "pbx-transfer", transferer->language, AST_DIGIT_ANY);
690 finishup(transferee);
692 } else if (res > 0) /* If they've typed a digit already, handle it */
693 xferto[0] = (char) res;
695 if ((ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout))) {
696 cid_num = transferer->cid.cid_num;
697 cid_name = transferer->cid.cid_name;
698 if (ast_exists_extension(transferer, transferer_real_context,xferto, 1, cid_num)) {
699 snprintf(dialstr, sizeof(dialstr), "%s@%s/n", xferto, transferer_real_context);
700 newchan = ast_feature_request_and_dial(transferer, "Local", ast_best_codec(transferer->nativeformats), dialstr, 15000, &outstate, cid_num, cid_name);
701 ast_indicate(transferer, -1);
703 res = ast_channel_make_compatible(transferer, newchan);
705 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", transferer->name, newchan->name);
709 memset(&bconfig,0,sizeof(struct ast_bridge_config));
710 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
711 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
712 res = ast_bridge_call(transferer,newchan,&bconfig);
713 if (newchan->_softhangup || newchan->_state != AST_STATE_UP || !transferer->_softhangup) {
719 if (!ast_strlen_zero(xfersound) && !ast_streamfile(transferer, xfersound, transferer->language)) {
720 if (ast_waitstream(transferer, "") < 0) {
721 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
724 ast_moh_stop(transferee);
725 ast_autoservice_stop(transferee);
726 ast_indicate(transferee, AST_CONTROL_UNHOLD);
727 transferer->_softhangup = 0;
728 return FEATURE_RETURN_SUCCESS;
731 res = ast_channel_make_compatible(transferee, newchan);
733 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", transferee->name, newchan->name);
739 ast_moh_stop(transferee);
741 if ((ast_autoservice_stop(transferee) < 0)
742 || (ast_waitfordigit(transferee, 100) < 0)
743 || (ast_waitfordigit(newchan, 100) < 0)
744 || ast_check_hangup(transferee)
745 || ast_check_hangup(newchan)) {
751 if ((xferchan = ast_channel_alloc(0))) {
752 ast_string_field_build(xferchan, name, "Transfered/%s", transferee->name);
753 /* Make formats okay */
754 xferchan->readformat = transferee->readformat;
755 xferchan->writeformat = transferee->writeformat;
756 ast_channel_masquerade(xferchan, transferee);
757 ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority);
758 xferchan->_state = AST_STATE_UP;
759 ast_clear_flag(xferchan, AST_FLAGS_ALL);
760 xferchan->_softhangup = 0;
762 if ((f = ast_read(xferchan))) {
772 newchan->_state = AST_STATE_UP;
773 ast_clear_flag(newchan, AST_FLAGS_ALL);
774 newchan->_softhangup = 0;
776 if ((tobj = ast_calloc(1, sizeof(*tobj)))) {
777 tobj->chan = xferchan;
778 tobj->peer = newchan;
779 tobj->bconfig = *config;
781 if (!ast_strlen_zero(xfersound) && !ast_streamfile(newchan, xfersound, newchan->language) &&
782 ast_waitstream(newchan, "") < 0) {
783 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
785 ast_bridge_call_thread_launch(tobj);
787 ast_hangup(xferchan);
793 ast_moh_stop(transferee);
794 ast_autoservice_stop(transferee);
795 ast_indicate(transferee, AST_CONTROL_UNHOLD);
796 /* any reason besides user requested cancel and busy triggers the failed sound */
797 if (outstate != AST_CONTROL_UNHOLD && outstate != AST_CONTROL_BUSY && !ast_strlen_zero(xferfailsound)) {
798 res = ast_streamfile(transferer, xferfailsound, transferer->language);
799 if (!res && (ast_waitstream(transferer, "") < 0)) {
803 return FEATURE_RETURN_SUCCESS;
806 ast_log(LOG_WARNING, "Extension %s does not exist in context %s\n",xferto,transferer_real_context);
807 ast_moh_stop(transferee);
808 ast_autoservice_stop(transferee);
809 ast_indicate(transferee, AST_CONTROL_UNHOLD);
810 res = ast_streamfile(transferer, "beeperr", transferer->language);
811 if (!res && (ast_waitstream(transferer, "") < 0)) {
816 ast_log(LOG_WARNING, "Did not read data.\n");
817 res = ast_streamfile(transferer, "beeperr", transferer->language);
818 if (ast_waitstream(transferer, "") < 0) {
822 ast_moh_stop(transferee);
823 ast_autoservice_stop(transferee);
824 ast_indicate(transferee, AST_CONTROL_UNHOLD);
826 return FEATURE_RETURN_SUCCESS;
830 /* add atxfer and automon as undefined so you can only use em if you configure them */
831 #define FEATURES_COUNT (sizeof(builtin_features) / sizeof(builtin_features[0]))
833 struct ast_call_feature builtin_features[] =
835 { AST_FEATURE_REDIRECT, "Blind Transfer", "blindxfer", "#", "#", builtin_blindtransfer, AST_FEATURE_FLAG_NEEDSDTMF },
836 { AST_FEATURE_REDIRECT, "Attended Transfer", "atxfer", "", "", builtin_atxfer, AST_FEATURE_FLAG_NEEDSDTMF },
837 { AST_FEATURE_AUTOMON, "One Touch Monitor", "automon", "", "", builtin_automonitor, AST_FEATURE_FLAG_NEEDSDTMF },
838 { AST_FEATURE_DISCONNECT, "Disconnect Call", "disconnect", "*", "*", builtin_disconnect, AST_FEATURE_FLAG_NEEDSDTMF },
842 static AST_LIST_HEAD(feature_list,ast_call_feature) feature_list;
844 /*! \brief register new feature into feature_list*/
845 void ast_register_feature(struct ast_call_feature *feature)
848 ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
852 AST_LIST_LOCK(&feature_list);
853 AST_LIST_INSERT_HEAD(&feature_list,feature,feature_entry);
854 AST_LIST_UNLOCK(&feature_list);
856 if (option_verbose >= 2)
857 ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname);
860 /*! \brief unregister feature from feature_list */
861 void ast_unregister_feature(struct ast_call_feature *feature)
866 AST_LIST_LOCK(&feature_list);
867 AST_LIST_REMOVE(&feature_list,feature,feature_entry);
868 AST_LIST_UNLOCK(&feature_list);
872 static void ast_unregister_features(void)
874 struct ast_call_feature *feature;
876 AST_LIST_LOCK(&feature_list);
877 while ((feature = AST_LIST_REMOVE_HEAD(&feature_list,feature_entry)))
879 AST_LIST_UNLOCK(&feature_list);
882 /*! \brief find a feature by name */
883 static struct ast_call_feature *find_feature(char *name)
885 struct ast_call_feature *tmp;
887 AST_LIST_LOCK(&feature_list);
888 AST_LIST_TRAVERSE(&feature_list, tmp, feature_entry) {
889 if (!strcasecmp(tmp->sname, name))
892 AST_LIST_UNLOCK(&feature_list);
897 /*! \brief exec an app by feature */
898 static int feature_exec_app(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
901 struct ast_call_feature *feature;
904 AST_LIST_LOCK(&feature_list);
905 AST_LIST_TRAVERSE(&feature_list,feature,feature_entry) {
906 if (!strcasecmp(feature->exten,code))
909 AST_LIST_UNLOCK(&feature_list);
911 if (!feature) { /* shouldn't ever happen! */
912 ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n");
916 app = pbx_findapp(feature->app);
918 struct ast_channel *work = ast_test_flag(feature,AST_FEATURE_FLAG_CALLEE) ? peer : chan;
919 res = pbx_exec(work, app, feature->app_args);
923 ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app);
927 return FEATURE_RETURN_SUCCESS; /* XXX should probably return res */
930 static void unmap_features(void)
933 for (x = 0; x < FEATURES_COUNT; x++)
934 strcpy(builtin_features[x].exten, builtin_features[x].default_exten);
937 static int remap_feature(const char *name, const char *value)
941 for (x = 0; x < FEATURES_COUNT; x++) {
942 if (!strcasecmp(name, builtin_features[x].sname)) {
943 ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten));
944 if (option_verbose > 1)
945 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);
947 } else if (!strcmp(value, builtin_features[x].exten))
948 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);
953 static int ast_feature_interpret(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
956 struct ast_flags features;
957 int res = FEATURE_RETURN_PASSDIGITS;
958 struct ast_call_feature *feature;
959 const char *dynamic_features=pbx_builtin_getvar_helper(chan,"DYNAMIC_FEATURES");
961 if (sense == FEATURE_SENSE_CHAN)
962 ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);
964 ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL);
965 ast_log(LOG_DEBUG, "Feature interpret: chan=%s, peer=%s, sense=%d, features=%d\n", chan->name, peer->name, sense, features.flags);
967 for (x=0; x < FEATURES_COUNT; x++) {
968 if ((ast_test_flag(&features, builtin_features[x].feature_mask)) &&
969 !ast_strlen_zero(builtin_features[x].exten)) {
970 /* Feature is up for consideration */
971 if (!strcmp(builtin_features[x].exten, code)) {
972 res = builtin_features[x].operation(chan, peer, config, code, sense);
974 } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) {
975 if (res == FEATURE_RETURN_PASSDIGITS)
976 res = FEATURE_RETURN_STOREDIGITS;
982 if (!ast_strlen_zero(dynamic_features)) {
983 char *tmp = ast_strdupa(dynamic_features);
989 while ((tok = strsep(&tmp, "#")) != NULL) {
990 feature = find_feature(tok);
993 /* Feature is up for consideration */
994 if (!strcmp(feature->exten, code)) {
995 if (option_verbose > 2)
996 ast_verbose(VERBOSE_PREFIX_3 " Feature Found: %s exten: %s\n",feature->sname, tok);
997 res = feature->operation(chan, peer, config, code, sense);
999 } else if (!strncmp(feature->exten, code, strlen(code))) {
1000 res = FEATURE_RETURN_STOREDIGITS;
1009 static void set_config_flags(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
1013 ast_clear_flag(config, AST_FLAGS_ALL);
1014 for (x = 0; x < FEATURES_COUNT; x++) {
1015 if (ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF)) {
1016 if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask))
1017 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
1019 if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask))
1020 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
1024 if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) {
1025 const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
1027 if (dynamic_features) {
1028 char *tmp = ast_strdupa(dynamic_features);
1030 struct ast_call_feature *feature;
1032 if (!tmp) /* no memory */
1035 /* while we have a feature */
1036 while (NULL != (tok = strsep(&tmp, "#"))) {
1037 if ((feature = find_feature(tok)) && ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) {
1038 if (ast_test_flag(feature, AST_FEATURE_FLAG_CALLER))
1039 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
1040 if (ast_test_flag(feature, AST_FEATURE_FLAG_CALLEE))
1041 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
1048 /* XXX this is very similar to the code in channel.c */
1049 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)
1054 struct ast_channel *chan;
1055 struct ast_channel *monitor_chans[2];
1056 struct ast_channel *active_channel;
1057 struct ast_frame *f = NULL;
1058 int res = 0, ready = 0;
1060 if ((chan = ast_request(type, format, data, &cause))) {
1061 ast_set_callerid(chan, cid_num, cid_name, cid_num);
1062 ast_channel_inherit_variables(caller, chan);
1063 if (!ast_call(chan, data, timeout)) {
1064 struct timeval started;
1066 char *disconnect_code = NULL, *dialed_code = NULL;
1068 ast_indicate(caller, AST_CONTROL_RINGING);
1069 /* support dialing of the featuremap disconnect code while performing an attended tranfer */
1070 for (x=0; x < FEATURES_COUNT; x++) {
1071 if (strcasecmp(builtin_features[x].sname, "disconnect"))
1074 disconnect_code = builtin_features[x].exten;
1075 len = strlen(disconnect_code) + 1;
1076 dialed_code = alloca(len);
1077 memset(dialed_code, 0, len);
1081 started = ast_tvnow();
1083 while (!ast_check_hangup(caller) && timeout && (chan->_state != AST_STATE_UP)) {
1084 monitor_chans[0] = caller;
1085 monitor_chans[1] = chan;
1086 active_channel = ast_waitfor_n(monitor_chans, 2, &to);
1088 /* see if the timeout has been violated */
1089 if(ast_tvdiff_ms(ast_tvnow(), started) > timeout) {
1090 state = AST_CONTROL_UNHOLD;
1091 ast_log(LOG_NOTICE, "We exceeded our AT-timeout\n");
1092 break; /*doh! timeout*/
1095 if (!active_channel) {
1099 if (chan && (chan == active_channel)){
1101 if (f == NULL) { /*doh! where'd he go?*/
1102 state = AST_CONTROL_HANGUP;
1107 if (f->frametype == AST_FRAME_CONTROL || f->frametype == AST_FRAME_DTMF || f->frametype == AST_FRAME_TEXT) {
1108 if (f->subclass == AST_CONTROL_RINGING) {
1109 state = f->subclass;
1110 if (option_verbose > 2)
1111 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", chan->name);
1112 ast_indicate(caller, AST_CONTROL_RINGING);
1113 } else if ((f->subclass == AST_CONTROL_BUSY) || (f->subclass == AST_CONTROL_CONGESTION)) {
1114 state = f->subclass;
1115 if (option_verbose > 2)
1116 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", chan->name);
1117 ast_indicate(caller, AST_CONTROL_BUSY);
1121 } else if (f->subclass == AST_CONTROL_ANSWER) {
1122 /* This is what we are hoping for */
1123 state = f->subclass;
1129 ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass);
1131 /* else who cares */
1134 } else if (caller && (active_channel == caller)) {
1135 f = ast_read(caller);
1136 if (f == NULL) { /*doh! where'd he go?*/
1137 if (caller->_softhangup && !chan->_softhangup) {
1138 /* make this a blind transfer */
1142 state = AST_CONTROL_HANGUP;
1147 if (f->frametype == AST_FRAME_DTMF) {
1148 dialed_code[x++] = f->subclass;
1149 dialed_code[x] = '\0';
1150 if (strlen(dialed_code) == len) {
1152 } else if (x && strncmp(dialed_code, disconnect_code, x)) {
1154 dialed_code[x] = '\0';
1156 if (*dialed_code && !strcmp(dialed_code, disconnect_code)) {
1157 /* Caller Canceled the call */
1158 state = AST_CONTROL_UNHOLD;
1170 ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data);
1172 ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
1174 case AST_CAUSE_BUSY:
1175 state = AST_CONTROL_BUSY;
1177 case AST_CAUSE_CONGESTION:
1178 state = AST_CONTROL_CONGESTION;
1183 ast_indicate(caller, -1);
1184 if (chan && ready) {
1185 if (chan->_state == AST_STATE_UP)
1186 state = AST_CONTROL_ANSWER;
1199 if (chan && res <= 0) {
1200 if (chan->cdr || (chan->cdr = ast_cdr_alloc())) {
1202 ast_cdr_init(chan->cdr, chan);
1203 snprintf(tmp, 256, "%s/%s", type, (char *)data);
1204 ast_cdr_setapp(chan->cdr,"Dial",tmp);
1205 ast_cdr_update(chan);
1206 ast_cdr_start(chan->cdr);
1207 ast_cdr_end(chan->cdr);
1208 /* If the cause wasn't handled properly */
1209 if (ast_cdr_disposition(chan->cdr,chan->hangupcause))
1210 ast_cdr_failed(chan->cdr);
1212 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
1219 int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast_bridge_config *config)
1221 /* Copy voice back and forth between the two channels. Give the peer
1222 the ability to transfer calls with '#<extension' syntax. */
1223 struct ast_frame *f;
1224 struct ast_channel *who;
1225 char chan_featurecode[FEATURE_MAX_LEN + 1]="";
1226 char peer_featurecode[FEATURE_MAX_LEN + 1]="";
1231 struct ast_option_header *aoh;
1232 struct timeval start = { 0 , 0 };
1233 struct ast_bridge_config backup_config;
1235 memset(&backup_config, 0, sizeof(backup_config));
1237 config->start_time = ast_tvnow();
1240 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
1241 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
1243 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
1246 const char *monitor_exec;
1247 struct ast_channel *src = NULL;
1249 if (!(monitor_app = pbx_findapp("Monitor")))
1252 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR")))
1254 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
1256 if (monitor_app && src) {
1257 char *tmp = ast_strdupa(monitor_exec);
1259 pbx_exec(src, monitor_app, tmp);
1261 ast_log(LOG_ERROR, "Monitor failed: out of memory\n");
1266 set_config_flags(chan, peer, config);
1267 config->firstpass = 1;
1269 /* Answer if need be */
1270 if (ast_answer(chan))
1272 peer->appl = "Bridged Call";
1273 peer->data = (char *) chan->name;
1275 /* copy the userfield from the B-leg to A-leg if applicable */
1276 if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) {
1278 if (!ast_strlen_zero(chan->cdr->userfield)) {
1279 snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield);
1280 ast_cdr_appenduserfield(chan, tmp);
1282 ast_cdr_setuserfield(chan, peer->cdr->userfield);
1283 /* free the peer's cdr without ast_cdr_free complaining */
1288 struct ast_channel *other; /* used later */
1289 if (config->feature_timer)
1290 start = ast_tvnow();
1292 res = ast_channel_bridge(chan, peer, config, &f, &who);
1294 if (config->feature_timer) {
1295 /* Update time limit for next pass */
1296 diff = ast_tvdiff_ms(ast_tvnow(), start);
1297 config->feature_timer -= diff;
1299 /* Running on backup config, meaning a feature might be being
1300 activated, but that's no excuse to keep things going
1302 if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) {
1303 ast_log(LOG_DEBUG, "Timed out, realtime this time!\n");
1304 config->feature_timer = 0;
1310 } else if (config->feature_timer <= 0) {
1311 /* Not *really* out of time, just out of time for
1312 digits to come in for features. */
1313 ast_log(LOG_DEBUG, "Timed out for feature!\n");
1314 if (!ast_strlen_zero(peer_featurecode)) {
1315 ast_dtmf_stream(chan, peer, peer_featurecode, 0);
1316 memset(peer_featurecode, 0, sizeof(peer_featurecode));
1318 if (!ast_strlen_zero(chan_featurecode)) {
1319 ast_dtmf_stream(peer, chan, chan_featurecode, 0);
1320 memset(chan_featurecode, 0, sizeof(chan_featurecode));
1324 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
1326 /* Restore original (possibly time modified) bridge config */
1327 memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
1328 memset(&backup_config, 0, sizeof(backup_config));
1330 hadfeatures = hasfeatures;
1331 /* Continue as we were */
1335 if (config->feature_timer <=0) {
1336 /* We ran out of time */
1337 config->feature_timer = 0;
1347 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
1351 if (!f || (f->frametype == AST_FRAME_CONTROL &&
1352 (f->subclass == AST_CONTROL_HANGUP || f->subclass == AST_CONTROL_BUSY ||
1353 f->subclass == AST_CONTROL_CONGESTION ) ) ) {
1357 /* many things should be sent to the 'other' channel */
1358 other = (who == chan) ? peer : chan;
1359 if (f->frametype == AST_FRAME_CONTROL) {
1360 if (f->subclass == AST_CONTROL_RINGING)
1361 ast_indicate(other, AST_CONTROL_RINGING);
1362 else if (f->subclass == -1)
1363 ast_indicate(other, -1);
1364 else if (f->subclass == AST_CONTROL_FLASH)
1365 ast_indicate(other, AST_CONTROL_FLASH);
1366 else if (f->subclass == AST_CONTROL_OPTION) {
1368 /* Forward option Requests */
1369 if (aoh && (aoh->flag == AST_OPTION_FLAG_REQUEST))
1370 ast_channel_setoption(other, ntohs(aoh->option), aoh->data, f->datalen - sizeof(struct ast_option_header), 0);
1373 /* check for '*', if we find it it's time to disconnect */
1374 if (f && f->frametype == AST_FRAME_DTMF) {
1378 hadfeatures = hasfeatures;
1379 /* This cannot overrun because the longest feature is one shorter than our buffer */
1381 sense = FEATURE_SENSE_CHAN;
1382 featurecode = chan_featurecode;
1384 sense = FEATURE_SENSE_PEER;
1385 featurecode = peer_featurecode;
1387 /* append the event to featurecode. we rely on the string being zero-filled, and
1388 * not overflowing it. XXX how do we guarantee the latter ?
1390 featurecode[strlen(featurecode)] = f->subclass;
1391 config->feature_timer = backup_config.feature_timer;
1392 res = ast_feature_interpret(chan, peer, config, featurecode, sense);
1394 case FEATURE_RETURN_PASSDIGITS:
1395 ast_dtmf_stream(other, who, featurecode, 0);
1397 case FEATURE_RETURN_SUCCESS:
1398 memset(featurecode, 0, sizeof(chan_featurecode));
1401 if (res >= FEATURE_RETURN_PASSDIGITS) {
1407 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
1408 if (hadfeatures && !hasfeatures) {
1409 /* Restore backup */
1410 memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
1411 memset(&backup_config, 0, sizeof(struct ast_bridge_config));
1412 } else if (hasfeatures) {
1414 /* Backup configuration */
1415 memcpy(&backup_config, config, sizeof(struct ast_bridge_config));
1416 /* Setup temporary config options */
1417 config->play_warning = 0;
1418 ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
1419 ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
1420 config->warning_freq = 0;
1421 config->warning_sound = NULL;
1422 config->end_sound = NULL;
1423 config->start_sound = NULL;
1424 config->firstpass = 0;
1426 config->feature_timer = featuredigittimeout;
1427 ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->feature_timer);
1436 /*! \brief Take care of parked calls and unpark them if needed */
1437 static void *do_parking_thread(void *ignore)
1444 struct parkeduser *pu, *pl, *pt = NULL;
1445 int ms = -1; /* select timeout, uninitialized */
1446 int max = -1; /* max fd, none there yet */
1447 fd_set nrfds, nefds;
1450 char exten[AST_MAX_EXTENSION];
1456 ast_mutex_lock(&parking_lock);
1460 struct ast_channel *chan = pu->chan; /* shorthand */
1461 int tms; /* timeout for this item */
1462 int x; /* fd index in channel */
1463 struct ast_context *con;
1465 if (pu->notquiteyet) {
1466 /* Pretend this one isn't here yet */
1471 tms = ast_tvdiff_ms(ast_tvnow(), pu->start);
1472 if (tms > pu->parkingtime) {
1473 /* Stop music on hold */
1475 ast_indicate(chan, AST_CONTROL_UNHOLD);
1476 /* Get chan, exten from derived kludge */
1477 if (pu->peername[0]) {
1478 peername = ast_strdupa(pu->peername);
1479 cp = strrchr(peername, '-');
1482 con = ast_context_find(parking_con_dial);
1484 con = ast_context_create(NULL, parking_con_dial, registrar);
1486 ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial);
1490 char returnexten[AST_MAX_EXTENSION];
1491 snprintf(returnexten, sizeof(returnexten), "%s||t", peername);
1492 ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(returnexten), FREE, registrar);
1494 set_c_e_p(chan, parking_con_dial, peername, 1);
1496 /* They've been waiting too long, send them back to where they came. Theoretically they
1497 should have their original extensions and such, but we copy to be on the safe side */
1498 set_c_e_p(chan, pu->context, pu->exten, pu->priority);
1501 manager_event(EVENT_FLAG_CALL, "ParkedCallTimeOut",
1505 "CallerIDName: %s\r\n"
1506 ,pu->parkingnum, chan->name
1507 ,(chan->cid.cid_num ? chan->cid.cid_num : "<unknown>")
1508 ,(chan->cid.cid_name ? chan->cid.cid_name : "<unknown>")
1511 if (option_verbose > 1)
1512 ast_verbose(VERBOSE_PREFIX_2 "Timeout for %s parked on %d. Returning to %s,%s,%d\n", chan->name, pu->parkingnum, chan->context, chan->exten, chan->priority);
1513 /* Start up the PBX, or hang them up */
1514 if (ast_pbx_start(chan)) {
1515 ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", chan->name);
1516 ast_hangup(pu->chan);
1518 /* And take them out of the parking lot */
1520 pl->next = pu->next;
1522 parkinglot = pu->next;
1525 con = ast_context_find(parking_con);
1527 snprintf(exten, sizeof(exten), "%d", pt->parkingnum);
1528 if (ast_context_remove_extension2(con, exten, 1, NULL))
1529 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
1531 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
1534 for (x = 0; x < AST_MAX_FDS; x++) {
1535 struct ast_frame *f;
1537 if (chan->fds[x] < 0 || (!FD_ISSET(chan->fds[x], &rfds) && !FD_ISSET(chan->fds[x], &efds)))
1540 if (FD_ISSET(chan->fds[x], &efds))
1541 ast_set_flag(chan, AST_FLAG_EXCEPTION);
1543 ast_clear_flag(chan, AST_FLAG_EXCEPTION);
1545 /* See if they need servicing */
1547 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
1550 manager_event(EVENT_FLAG_CALL, "ParkedCallGiveUp",
1554 "CallerIDName: %s\r\n"
1555 ,pu->parkingnum, chan->name
1556 ,(chan->cid.cid_num ? chan->cid.cid_num : "<unknown>")
1557 ,(chan->cid.cid_name ? chan->cid.cid_name : "<unknown>")
1560 /* There's a problem, hang them up*/
1561 if (option_verbose > 1)
1562 ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being parked\n", chan->name);
1564 /* And take them out of the parking lot */
1566 pl->next = pu->next;
1568 parkinglot = pu->next;
1571 con = ast_context_find(parking_con);
1573 snprintf(exten, sizeof(exten), "%d", pt->parkingnum);
1574 if (ast_context_remove_extension2(con, exten, 1, NULL))
1575 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
1577 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
1581 /* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
1583 if (pu->moh_trys < 3 && !chan->generatordata) {
1584 ast_log(LOG_DEBUG, "MOH on parked call stopped by outside source. Restarting.\n");
1585 ast_moh_start(chan, NULL);
1588 goto std; /* XXX Ick: jumping into an else statement??? XXX */
1592 if (x >= AST_MAX_FDS) {
1593 std: for (x=0; x<AST_MAX_FDS; x++) {
1594 /* Keep this one for next one */
1595 if (chan->fds[x] > -1) {
1596 FD_SET(chan->fds[x], &nrfds);
1597 FD_SET(chan->fds[x], &nefds);
1598 if (chan->fds[x] > max)
1602 /* Keep track of our longest wait */
1603 if ((tms < ms) || (ms < 0))
1610 ast_mutex_unlock(&parking_lock);
1613 tv = ast_samp2tv(ms, 1000);
1614 /* Wait for something to happen */
1615 ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL);
1616 pthread_testcancel();
1618 return NULL; /* Never reached */
1621 static int park_call_exec(struct ast_channel *chan, void *data)
1623 /* Data is unused at the moment but could contain a parking
1624 lot context eventually */
1626 struct localuser *u;
1628 /* Setup the exten/priority to be s/1 since we don't know
1629 where this call should return */
1630 strcpy(chan->exten, "s");
1632 if (chan->_state != AST_STATE_UP)
1633 res = ast_answer(chan);
1635 res = ast_safe_sleep(chan, 1000);
1637 res = ast_park_call(chan, chan, 0, NULL);
1638 LOCAL_USER_REMOVE(u);
1640 res = AST_PBX_KEEPALIVE;
1644 static int park_exec(struct ast_channel *chan, void *data)
1647 struct localuser *u;
1648 struct ast_channel *peer=NULL;
1649 struct parkeduser *pu, *pl=NULL;
1650 char exten[AST_MAX_EXTENSION];
1651 struct ast_context *con;
1654 struct ast_bridge_config config;
1657 ast_log(LOG_WARNING, "Park requires an argument (extension number)\n");
1661 park = atoi((char *)data);
1662 ast_mutex_lock(&parking_lock);
1665 if (pu->parkingnum == park) {
1667 pl->next = pu->next;
1669 parkinglot = pu->next;
1675 ast_mutex_unlock(&parking_lock);
1678 con = ast_context_find(parking_con);
1680 snprintf(exten, sizeof(exten), "%d", pu->parkingnum);
1681 if (ast_context_remove_extension2(con, exten, 1, NULL))
1682 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
1684 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
1686 manager_event(EVENT_FLAG_CALL, "UnParkedCall",
1691 "CallerIDName: %s\r\n"
1692 ,pu->parkingnum, pu->chan->name, chan->name
1693 ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
1694 ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
1699 /* JK02: it helps to answer the channel if not already up */
1700 if (chan->_state != AST_STATE_UP) {
1705 /* Play a courtesy to the source(s) configured to prefix the bridge connecting */
1707 if (!ast_strlen_zero(courtesytone)) {
1708 if (parkedplay == 0) {
1709 if (!ast_streamfile(chan, courtesytone, chan->language)) {
1710 if (ast_waitstream(chan, "") < 0) {
1711 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
1717 ast_indicate(peer, AST_CONTROL_UNHOLD);
1720 ast_indicate(peer, AST_CONTROL_UNHOLD);
1721 if (parkedplay == 2) {
1722 if (!ast_streamfile(chan, courtesytone, chan->language) && !ast_streamfile(peer, courtesytone, chan->language)) {
1723 res = ast_waitstream(chan, "");
1725 res = ast_waitstream(peer, "");
1727 ast_log(LOG_WARNING, "Failed to play courtesy tones!\n");
1732 } else if (parkedplay == 1) {
1733 if (!ast_streamfile(peer, courtesytone, chan->language)) {
1734 if (ast_waitstream(peer, "") < 0) {
1735 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
1744 res = ast_channel_make_compatible(chan, peer);
1746 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
1750 /* This runs sorta backwards, since we give the incoming channel control, as if it
1751 were the person called. */
1752 if (option_verbose > 2)
1753 ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to parked call %d\n", chan->name, park);
1755 memset(&config, 0, sizeof(struct ast_bridge_config));
1756 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
1757 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
1758 config.timelimit = 0;
1759 config.play_warning = 0;
1760 config.warning_freq = 0;
1761 config.warning_sound=NULL;
1762 res = ast_bridge_call(chan, peer, &config);
1764 /* Simulate the PBX hanging up */
1765 if (res != AST_PBX_NO_HANGUP_PEER)
1769 /* XXX Play a message XXX */
1770 dres = ast_streamfile(chan, "pbx-invalidpark", chan->language);
1772 dres = ast_waitstream(chan, "");
1774 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
1777 if (option_verbose > 2)
1778 ast_verbose(VERBOSE_PREFIX_3 "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park);
1781 LOCAL_USER_REMOVE(u);
1785 static int handle_showfeatures(int fd, int argc, char *argv[])
1789 struct ast_call_feature *feature;
1790 char format[] = "%-25s %-7s %-7s\n";
1792 ast_cli(fd, format, "Builtin Feature", "Default", "Current");
1793 ast_cli(fd, format, "---------------", "-------", "-------");
1795 ast_cli(fd, format, "Pickup", "*8", ast_pickup_ext()); /* default hardcoded above, so we'll hardcode it here */
1797 fcount = sizeof(builtin_features) / sizeof(builtin_features[0]);
1799 for (i = 0; i < fcount; i++)
1801 ast_cli(fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
1804 ast_cli(fd, format, "Dynamic Feature", "Default", "Current");
1805 ast_cli(fd, format, "---------------", "-------", "-------");
1806 if (AST_LIST_EMPTY(&feature_list)) {
1807 ast_cli(fd, "(none)\n");
1810 AST_LIST_LOCK(&feature_list);
1811 AST_LIST_TRAVERSE(&feature_list, feature, feature_entry) {
1812 ast_cli(fd, format, feature->sname, "no def", feature->exten);
1814 AST_LIST_UNLOCK(&feature_list);
1816 ast_cli(fd, "\nCall parking\n");
1817 ast_cli(fd, "------------\n");
1818 ast_cli(fd,"%-20s: %s\n", "Parking extension", parking_ext);
1819 ast_cli(fd,"%-20s: %s\n", "Parking context", parking_con);
1820 ast_cli(fd,"%-20s: %d-%d\n", "Parked call extensions", parking_start, parking_stop);
1823 return RESULT_SUCCESS;
1826 static char showfeatures_help[] =
1827 "Usage: show features\n"
1828 " Lists currently configured features.\n";
1830 static struct ast_cli_entry showfeatures =
1831 { { "show", "features", NULL }, handle_showfeatures, "Lists configured features", showfeatures_help };
1833 static int handle_parkedcalls(int fd, int argc, char *argv[])
1835 struct parkeduser *cur;
1838 ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
1839 , "Context", "Extension", "Pri", "Timeout");
1841 ast_mutex_lock(&parking_lock);
1843 for (cur = parkinglot; cur; cur = cur->next) {
1844 ast_cli(fd, "%4d %25s (%-15s %-12s %-4d) %6lds\n"
1845 ,cur->parkingnum, cur->chan->name, cur->context, cur->exten
1846 ,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL));
1850 ast_cli(fd, "%d parked call%s.\n", numparked, (numparked != 1) ? "s" : "");
1852 ast_mutex_unlock(&parking_lock);
1854 return RESULT_SUCCESS;
1857 static char showparked_help[] =
1858 "Usage: show parkedcalls\n"
1859 " Lists currently parked calls.\n";
1861 static struct ast_cli_entry showparked =
1862 { { "show", "parkedcalls", NULL }, handle_parkedcalls, "Lists parked calls", showparked_help };
1864 /*! \brief Dump lot status */
1865 static int manager_parking_status( struct mansession *s, struct message *m )
1867 struct parkeduser *cur;
1868 char *id = astman_get_header(m,"ActionID");
1869 char idText[256] = "";
1871 if (!ast_strlen_zero(id))
1872 snprintf(idText,256,"ActionID: %s\r\n",id);
1874 astman_send_ack(s, m, "Parked calls will follow");
1876 ast_mutex_lock(&parking_lock);
1880 astman_append(s, "Event: ParkedCall\r\n"
1886 "CallerIDName: %s\r\n"
1889 ,cur->parkingnum, cur->chan->name, cur->peername
1890 ,(long)cur->start.tv_sec + (long)(cur->parkingtime/1000) - (long)time(NULL)
1891 ,(cur->chan->cid.cid_num ? cur->chan->cid.cid_num : "")
1892 ,(cur->chan->cid.cid_name ? cur->chan->cid.cid_name : "")
1899 "Event: ParkedCallsComplete\r\n"
1903 ast_mutex_unlock(&parking_lock);
1905 return RESULT_SUCCESS;
1908 static char mandescr_park[] =
1909 "Description: Park a channel.\n"
1910 "Variables: (Names marked with * are required)\n"
1911 " *Channel: Channel name to park\n"
1912 " *Channel2: Channel to announce park info to (and return to if timeout)\n"
1913 " Timeout: Number of milliseconds to wait before callback.\n";
1915 static int manager_park(struct mansession *s, struct message *m)
1917 char *channel = astman_get_header(m, "Channel");
1918 char *channel2 = astman_get_header(m, "Channel2");
1919 char *timeout = astman_get_header(m, "Timeout");
1924 struct ast_channel *ch1, *ch2;
1926 if (ast_strlen_zero(channel)) {
1927 astman_send_error(s, m, "Channel not specified");
1931 if (ast_strlen_zero(channel2)) {
1932 astman_send_error(s, m, "Channel2 not specified");
1936 ch1 = ast_get_channel_by_name_locked(channel);
1938 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel);
1939 astman_send_error(s, m, buf);
1943 ch2 = ast_get_channel_by_name_locked(channel2);
1945 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2);
1946 astman_send_error(s, m, buf);
1947 ast_mutex_unlock(&ch1->lock);
1951 if (!ast_strlen_zero(timeout)) {
1952 sscanf(timeout, "%d", &to);
1955 res = ast_masq_park_call(ch1, ch2, to, &parkExt);
1957 ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT);
1958 astman_send_ack(s, m, "Park successful");
1960 astman_send_error(s, m, "Park failure");
1963 ast_mutex_unlock(&ch1->lock);
1964 ast_mutex_unlock(&ch2->lock);
1970 int ast_pickup_call(struct ast_channel *chan)
1972 struct ast_channel *cur = NULL;
1975 while ( (cur = ast_channel_walk_locked(cur)) != NULL) {
1978 (chan->pickupgroup & cur->callgroup) &&
1979 ((cur->_state == AST_STATE_RINGING) ||
1980 (cur->_state == AST_STATE_RING))) {
1983 ast_mutex_unlock(&cur->lock);
1987 ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
1988 res = ast_answer(chan);
1990 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
1991 res = ast_queue_control(chan, AST_CONTROL_ANSWER);
1993 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
1994 res = ast_channel_masquerade(cur, chan);
1996 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name); /* Done */
1997 ast_mutex_unlock(&cur->lock);
2000 ast_log(LOG_DEBUG, "No call pickup possible...\n");
2005 static int load_config(void)
2007 int start = 0, end = 0;
2008 struct ast_context *con = NULL;
2009 struct ast_config *cfg = NULL;
2010 struct ast_variable *var = NULL;
2011 char old_parking_ext[AST_MAX_EXTENSION];
2012 char old_parking_con[AST_MAX_EXTENSION] = "";
2014 if (!ast_strlen_zero(parking_con)) {
2015 strcpy(old_parking_ext, parking_ext);
2016 strcpy(old_parking_con, parking_con);
2019 /* Reset to defaults */
2020 strcpy(parking_con, "parkedcalls");
2021 strcpy(parking_con_dial, "park-dial");
2022 strcpy(parking_ext, "700");
2023 strcpy(pickup_ext, "*8");
2024 courtesytone[0] = '\0';
2025 strcpy(xfersound, "beep");
2026 strcpy(xferfailsound, "pbx-invalid");
2027 parking_start = 701;
2032 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
2033 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
2035 cfg = ast_config_load("features.conf");
2037 for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
2038 if (!strcasecmp(var->name, "parkext")) {
2039 ast_copy_string(parking_ext, var->value, sizeof(parking_ext));
2040 } else if (!strcasecmp(var->name, "context")) {
2041 ast_copy_string(parking_con, var->value, sizeof(parking_con));
2042 } else if (!strcasecmp(var->name, "parkingtime")) {
2043 if ((sscanf(var->value, "%d", &parkingtime) != 1) || (parkingtime < 1)) {
2044 ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value);
2045 parkingtime = DEFAULT_PARK_TIME;
2047 parkingtime = parkingtime * 1000;
2048 } else if (!strcasecmp(var->name, "parkpos")) {
2049 if (sscanf(var->value, "%d-%d", &start, &end) != 2) {
2050 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);
2052 parking_start = start;
2055 } else if (!strcasecmp(var->name, "findslot")) {
2056 parkfindnext = (!strcasecmp(var->value, "next"));
2057 } else if (!strcasecmp(var->name, "adsipark")) {
2058 adsipark = ast_true(var->value);
2059 } else if (!strcasecmp(var->name, "transferdigittimeout")) {
2060 if ((sscanf(var->value, "%d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) {
2061 ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value);
2062 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
2064 transferdigittimeout = transferdigittimeout * 1000;
2065 } else if (!strcasecmp(var->name, "featuredigittimeout")) {
2066 if ((sscanf(var->value, "%d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) {
2067 ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value);
2068 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
2070 } else if (!strcasecmp(var->name, "courtesytone")) {
2071 ast_copy_string(courtesytone, var->value, sizeof(courtesytone));
2072 } else if (!strcasecmp(var->name, "parkedplay")) {
2073 if (!strcasecmp(var->value, "both"))
2075 else if (!strcasecmp(var->value, "parked"))
2079 } else if (!strcasecmp(var->name, "xfersound")) {
2080 ast_copy_string(xfersound, var->value, sizeof(xfersound));
2081 } else if (!strcasecmp(var->name, "xferfailsound")) {
2082 ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound));
2083 } else if (!strcasecmp(var->name, "pickupexten")) {
2084 ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext));
2089 for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) {
2090 if (remap_feature(var->name, var->value))
2091 ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name);
2094 /* Map a key combination to an application*/
2095 ast_unregister_features();
2096 for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) {
2097 char *tmp_val = ast_strdup(var->value);
2098 char *exten, *party=NULL, *app=NULL, *app_args=NULL;
2101 /* XXX No memory. We should probably break, but at least we do not
2102 * insist on this entry or we could be stuck in an
2108 /* strsep() sets the argument to NULL if match not found, and it
2109 * is safe to use it with a NULL argument, so we don't check
2112 exten = strsep(&tmp_val,",");
2113 party = strsep(&tmp_val,",");
2114 app = strsep(&tmp_val,",");
2115 app_args = strsep(&tmp_val,",");
2117 /* XXX var_name or app_args ? */
2118 if (ast_strlen_zero(app) || ast_strlen_zero(exten) || ast_strlen_zero(party) || ast_strlen_zero(var->name)) {
2119 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);
2125 struct ast_call_feature *feature;
2128 if (!(feature = find_feature(var->name))) {
2131 if (!(feature = ast_calloc(1, sizeof(*feature)))) {
2137 ast_copy_string(feature->sname,var->name,FEATURE_SNAME_LEN);
2138 ast_copy_string(feature->app,app,FEATURE_APP_LEN);
2139 ast_copy_string(feature->exten, exten,FEATURE_EXTEN_LEN);
2143 ast_copy_string(feature->app_args,app_args,FEATURE_APP_ARGS_LEN);
2145 ast_copy_string(feature->exten, exten,sizeof(feature->exten));
2146 feature->operation=feature_exec_app;
2147 ast_set_flag(feature,AST_FEATURE_FLAG_NEEDSDTMF);
2149 if (!strcasecmp(party,"caller"))
2150 ast_set_flag(feature,AST_FEATURE_FLAG_CALLER);
2151 else if (!strcasecmp(party, "callee"))
2152 ast_set_flag(feature,AST_FEATURE_FLAG_CALLEE);
2154 ast_log(LOG_NOTICE, "Invalid party specification for feature '%s', must be caller, or callee\n", var->name);
2158 ast_register_feature(feature);
2160 if (option_verbose >=1)
2161 ast_verbose(VERBOSE_PREFIX_2 "Mapping Feature '%s' to app '%s' with code '%s'\n", var->name, app, exten);
2165 ast_config_destroy(cfg);
2167 /* Remove the old parking extension */
2168 if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con))) {
2169 ast_context_remove_extension2(con, old_parking_ext, 1, registrar);
2170 ast_log(LOG_DEBUG, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con);
2173 if (!(con = ast_context_find(parking_con)) && !(con = ast_context_create(NULL, parking_con, registrar))) {
2174 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
2177 return ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, strdup(""), FREE, registrar);
2180 static int reload(void *mod)
2182 return load_config();
2185 static int load_module(void *mod)
2190 AST_LIST_HEAD_INIT(&feature_list);
2191 memset(parking_ext, 0, sizeof(parking_ext));
2192 memset(parking_con, 0, sizeof(parking_con));
2194 if ((res = load_config()))
2196 ast_cli_register(&showparked);
2197 ast_cli_register(&showfeatures);
2198 ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
2199 res = ast_register_application(parkedcall, park_exec, synopsis, descrip);
2201 res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2);
2203 ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls" );
2204 ast_manager_register2("Park", EVENT_FLAG_CALL, manager_park,
2205 "Park a channel", mandescr_park);
2211 static int unload_module(void *mod)
2213 STANDARD_HANGUP_LOCALUSERS;
2215 ast_manager_unregister("ParkedCalls");
2216 ast_manager_unregister("Park");
2217 ast_cli_unregister(&showfeatures);
2218 ast_cli_unregister(&showparked);
2219 ast_unregister_application(parkcall);
2220 return ast_unregister_application(parkedcall);
2223 static const char *description(void)
2225 return "Call Features Resource";
2228 static const char *key(void)
2230 return ASTERISK_GPL_KEY;
2233 STD_MOD(MOD_0 | NO_UNLOAD, reload, NULL, NULL);