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
570 ast_indicate(transferee, AST_CONTROL_HOLD);
571 ast_autoservice_start(transferee);
572 ast_moh_start(transferee, NULL);
574 memset(newext, 0, sizeof(newext));
577 if ((res=ast_streamfile(transferer, "pbx-transfer", transferer->language))) {
578 ast_moh_stop(transferee);
579 ast_autoservice_stop(transferee);
580 ast_indicate(transferee, AST_CONTROL_UNHOLD);
583 if ((res=ast_waitstream(transferer, AST_DIGIT_ANY)) < 0) {
584 ast_moh_stop(transferee);
585 ast_autoservice_stop(transferee);
586 ast_indicate(transferee, AST_CONTROL_UNHOLD);
588 } else if (res > 0) {
589 /* If they've typed a digit already, handle it */
590 newext[0] = (char) res;
593 ast_stopstream(transferer);
594 res = ast_app_dtget(transferer, transferer_real_context, newext, sizeof(newext), 100, transferdigittimeout);
596 ast_moh_stop(transferee);
597 ast_autoservice_stop(transferee);
598 ast_indicate(transferee, AST_CONTROL_UNHOLD);
601 if (!strcmp(newext, ast_parking_ext())) {
602 ast_moh_stop(transferee);
604 res = ast_autoservice_stop(transferee);
605 ast_indicate(transferee, AST_CONTROL_UNHOLD);
608 else if (!ast_park_call(transferee, transferer, 0, NULL)) {
609 /* We return non-zero, but tell the PBX not to hang the channel when
610 the thread dies -- We have to be careful now though. We are responsible for
611 hanging up the channel, else it will never be hung up! */
613 return (transferer == peer) ? AST_PBX_KEEPALIVE : AST_PBX_NO_HANGUP_PEER;
615 ast_log(LOG_WARNING, "Unable to park call %s\n", transferee->name);
617 /* XXX Maybe we should have another message here instead of invalid extension XXX */
618 } else if (ast_exists_extension(transferee, transferer_real_context, newext, 1, transferer->cid.cid_num)) {
619 pbx_builtin_setvar_helper(peer, "BLINDTRANSFER", chan->name);
620 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", peer->name);
621 ast_moh_stop(transferee);
622 res=ast_autoservice_stop(transferee);
623 ast_indicate(transferee, AST_CONTROL_UNHOLD);
624 if (!transferee->pbx) {
625 /* Doh! Use our handy async_goto functions */
626 if (option_verbose > 2)
627 ast_verbose(VERBOSE_PREFIX_3 "Transferring %s to '%s' (context %s) priority 1\n"
628 ,transferee->name, newext, transferer_real_context);
629 if (ast_async_goto(transferee, transferer_real_context, newext, 1))
630 ast_log(LOG_WARNING, "Async goto failed :-(\n");
633 /* Set the channel's new extension, since it exists, using transferer context */
634 set_c_e_p(transferee, transferer_real_context, newext, 0);
636 check_goto_on_transfer(transferer);
639 if (option_verbose > 2)
640 ast_verbose(VERBOSE_PREFIX_3 "Unable to find extension '%s' in context '%s'\n", newext, transferer_real_context);
642 if (!ast_strlen_zero(xferfailsound))
643 res = ast_streamfile(transferer, xferfailsound, transferee->language);
647 ast_moh_stop(transferee);
648 ast_autoservice_stop(transferee);
649 ast_indicate(transferee, AST_CONTROL_UNHOLD);
652 res = ast_waitstream(transferer, AST_DIGIT_ANY);
653 ast_stopstream(transferer);
654 ast_moh_stop(transferee);
655 res = ast_autoservice_stop(transferee);
656 ast_indicate(transferee, AST_CONTROL_UNHOLD);
658 if (option_verbose > 1)
659 ast_verbose(VERBOSE_PREFIX_2 "Hungup during autoservice stop on '%s'\n", transferee->name);
662 return FEATURE_RETURN_SUCCESS;
665 static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
667 struct ast_channel *transferer;
668 struct ast_channel *transferee;
669 struct ast_channel *newchan, *xferchan=NULL;
671 struct ast_bridge_config bconfig;
672 const char *transferer_real_context;
673 char xferto[256],dialstr[265];
677 struct ast_frame *f = NULL;
678 struct ast_bridge_thread_obj *tobj;
680 ast_log(LOG_DEBUG, "Executing Attended Transfer %s, %s (sense=%d) XXX\n", chan->name, peer->name, sense);
681 set_peers(&transferer, &transferee, peer, chan, sense);
682 transferer_real_context = real_ctx(transferer, transferee);
683 /* Start autoservice on chan while we talk
685 ast_indicate(transferee, AST_CONTROL_HOLD);
686 ast_autoservice_start(transferee);
687 ast_moh_start(transferee, NULL);
688 memset(xferto, 0, sizeof(xferto));
690 res = stream_and_wait(transferer, "pbx-transfer", transferer->language, AST_DIGIT_ANY);
692 finishup(transferee);
694 } else if (res > 0) /* If they've typed a digit already, handle it */
695 xferto[0] = (char) res;
697 if ((ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout))) {
698 cid_num = transferer->cid.cid_num;
699 cid_name = transferer->cid.cid_name;
700 if (ast_exists_extension(transferer, transferer_real_context,xferto, 1, cid_num)) {
701 snprintf(dialstr, sizeof(dialstr), "%s@%s/n", xferto, transferer_real_context);
702 newchan = ast_feature_request_and_dial(transferer, "Local", ast_best_codec(transferer->nativeformats), dialstr, 15000, &outstate, cid_num, cid_name);
703 ast_indicate(transferer, -1);
705 res = ast_channel_make_compatible(transferer, newchan);
707 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", transferer->name, newchan->name);
711 memset(&bconfig,0,sizeof(struct ast_bridge_config));
712 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
713 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
714 res = ast_bridge_call(transferer,newchan,&bconfig);
715 if (newchan->_softhangup || newchan->_state != AST_STATE_UP || !transferer->_softhangup) {
721 if (!ast_strlen_zero(xfersound) && !ast_streamfile(transferer, xfersound, transferer->language)) {
722 if (ast_waitstream(transferer, "") < 0) {
723 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
726 ast_moh_stop(transferee);
727 ast_autoservice_stop(transferee);
728 ast_indicate(transferee, AST_CONTROL_UNHOLD);
729 transferer->_softhangup = 0;
730 return FEATURE_RETURN_SUCCESS;
733 res = ast_channel_make_compatible(transferee, newchan);
735 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", transferee->name, newchan->name);
741 ast_moh_stop(transferee);
743 if ((ast_autoservice_stop(transferee) < 0)
744 || (ast_waitfordigit(transferee, 100) < 0)
745 || (ast_waitfordigit(newchan, 100) < 0)
746 || ast_check_hangup(transferee)
747 || ast_check_hangup(newchan)) {
753 if ((xferchan = ast_channel_alloc(0))) {
754 ast_string_field_build(xferchan, name, "Transfered/%s", transferee->name);
755 /* Make formats okay */
756 xferchan->readformat = transferee->readformat;
757 xferchan->writeformat = transferee->writeformat;
758 ast_channel_masquerade(xferchan, transferee);
759 ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority);
760 xferchan->_state = AST_STATE_UP;
761 ast_clear_flag(xferchan, AST_FLAGS_ALL);
762 xferchan->_softhangup = 0;
764 if ((f = ast_read(xferchan))) {
774 newchan->_state = AST_STATE_UP;
775 ast_clear_flag(newchan, AST_FLAGS_ALL);
776 newchan->_softhangup = 0;
778 if ((tobj = ast_calloc(1, sizeof(*tobj)))) {
779 tobj->chan = xferchan;
780 tobj->peer = newchan;
781 tobj->bconfig = *config;
783 if (!ast_strlen_zero(xfersound) && !ast_streamfile(newchan, xfersound, newchan->language) &&
784 ast_waitstream(newchan, "") < 0) {
785 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
787 ast_bridge_call_thread_launch(tobj);
789 ast_hangup(xferchan);
795 ast_moh_stop(transferee);
796 ast_autoservice_stop(transferee);
797 ast_indicate(transferee, AST_CONTROL_UNHOLD);
798 /* any reason besides user requested cancel and busy triggers the failed sound */
799 if (outstate != AST_CONTROL_UNHOLD && outstate != AST_CONTROL_BUSY && !ast_strlen_zero(xferfailsound)) {
800 res = ast_streamfile(transferer, xferfailsound, transferer->language);
801 if (!res && (ast_waitstream(transferer, "") < 0)) {
805 return FEATURE_RETURN_SUCCESS;
808 ast_log(LOG_WARNING, "Extension %s does not exist in context %s\n",xferto,transferer_real_context);
809 ast_moh_stop(transferee);
810 ast_autoservice_stop(transferee);
811 ast_indicate(transferee, AST_CONTROL_UNHOLD);
812 res = ast_streamfile(transferer, "beeperr", transferer->language);
813 if (!res && (ast_waitstream(transferer, "") < 0)) {
818 ast_log(LOG_WARNING, "Did not read data.\n");
819 res = ast_streamfile(transferer, "beeperr", transferer->language);
820 if (ast_waitstream(transferer, "") < 0) {
824 ast_moh_stop(transferee);
825 ast_autoservice_stop(transferee);
826 ast_indicate(transferee, AST_CONTROL_UNHOLD);
828 return FEATURE_RETURN_SUCCESS;
832 /* add atxfer and automon as undefined so you can only use em if you configure them */
833 #define FEATURES_COUNT (sizeof(builtin_features) / sizeof(builtin_features[0]))
835 struct ast_call_feature builtin_features[] =
837 { AST_FEATURE_REDIRECT, "Blind Transfer", "blindxfer", "#", "#", builtin_blindtransfer, AST_FEATURE_FLAG_NEEDSDTMF },
838 { AST_FEATURE_REDIRECT, "Attended Transfer", "atxfer", "", "", builtin_atxfer, AST_FEATURE_FLAG_NEEDSDTMF },
839 { AST_FEATURE_AUTOMON, "One Touch Monitor", "automon", "", "", builtin_automonitor, AST_FEATURE_FLAG_NEEDSDTMF },
840 { AST_FEATURE_DISCONNECT, "Disconnect Call", "disconnect", "*", "*", builtin_disconnect, AST_FEATURE_FLAG_NEEDSDTMF },
844 static AST_LIST_HEAD(feature_list,ast_call_feature) feature_list;
846 /*! \brief register new feature into feature_list*/
847 void ast_register_feature(struct ast_call_feature *feature)
850 ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
854 AST_LIST_LOCK(&feature_list);
855 AST_LIST_INSERT_HEAD(&feature_list,feature,feature_entry);
856 AST_LIST_UNLOCK(&feature_list);
858 if (option_verbose >= 2)
859 ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname);
862 /*! \brief unregister feature from feature_list */
863 void ast_unregister_feature(struct ast_call_feature *feature)
868 AST_LIST_LOCK(&feature_list);
869 AST_LIST_REMOVE(&feature_list,feature,feature_entry);
870 AST_LIST_UNLOCK(&feature_list);
874 static void ast_unregister_features(void)
876 struct ast_call_feature *feature;
878 AST_LIST_LOCK(&feature_list);
879 while ((feature = AST_LIST_REMOVE_HEAD(&feature_list,feature_entry)))
881 AST_LIST_UNLOCK(&feature_list);
884 /*! \brief find a feature by name */
885 static struct ast_call_feature *find_feature(char *name)
887 struct ast_call_feature *tmp;
889 AST_LIST_LOCK(&feature_list);
890 AST_LIST_TRAVERSE(&feature_list, tmp, feature_entry) {
891 if (!strcasecmp(tmp->sname, name))
894 AST_LIST_UNLOCK(&feature_list);
899 /*! \brief exec an app by feature */
900 static int feature_exec_app(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
903 struct ast_call_feature *feature;
906 AST_LIST_LOCK(&feature_list);
907 AST_LIST_TRAVERSE(&feature_list,feature,feature_entry) {
908 if (!strcasecmp(feature->exten,code))
911 AST_LIST_UNLOCK(&feature_list);
913 if (!feature) { /* shouldn't ever happen! */
914 ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n");
918 app = pbx_findapp(feature->app);
920 struct ast_channel *work = ast_test_flag(feature,AST_FEATURE_FLAG_CALLEE) ? peer : chan;
921 res = pbx_exec(work, app, feature->app_args);
925 ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app);
929 return FEATURE_RETURN_SUCCESS; /* XXX should probably return res */
932 static void unmap_features(void)
935 for (x = 0; x < FEATURES_COUNT; x++)
936 strcpy(builtin_features[x].exten, builtin_features[x].default_exten);
939 static int remap_feature(const char *name, const char *value)
943 for (x = 0; x < FEATURES_COUNT; x++) {
944 if (!strcasecmp(name, builtin_features[x].sname)) {
945 ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten));
946 if (option_verbose > 1)
947 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);
949 } else if (!strcmp(value, builtin_features[x].exten))
950 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);
955 static int ast_feature_interpret(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
958 struct ast_flags features;
959 int res = FEATURE_RETURN_PASSDIGITS;
960 struct ast_call_feature *feature;
961 const char *dynamic_features=pbx_builtin_getvar_helper(chan,"DYNAMIC_FEATURES");
963 if (sense == FEATURE_SENSE_CHAN)
964 ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);
966 ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL);
967 ast_log(LOG_DEBUG, "Feature interpret: chan=%s, peer=%s, sense=%d, features=%d\n", chan->name, peer->name, sense, features.flags);
969 for (x=0; x < FEATURES_COUNT; x++) {
970 if ((ast_test_flag(&features, builtin_features[x].feature_mask)) &&
971 !ast_strlen_zero(builtin_features[x].exten)) {
972 /* Feature is up for consideration */
973 if (!strcmp(builtin_features[x].exten, code)) {
974 res = builtin_features[x].operation(chan, peer, config, code, sense);
976 } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) {
977 if (res == FEATURE_RETURN_PASSDIGITS)
978 res = FEATURE_RETURN_STOREDIGITS;
984 if (!ast_strlen_zero(dynamic_features)) {
985 char *tmp = ast_strdupa(dynamic_features);
991 while ((tok = strsep(&tmp, "#")) != NULL) {
992 feature = find_feature(tok);
995 /* Feature is up for consideration */
996 if (!strcmp(feature->exten, code)) {
997 if (option_verbose > 2)
998 ast_verbose(VERBOSE_PREFIX_3 " Feature Found: %s exten: %s\n",feature->sname, tok);
999 res = feature->operation(chan, peer, config, code, sense);
1001 } else if (!strncmp(feature->exten, code, strlen(code))) {
1002 res = FEATURE_RETURN_STOREDIGITS;
1011 static void set_config_flags(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
1015 ast_clear_flag(config, AST_FLAGS_ALL);
1016 for (x = 0; x < FEATURES_COUNT; x++) {
1017 if (ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF)) {
1018 if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask))
1019 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
1021 if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask))
1022 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
1026 if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) {
1027 const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
1029 if (dynamic_features) {
1030 char *tmp = ast_strdupa(dynamic_features);
1032 struct ast_call_feature *feature;
1034 if (!tmp) /* no memory */
1037 /* while we have a feature */
1038 while (NULL != (tok = strsep(&tmp, "#"))) {
1039 if ((feature = find_feature(tok)) && ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) {
1040 if (ast_test_flag(feature, AST_FEATURE_FLAG_CALLER))
1041 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
1042 if (ast_test_flag(feature, AST_FEATURE_FLAG_CALLEE))
1043 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
1050 /* XXX this is very similar to the code in channel.c */
1051 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)
1056 struct ast_channel *chan;
1057 struct ast_channel *monitor_chans[2];
1058 struct ast_channel *active_channel;
1059 struct ast_frame *f = NULL;
1060 int res = 0, ready = 0;
1062 if ((chan = ast_request(type, format, data, &cause))) {
1063 ast_set_callerid(chan, cid_num, cid_name, cid_num);
1064 ast_channel_inherit_variables(caller, chan);
1065 if (!ast_call(chan, data, timeout)) {
1066 struct timeval started;
1068 char *disconnect_code = NULL, *dialed_code = NULL;
1070 ast_indicate(caller, AST_CONTROL_RINGING);
1071 /* support dialing of the featuremap disconnect code while performing an attended tranfer */
1072 for (x=0; x < FEATURES_COUNT; x++) {
1073 if (strcasecmp(builtin_features[x].sname, "disconnect"))
1076 disconnect_code = builtin_features[x].exten;
1077 len = strlen(disconnect_code) + 1;
1078 dialed_code = alloca(len);
1079 memset(dialed_code, 0, len);
1083 started = ast_tvnow();
1085 while (!ast_check_hangup(caller) && timeout && (chan->_state != AST_STATE_UP)) {
1086 monitor_chans[0] = caller;
1087 monitor_chans[1] = chan;
1088 active_channel = ast_waitfor_n(monitor_chans, 2, &to);
1090 /* see if the timeout has been violated */
1091 if(ast_tvdiff_ms(ast_tvnow(), started) > timeout) {
1092 state = AST_CONTROL_UNHOLD;
1093 ast_log(LOG_NOTICE, "We exceeded our AT-timeout\n");
1094 break; /*doh! timeout*/
1097 if (!active_channel) {
1101 if (chan && (chan == active_channel)){
1103 if (f == NULL) { /*doh! where'd he go?*/
1104 state = AST_CONTROL_HANGUP;
1109 if (f->frametype == AST_FRAME_CONTROL || f->frametype == AST_FRAME_DTMF || f->frametype == AST_FRAME_TEXT) {
1110 if (f->subclass == AST_CONTROL_RINGING) {
1111 state = f->subclass;
1112 if (option_verbose > 2)
1113 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", chan->name);
1114 ast_indicate(caller, AST_CONTROL_RINGING);
1115 } else if ((f->subclass == AST_CONTROL_BUSY) || (f->subclass == AST_CONTROL_CONGESTION)) {
1116 state = f->subclass;
1117 if (option_verbose > 2)
1118 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", chan->name);
1119 ast_indicate(caller, AST_CONTROL_BUSY);
1123 } else if (f->subclass == AST_CONTROL_ANSWER) {
1124 /* This is what we are hoping for */
1125 state = f->subclass;
1131 ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass);
1133 /* else who cares */
1136 } else if (caller && (active_channel == caller)) {
1137 f = ast_read(caller);
1138 if (f == NULL) { /*doh! where'd he go?*/
1139 if (caller->_softhangup && !chan->_softhangup) {
1140 /* make this a blind transfer */
1144 state = AST_CONTROL_HANGUP;
1149 if (f->frametype == AST_FRAME_DTMF) {
1150 dialed_code[x++] = f->subclass;
1151 dialed_code[x] = '\0';
1152 if (strlen(dialed_code) == len) {
1154 } else if (x && strncmp(dialed_code, disconnect_code, x)) {
1156 dialed_code[x] = '\0';
1158 if (*dialed_code && !strcmp(dialed_code, disconnect_code)) {
1159 /* Caller Canceled the call */
1160 state = AST_CONTROL_UNHOLD;
1172 ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data);
1174 ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
1176 case AST_CAUSE_BUSY:
1177 state = AST_CONTROL_BUSY;
1179 case AST_CAUSE_CONGESTION:
1180 state = AST_CONTROL_CONGESTION;
1185 ast_indicate(caller, -1);
1186 if (chan && ready) {
1187 if (chan->_state == AST_STATE_UP)
1188 state = AST_CONTROL_ANSWER;
1201 if (chan && res <= 0) {
1202 if (chan->cdr || (chan->cdr = ast_cdr_alloc())) {
1204 ast_cdr_init(chan->cdr, chan);
1205 snprintf(tmp, 256, "%s/%s", type, (char *)data);
1206 ast_cdr_setapp(chan->cdr,"Dial",tmp);
1207 ast_cdr_update(chan);
1208 ast_cdr_start(chan->cdr);
1209 ast_cdr_end(chan->cdr);
1210 /* If the cause wasn't handled properly */
1211 if (ast_cdr_disposition(chan->cdr,chan->hangupcause))
1212 ast_cdr_failed(chan->cdr);
1214 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
1221 int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast_bridge_config *config)
1223 /* Copy voice back and forth between the two channels. Give the peer
1224 the ability to transfer calls with '#<extension' syntax. */
1225 struct ast_frame *f;
1226 struct ast_channel *who;
1227 char chan_featurecode[FEATURE_MAX_LEN + 1]="";
1228 char peer_featurecode[FEATURE_MAX_LEN + 1]="";
1233 struct ast_option_header *aoh;
1234 struct timeval start = { 0 , 0 };
1235 struct ast_bridge_config backup_config;
1237 memset(&backup_config, 0, sizeof(backup_config));
1239 config->start_time = ast_tvnow();
1242 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
1243 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
1245 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
1248 const char *monitor_exec;
1249 struct ast_channel *src = NULL;
1251 if (!(monitor_app = pbx_findapp("Monitor")))
1254 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR")))
1256 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
1258 if (monitor_app && src) {
1259 char *tmp = ast_strdupa(monitor_exec);
1261 pbx_exec(src, monitor_app, tmp);
1263 ast_log(LOG_ERROR, "Monitor failed: out of memory\n");
1268 set_config_flags(chan, peer, config);
1269 config->firstpass = 1;
1271 /* Answer if need be */
1272 if (ast_answer(chan))
1274 peer->appl = "Bridged Call";
1275 peer->data = (char *) chan->name;
1277 /* copy the userfield from the B-leg to A-leg if applicable */
1278 if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) {
1280 if (!ast_strlen_zero(chan->cdr->userfield)) {
1281 snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield);
1282 ast_cdr_appenduserfield(chan, tmp);
1284 ast_cdr_setuserfield(chan, peer->cdr->userfield);
1285 /* free the peer's cdr without ast_cdr_free complaining */
1290 struct ast_channel *other; /* used later */
1291 if (config->feature_timer)
1292 start = ast_tvnow();
1294 res = ast_channel_bridge(chan, peer, config, &f, &who);
1296 if (config->feature_timer) {
1297 /* Update time limit for next pass */
1298 diff = ast_tvdiff_ms(ast_tvnow(), start);
1299 config->feature_timer -= diff;
1301 /* Running on backup config, meaning a feature might be being
1302 activated, but that's no excuse to keep things going
1304 if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) {
1305 ast_log(LOG_DEBUG, "Timed out, realtime this time!\n");
1306 config->feature_timer = 0;
1312 } else if (config->feature_timer <= 0) {
1313 /* Not *really* out of time, just out of time for
1314 digits to come in for features. */
1315 ast_log(LOG_DEBUG, "Timed out for feature!\n");
1316 if (!ast_strlen_zero(peer_featurecode)) {
1317 ast_dtmf_stream(chan, peer, peer_featurecode, 0);
1318 memset(peer_featurecode, 0, sizeof(peer_featurecode));
1320 if (!ast_strlen_zero(chan_featurecode)) {
1321 ast_dtmf_stream(peer, chan, chan_featurecode, 0);
1322 memset(chan_featurecode, 0, sizeof(chan_featurecode));
1326 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
1328 /* Restore original (possibly time modified) bridge config */
1329 memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
1330 memset(&backup_config, 0, sizeof(backup_config));
1332 hadfeatures = hasfeatures;
1333 /* Continue as we were */
1337 if (config->feature_timer <=0) {
1338 /* We ran out of time */
1339 config->feature_timer = 0;
1349 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
1353 if (!f || (f->frametype == AST_FRAME_CONTROL &&
1354 (f->subclass == AST_CONTROL_HANGUP || f->subclass == AST_CONTROL_BUSY ||
1355 f->subclass == AST_CONTROL_CONGESTION ) ) ) {
1359 /* many things should be sent to the 'other' channel */
1360 other = (who == chan) ? peer : chan;
1361 if (f->frametype == AST_FRAME_CONTROL) {
1362 if (f->subclass == AST_CONTROL_RINGING)
1363 ast_indicate(other, AST_CONTROL_RINGING);
1364 else if (f->subclass == -1)
1365 ast_indicate(other, -1);
1366 else if (f->subclass == AST_CONTROL_FLASH)
1367 ast_indicate(other, AST_CONTROL_FLASH);
1368 else if (f->subclass == AST_CONTROL_OPTION) {
1370 /* Forward option Requests */
1371 if (aoh && (aoh->flag == AST_OPTION_FLAG_REQUEST))
1372 ast_channel_setoption(other, ntohs(aoh->option), aoh->data, f->datalen - sizeof(struct ast_option_header), 0);
1375 /* check for '*', if we find it it's time to disconnect */
1376 if (f && f->frametype == AST_FRAME_DTMF) {
1380 hadfeatures = hasfeatures;
1381 /* This cannot overrun because the longest feature is one shorter than our buffer */
1383 sense = FEATURE_SENSE_CHAN;
1384 featurecode = chan_featurecode;
1386 sense = FEATURE_SENSE_PEER;
1387 featurecode = peer_featurecode;
1389 /* append the event to featurecode. we rely on the string being zero-filled, and
1390 * not overflowing it. XXX how do we guarantee the latter ?
1392 featurecode[strlen(featurecode)] = f->subclass;
1393 config->feature_timer = backup_config.feature_timer;
1394 res = ast_feature_interpret(chan, peer, config, featurecode, sense);
1396 case FEATURE_RETURN_PASSDIGITS:
1397 ast_dtmf_stream(other, who, featurecode, 0);
1399 case FEATURE_RETURN_SUCCESS:
1400 memset(featurecode, 0, sizeof(chan_featurecode));
1403 if (res >= FEATURE_RETURN_PASSDIGITS) {
1409 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
1410 if (hadfeatures && !hasfeatures) {
1411 /* Restore backup */
1412 memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
1413 memset(&backup_config, 0, sizeof(struct ast_bridge_config));
1414 } else if (hasfeatures) {
1416 /* Backup configuration */
1417 memcpy(&backup_config, config, sizeof(struct ast_bridge_config));
1418 /* Setup temporary config options */
1419 config->play_warning = 0;
1420 ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
1421 ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
1422 config->warning_freq = 0;
1423 config->warning_sound = NULL;
1424 config->end_sound = NULL;
1425 config->start_sound = NULL;
1426 config->firstpass = 0;
1428 config->feature_timer = featuredigittimeout;
1429 ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->feature_timer);
1438 /*! \brief Take care of parked calls and unpark them if needed */
1439 static void *do_parking_thread(void *ignore)
1446 struct parkeduser *pu, *pl, *pt = NULL;
1447 int ms = -1; /* select timeout, uninitialized */
1448 int max = -1; /* max fd, none there yet */
1449 fd_set nrfds, nefds;
1452 char exten[AST_MAX_EXTENSION];
1458 ast_mutex_lock(&parking_lock);
1462 int tms; /* timeout for this item */
1463 int x; /* fd index in channel */
1464 struct ast_context *con;
1466 if (pu->notquiteyet) {
1467 /* Pretend this one isn't here yet */
1472 tms = ast_tvdiff_ms(ast_tvnow(), pu->start);
1473 if (tms > pu->parkingtime) {
1474 /* Stop music on hold */
1475 ast_moh_stop(pu->chan);
1476 ast_indicate(pu->chan, AST_CONTROL_UNHOLD);
1477 /* Get chan, exten from derived kludge */
1478 if (pu->peername[0]) {
1479 peername = ast_strdupa(pu->peername);
1480 cp = strrchr(peername, '-');
1483 con = ast_context_find(parking_con_dial);
1485 con = ast_context_create(NULL, parking_con_dial, registrar);
1487 ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial);
1491 char returnexten[AST_MAX_EXTENSION];
1492 snprintf(returnexten, sizeof(returnexten), "%s||t", peername);
1493 ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(returnexten), FREE, registrar);
1495 ast_copy_string(pu->chan->exten, peername, sizeof(pu->chan->exten));
1496 ast_copy_string(pu->chan->context, parking_con_dial, sizeof(pu->chan->context));
1497 pu->chan->priority = 1;
1500 /* They've been waiting too long, send them back to where they came. Theoretically they
1501 should have their original extensions and such, but we copy to be on the safe side */
1502 ast_copy_string(pu->chan->exten, pu->exten, sizeof(pu->chan->exten));
1503 ast_copy_string(pu->chan->context, pu->context, sizeof(pu->chan->context));
1504 pu->chan->priority = pu->priority;
1507 manager_event(EVENT_FLAG_CALL, "ParkedCallTimeOut",
1511 "CallerIDName: %s\r\n"
1512 ,pu->parkingnum, pu->chan->name
1513 ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
1514 ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
1517 if (option_verbose > 1)
1518 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);
1519 /* Start up the PBX, or hang them up */
1520 if (ast_pbx_start(pu->chan)) {
1521 ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", pu->chan->name);
1522 ast_hangup(pu->chan);
1524 /* And take them out of the parking lot */
1526 pl->next = pu->next;
1528 parkinglot = pu->next;
1531 con = ast_context_find(parking_con);
1533 snprintf(exten, sizeof(exten), "%d", pt->parkingnum);
1534 if (ast_context_remove_extension2(con, exten, 1, NULL))
1535 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
1537 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
1540 for (x = 0; x < AST_MAX_FDS; x++) {
1541 struct ast_frame *f;
1543 if (pu->chan->fds[x] < 0 || (!FD_ISSET(pu->chan->fds[x], &rfds) && !FD_ISSET(pu->chan->fds[x], &efds)))
1546 if (FD_ISSET(pu->chan->fds[x], &efds))
1547 ast_set_flag(pu->chan, AST_FLAG_EXCEPTION);
1549 ast_clear_flag(pu->chan, AST_FLAG_EXCEPTION);
1551 /* See if they need servicing */
1552 f = ast_read(pu->chan);
1553 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
1556 manager_event(EVENT_FLAG_CALL, "ParkedCallGiveUp",
1560 "CallerIDName: %s\r\n"
1561 ,pu->parkingnum, pu->chan->name
1562 ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
1563 ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
1566 /* There's a problem, hang them up*/
1567 if (option_verbose > 1)
1568 ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being parked\n", pu->chan->name);
1569 ast_hangup(pu->chan);
1570 /* And take them out of the parking lot */
1572 pl->next = pu->next;
1574 parkinglot = pu->next;
1577 con = ast_context_find(parking_con);
1579 snprintf(exten, sizeof(exten), "%d", pt->parkingnum);
1580 if (ast_context_remove_extension2(con, exten, 1, NULL))
1581 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
1583 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
1587 /* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
1589 if (pu->moh_trys < 3 && !pu->chan->generatordata) {
1590 ast_log(LOG_DEBUG, "MOH on parked call stopped by outside source. Restarting.\n");
1591 ast_moh_start(pu->chan, NULL);
1594 goto std; /* XXX Ick: jumping into an else statement??? XXX */
1598 if (x >= AST_MAX_FDS) {
1599 std: for (x=0; x<AST_MAX_FDS; x++) {
1600 /* Keep this one for next one */
1601 if (pu->chan->fds[x] > -1) {
1602 FD_SET(pu->chan->fds[x], &nrfds);
1603 FD_SET(pu->chan->fds[x], &nefds);
1604 if (pu->chan->fds[x] > max)
1605 max = pu->chan->fds[x];
1608 /* Keep track of our longest wait */
1609 if ((tms < ms) || (ms < 0))
1616 ast_mutex_unlock(&parking_lock);
1619 tv = ast_samp2tv(ms, 1000);
1620 /* Wait for something to happen */
1621 ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL);
1622 pthread_testcancel();
1624 return NULL; /* Never reached */
1627 static int park_call_exec(struct ast_channel *chan, void *data)
1629 /* Data is unused at the moment but could contain a parking
1630 lot context eventually */
1632 struct localuser *u;
1634 /* Setup the exten/priority to be s/1 since we don't know
1635 where this call should return */
1636 strcpy(chan->exten, "s");
1638 if (chan->_state != AST_STATE_UP)
1639 res = ast_answer(chan);
1641 res = ast_safe_sleep(chan, 1000);
1643 res = ast_park_call(chan, chan, 0, NULL);
1644 LOCAL_USER_REMOVE(u);
1646 res = AST_PBX_KEEPALIVE;
1650 static int park_exec(struct ast_channel *chan, void *data)
1653 struct localuser *u;
1654 struct ast_channel *peer=NULL;
1655 struct parkeduser *pu, *pl=NULL;
1656 char exten[AST_MAX_EXTENSION];
1657 struct ast_context *con;
1660 struct ast_bridge_config config;
1663 ast_log(LOG_WARNING, "Park requires an argument (extension number)\n");
1667 park = atoi((char *)data);
1668 ast_mutex_lock(&parking_lock);
1671 if (pu->parkingnum == park) {
1673 pl->next = pu->next;
1675 parkinglot = pu->next;
1681 ast_mutex_unlock(&parking_lock);
1684 con = ast_context_find(parking_con);
1686 snprintf(exten, sizeof(exten), "%d", pu->parkingnum);
1687 if (ast_context_remove_extension2(con, exten, 1, NULL))
1688 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
1690 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
1692 manager_event(EVENT_FLAG_CALL, "UnParkedCall",
1697 "CallerIDName: %s\r\n"
1698 ,pu->parkingnum, pu->chan->name, chan->name
1699 ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
1700 ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
1705 /* JK02: it helps to answer the channel if not already up */
1706 if (chan->_state != AST_STATE_UP) {
1711 /* Play a courtesy to the source(s) configured to prefix the bridge connecting */
1713 if (!ast_strlen_zero(courtesytone)) {
1714 if (parkedplay == 0) {
1715 if (!ast_streamfile(chan, courtesytone, chan->language)) {
1716 if (ast_waitstream(chan, "") < 0) {
1717 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
1723 ast_indicate(peer, AST_CONTROL_UNHOLD);
1726 ast_indicate(peer, AST_CONTROL_UNHOLD);
1727 if (parkedplay == 2) {
1728 if (!ast_streamfile(chan, courtesytone, chan->language) && !ast_streamfile(peer, courtesytone, chan->language)) {
1729 res = ast_waitstream(chan, "");
1731 res = ast_waitstream(peer, "");
1733 ast_log(LOG_WARNING, "Failed to play courtesy tones!\n");
1738 } else if (parkedplay == 1) {
1739 if (!ast_streamfile(peer, courtesytone, chan->language)) {
1740 if (ast_waitstream(peer, "") < 0) {
1741 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
1750 res = ast_channel_make_compatible(chan, peer);
1752 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
1756 /* This runs sorta backwards, since we give the incoming channel control, as if it
1757 were the person called. */
1758 if (option_verbose > 2)
1759 ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to parked call %d\n", chan->name, park);
1761 memset(&config, 0, sizeof(struct ast_bridge_config));
1762 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
1763 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
1764 config.timelimit = 0;
1765 config.play_warning = 0;
1766 config.warning_freq = 0;
1767 config.warning_sound=NULL;
1768 res = ast_bridge_call(chan, peer, &config);
1770 /* Simulate the PBX hanging up */
1771 if (res != AST_PBX_NO_HANGUP_PEER)
1775 /* XXX Play a message XXX */
1776 dres = ast_streamfile(chan, "pbx-invalidpark", chan->language);
1778 dres = ast_waitstream(chan, "");
1780 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
1783 if (option_verbose > 2)
1784 ast_verbose(VERBOSE_PREFIX_3 "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park);
1787 LOCAL_USER_REMOVE(u);
1791 static int handle_showfeatures(int fd, int argc, char *argv[])
1795 struct ast_call_feature *feature;
1796 char format[] = "%-25s %-7s %-7s\n";
1798 ast_cli(fd, format, "Builtin Feature", "Default", "Current");
1799 ast_cli(fd, format, "---------------", "-------", "-------");
1801 ast_cli(fd, format, "Pickup", "*8", ast_pickup_ext()); /* default hardcoded above, so we'll hardcode it here */
1803 fcount = sizeof(builtin_features) / sizeof(builtin_features[0]);
1805 for (i = 0; i < fcount; i++)
1807 ast_cli(fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
1810 ast_cli(fd, format, "Dynamic Feature", "Default", "Current");
1811 ast_cli(fd, format, "---------------", "-------", "-------");
1812 if (AST_LIST_EMPTY(&feature_list)) {
1813 ast_cli(fd, "(none)\n");
1816 AST_LIST_LOCK(&feature_list);
1817 AST_LIST_TRAVERSE(&feature_list, feature, feature_entry) {
1818 ast_cli(fd, format, feature->sname, "no def", feature->exten);
1820 AST_LIST_UNLOCK(&feature_list);
1822 ast_cli(fd, "\nCall parking\n");
1823 ast_cli(fd, "------------\n");
1824 ast_cli(fd,"%-20s: %s\n", "Parking extension", parking_ext);
1825 ast_cli(fd,"%-20s: %s\n", "Parking context", parking_con);
1826 ast_cli(fd,"%-20s: %d-%d\n", "Parked call extensions", parking_start, parking_stop);
1829 return RESULT_SUCCESS;
1832 static char showfeatures_help[] =
1833 "Usage: show features\n"
1834 " Lists currently configured features.\n";
1836 static struct ast_cli_entry showfeatures =
1837 { { "show", "features", NULL }, handle_showfeatures, "Lists configured features", showfeatures_help };
1839 static int handle_parkedcalls(int fd, int argc, char *argv[])
1841 struct parkeduser *cur;
1844 ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
1845 , "Context", "Extension", "Pri", "Timeout");
1847 ast_mutex_lock(&parking_lock);
1849 for (cur = parkinglot; cur; cur = cur->next) {
1850 ast_cli(fd, "%4d %25s (%-15s %-12s %-4d) %6lds\n"
1851 ,cur->parkingnum, cur->chan->name, cur->context, cur->exten
1852 ,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL));
1856 ast_cli(fd, "%d parked call%s.\n", numparked, (numparked != 1) ? "s" : "");
1858 ast_mutex_unlock(&parking_lock);
1860 return RESULT_SUCCESS;
1863 static char showparked_help[] =
1864 "Usage: show parkedcalls\n"
1865 " Lists currently parked calls.\n";
1867 static struct ast_cli_entry showparked =
1868 { { "show", "parkedcalls", NULL }, handle_parkedcalls, "Lists parked calls", showparked_help };
1870 /*! \brief Dump lot status */
1871 static int manager_parking_status( struct mansession *s, struct message *m )
1873 struct parkeduser *cur;
1874 char *id = astman_get_header(m,"ActionID");
1875 char idText[256] = "";
1877 if (!ast_strlen_zero(id))
1878 snprintf(idText,256,"ActionID: %s\r\n",id);
1880 astman_send_ack(s, m, "Parked calls will follow");
1882 ast_mutex_lock(&parking_lock);
1886 astman_append(s, "Event: ParkedCall\r\n"
1892 "CallerIDName: %s\r\n"
1895 ,cur->parkingnum, cur->chan->name, cur->peername
1896 ,(long)cur->start.tv_sec + (long)(cur->parkingtime/1000) - (long)time(NULL)
1897 ,(cur->chan->cid.cid_num ? cur->chan->cid.cid_num : "")
1898 ,(cur->chan->cid.cid_name ? cur->chan->cid.cid_name : "")
1905 "Event: ParkedCallsComplete\r\n"
1909 ast_mutex_unlock(&parking_lock);
1911 return RESULT_SUCCESS;
1914 static char mandescr_park[] =
1915 "Description: Park a channel.\n"
1916 "Variables: (Names marked with * are required)\n"
1917 " *Channel: Channel name to park\n"
1918 " *Channel2: Channel to announce park info to (and return to if timeout)\n"
1919 " Timeout: Number of milliseconds to wait before callback.\n";
1921 static int manager_park(struct mansession *s, struct message *m)
1923 char *channel = astman_get_header(m, "Channel");
1924 char *channel2 = astman_get_header(m, "Channel2");
1925 char *timeout = astman_get_header(m, "Timeout");
1930 struct ast_channel *ch1, *ch2;
1932 if (ast_strlen_zero(channel)) {
1933 astman_send_error(s, m, "Channel not specified");
1937 if (ast_strlen_zero(channel2)) {
1938 astman_send_error(s, m, "Channel2 not specified");
1942 ch1 = ast_get_channel_by_name_locked(channel);
1944 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel);
1945 astman_send_error(s, m, buf);
1949 ch2 = ast_get_channel_by_name_locked(channel2);
1951 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2);
1952 astman_send_error(s, m, buf);
1953 ast_mutex_unlock(&ch1->lock);
1957 if (!ast_strlen_zero(timeout)) {
1958 sscanf(timeout, "%d", &to);
1961 res = ast_masq_park_call(ch1, ch2, to, &parkExt);
1963 ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT);
1964 astman_send_ack(s, m, "Park successful");
1966 astman_send_error(s, m, "Park failure");
1969 ast_mutex_unlock(&ch1->lock);
1970 ast_mutex_unlock(&ch2->lock);
1976 int ast_pickup_call(struct ast_channel *chan)
1978 struct ast_channel *cur = NULL;
1981 while ( (cur = ast_channel_walk_locked(cur)) != NULL) {
1984 (chan->pickupgroup & cur->callgroup) &&
1985 ((cur->_state == AST_STATE_RINGING) ||
1986 (cur->_state == AST_STATE_RING))) {
1989 ast_mutex_unlock(&cur->lock);
1993 ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
1994 res = ast_answer(chan);
1996 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
1997 res = ast_queue_control(chan, AST_CONTROL_ANSWER);
1999 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
2000 res = ast_channel_masquerade(cur, chan);
2002 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name); /* Done */
2003 ast_mutex_unlock(&cur->lock);
2006 ast_log(LOG_DEBUG, "No call pickup possible...\n");
2011 static int load_config(void)
2013 int start = 0, end = 0;
2014 struct ast_context *con = NULL;
2015 struct ast_config *cfg = NULL;
2016 struct ast_variable *var = NULL;
2017 char old_parking_ext[AST_MAX_EXTENSION];
2018 char old_parking_con[AST_MAX_EXTENSION] = "";
2020 if (!ast_strlen_zero(parking_con)) {
2021 strcpy(old_parking_ext, parking_ext);
2022 strcpy(old_parking_con, parking_con);
2025 /* Reset to defaults */
2026 strcpy(parking_con, "parkedcalls");
2027 strcpy(parking_con_dial, "park-dial");
2028 strcpy(parking_ext, "700");
2029 strcpy(pickup_ext, "*8");
2030 courtesytone[0] = '\0';
2031 strcpy(xfersound, "beep");
2032 strcpy(xferfailsound, "pbx-invalid");
2033 parking_start = 701;
2038 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
2039 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
2041 cfg = ast_config_load("features.conf");
2043 for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
2044 if (!strcasecmp(var->name, "parkext")) {
2045 ast_copy_string(parking_ext, var->value, sizeof(parking_ext));
2046 } else if (!strcasecmp(var->name, "context")) {
2047 ast_copy_string(parking_con, var->value, sizeof(parking_con));
2048 } else if (!strcasecmp(var->name, "parkingtime")) {
2049 if ((sscanf(var->value, "%d", &parkingtime) != 1) || (parkingtime < 1)) {
2050 ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value);
2051 parkingtime = DEFAULT_PARK_TIME;
2053 parkingtime = parkingtime * 1000;
2054 } else if (!strcasecmp(var->name, "parkpos")) {
2055 if (sscanf(var->value, "%d-%d", &start, &end) != 2) {
2056 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);
2058 parking_start = start;
2061 } else if (!strcasecmp(var->name, "findslot")) {
2062 parkfindnext = (!strcasecmp(var->value, "next"));
2063 } else if (!strcasecmp(var->name, "adsipark")) {
2064 adsipark = ast_true(var->value);
2065 } else if (!strcasecmp(var->name, "transferdigittimeout")) {
2066 if ((sscanf(var->value, "%d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) {
2067 ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value);
2068 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
2070 transferdigittimeout = transferdigittimeout * 1000;
2071 } else if (!strcasecmp(var->name, "featuredigittimeout")) {
2072 if ((sscanf(var->value, "%d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) {
2073 ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value);
2074 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
2076 } else if (!strcasecmp(var->name, "courtesytone")) {
2077 ast_copy_string(courtesytone, var->value, sizeof(courtesytone));
2078 } else if (!strcasecmp(var->name, "parkedplay")) {
2079 if (!strcasecmp(var->value, "both"))
2081 else if (!strcasecmp(var->value, "parked"))
2085 } else if (!strcasecmp(var->name, "xfersound")) {
2086 ast_copy_string(xfersound, var->value, sizeof(xfersound));
2087 } else if (!strcasecmp(var->name, "xferfailsound")) {
2088 ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound));
2089 } else if (!strcasecmp(var->name, "pickupexten")) {
2090 ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext));
2095 for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) {
2096 if (remap_feature(var->name, var->value))
2097 ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name);
2100 /* Map a key combination to an application*/
2101 ast_unregister_features();
2102 for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) {
2103 char *tmp_val = ast_strdup(var->value);
2104 char *exten, *party=NULL, *app=NULL, *app_args=NULL;
2107 /* XXX No memory. We should probably break, but at least we do not
2108 * insist on this entry or we could be stuck in an
2114 /* strsep() sets the argument to NULL if match not found, and it
2115 * is safe to use it with a NULL argument, so we don't check
2118 exten = strsep(&tmp_val,",");
2119 party = strsep(&tmp_val,",");
2120 app = strsep(&tmp_val,",");
2121 app_args = strsep(&tmp_val,",");
2123 /* XXX var_name or app_args ? */
2124 if (ast_strlen_zero(app) || ast_strlen_zero(exten) || ast_strlen_zero(party) || ast_strlen_zero(var->name)) {
2125 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);
2131 struct ast_call_feature *feature;
2134 if (!(feature = find_feature(var->name))) {
2137 if (!(feature = ast_calloc(1, sizeof(*feature)))) {
2143 ast_copy_string(feature->sname,var->name,FEATURE_SNAME_LEN);
2144 ast_copy_string(feature->app,app,FEATURE_APP_LEN);
2145 ast_copy_string(feature->exten, exten,FEATURE_EXTEN_LEN);
2149 ast_copy_string(feature->app_args,app_args,FEATURE_APP_ARGS_LEN);
2151 ast_copy_string(feature->exten, exten,sizeof(feature->exten));
2152 feature->operation=feature_exec_app;
2153 ast_set_flag(feature,AST_FEATURE_FLAG_NEEDSDTMF);
2155 if (!strcasecmp(party,"caller"))
2156 ast_set_flag(feature,AST_FEATURE_FLAG_CALLER);
2157 else if (!strcasecmp(party, "callee"))
2158 ast_set_flag(feature,AST_FEATURE_FLAG_CALLEE);
2160 ast_log(LOG_NOTICE, "Invalid party specification for feature '%s', must be caller, or callee\n", var->name);
2164 ast_register_feature(feature);
2166 if (option_verbose >=1)
2167 ast_verbose(VERBOSE_PREFIX_2 "Mapping Feature '%s' to app '%s' with code '%s'\n", var->name, app, exten);
2171 ast_config_destroy(cfg);
2173 /* Remove the old parking extension */
2174 if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con))) {
2175 ast_context_remove_extension2(con, old_parking_ext, 1, registrar);
2176 ast_log(LOG_DEBUG, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con);
2179 if (!(con = ast_context_find(parking_con)) && !(con = ast_context_create(NULL, parking_con, registrar))) {
2180 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
2183 return ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, strdup(""), FREE, registrar);
2186 static int reload(void *mod)
2188 return load_config();
2191 static int load_module(void *mod)
2196 AST_LIST_HEAD_INIT(&feature_list);
2197 memset(parking_ext, 0, sizeof(parking_ext));
2198 memset(parking_con, 0, sizeof(parking_con));
2200 if ((res = load_config()))
2202 ast_cli_register(&showparked);
2203 ast_cli_register(&showfeatures);
2204 ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
2205 res = ast_register_application(parkedcall, park_exec, synopsis, descrip);
2207 res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2);
2209 ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls" );
2210 ast_manager_register2("Park", EVENT_FLAG_CALL, manager_park,
2211 "Park a channel", mandescr_park);
2217 static int unload_module(void *mod)
2219 STANDARD_HANGUP_LOCALUSERS;
2221 ast_manager_unregister("ParkedCalls");
2222 ast_manager_unregister("Park");
2223 ast_cli_unregister(&showfeatures);
2224 ast_cli_unregister(&showparked);
2225 ast_unregister_application(parkcall);
2226 return ast_unregister_application(parkedcall);
2229 static const char *description(void)
2231 return "Call Features Resource";
2234 static const char *key(void)
2236 return ASTERISK_GPL_KEY;
2239 STD_MOD(MOD_0 | NO_UNLOAD, reload, NULL, NULL);