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>
28 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
38 #include <sys/signal.h>
39 #include <netinet/in.h>
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/devicestate.h"
60 #include "asterisk/monitor.h"
62 #define DEFAULT_PARK_TIME 45000
63 #define DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000
64 #define DEFAULT_FEATURE_DIGIT_TIMEOUT 500
65 #define DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER 15000
66 #define DEFAULT_ATXFER_DROP_CALL 0
67 #define DEFAULT_ATXFER_LOOP_DELAY 10000
68 #define DEFAULT_ATXFER_CALLBACK_RETRIES 2
70 #define AST_MAX_WATCHERS 256
73 AST_FEATURE_FLAG_NEEDSDTMF = (1 << 0),
74 AST_FEATURE_FLAG_ONPEER = (1 << 1),
75 AST_FEATURE_FLAG_ONSELF = (1 << 2),
76 AST_FEATURE_FLAG_BYCALLEE = (1 << 3),
77 AST_FEATURE_FLAG_BYCALLER = (1 << 4),
78 AST_FEATURE_FLAG_BYBOTH = (3 << 3),
81 struct feature_group_exten {
82 AST_LIST_ENTRY(feature_group_exten) entry;
83 AST_DECLARE_STRING_FIELDS(
84 AST_STRING_FIELD(exten);
86 struct ast_call_feature *feature;
89 struct feature_group {
90 AST_LIST_ENTRY(feature_group) entry;
91 AST_DECLARE_STRING_FIELDS(
92 AST_STRING_FIELD(gname);
94 AST_LIST_HEAD_NOLOCK(, feature_group_exten) features;
97 static AST_RWLIST_HEAD_STATIC(feature_groups, feature_group);
99 static char *parkedcall = "ParkedCall";
101 static int parkaddhints = 0; /*!< Add parking hints automatically */
102 static int parkedcalltransfers = 0; /*!< Enable DTMF based transfers on bridge when picking up parked calls */
103 static int parkedcallreparking = 0; /*!< Enable DTMF based parking on bridge when picking up parked calls */
104 static int parkingtime = DEFAULT_PARK_TIME; /*!< No more than 45 seconds parked before you do something with them */
105 static char parking_con[AST_MAX_EXTENSION]; /*!< Context for which parking is made accessible */
106 static char parking_con_dial[AST_MAX_EXTENSION]; /*!< Context for dialback for parking (KLUDGE) */
107 static char parking_ext[AST_MAX_EXTENSION]; /*!< Extension you type to park the call */
108 static char pickup_ext[AST_MAX_EXTENSION]; /*!< Call pickup extension */
109 static char parkmohclass[MAX_MUSICCLASS]; /*!< Music class used for parking */
110 static int parking_start; /*!< First available extension for parking */
111 static int parking_stop; /*!< Last available extension for parking */
113 static char courtesytone[256]; /*!< Courtesy tone */
114 static int parkedplay = 0; /*!< Who to play the courtesy tone to */
115 static char xfersound[256]; /*!< Call transfer sound */
116 static char xferfailsound[256]; /*!< Call transfer failure sound */
118 static int parking_offset;
119 static int parkfindnext;
123 static int transferdigittimeout;
124 static int featuredigittimeout;
125 static int comebacktoorigin = 1;
127 static int atxfernoanswertimeout;
128 static unsigned int atxferdropcall;
129 static unsigned int atxferloopdelay;
130 static unsigned int atxfercallbackretries;
132 static char *registrar = "res_features"; /*!< Registrar for operations */
134 /* module and CLI command definitions */
135 static char *synopsis = "Answer a parked call";
137 static char *descrip = "ParkedCall(exten):"
138 "Used to connect to a parked call. This application is always\n"
139 "registered internally and does not need to be explicitly added\n"
140 "into the dialplan, although you should include the 'parkedcalls'\n"
143 static char *parkcall = "Park";
145 static char *synopsis2 = "Park yourself";
147 static char *descrip2 = "Park():"
148 "Used to park yourself (typically in combination with a supervised\n"
149 "transfer to know the parking space). This application is always\n"
150 "registered internally and does not need to be explicitly added\n"
151 "into the dialplan, although you should include the 'parkedcalls'\n"
152 "context (or the context specified in features.conf).\n\n"
153 "If you set the PARKINGEXTEN variable to an extension in your\n"
154 "parking context, park() will park the call on that extension, unless\n"
155 "it already exists. In that case, execution will continue at next\n"
158 static struct ast_app *monitor_app = NULL;
159 static int monitor_ok = 1;
162 struct ast_channel *chan; /*!< Parking channel */
163 struct timeval start; /*!< Time the parking started */
164 int parkingnum; /*!< Parking lot */
165 char parkingexten[AST_MAX_EXTENSION]; /*!< If set beforehand, parking extension used for this call */
166 char context[AST_MAX_CONTEXT]; /*!< Where to go if our parking time expires */
167 char exten[AST_MAX_EXTENSION];
169 int parkingtime; /*!< Maximum length in parking lot before return */
172 unsigned char moh_trys;
173 AST_LIST_ENTRY(parkeduser) list;
176 static AST_LIST_HEAD_STATIC(parkinglot, parkeduser);
178 static pthread_t parking_thread;
180 const char *ast_parking_ext(void)
185 const char *ast_pickup_ext(void)
190 struct ast_bridge_thread_obj
192 struct ast_bridge_config bconfig;
193 struct ast_channel *chan;
194 struct ast_channel *peer;
195 unsigned int return_to_pbx:1;
201 * \brief store context, extension and priority
202 * \param chan, context, ext, pri
204 static void set_c_e_p(struct ast_channel *chan, const char *context, const char *ext, int pri)
206 ast_copy_string(chan->context, context, sizeof(chan->context));
207 ast_copy_string(chan->exten, ext, sizeof(chan->exten));
208 chan->priority = pri;
212 * \brief Check goto on transfer
214 * Check if channel has 'GOTO_ON_BLINDXFR' set, if not exit.
215 * When found make sure the types are compatible. Check if channel is valid
216 * if so start the new channel else hangup the call.
218 static void check_goto_on_transfer(struct ast_channel *chan)
220 struct ast_channel *xferchan;
221 const char *val = pbx_builtin_getvar_helper(chan, "GOTO_ON_BLINDXFR");
222 char *x, *goto_on_transfer;
225 if (ast_strlen_zero(val))
228 goto_on_transfer = ast_strdupa(val);
230 if (!(xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, chan->name)))
233 for (x = goto_on_transfer; x && *x; x++) {
237 /* Make formats okay */
238 xferchan->readformat = chan->readformat;
239 xferchan->writeformat = chan->writeformat;
240 ast_channel_masquerade(xferchan, chan);
241 ast_parseable_goto(xferchan, goto_on_transfer);
242 xferchan->_state = AST_STATE_UP;
243 ast_clear_flag(xferchan, AST_FLAGS_ALL);
244 xferchan->_softhangup = 0;
245 if ((f = ast_read(xferchan))) {
248 ast_pbx_start(xferchan);
250 ast_hangup(xferchan);
254 static struct ast_channel *ast_feature_request_and_dial(struct ast_channel *caller, struct ast_channel *transferee, const char *type, int format, void *data, int timeout, int *outstate, const char *cid_num, const char *cid_name, int igncallerstate);
257 * \brief bridge the call
258 * \param data thread bridge
259 * Set Last Data for respective channels, reset cdr for channels
260 * bridge call, check if we're going back to dialplan
261 * if not hangup both legs of the call
263 static void *ast_bridge_call_thread(void *data)
265 struct ast_bridge_thread_obj *tobj = data;
268 tobj->chan->appl = !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge";
269 tobj->chan->data = tobj->peer->name;
270 tobj->peer->appl = !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge";
271 tobj->peer->data = tobj->chan->name;
273 if (tobj->chan->cdr) {
274 ast_cdr_reset(tobj->chan->cdr, NULL);
275 ast_cdr_setdestchan(tobj->chan->cdr, tobj->peer->name);
277 if (tobj->peer->cdr) {
278 ast_cdr_reset(tobj->peer->cdr, NULL);
279 ast_cdr_setdestchan(tobj->peer->cdr, tobj->chan->name);
282 ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig);
284 if (tobj->return_to_pbx) {
285 if (!ast_check_hangup(tobj->peer)) {
286 ast_log(LOG_VERBOSE, "putting peer %s into PBX again\n", tobj->peer->name);
287 res = ast_pbx_start(tobj->peer);
288 if (res != AST_PBX_SUCCESS)
289 ast_log(LOG_WARNING, "FAILED continuing PBX on peer %s\n", tobj->peer->name);
291 ast_hangup(tobj->peer);
292 if (!ast_check_hangup(tobj->chan)) {
293 ast_log(LOG_VERBOSE, "putting chan %s into PBX again\n", tobj->chan->name);
294 res = ast_pbx_start(tobj->chan);
295 if (res != AST_PBX_SUCCESS)
296 ast_log(LOG_WARNING, "FAILED continuing PBX on chan %s\n", tobj->chan->name);
298 ast_hangup(tobj->chan);
300 ast_hangup(tobj->chan);
301 ast_hangup(tobj->peer);
310 * \brief create thread for the parked call
312 * Create thread and attributes, call ast_bridge_call_thread
314 static void ast_bridge_call_thread_launch(void *data)
318 struct sched_param sched;
320 pthread_attr_init(&attr);
321 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
322 ast_pthread_create(&thread, &attr,ast_bridge_call_thread, data);
323 pthread_attr_destroy(&attr);
324 memset(&sched, 0, sizeof(sched));
325 pthread_setschedparam(thread, SCHED_RR, &sched);
329 * \brief Announce call parking by ADSI
331 * \param parkingexten
332 * Create message to show for ADSI, display message.
333 * \retval 0 on success.
334 * \retval -1 on failure.
336 static int adsi_announce_park(struct ast_channel *chan, char *parkingexten)
339 int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT};
341 char *message[5] = {NULL, NULL, NULL, NULL, NULL};
343 snprintf(tmp, sizeof(tmp), "Parked on %s", parkingexten);
345 res = ast_adsi_load_session(chan, NULL, 0, 1);
348 return ast_adsi_print(chan, message, justify, 1);
351 /*! \brief Notify metermaids that we've changed an extension */
352 static void notify_metermaids(const char *exten, char *context, enum ast_device_state state)
354 ast_debug(4, "Notification of state change to metermaids %s@%s\n to state '%s'",
355 exten, context, devstate2str(state));
357 ast_devstate_changed(state, "park:%s@%s", exten, context);
360 /*! \brief metermaids callback from devicestate.c */
361 static enum ast_device_state metermaidstate(const char *data)
366 context = ast_strdupa(data);
368 exten = strsep(&context, "@");
370 return AST_DEVICE_INVALID;
372 ast_debug(4, "Checking state of exten %s in context %s\n", exten, context);
374 if (!ast_exists_extension(NULL, context, exten, 1, NULL))
375 return AST_DEVICE_NOT_INUSE;
377 return AST_DEVICE_INUSE;
381 int ast_park_call(struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout)
383 struct parkeduser *pu, *cur;
384 int i, x = -1, parking_range;
385 struct ast_context *con;
386 const char *parkingexten;
388 /* Allocate memory for parking data */
389 if (!(pu = ast_calloc(1, sizeof(*pu))))
392 /* Lock parking lot */
393 AST_LIST_LOCK(&parkinglot);
394 /* Check for channel variable PARKINGEXTEN */
395 parkingexten = pbx_builtin_getvar_helper(chan, "PARKINGEXTEN");
396 if (!ast_strlen_zero(parkingexten)) {
397 if (ast_exists_extension(NULL, parking_con, parkingexten, 1, NULL)) {
398 AST_LIST_UNLOCK(&parkinglot);
400 ast_log(LOG_WARNING, "Requested parking extension already exists: %s@%s\n", parkingexten, parking_con);
401 return -1; /* We failed to park this call, plain and simple so we need to error out */
403 ast_copy_string(pu->parkingexten, parkingexten, sizeof(pu->parkingexten));
404 x = atoi(parkingexten);
406 /* Select parking space within range */
407 parking_range = parking_stop - parking_start+1;
408 for (i = 0; i < parking_range; i++) {
409 x = (i + parking_offset) % parking_range + parking_start;
410 AST_LIST_TRAVERSE(&parkinglot, cur, list) {
411 if (cur->parkingnum == x)
418 if (!(i < parking_range)) {
419 ast_log(LOG_WARNING, "No more parking spaces\n");
421 AST_LIST_UNLOCK(&parkinglot);
424 /* Set pointer for next parking */
426 parking_offset = x - parking_start + 1;
429 chan->appl = "Parked Call";
434 /* Put the parked channel on hold if we have two different channels */
436 ast_indicate_data(pu->chan, AST_CONTROL_HOLD,
437 S_OR(parkmohclass, NULL),
438 !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
441 pu->start = ast_tvnow();
443 pu->parkingtime = (timeout > 0) ? timeout : parkingtime;
448 ast_copy_string(pu->peername, peer->name, sizeof(pu->peername));
450 /* Remember what had been dialed, so that if the parking
451 expires, we try to come back to the same place */
452 ast_copy_string(pu->context, S_OR(chan->macrocontext, chan->context), sizeof(pu->context));
453 ast_copy_string(pu->exten, S_OR(chan->macroexten, chan->exten), sizeof(pu->exten));
454 pu->priority = chan->macropriority ? chan->macropriority : chan->priority;
455 AST_LIST_INSERT_TAIL(&parkinglot, pu, list);
457 /* If parking a channel directly, don't quiet yet get parking running on it */
460 AST_LIST_UNLOCK(&parkinglot);
461 /* Wake up the (presumably select()ing) thread */
462 pthread_kill(parking_thread, SIGURG);
463 ast_verb(2, "Parked %s on %d@%s. Will timeout back to extension [%s] %s, %d in %d seconds\n", pu->chan->name, pu->parkingnum, parking_con, pu->context, pu->exten, pu->priority, (pu->parkingtime/1000));
465 if (pu->parkingnum != -1)
466 snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", x);
467 manager_event(EVENT_FLAG_CALL, "ParkedCall",
472 "CallerIDNum: %s\r\n"
473 "CallerIDName: %s\r\n",
474 pu->parkingexten, pu->chan->name, peer ? peer->name : "",
475 (long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL),
476 S_OR(pu->chan->cid.cid_num, "<unknown>"),
477 S_OR(pu->chan->cid.cid_name, "<unknown>")
480 if (peer && adsipark && ast_adsi_available(peer)) {
481 adsi_announce_park(peer, pu->parkingexten); /* Only supports parking numbers */
482 ast_adsi_unload_session(peer);
485 con = ast_context_find(parking_con);
487 con = ast_context_create(NULL, parking_con, registrar);
488 if (!con) /* Still no context? Bad */
489 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
490 /* Tell the peer channel the number of the parking space */
491 if (peer && pu->parkingnum != -1) /* Only say number if it's a number */
492 ast_say_digits(peer, pu->parkingnum, "", peer->language);
494 if (!ast_add_extension2(con, 1, pu->parkingexten, 1, NULL, NULL, parkedcall, ast_strdup(pu->parkingexten), ast_free, registrar))
495 notify_metermaids(pu->parkingexten, parking_con, AST_DEVICE_INUSE);
497 if (pu->notquiteyet) {
498 /* Wake up parking thread if we're really done */
499 ast_indicate_data(pu->chan, AST_CONTROL_HOLD,
500 S_OR(parkmohclass, NULL),
501 !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
503 pthread_kill(parking_thread, SIGURG);
508 /* Park call via masquraded channel */
509 int ast_masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout)
511 struct ast_channel *chan;
514 /* Make a new, fake channel that we'll use to masquerade in the real one */
515 if (!(chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, rchan->accountcode, rchan->exten, rchan->context, rchan->amaflags, "Parked/%s",rchan->name))) {
516 ast_log(LOG_WARNING, "Unable to create parked channel\n");
520 /* Make formats okay */
521 chan->readformat = rchan->readformat;
522 chan->writeformat = rchan->writeformat;
523 ast_channel_masquerade(chan, rchan);
525 /* Setup the extensions and such */
526 set_c_e_p(chan, rchan->context, rchan->exten, rchan->priority);
528 /* Make the masq execute */
533 ast_park_call(chan, peer, timeout, extout);
538 #define FEATURE_RETURN_HANGUP -1
539 #define FEATURE_RETURN_SUCCESSBREAK 0
540 #define FEATURE_RETURN_PBX_KEEPALIVE AST_PBX_KEEPALIVE
541 #define FEATURE_RETURN_NO_HANGUP_PEER AST_PBX_NO_HANGUP_PEER
542 #define FEATURE_RETURN_PASSDIGITS 21
543 #define FEATURE_RETURN_STOREDIGITS 22
544 #define FEATURE_RETURN_SUCCESS 23
546 #define FEATURE_SENSE_CHAN (1 << 0)
547 #define FEATURE_SENSE_PEER (1 << 1)
550 * \brief set caller and callee according to the direction
551 * \param caller, callee, peer, chan, sense
552 * Detect who triggered feature and set callee/caller variables accordingly
554 static void set_peers(struct ast_channel **caller, struct ast_channel **callee,
555 struct ast_channel *peer, struct ast_channel *chan, int sense)
557 if (sense == FEATURE_SENSE_PEER) {
567 * \brief support routing for one touch call parking
568 * \param chan channel parking call
569 * \param peer channel to be parked
570 * \param config unsed
572 * \param sense feature options
573 * Setup channel, set return exten,priority to 's,1'
574 * answer chan, sleep chan, park call
576 static int builtin_parkcall(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
578 struct ast_channel *parker;
579 struct ast_channel *parkee;
581 struct ast_module_user *u;
583 u = ast_module_user_add(chan);
585 set_peers(&parker, &parkee, peer, chan, sense);
586 /* Setup the exten/priority to be s/1 since we don't know
587 where this call should return */
588 strcpy(chan->exten, "s");
590 if (chan->_state != AST_STATE_UP)
591 res = ast_answer(chan);
593 res = ast_safe_sleep(chan, 1000);
595 res = ast_park_call(parkee, parker, 0, NULL);
597 ast_module_user_remove(u);
600 if (sense == FEATURE_SENSE_CHAN)
601 res = AST_PBX_NO_HANGUP_PEER;
603 res = AST_PBX_KEEPALIVE;
610 * \brief Monitor a channel by DTMF
611 * \param chan channel requesting monitor
612 * \param peer channel to be monitored
616 * Check monitor app enabled, setup channels, both caller/callee chans not null
617 * get TOUCH_MONITOR variable for filename if exists, exec monitor app.
618 * \retval FEATURE_RETURN_SUCCESS on success.
619 * \retval -1 on error.
621 static int builtin_automonitor(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
623 char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL;
626 struct ast_channel *caller_chan, *callee_chan;
629 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
633 if (!monitor_app && !(monitor_app = pbx_findapp("Monitor"))) {
635 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
639 set_peers(&caller_chan, &callee_chan, peer, chan, sense);
641 if (!ast_strlen_zero(courtesytone)) {
642 if (ast_autoservice_start(callee_chan))
644 if (ast_stream_and_wait(caller_chan, courtesytone, "")) {
645 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
646 ast_autoservice_stop(callee_chan);
649 if (ast_autoservice_stop(callee_chan))
653 if (callee_chan->monitor) {
654 ast_verb(4, "User hit '%s' to stop recording call.\n", code);
655 ast_monitor_stop(callee_chan, 1);
656 return FEATURE_RETURN_SUCCESS;
659 if (caller_chan && callee_chan) {
660 const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT");
661 const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR");
664 touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT");
667 touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR");
670 len = strlen(touch_monitor) + 50;
672 touch_filename = alloca(len);
673 snprintf(touch_filename, len, "auto-%ld-%s", (long)time(NULL), touch_monitor);
674 snprintf(args, len, "%s|%s|m", (touch_format) ? touch_format : "wav", touch_filename);
676 caller_chan_id = ast_strdupa(S_OR(caller_chan->cid.cid_num, caller_chan->name));
677 callee_chan_id = ast_strdupa(S_OR(callee_chan->cid.cid_num, callee_chan->name));
678 len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50;
680 touch_filename = alloca(len);
681 snprintf(touch_filename, len, "auto-%ld-%s-%s", (long)time(NULL), caller_chan_id, callee_chan_id);
682 snprintf(args, len, "%s|%s|m", S_OR(touch_format, "wav"), touch_filename);
685 for(x = 0; x < strlen(args); x++) {
690 ast_verb(4, "User hit '%s' to record call. filename: %s\n", code, args);
692 pbx_exec(callee_chan, monitor_app, args);
693 pbx_builtin_setvar_helper(callee_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
694 pbx_builtin_setvar_helper(caller_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
696 return FEATURE_RETURN_SUCCESS;
699 ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n");
703 static int builtin_disconnect(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
705 ast_verb(4, "User hit '%s' to disconnect call.\n", code);
706 return FEATURE_RETURN_HANGUP;
709 static int finishup(struct ast_channel *chan)
711 ast_indicate(chan, AST_CONTROL_UNHOLD);
713 return ast_autoservice_stop(chan);
717 * \brief Find the context for the transfer
720 * Grab the TRANSFER_CONTEXT, if fails try grabbing macrocontext.
721 * \return a context string
723 static const char *real_ctx(struct ast_channel *transferer, struct ast_channel *transferee)
725 const char *s = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT");
726 if (ast_strlen_zero(s))
727 s = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT");
728 if (ast_strlen_zero(s)) /* Use the non-macro context to transfer the call XXX ? */
729 s = transferer->macrocontext;
730 if (ast_strlen_zero(s))
731 s = transferer->context;
736 * \brief Blind transfer user to another extension
737 * \param chan channel initiated blind transfer
738 * \param peer channel to be transfered
742 * Place peer on hold, check if tranfered to parkinglot extension,
743 * otherwise check extension exists and transfer caller.
744 * \retval FEATURE_RETURN_SUCCESS.
745 * \retval -1 on failure.
747 static int builtin_blindtransfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
749 struct ast_channel *transferer;
750 struct ast_channel *transferee;
751 const char *transferer_real_context;
755 set_peers(&transferer, &transferee, peer, chan, sense);
756 transferer_real_context = real_ctx(transferer, transferee);
757 /* Start autoservice on chan while we talk to the originator */
758 ast_autoservice_start(transferee);
759 ast_indicate(transferee, AST_CONTROL_HOLD);
761 memset(xferto, 0, sizeof(xferto));
764 res = ast_stream_and_wait(transferer, "pbx-transfer", AST_DIGIT_ANY);
766 finishup(transferee);
767 return -1; /* error ? */
769 if (res > 0) /* If they've typed a digit already, handle it */
770 xferto[0] = (char) res;
772 ast_stopstream(transferer);
773 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
774 if (res < 0) { /* hangup, would be 0 for invalid and 1 for valid */
775 finishup(transferee);
778 if (!strcmp(xferto, ast_parking_ext())) {
779 res = finishup(transferee);
782 else if (!ast_park_call(transferee, transferer, 0, NULL)) { /* success */
783 /* We return non-zero, but tell the PBX not to hang the channel when
784 the thread dies -- We have to be careful now though. We are responsible for
785 hanging up the channel, else it will never be hung up! */
787 return (transferer == peer) ? AST_PBX_KEEPALIVE : AST_PBX_NO_HANGUP_PEER;
789 ast_log(LOG_WARNING, "Unable to park call %s\n", transferee->name);
791 /*! \todo XXX Maybe we should have another message here instead of invalid extension XXX */
792 } else if (ast_exists_extension(transferee, transferer_real_context, xferto, 1, transferer->cid.cid_num)) {
793 pbx_builtin_setvar_helper(peer, "BLINDTRANSFER", transferee->name);
794 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", peer->name);
795 res=finishup(transferee);
796 if (!transferer->cdr) {
797 transferer->cdr=ast_cdr_alloc();
799 ast_cdr_init(transferer->cdr, transferer); /* initilize our channel's cdr */
800 ast_cdr_start(transferer->cdr);
803 if (transferer->cdr) {
804 ast_cdr_setdestchan(transferer->cdr, transferee->name);
805 ast_cdr_setapp(transferer->cdr, "BLINDTRANSFER","");
808 if (!transferee->pbx)
811 /* Doh! Use our handy async_goto functions */
812 ast_verb(3, "Transferring %s to '%s' (context %s) priority 1\n"
813 ,transferee->name, xferto, transferer_real_context);
814 if (ast_async_goto(transferee, transferer_real_context, xferto, 1))
815 ast_log(LOG_WARNING, "Async goto failed :-(\n");
816 check_goto_on_transfer(transferer);
819 ast_verb(3, "Unable to find extension '%s' in context '%s'\n", xferto, transferer_real_context);
821 if (ast_stream_and_wait(transferer, xferfailsound, AST_DIGIT_ANY) < 0) {
822 finishup(transferee);
825 ast_stopstream(transferer);
826 res = finishup(transferee);
828 ast_verb(2, "Hungup during autoservice stop on '%s'\n", transferee->name);
831 return FEATURE_RETURN_SUCCESS;
835 * \brief make channels compatible
838 * \retval 0 on success.
839 * \retval -1 on failure.
841 static int check_compat(struct ast_channel *c, struct ast_channel *newchan)
843 if (ast_channel_make_compatible(c, newchan) < 0) {
844 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n",
845 c->name, newchan->name);
853 * \brief Attended transfer
859 * Get extension to transfer to, if you cannot generate channel (or find extension)
860 * return to host channel. After called channel answered wait for hangup of transferer,
861 * bridge call between transfer peer (taking them off hold) to attended transfer channel.
862 * \return -1 means what failure/success both?
864 static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
866 struct ast_channel *transferer;
867 struct ast_channel *transferee;
868 const char *transferer_real_context;
869 char xferto[256] = "";
870 char callbackto[256] = "";
873 struct ast_channel *newchan;
874 struct ast_channel *xferchan;
875 struct ast_bridge_thread_obj *tobj;
876 struct ast_bridge_config bconfig;
880 ast_debug(1, "Executing Attended Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense);
881 set_peers(&transferer, &transferee, peer, chan, sense);
882 transferer_real_context = real_ctx(transferer, transferee);
883 /* Start autoservice on chan while we talk to the originator */
884 ast_autoservice_start(transferee);
885 ast_indicate(transferee, AST_CONTROL_HOLD);
888 res = ast_stream_and_wait(transferer, "pbx-transfer", AST_DIGIT_ANY);
890 finishup(transferee);
893 if (res > 0) /* If they've typed a digit already, handle it */
894 xferto[0] = (char) res;
896 /* this is specific of atxfer */
897 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
898 if (res < 0) { /* hangup, would be 0 for invalid and 1 for valid */
899 finishup(transferee);
903 ast_log(LOG_WARNING, "Did not read data.\n");
904 finishup(transferee);
905 if (ast_stream_and_wait(transferer, "beeperr", ""))
907 return FEATURE_RETURN_SUCCESS;
910 /* valid extension, res == 1 */
911 if (!ast_exists_extension(transferer, transferer_real_context, xferto, 1, transferer->cid.cid_num)) {
912 ast_log(LOG_WARNING, "Extension %s does not exist in context %s\n",xferto,transferer_real_context);
913 finishup(transferee);
914 if (ast_stream_and_wait(transferer, "beeperr", ""))
916 return FEATURE_RETURN_SUCCESS;
920 snprintf(xferto + l, sizeof(xferto) - l, "@%s/n", transferer_real_context); /* append context */
921 newchan = ast_feature_request_and_dial(transferer, transferee, "Local", ast_best_codec(transferer->nativeformats),
922 xferto, atxfernoanswertimeout, &outstate, transferer->cid.cid_num, transferer->cid.cid_name, 1);
924 if (!ast_check_hangup(transferer)) {
925 /* Transferer is up - old behaviour */
926 ast_indicate(transferer, -1);
928 finishup(transferee);
929 /* any reason besides user requested cancel and busy triggers the failed sound */
930 if (outstate != AST_CONTROL_UNHOLD && outstate != AST_CONTROL_BUSY &&
931 ast_stream_and_wait(transferer, xferfailsound, ""))
933 if (ast_stream_and_wait(transferer, xfersound, ""))
934 ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
935 return FEATURE_RETURN_SUCCESS;
938 if (check_compat(transferer, newchan))
940 memset(&bconfig,0,sizeof(struct ast_bridge_config));
941 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
942 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
943 res = ast_bridge_call(transferer, newchan, &bconfig);
944 if (ast_check_hangup(newchan) || !ast_check_hangup(transferer)) {
946 if (ast_stream_and_wait(transferer, xfersound, ""))
947 ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
948 finishup(transferee);
949 transferer->_softhangup = 0;
950 return FEATURE_RETURN_SUCCESS;
952 if (check_compat(transferee, newchan))
954 ast_indicate(transferee, AST_CONTROL_UNHOLD);
956 if ((ast_autoservice_stop(transferee) < 0)
957 || (ast_waitfordigit(transferee, 100) < 0)
958 || (ast_waitfordigit(newchan, 100) < 0)
959 || ast_check_hangup(transferee)
960 || ast_check_hangup(newchan)) {
964 xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Transfered/%s", transferee->name);
969 /* Make formats okay */
970 xferchan->readformat = transferee->readformat;
971 xferchan->writeformat = transferee->writeformat;
972 ast_channel_masquerade(xferchan, transferee);
973 ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority);
974 xferchan->_state = AST_STATE_UP;
975 ast_clear_flag(xferchan, AST_FLAGS_ALL);
976 xferchan->_softhangup = 0;
977 if ((f = ast_read(xferchan)))
979 newchan->_state = AST_STATE_UP;
980 ast_clear_flag(newchan, AST_FLAGS_ALL);
981 newchan->_softhangup = 0;
982 if (!(tobj = ast_calloc(1, sizeof(*tobj)))) {
983 ast_hangup(xferchan);
987 tobj->chan = xferchan;
988 tobj->peer = newchan;
989 tobj->bconfig = *config;
991 if (ast_stream_and_wait(newchan, xfersound, ""))
992 ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
993 ast_bridge_call_thread_launch(tobj);
994 return -1; /* XXX meaning the channel is bridged ? */
995 } else if (!ast_check_hangup(transferee)) {
996 /* act as blind transfer */
997 if (ast_autoservice_stop(transferee) < 0) {
1003 unsigned int tries = 0;
1005 /* newchan wasn't created - we should callback to transferer */
1006 if (!ast_exists_extension(transferer, transferer_real_context, transferer->cid.cid_num, 1, transferee->cid.cid_num)) {
1007 ast_log(LOG_WARNING, "Extension %s does not exist in context %s - callback failed\n",transferer->cid.cid_num,transferer_real_context);
1008 if (ast_stream_and_wait(transferee, "beeperr", ""))
1010 return FEATURE_RETURN_SUCCESS;
1012 snprintf(callbackto, sizeof(callbackto), "%s@%s/n", transferer->cid.cid_num, transferer_real_context); /* append context */
1014 newchan = ast_feature_request_and_dial(transferee, NULL, "Local", ast_best_codec(transferee->nativeformats),
1015 callbackto, atxfernoanswertimeout, &outstate, transferee->cid.cid_num, transferee->cid.cid_name, 0);
1016 while (!newchan && !atxferdropcall && tries < atxfercallbackretries) {
1017 /* Trying to transfer again */
1018 ast_autoservice_start(transferee);
1019 ast_indicate(transferee, AST_CONTROL_HOLD);
1021 newchan = ast_feature_request_and_dial(transferer, transferee, "Local", ast_best_codec(transferer->nativeformats),
1022 xferto, atxfernoanswertimeout, &outstate, transferer->cid.cid_num, transferer->cid.cid_name, 1);
1023 if (ast_autoservice_stop(transferee) < 0) {
1024 ast_hangup(newchan);
1028 /* Transfer failed, sleeping */
1029 ast_debug(1, "Sleeping for %d ms before callback.\n", atxferloopdelay);
1030 ast_safe_sleep(transferee, atxferloopdelay);
1031 ast_debug(1, "Trying to callback...\n");
1032 newchan = ast_feature_request_and_dial(transferee, NULL, "Local", ast_best_codec(transferee->nativeformats),
1033 callbackto, atxfernoanswertimeout, &outstate, transferee->cid.cid_num, transferee->cid.cid_name, 0);
1041 /* newchan is up, we should prepare transferee and bridge them */
1042 if (check_compat(transferee, newchan))
1044 ast_indicate(transferee, AST_CONTROL_UNHOLD);
1046 if ((ast_waitfordigit(transferee, 100) < 0)
1047 || (ast_waitfordigit(newchan, 100) < 0)
1048 || ast_check_hangup(transferee)
1049 || ast_check_hangup(newchan)) {
1050 ast_hangup(newchan);
1054 xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Transfered/%s", transferee->name);
1056 ast_hangup(newchan);
1059 /* Make formats okay */
1060 xferchan->readformat = transferee->readformat;
1061 xferchan->writeformat = transferee->writeformat;
1062 ast_channel_masquerade(xferchan, transferee);
1063 ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority);
1064 xferchan->_state = AST_STATE_UP;
1065 ast_clear_flag(xferchan, AST_FLAGS_ALL);
1066 xferchan->_softhangup = 0;
1067 if ((f = ast_read(xferchan)))
1069 newchan->_state = AST_STATE_UP;
1070 ast_clear_flag(newchan, AST_FLAGS_ALL);
1071 newchan->_softhangup = 0;
1072 if (!(tobj = ast_calloc(1, sizeof(*tobj)))) {
1073 ast_hangup(xferchan);
1074 ast_hangup(newchan);
1077 tobj->chan = xferchan;
1078 tobj->peer = newchan;
1079 tobj->bconfig = *config;
1081 if (ast_stream_and_wait(newchan, xfersound, ""))
1082 ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
1083 ast_bridge_call_thread_launch(tobj);
1084 return -1; /* XXX meaning the channel is bridged ? */
1086 /* Transferee hung up */
1087 finishup(transferee);
1092 /* add atxfer and automon as undefined so you can only use em if you configure them */
1093 #define FEATURES_COUNT ARRAY_LEN(builtin_features)
1095 AST_RWLOCK_DEFINE_STATIC(features_lock);
1097 static struct ast_call_feature builtin_features[] =
1099 { AST_FEATURE_REDIRECT, "Blind Transfer", "blindxfer", "#", "#", builtin_blindtransfer, AST_FEATURE_FLAG_NEEDSDTMF, "" },
1100 { AST_FEATURE_REDIRECT, "Attended Transfer", "atxfer", "", "", builtin_atxfer, AST_FEATURE_FLAG_NEEDSDTMF, "" },
1101 { AST_FEATURE_AUTOMON, "One Touch Monitor", "automon", "", "", builtin_automonitor, AST_FEATURE_FLAG_NEEDSDTMF, "" },
1102 { AST_FEATURE_DISCONNECT, "Disconnect Call", "disconnect", "*", "*", builtin_disconnect, AST_FEATURE_FLAG_NEEDSDTMF, "" },
1103 { AST_FEATURE_PARKCALL, "Park Call", "parkcall", "", "", builtin_parkcall, AST_FEATURE_FLAG_NEEDSDTMF, "" },
1107 static AST_LIST_HEAD_STATIC(feature_list,ast_call_feature);
1109 /*! \brief register new feature into feature_list*/
1110 void ast_register_feature(struct ast_call_feature *feature)
1113 ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
1117 AST_LIST_LOCK(&feature_list);
1118 AST_LIST_INSERT_HEAD(&feature_list,feature,feature_entry);
1119 AST_LIST_UNLOCK(&feature_list);
1121 ast_verb(2, "Registered Feature '%s'\n",feature->sname);
1125 * \brief Add new feature group
1126 * \param fgname feature group name
1127 * Add new feature group to the feature group list insert at head of list.
1128 * \note This function MUST be called while feature_groups is locked.
1130 static struct feature_group* register_group(const char *fgname)
1132 struct feature_group *fg;
1135 ast_log(LOG_NOTICE, "You didn't pass a new group name!\n");
1139 if (!(fg = ast_calloc(1, sizeof(*fg))))
1142 if (ast_string_field_init(fg, 128)) {
1147 ast_string_field_set(fg, gname, fgname);
1149 AST_LIST_INSERT_HEAD(&feature_groups, fg, entry);
1151 ast_verb(2, "Registered group '%s'\n", fg->gname);
1157 * \brief Add feature to group
1158 * \param fg feature group
1160 * \param feature feature to add
1161 * Check fg and feature specified, add feature to list
1162 * \note This function MUST be called while feature_groups is locked.
1164 static void register_group_feature(struct feature_group *fg, const char *exten, struct ast_call_feature *feature)
1166 struct feature_group_exten *fge;
1168 if (!(fge = ast_calloc(1, sizeof(*fge))))
1171 if (ast_string_field_init(fge, 128)) {
1177 ast_log(LOG_NOTICE, "You didn't pass a group!\n");
1182 ast_log(LOG_NOTICE, "You didn't pass a feature!\n");
1186 ast_string_field_set(fge, exten, (ast_strlen_zero(exten) ? feature->exten : exten));
1188 fge->feature = feature;
1190 AST_LIST_INSERT_HEAD(&fg->features, fge, entry);
1192 ast_verb(2, "Registered feature '%s' for group '%s' at exten '%s'\n",
1193 feature->sname, fg->gname, exten);
1196 void ast_unregister_feature(struct ast_call_feature *feature)
1201 AST_LIST_LOCK(&feature_list);
1202 AST_LIST_REMOVE(&feature_list,feature,feature_entry);
1203 AST_LIST_UNLOCK(&feature_list);
1207 /*! \brief Remove all features in the list */
1208 static void ast_unregister_features(void)
1210 struct ast_call_feature *feature;
1212 AST_LIST_LOCK(&feature_list);
1213 while ((feature = AST_LIST_REMOVE_HEAD(&feature_list,feature_entry)))
1215 AST_LIST_UNLOCK(&feature_list);
1218 /*! \brief find a call feature by name */
1219 static struct ast_call_feature *find_dynamic_feature(const char *name)
1221 struct ast_call_feature *tmp;
1223 AST_LIST_TRAVERSE(&feature_list, tmp, feature_entry) {
1224 if (!strcasecmp(tmp->sname, name))
1231 /*! \brief Remove all feature groups in the list */
1232 static void ast_unregister_groups(void)
1234 struct feature_group *fg;
1235 struct feature_group_exten *fge;
1237 AST_RWLIST_WRLOCK(&feature_groups);
1238 while ((fg = AST_LIST_REMOVE_HEAD(&feature_groups, entry))) {
1239 while ((fge = AST_LIST_REMOVE_HEAD(&fg->features, entry))) {
1240 ast_string_field_free_all(fge);
1244 ast_string_field_free_all(fg);
1247 AST_RWLIST_UNLOCK(&feature_groups);
1251 * \brief Find a group by name
1252 * \param name feature name
1253 * \retval feature group on success.
1254 * \retval NULL on failure.
1256 static struct feature_group *find_group(const char *name) {
1257 struct feature_group *fg = NULL;
1259 AST_LIST_TRAVERSE(&feature_groups, fg, entry) {
1260 if (!strcasecmp(fg->gname, name))
1268 * \brief Find a feature extension
1270 * \retval feature group extension on success.
1271 * \retval NULL on failure.
1273 static struct feature_group_exten *find_group_exten(struct feature_group *fg, const char *code) {
1274 struct feature_group_exten *fge = NULL;
1276 AST_LIST_TRAVERSE(&fg->features, fge, entry) {
1277 if(!strcasecmp(fge->exten, code))
1284 void ast_rdlock_call_features(void)
1286 ast_rwlock_rdlock(&features_lock);
1289 void ast_unlock_call_features(void)
1291 ast_rwlock_unlock(&features_lock);
1294 struct ast_call_feature *ast_find_call_feature(const char *name)
1297 for (x = 0; x < FEATURES_COUNT; x++) {
1298 if (!strcasecmp(name, builtin_features[x].sname))
1299 return &builtin_features[x];
1305 * \brief exec an app by feature
1306 * \param chan,peer,config,code,sense
1307 * Find a feature, determine which channel activated
1308 * \retval FEATURE_RETURN_PBX_KEEPALIVE,FEATURE_RETURN_NO_HANGUP_PEER
1310 * \retval -2 when an application cannot be found.
1312 static int feature_exec_app(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
1314 struct ast_app *app;
1315 struct ast_call_feature *feature;
1316 struct ast_channel *work, *idle;
1319 AST_LIST_LOCK(&feature_list);
1320 AST_LIST_TRAVERSE(&feature_list, feature, feature_entry) {
1321 if (!strcasecmp(feature->exten, code))
1324 AST_LIST_UNLOCK(&feature_list);
1326 if (!feature) { /* shouldn't ever happen! */
1327 ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n");
1331 if (sense == FEATURE_SENSE_CHAN) {
1332 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
1333 return FEATURE_RETURN_PASSDIGITS;
1334 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
1342 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
1343 return FEATURE_RETURN_PASSDIGITS;
1344 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
1353 if (!(app = pbx_findapp(feature->app))) {
1354 ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app);
1358 ast_autoservice_start(idle);
1360 if (!ast_strlen_zero(feature->moh_class))
1361 ast_moh_start(idle, feature->moh_class, NULL);
1363 res = pbx_exec(work, app, feature->app_args);
1365 if (!ast_strlen_zero(feature->moh_class))
1368 ast_autoservice_stop(idle);
1370 if (res == AST_PBX_KEEPALIVE)
1371 return FEATURE_RETURN_PBX_KEEPALIVE;
1372 else if (res == AST_PBX_NO_HANGUP_PEER)
1373 return FEATURE_RETURN_NO_HANGUP_PEER;
1375 return FEATURE_RETURN_SUCCESSBREAK;
1377 return FEATURE_RETURN_SUCCESS; /*! \todo XXX should probably return res */
1380 static void unmap_features(void)
1384 ast_rwlock_wrlock(&features_lock);
1385 for (x = 0; x < FEATURES_COUNT; x++)
1386 strcpy(builtin_features[x].exten, builtin_features[x].default_exten);
1387 ast_rwlock_unlock(&features_lock);
1390 static int remap_feature(const char *name, const char *value)
1394 ast_rwlock_wrlock(&features_lock);
1395 for (x = 0; x < FEATURES_COUNT; x++) {
1396 if (strcasecmp(builtin_features[x].sname, name))
1399 ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten));
1403 ast_rwlock_unlock(&features_lock);
1409 * \brief Check the dynamic features
1410 * \param chan,peer,config,code,sense
1411 * Lock features list, browse for code, unlock list
1412 * \retval res on success.
1413 * \retval -1 on failure.
1415 static int ast_feature_interpret(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
1418 struct ast_flags features;
1419 int res = FEATURE_RETURN_PASSDIGITS;
1420 struct ast_call_feature *feature;
1421 struct feature_group *fg = NULL;
1422 struct feature_group_exten *fge;
1423 const char *dynamic_features=pbx_builtin_getvar_helper(chan,"DYNAMIC_FEATURES");
1426 if (sense == FEATURE_SENSE_CHAN)
1427 ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);
1429 ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL);
1430 ast_debug(3, "Feature interpret: chan=%s, peer=%s, sense=%d, features=%d\n", chan->name, peer->name, sense, features.flags);
1432 ast_rwlock_rdlock(&features_lock);
1433 for (x = 0; x < FEATURES_COUNT; x++) {
1434 if ((ast_test_flag(&features, builtin_features[x].feature_mask)) &&
1435 !ast_strlen_zero(builtin_features[x].exten)) {
1436 /* Feature is up for consideration */
1437 if (!strcmp(builtin_features[x].exten, code)) {
1438 res = builtin_features[x].operation(chan, peer, config, code, sense);
1440 } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) {
1441 if (res == FEATURE_RETURN_PASSDIGITS)
1442 res = FEATURE_RETURN_STOREDIGITS;
1446 ast_rwlock_unlock(&features_lock);
1448 if (ast_strlen_zero(dynamic_features))
1451 tmp = ast_strdupa(dynamic_features);
1453 while ((tok = strsep(&tmp, "#"))) {
1454 AST_RWLIST_RDLOCK(&feature_groups);
1456 fg = find_group(tok);
1458 if (fg && (fge = find_group_exten(fg, code))) {
1459 res = fge->feature->operation(chan, peer, config, code, sense);
1460 AST_RWLIST_UNLOCK(&feature_groups);
1464 AST_RWLIST_UNLOCK(&feature_groups);
1465 AST_LIST_LOCK(&feature_list);
1467 if(!(feature = find_dynamic_feature(tok))) {
1468 AST_LIST_UNLOCK(&feature_list);
1472 /* Feature is up for consideration */
1473 if (!strcmp(feature->exten, code)) {
1474 ast_verb(3, " Feature Found: %s exten: %s\n",feature->sname, tok);
1475 res = feature->operation(chan, peer, config, code, sense);
1476 AST_LIST_UNLOCK(&feature_list);
1478 } else if (!strncmp(feature->exten, code, strlen(code)))
1479 res = FEATURE_RETURN_STOREDIGITS;
1481 AST_LIST_UNLOCK(&feature_list);
1487 static void set_config_flags(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
1491 ast_clear_flag(config, AST_FLAGS_ALL);
1493 ast_rwlock_rdlock(&features_lock);
1494 for (x = 0; x < FEATURES_COUNT; x++) {
1495 if (!ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF))
1498 if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask))
1499 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
1501 if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask))
1502 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
1504 ast_rwlock_unlock(&features_lock);
1506 if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) {
1507 const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
1509 if (dynamic_features) {
1510 char *tmp = ast_strdupa(dynamic_features);
1512 struct ast_call_feature *feature;
1514 /* while we have a feature */
1515 while ((tok = strsep(&tmp, "#"))) {
1516 AST_LIST_LOCK(&feature_list);
1517 if ((feature = find_dynamic_feature(tok)) && ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) {
1518 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
1519 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
1520 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
1521 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
1523 AST_LIST_UNLOCK(&feature_list);
1531 * \param caller,transferee,type,format,data,timeout,outstate,cid_num,cid_name,igncallerstate
1532 * Request channel, set channel variables, initiate call,check if they want to disconnect
1533 * go into loop, check if timeout has elapsed, check if person to be transfered hung up,
1534 * check for answer break loop, set cdr return channel.
1535 * \todo XXX Check - this is very similar to the code in channel.c
1536 * \return always a channel
1538 static struct ast_channel *ast_feature_request_and_dial(struct ast_channel *caller, struct ast_channel *transferee, const char *type, int format, void *data, int timeout, int *outstate, const char *cid_num, const char *cid_name, int igncallerstate)
1543 struct ast_channel *chan;
1544 struct ast_channel *monitor_chans[2];
1545 struct ast_channel *active_channel;
1546 int res = 0, ready = 0;
1548 if ((chan = ast_request(type, format, data, &cause))) {
1549 ast_set_callerid(chan, cid_num, cid_name, cid_num);
1550 ast_channel_inherit_variables(caller, chan);
1551 pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", caller->name);
1553 chan->cdr=ast_cdr_alloc();
1555 ast_cdr_init(chan->cdr, chan); /* initilize our channel's cdr */
1556 ast_cdr_start(chan->cdr);
1560 if (!ast_call(chan, data, timeout)) {
1561 struct timeval started;
1563 char *disconnect_code = NULL, *dialed_code = NULL;
1565 ast_indicate(caller, AST_CONTROL_RINGING);
1566 /* support dialing of the featuremap disconnect code while performing an attended tranfer */
1567 ast_rwlock_rdlock(&features_lock);
1568 for (x = 0; x < FEATURES_COUNT; x++) {
1569 if (strcasecmp(builtin_features[x].sname, "disconnect"))
1572 disconnect_code = builtin_features[x].exten;
1573 len = strlen(disconnect_code) + 1;
1574 dialed_code = alloca(len);
1575 memset(dialed_code, 0, len);
1578 ast_rwlock_unlock(&features_lock);
1580 started = ast_tvnow();
1582 while (!((transferee && ast_check_hangup(transferee)) && (!igncallerstate && ast_check_hangup(caller))) && timeout && (chan->_state != AST_STATE_UP)) {
1583 struct ast_frame *f = NULL;
1585 monitor_chans[0] = caller;
1586 monitor_chans[1] = chan;
1587 active_channel = ast_waitfor_n(monitor_chans, 2, &to);
1589 /* see if the timeout has been violated */
1590 if(ast_tvdiff_ms(ast_tvnow(), started) > timeout) {
1591 state = AST_CONTROL_UNHOLD;
1592 ast_log(LOG_NOTICE, "We exceeded our AT-timeout\n");
1593 break; /*doh! timeout*/
1596 if (!active_channel)
1599 if (chan && (chan == active_channel)){
1601 if (f == NULL) { /*doh! where'd he go?*/
1602 state = AST_CONTROL_HANGUP;
1607 if (f->frametype == AST_FRAME_CONTROL || f->frametype == AST_FRAME_DTMF || f->frametype == AST_FRAME_TEXT) {
1608 if (f->subclass == AST_CONTROL_RINGING) {
1609 state = f->subclass;
1610 ast_verb(3, "%s is ringing\n", chan->name);
1611 ast_indicate(caller, AST_CONTROL_RINGING);
1612 } else if ((f->subclass == AST_CONTROL_BUSY) || (f->subclass == AST_CONTROL_CONGESTION)) {
1613 state = f->subclass;
1614 ast_verb(3, "%s is busy\n", chan->name);
1615 ast_indicate(caller, AST_CONTROL_BUSY);
1619 } else if (f->subclass == AST_CONTROL_ANSWER) {
1620 /* This is what we are hoping for */
1621 state = f->subclass;
1627 ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass);
1629 /* else who cares */
1632 } else if (caller && (active_channel == caller)) {
1633 f = ast_read(caller);
1634 if (f == NULL) { /*doh! where'd he go?*/
1635 if (!igncallerstate) {
1636 if (ast_check_hangup(caller) && !ast_check_hangup(chan)) {
1637 /* make this a blind transfer */
1641 state = AST_CONTROL_HANGUP;
1647 if (f->frametype == AST_FRAME_DTMF) {
1648 dialed_code[x++] = f->subclass;
1649 dialed_code[x] = '\0';
1650 if (strlen(dialed_code) == len) {
1652 } else if (x && strncmp(dialed_code, disconnect_code, x)) {
1654 dialed_code[x] = '\0';
1656 if (*dialed_code && !strcmp(dialed_code, disconnect_code)) {
1657 /* Caller Canceled the call */
1658 state = AST_CONTROL_UNHOLD;
1670 ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data);
1672 ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
1674 case AST_CAUSE_BUSY:
1675 state = AST_CONTROL_BUSY;
1677 case AST_CAUSE_CONGESTION:
1678 state = AST_CONTROL_CONGESTION;
1683 ast_indicate(caller, -1);
1684 if (chan && ready) {
1685 if (chan->_state == AST_STATE_UP)
1686 state = AST_CONTROL_ANSWER;
1699 if (chan && res <= 0) {
1700 if (chan->cdr || (chan->cdr = ast_cdr_alloc())) {
1702 ast_cdr_init(chan->cdr, chan);
1703 snprintf(tmp, 256, "%s/%s", type, (char *)data);
1704 ast_cdr_setapp(chan->cdr,"Dial",tmp);
1705 ast_cdr_update(chan);
1706 ast_cdr_start(chan->cdr);
1707 ast_cdr_end(chan->cdr);
1708 /* If the cause wasn't handled properly */
1709 if (ast_cdr_disposition(chan->cdr,chan->hangupcause))
1710 ast_cdr_failed(chan->cdr);
1712 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
1720 * \brief bridge the call and set CDR
1721 * \param chan,peer,config
1722 * Set start time, check for two channels,check if monitor on
1723 * check for feature activation, create new CDR
1724 * \retval res on success.
1725 * \retval -1 on failure to bridge.
1727 int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast_bridge_config *config)
1729 /* Copy voice back and forth between the two channels. Give the peer
1730 the ability to transfer calls with '#<extension' syntax. */
1731 struct ast_frame *f;
1732 struct ast_channel *who;
1733 char chan_featurecode[FEATURE_MAX_LEN + 1]="";
1734 char peer_featurecode[FEATURE_MAX_LEN + 1]="";
1739 struct ast_option_header *aoh;
1740 struct ast_bridge_config backup_config;
1741 struct ast_cdr *bridge_cdr;
1743 memset(&backup_config, 0, sizeof(backup_config));
1745 config->start_time = ast_tvnow();
1748 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
1749 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
1751 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
1754 const char *monitor_exec;
1755 struct ast_channel *src = NULL;
1757 if (!(monitor_app = pbx_findapp("Monitor")))
1760 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR")))
1762 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
1764 if (monitor_app && src) {
1765 char *tmp = ast_strdupa(monitor_exec);
1766 pbx_exec(src, monitor_app, tmp);
1770 set_config_flags(chan, peer, config);
1771 config->firstpass = 1;
1773 /* Answer if need be */
1774 if (ast_answer(chan))
1776 peer->appl = "Bridged Call";
1777 peer->data = chan->name;
1779 /* copy the userfield from the B-leg to A-leg if applicable */
1780 if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) {
1782 if (!ast_strlen_zero(chan->cdr->userfield)) {
1783 snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield);
1784 ast_cdr_appenduserfield(chan, tmp);
1786 ast_cdr_setuserfield(chan, peer->cdr->userfield);
1787 /* free the peer's cdr without ast_cdr_free complaining */
1788 ast_free(peer->cdr);
1793 struct ast_channel *other; /* used later */
1795 res = ast_channel_bridge(chan, peer, config, &f, &who);
1797 if (config->feature_timer) {
1798 /* Update time limit for next pass */
1799 diff = ast_tvdiff_ms(ast_tvnow(), config->start_time);
1800 config->feature_timer -= diff;
1802 /* Running on backup config, meaning a feature might be being
1803 activated, but that's no excuse to keep things going
1805 if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) {
1806 ast_debug(1, "Timed out, realtime this time!\n");
1807 config->feature_timer = 0;
1813 } else if (config->feature_timer <= 0) {
1814 /* Not *really* out of time, just out of time for
1815 digits to come in for features. */
1816 ast_debug(1, "Timed out for feature!\n");
1817 if (!ast_strlen_zero(peer_featurecode)) {
1818 ast_dtmf_stream(chan, peer, peer_featurecode, 0, 0);
1819 memset(peer_featurecode, 0, sizeof(peer_featurecode));
1821 if (!ast_strlen_zero(chan_featurecode)) {
1822 ast_dtmf_stream(peer, chan, chan_featurecode, 0, 0);
1823 memset(chan_featurecode, 0, sizeof(chan_featurecode));
1827 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
1829 /* Restore original (possibly time modified) bridge config */
1830 memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
1831 memset(&backup_config, 0, sizeof(backup_config));
1833 hadfeatures = hasfeatures;
1834 /* Continue as we were */
1837 /* The bridge returned without a frame and there is a feature in progress.
1838 * However, we don't think the feature has quite yet timed out, so just
1839 * go back into the bridge. */
1843 if (config->feature_timer <=0) {
1844 /* We ran out of time */
1845 config->feature_timer = 0;
1855 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
1859 if (!f || (f->frametype == AST_FRAME_CONTROL &&
1860 (f->subclass == AST_CONTROL_HANGUP || f->subclass == AST_CONTROL_BUSY ||
1861 f->subclass == AST_CONTROL_CONGESTION))) {
1865 /* many things should be sent to the 'other' channel */
1866 other = (who == chan) ? peer : chan;
1867 if (f->frametype == AST_FRAME_CONTROL) {
1868 switch (f->subclass) {
1869 case AST_CONTROL_RINGING:
1870 case AST_CONTROL_FLASH:
1872 ast_indicate(other, f->subclass);
1874 case AST_CONTROL_HOLD:
1875 case AST_CONTROL_UNHOLD:
1876 ast_indicate_data(other, f->subclass, f->data, f->datalen);
1878 case AST_CONTROL_OPTION:
1880 /* Forward option Requests */
1881 if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) {
1882 ast_channel_setoption(other, ntohs(aoh->option), aoh->data,
1883 f->datalen - sizeof(struct ast_option_header), 0);
1887 } else if (f->frametype == AST_FRAME_DTMF_BEGIN) {
1889 } else if (f->frametype == AST_FRAME_DTMF) {
1893 hadfeatures = hasfeatures;
1894 /* This cannot overrun because the longest feature is one shorter than our buffer */
1896 sense = FEATURE_SENSE_CHAN;
1897 featurecode = chan_featurecode;
1899 sense = FEATURE_SENSE_PEER;
1900 featurecode = peer_featurecode;
1902 /*! append the event to featurecode. we rely on the string being zero-filled, and
1903 * not overflowing it.
1904 * \todo XXX how do we guarantee the latter ?
1906 featurecode[strlen(featurecode)] = f->subclass;
1907 /* Get rid of the frame before we start doing "stuff" with the channels */
1910 config->feature_timer = backup_config.feature_timer;
1911 res = ast_feature_interpret(chan, peer, config, featurecode, sense);
1913 case FEATURE_RETURN_PASSDIGITS:
1914 ast_dtmf_stream(other, who, featurecode, 0, 0);
1916 case FEATURE_RETURN_SUCCESS:
1917 memset(featurecode, 0, sizeof(chan_featurecode));
1920 if (res >= FEATURE_RETURN_PASSDIGITS) {
1924 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
1925 if (hadfeatures && !hasfeatures) {
1926 /* Restore backup */
1927 memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
1928 memset(&backup_config, 0, sizeof(struct ast_bridge_config));
1929 } else if (hasfeatures) {
1931 /* Backup configuration */
1932 memcpy(&backup_config, config, sizeof(struct ast_bridge_config));
1933 /* Setup temporary config options */
1934 config->play_warning = 0;
1935 ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
1936 ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
1937 config->warning_freq = 0;
1938 config->warning_sound = NULL;
1939 config->end_sound = NULL;
1940 config->start_sound = NULL;
1941 config->firstpass = 0;
1943 config->start_time = ast_tvnow();
1944 config->feature_timer = featuredigittimeout;
1945 ast_debug(1, "Set time limit to %ld\n", config->feature_timer);
1952 /* arrange the cdrs */
1953 bridge_cdr = ast_cdr_alloc();
1955 if (chan->cdr && peer->cdr) { /* both of them? merge */
1956 ast_cdr_init(bridge_cdr,chan); /* seems more logicaller to use the destination as a base, but, really, it's random */
1957 ast_cdr_start(bridge_cdr); /* now is the time to start */
1959 /* absorb the channel cdr */
1960 ast_cdr_merge(bridge_cdr, chan->cdr);
1961 if (!ast_test_flag(chan->cdr, AST_CDR_FLAG_LOCKED))
1962 ast_cdr_discard(chan->cdr); /* if locked cdrs are in chan, they are taken over in the merge */
1964 /* absorb the peer cdr */
1965 ast_cdr_merge(bridge_cdr, peer->cdr);
1966 if (ast_test_flag(peer->cdr, AST_CDR_FLAG_LOCKED))
1967 ast_cdr_discard(peer->cdr); /* if locked cdrs are in peer, they are taken over in the merge */
1970 chan->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */
1971 } else if (chan->cdr) {
1972 /* take the cdr from the channel - literally */
1973 ast_cdr_init(bridge_cdr,chan);
1974 /* absorb this data */
1975 ast_cdr_merge(bridge_cdr, chan->cdr);
1976 if (!ast_test_flag(chan->cdr, AST_CDR_FLAG_LOCKED))
1977 ast_cdr_discard(chan->cdr); /* if locked cdrs are in chan, they are taken over in the merge */
1978 chan->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */
1979 } else if (peer->cdr) {
1980 /* take the cdr from the peer - literally */
1981 ast_cdr_init(bridge_cdr,peer);
1982 /* absorb this data */
1983 ast_cdr_merge(bridge_cdr, peer->cdr);
1984 if (!ast_test_flag(peer->cdr, AST_CDR_FLAG_LOCKED))
1985 ast_cdr_discard(peer->cdr); /* if locked cdrs are in chan, they are taken over in the merge */
1987 peer->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */
1989 /* make up a new cdr */
1990 ast_cdr_init(bridge_cdr,chan); /* eh, just pick one of them */
1991 chan->cdr = bridge_cdr; /* */
1993 if (ast_strlen_zero(bridge_cdr->dstchannel)) {
1994 if (strcmp(bridge_cdr->channel, peer->name) != 0)
1995 ast_cdr_setdestchan(bridge_cdr, peer->name);
1997 ast_cdr_setdestchan(bridge_cdr, chan->name);
2003 /*! \brief Output parking event to manager */
2004 static void post_manager_event(const char *s, struct parkeduser *pu)
2006 manager_event(EVENT_FLAG_CALL, s,
2009 "CallerIDNum: %s\r\n"
2010 "CallerIDName: %s\r\n\r\n",
2013 S_OR(pu->chan->cid.cid_num, "<unknown>"),
2014 S_OR(pu->chan->cid.cid_name, "<unknown>")
2019 * \brief Take care of parked calls and unpark them if needed
2020 * \param ignore unused var
2021 * Start inf loop, lock parking lot, check if any parked channels have gone above timeout
2022 * if so, remove channel from parking lot and return it to the extension that parked it.
2023 * Check if parked channel decided to hangup, wait until next FD via select().
2025 static void *do_parking_thread(void *ignore)
2027 char parkingslot[AST_MAX_EXTENSION];
2028 fd_set rfds, efds; /* results from previous select, to be preserved across loops. */
2034 struct parkeduser *pu;
2035 int ms = -1; /* select timeout, uninitialized */
2036 int max = -1; /* max fd, none there yet */
2037 fd_set nrfds, nefds; /* args for the next select */
2041 AST_LIST_LOCK(&parkinglot);
2042 AST_LIST_TRAVERSE_SAFE_BEGIN(&parkinglot, pu, list) {
2043 struct ast_channel *chan = pu->chan; /* shorthand */
2044 int tms; /* timeout for this item */
2045 int x; /* fd index in channel */
2046 struct ast_context *con;
2048 if (pu->notquiteyet) /* Pretend this one isn't here yet */
2050 tms = ast_tvdiff_ms(ast_tvnow(), pu->start);
2051 if (tms > pu->parkingtime) {
2052 ast_indicate(chan, AST_CONTROL_UNHOLD);
2053 /* Get chan, exten from derived kludge */
2054 if (pu->peername[0]) {
2055 char *peername = ast_strdupa(pu->peername);
2056 char *cp = strrchr(peername, '-');
2059 con = ast_context_find(parking_con_dial);
2061 con = ast_context_create(NULL, parking_con_dial, registrar);
2063 ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial);
2066 char returnexten[AST_MAX_EXTENSION];
2067 snprintf(returnexten, sizeof(returnexten), "%s||t", peername);
2068 ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", ast_strdup(returnexten), ast_free, registrar);
2070 if (comebacktoorigin) {
2071 set_c_e_p(chan, parking_con_dial, peername, 1);
2073 ast_log(LOG_WARNING, "now going to parkedcallstimeout,s,1 | ps is %d\n",pu->parkingnum);
2074 snprintf(parkingslot, sizeof(parkingslot), "%d", pu->parkingnum);
2075 pbx_builtin_setvar_helper(pu->chan, "PARKINGSLOT", parkingslot);
2076 set_c_e_p(chan, "parkedcallstimeout", peername, 1);
2079 /* They've been waiting too long, send them back to where they came. Theoretically they
2080 should have their original extensions and such, but we copy to be on the safe side */
2081 set_c_e_p(chan, pu->context, pu->exten, pu->priority);
2084 post_manager_event("ParkedCallTimeOut", pu);
2086 ast_verb(2, "Timeout for %s parked on %d. Returning to %s,%s,%d\n", chan->name, pu->parkingnum, chan->context, chan->exten, chan->priority);
2087 /* Start up the PBX, or hang them up */
2088 if (ast_pbx_start(chan)) {
2089 ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", chan->name);
2092 /* And take them out of the parking lot */
2093 AST_LIST_REMOVE_CURRENT(&parkinglot, list);
2094 con = ast_context_find(parking_con);
2096 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL))
2097 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
2099 notify_metermaids(pu->parkingexten, parking_con, AST_DEVICE_NOT_INUSE);
2101 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
2103 } else { /* still within parking time, process descriptors */
2104 for (x = 0; x < AST_MAX_FDS; x++) {
2105 struct ast_frame *f;
2107 if (chan->fds[x] == -1 || (!FD_ISSET(chan->fds[x], &rfds) && !FD_ISSET(chan->fds[x], &efds)))
2108 continue; /* nothing on this descriptor */
2110 if (FD_ISSET(chan->fds[x], &efds))
2111 ast_set_flag(chan, AST_FLAG_EXCEPTION);
2113 ast_clear_flag(chan, AST_FLAG_EXCEPTION);
2116 /* See if they need servicing */
2118 if (!f || (f->frametype == AST_FRAME_CONTROL && f->subclass == AST_CONTROL_HANGUP)) {
2121 post_manager_event("ParkedCallGiveUp", pu);
2123 /* There's a problem, hang them up*/
2124 ast_verb(2, "%s got tired of being parked\n", chan->name);
2126 /* And take them out of the parking lot */
2127 AST_LIST_REMOVE_CURRENT(&parkinglot, list);
2128 con = ast_context_find(parking_con);
2130 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL))
2131 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
2133 notify_metermaids(pu->parkingexten, parking_con, AST_DEVICE_NOT_INUSE);
2135 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
2139 /*! \todo XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
2141 if (pu->moh_trys < 3 && !chan->generatordata) {
2142 ast_debug(1, "MOH on parked call stopped by outside source. Restarting.\n");
2143 ast_indicate_data(chan, AST_CONTROL_HOLD,
2144 S_OR(parkmohclass, NULL),
2145 !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
2148 goto std; /*! \todo XXX Ick: jumping into an else statement??? XXX */
2152 if (x >= AST_MAX_FDS) {
2153 std: for (x=0; x<AST_MAX_FDS; x++) { /* mark fds for next round */
2154 if (chan->fds[x] > -1) {
2155 FD_SET(chan->fds[x], &nrfds);
2156 FD_SET(chan->fds[x], &nefds);
2157 if (chan->fds[x] > max)
2161 /* Keep track of our shortest wait */
2162 if (tms < ms || ms < 0)
2167 AST_LIST_TRAVERSE_SAFE_END
2168 AST_LIST_UNLOCK(&parkinglot);
2172 struct timeval tv = ast_samp2tv(ms, 1000);
2173 /* Wait for something to happen */
2174 ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL);
2176 pthread_testcancel();
2178 return NULL; /* Never reached */
2181 /*! \brief Park a call */
2182 static int park_call_exec(struct ast_channel *chan, void *data)
2184 /* Data is unused at the moment but could contain a parking
2185 lot context eventually */
2187 struct ast_module_user *u;
2189 u = ast_module_user_add(chan);
2191 /* Setup the exten/priority to be s/1 since we don't know
2192 where this call should return */
2193 strcpy(chan->exten, "s");
2195 /* Answer if call is not up */
2196 if (chan->_state != AST_STATE_UP)
2197 res = ast_answer(chan);
2198 /* Sleep to allow VoIP streams to settle down */
2200 res = ast_safe_sleep(chan, 1000);
2203 res = ast_park_call(chan, chan, 0, NULL);
2205 ast_module_user_remove(u);
2207 return !res ? AST_PBX_KEEPALIVE : res;
2210 /*! \brief Pickup parked call */
2211 static int park_exec(struct ast_channel *chan, void *data)
2214 struct ast_module_user *u;
2215 struct ast_channel *peer=NULL;
2216 struct parkeduser *pu;
2217 struct ast_context *con;
2220 struct ast_bridge_config config;
2223 ast_log(LOG_WARNING, "Parkedcall requires an argument (extension number)\n");
2227 u = ast_module_user_add(chan);
2229 park = atoi((char *)data);
2231 AST_LIST_LOCK(&parkinglot);
2232 AST_LIST_TRAVERSE_SAFE_BEGIN(&parkinglot, pu, list) {
2233 if (pu->parkingnum == park) {
2234 AST_LIST_REMOVE_CURRENT(&parkinglot, list);
2238 AST_LIST_TRAVERSE_SAFE_END
2239 AST_LIST_UNLOCK(&parkinglot);
2243 con = ast_context_find(parking_con);
2245 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL))
2246 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
2248 notify_metermaids(pu->parkingexten, parking_con, AST_DEVICE_NOT_INUSE);
2250 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
2252 manager_event(EVENT_FLAG_CALL, "UnParkedCall",
2256 "CallerIDNum: %s\r\n"
2257 "CallerIDName: %s\r\n",
2258 pu->parkingexten, pu->chan->name, chan->name,
2259 S_OR(pu->chan->cid.cid_num, "<unknown>"),
2260 S_OR(pu->chan->cid.cid_name, "<unknown>")
2265 /* JK02: it helps to answer the channel if not already up */
2266 if (chan->_state != AST_STATE_UP)
2270 /* Play a courtesy to the source(s) configured to prefix the bridge connecting */
2272 if (!ast_strlen_zero(courtesytone)) {
2274 ast_indicate(peer, AST_CONTROL_UNHOLD);
2275 if (parkedplay == 0) {
2276 error = ast_stream_and_wait(chan, courtesytone, "");
2277 } else if (parkedplay == 1) {
2278 error = ast_stream_and_wait(peer, courtesytone, "");
2279 } else if (parkedplay == 2) {
2280 if (!ast_streamfile(chan, courtesytone, chan->language) &&
2281 !ast_streamfile(peer, courtesytone, chan->language)) {
2282 /*! \todo XXX we would like to wait on both! */
2283 res = ast_waitstream(chan, "");
2285 res = ast_waitstream(peer, "");
2291 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
2296 ast_indicate(peer, AST_CONTROL_UNHOLD);
2298 res = ast_channel_make_compatible(chan, peer);
2300 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
2304 /* This runs sorta backwards, since we give the incoming channel control, as if it
2305 were the person called. */
2306 ast_verb(3, "Channel %s connected to parked call %d\n", chan->name, park);
2308 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
2309 ast_cdr_setdestchan(chan->cdr, peer->name);
2310 memset(&config, 0, sizeof(struct ast_bridge_config));
2311 if ((parkedcalltransfers == AST_FEATURE_FLAG_BYCALLEE) || (parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH))
2312 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
2313 if ((parkedcalltransfers == AST_FEATURE_FLAG_BYCALLER) || (parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH))
2314 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
2315 if ((parkedcallreparking == AST_FEATURE_FLAG_BYCALLEE) || (parkedcallreparking == AST_FEATURE_FLAG_BYBOTH))
2316 ast_set_flag(&(config.features_callee), AST_FEATURE_PARKCALL);
2317 if ((parkedcallreparking == AST_FEATURE_FLAG_BYCALLER) || (parkedcallreparking == AST_FEATURE_FLAG_BYBOTH))
2318 ast_set_flag(&(config.features_caller), AST_FEATURE_PARKCALL);
2319 res = ast_bridge_call(chan, peer, &config);
2321 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
2322 ast_cdr_setdestchan(chan->cdr, peer->name);
2324 /* Simulate the PBX hanging up */
2325 if (res != AST_PBX_NO_HANGUP_PEER)
2329 /*! \todo XXX Play a message XXX */
2330 if (ast_stream_and_wait(chan, "pbx-invalidpark", ""))
2331 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
2332 ast_verb(3, "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park);
2336 ast_module_user_remove(u);
2341 static int handle_showfeatures(int fd, int argc, char *argv[])
2344 struct ast_call_feature *feature;
2345 char format[] = "%-25s %-7s %-7s\n";
2347 ast_cli(fd, format, "Builtin Feature", "Default", "Current");
2348 ast_cli(fd, format, "---------------", "-------", "-------");
2350 ast_cli(fd, format, "Pickup", "*8", ast_pickup_ext()); /* default hardcoded above, so we'll hardcode it here */
2352 ast_rwlock_rdlock(&features_lock);
2353 for (i = 0; i < FEATURES_COUNT; i++)
2354 ast_cli(fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
2355 ast_rwlock_unlock(&features_lock);
2358 ast_cli(fd, format, "Dynamic Feature", "Default", "Current");
2359 ast_cli(fd, format, "---------------", "-------", "-------");
2360 if (AST_LIST_EMPTY(&feature_list))
2361 ast_cli(fd, "(none)\n");
2363 AST_LIST_LOCK(&feature_list);
2364 AST_LIST_TRAVERSE(&feature_list, feature, feature_entry)
2365 ast_cli(fd, format, feature->sname, "no def", feature->exten);
2366 AST_LIST_UNLOCK(&feature_list);
2368 ast_cli(fd, "\nCall parking\n");
2369 ast_cli(fd, "------------\n");
2370 ast_cli(fd,"%-20s: %s\n", "Parking extension", parking_ext);
2371 ast_cli(fd,"%-20s: %s\n", "Parking context", parking_con);
2372 ast_cli(fd,"%-20s: %d-%d\n", "Parked call extensions", parking_start, parking_stop);
2375 return RESULT_SUCCESS;
2378 static char mandescr_bridge[] =
2379 "Description: Bridge together two channels already in the PBX\n"
2380 "Variables: ( Headers marked with * are required )\n"
2381 " *Channel1: Channel to Bridge to Channel2\n"
2382 " *Channel2: Channel to Bridge to Channel1\n"
2383 " Tone: (Yes|No) Play courtesy tone to Channel 2\n"
2387 * \brief Actual bridge
2390 * Stop hold music, lock both channels, masq channels,
2391 * after bridge return channel to next priority.
2393 static void do_bridge_masquerade(struct ast_channel *chan, struct ast_channel *tmpchan)
2396 ast_mutex_lock(&chan->lock);
2397 ast_setstate(tmpchan, chan->_state);
2398 tmpchan->readformat = chan->readformat;
2399 tmpchan->writeformat = chan->writeformat;
2400 ast_channel_masquerade(tmpchan, chan);
2401 ast_mutex_lock(&tmpchan->lock);
2402 ast_do_masquerade(tmpchan);
2403 /* when returning from bridge, the channel will continue at the next priority */
2404 ast_explicit_goto(tmpchan, chan->context, chan->exten, chan->priority + 1);
2405 ast_mutex_unlock(&tmpchan->lock);
2406 ast_mutex_unlock(&chan->lock);
2410 * \brief Bridge channels together
2413 * Make sure valid channels were specified,
2414 * send errors if any of the channels could not be found/locked, answer channels if needed,
2415 * create the placeholder channels and grab the other channels
2416 * make the channels compatible, send error if we fail doing so
2417 * setup the bridge thread object and start the bridge.
2418 * \retval 0 on success or on incorrect use.
2419 * \retval 1 on failure to bridge channels.
2421 static int action_bridge(struct mansession *s, const struct message *m)
2423 const char *channela = astman_get_header(m, "Channel1");
2424 const char *channelb = astman_get_header(m, "Channel2");
2425 const char *playtone = astman_get_header(m, "Tone");
2426 struct ast_channel *chana = NULL, *chanb = NULL;
2427 struct ast_channel *tmpchana = NULL, *tmpchanb = NULL;
2428 struct ast_bridge_thread_obj *tobj = NULL;
2430 /* make sure valid channels were specified */
2431 if (!ast_strlen_zero(channela) && !ast_strlen_zero(channelb)) {
2432 chana = ast_get_channel_by_name_prefix_locked(channela, strlen(channela));
2433 chanb = ast_get_channel_by_name_prefix_locked(channelb, strlen(channelb));
2435 ast_mutex_unlock(&chana->lock);
2437 ast_mutex_unlock(&chanb->lock);
2439 /* send errors if any of the channels could not be found/locked */
2442 snprintf(buf, sizeof(buf), "Channel1 does not exists: %s", channela);
2443 astman_send_error(s, m, buf);
2448 snprintf(buf, sizeof(buf), "Channel2 does not exists: %s", channelb);
2449 astman_send_error(s, m, buf);
2453 astman_send_error(s, m, "Missing channel parameter in request");
2457 /* Answer the channels if needed */
2458 if (chana->_state != AST_STATE_UP)
2460 if (chanb->_state != AST_STATE_UP)
2463 /* create the placeholder channels and grab the other channels */
2464 if (!(tmpchana = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
2465 NULL, NULL, 0, "Bridge/%s", chana->name))) {
2466 astman_send_error(s, m, "Unable to create temporary channel!");
2470 if (!(tmpchanb = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
2471 NULL, NULL, 0, "Bridge/%s", chanb->name))) {
2472 astman_send_error(s, m, "Unable to create temporary channels!");
2473 ast_channel_free(tmpchana);
2477 do_bridge_masquerade(chana, tmpchana);
2478 do_bridge_masquerade(chanb, tmpchanb);
2480 /* make the channels compatible, send error if we fail doing so */
2481 if (ast_channel_make_compatible(tmpchana, tmpchanb)) {
2482 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for manager bridge\n", tmpchana->name, tmpchanb->name);
2483 astman_send_error(s, m, "Could not make channels compatible for manager bridge");
2484 ast_hangup(tmpchana);
2485 ast_hangup(tmpchanb);
2489 /* setup the bridge thread object and start the bridge */
2490 if (!(tobj = ast_calloc(1, sizeof(*tobj)))) {
2491 ast_log(LOG_WARNING, "Unable to spawn a new bridge thread on %s and %s: %s\n", tmpchana->name, tmpchanb->name, strerror(errno));
2492 astman_send_error(s, m, "Unable to spawn a new bridge thread");
2493 ast_hangup(tmpchana);
2494 ast_hangup(tmpchanb);
2498 tobj->chan = tmpchana;
2499 tobj->peer = tmpchanb;
2500 tobj->return_to_pbx = 1;
2502 if (ast_true(playtone)) {
2503 if (!ast_strlen_zero(xfersound) && !ast_streamfile(tmpchanb, xfersound, tmpchanb->language)) {
2504 if (ast_waitstream(tmpchanb, "") < 0)
2505 ast_log(LOG_WARNING, "Failed to play a courtesy tone on chan %s\n", tmpchanb->name);
2509 ast_bridge_call_thread_launch(tobj);
2511 astman_send_ack(s, m, "Launched bridge thread with success");
2516 static char showfeatures_help[] =
2517 "Usage: feature list\n"
2518 " Lists currently configured features.\n";
2521 * \brief CLI command to list parked calls
2525 * Check right usage, lock parking lot, display parked calls, unlock parking lot list.
2526 * \retval CLI_SUCCESS on success.
2527 * \retval CLI_SHOWUSAGE on incorrect number of arguements.
2528 * \retval NULL when tab completion is used.
2530 static char *handle_parkedcalls(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2532 struct parkeduser *cur;
2537 e->command = "parkedcalls show";
2539 "Usage: parkedcalls show\n"
2540 " List currently parked calls\n";
2546 if (a->argc > e->args)
2547 return CLI_SHOWUSAGE;
2549 ast_cli(a->fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
2550 , "Context", "Extension", "Pri", "Timeout");
2552 AST_LIST_LOCK(&parkinglot);
2553 AST_LIST_TRAVERSE(&parkinglot, cur, list) {
2554 ast_cli(a->fd, "%-10.10s %25s (%-15s %-12s %-4d) %6lds\n"
2555 ,cur->parkingexten, cur->chan->name, cur->context, cur->exten
2556 ,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL));
2560 AST_LIST_UNLOCK(&parkinglot);
2561 ast_cli(a->fd, "%d parked call%s.\n", numparked, ESS(numparked));
2567 static char *handle_parkedcalls_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2569 char *res = handle_parkedcalls(e, cmd, a);
2570 if (cmd == CLI_INIT)
2571 e->command = "show parkedcalls";
2575 static struct ast_cli_entry cli_show_parkedcalls_deprecated = NEW_CLI(handle_parkedcalls_deprecated, "List currently parked calls.");
2577 static struct ast_cli_entry cli_features[] = {
2578 { { "feature", "show", NULL },
2579 handle_showfeatures, "Lists configured features",
2580 showfeatures_help },
2582 NEW_CLI(handle_parkedcalls, "List currently parked calls", .deprecate_cmd = &cli_show_parkedcalls_deprecated),
2586 * \brief Dump parking lot status
2589 * Lock parking lot, iterate list and append parked calls status, unlock parking lot.
2590 * \return Always RESULT_SUCCESS
2592 static int manager_parking_status(struct mansession *s, const struct message *m)
2594 struct parkeduser *cur;
2595 const char *id = astman_get_header(m, "ActionID");
2596 char idText[256] = "";
2598 if (!ast_strlen_zero(id))
2599 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
2601 astman_send_ack(s, m, "Parked calls will follow");
2603 AST_LIST_LOCK(&parkinglot);
2605 AST_LIST_TRAVERSE(&parkinglot, cur, list) {
2606 astman_append(s, "Event: ParkedCall\r\n"
2611 "CallerIDNum: %s\r\n"
2612 "CallerIDName: %s\r\n"
2615 cur->parkingnum, cur->chan->name, cur->peername,
2616 (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL),
2617 S_OR(cur->chan->cid.cid_num, ""), /* XXX in other places it is <unknown> */
2618 S_OR(cur->chan->cid.cid_name, ""),
2623 "Event: ParkedCallsComplete\r\n"
2627 AST_LIST_UNLOCK(&parkinglot);
2629 return RESULT_SUCCESS;
2632 static char mandescr_park[] =
2633 "Description: Park a channel.\n"
2634 "Variables: (Names marked with * are required)\n"
2635 " *Channel: Channel name to park\n"
2636 " *Channel2: Channel to announce park info to (and return to if timeout)\n"
2637 " Timeout: Number of milliseconds to wait before callback.\n";
2640 * \brief Create manager event for parked calls
2643 * Get channels involved in park, create event.
2646 static int manager_park(struct mansession *s, const struct message *m)
2648 const char *channel = astman_get_header(m, "Channel");
2649 const char *channel2 = astman_get_header(m, "Channel2");
2650 const char *timeout = astman_get_header(m, "Timeout");
2655 struct ast_channel *ch1, *ch2;
2657 if (ast_strlen_zero(channel)) {
2658 astman_send_error(s, m, "Channel not specified");
2662 if (ast_strlen_zero(channel2)) {
2663 astman_send_error(s, m, "Channel2 not specified");
2667 ch1 = ast_get_channel_by_name_locked(channel);
2669 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel);
2670 astman_send_error(s, m, buf);
2674 ch2 = ast_get_channel_by_name_locked(channel2);
2676 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2);
2677 astman_send_error(s, m, buf);
2678 ast_channel_unlock(ch1);
2682 if (!ast_strlen_zero(timeout)) {
2683 sscanf(timeout, "%d", &to);
2686 res = ast_masq_park_call(ch1, ch2, to, &parkExt);
2688 ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT);
2689 astman_send_ack(s, m, "Park successful");
2691 astman_send_error(s, m, "Park failure");
2694 ast_channel_unlock(ch1);
2695 ast_channel_unlock(ch2);
2701 * \brief Pickup a call
2702 * \param chan channel that initiated pickup
2703 * Walk list of channels, checking it is not itself, channel is pbx one,
2704 * check that the callgroup for both channels are the same and the channel is ringing.
2705 * Answer calling channel, flag channel as answered on queue, masq channels together.
2707 int ast_pickup_call(struct ast_channel *chan)
2709 struct ast_channel *cur = NULL;
2712 while ((cur = ast_channel_walk_locked(cur)) != NULL) {
2715 (chan->pickupgroup & cur->callgroup) &&
2716 ((cur->_state == AST_STATE_RINGING) ||
2717 (cur->_state == AST_STATE_RING))) {
2720 ast_channel_unlock(cur);
2723 ast_debug(1, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
2724 res = ast_answer(chan);
2726 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
2727 res = ast_queue_control(chan, AST_CONTROL_ANSWER);
2729 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
2730 res = ast_channel_masquerade(cur, chan);
2732 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name); /* Done */
2733 ast_channel_unlock(cur);
2735 ast_debug(1, "No call pickup possible...\n");
2741 * \brief Add parking hints for all defined parking lots
2743 * \param start starting parkinglot number
2744 * \param stop ending parkinglot number
2746 static void park_add_hints(char *context, int start, int stop)
2749 char device[AST_MAX_EXTENSION];
2752 for (numext = start; numext <= stop; numext++) {
2753 snprintf(exten, sizeof(exten), "%d", numext);
2754 snprintf(device, sizeof(device), "park:%s@%s", exten, context);
2755 ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar);
2760 static int load_config(void)
2762 int start = 0, end = 0;
2765 struct ast_context *con = NULL;
2766 struct ast_config *cfg = NULL;
2767 struct ast_variable *var = NULL;
2768 struct feature_group *fg = NULL;
2769 char old_parking_ext[AST_MAX_EXTENSION];
2770 char old_parking_con[AST_MAX_EXTENSION] = "";
2772 static const char *categories[] = {
2773 /* Categories in features.conf that are not
2774 * to be parsed as group categories
2781 if (!ast_strlen_zero(parking_con)) {
2782 strcpy(old_parking_ext, parking_ext);
2783 strcpy(old_parking_con, parking_con);
2786 /* Reset to defaults */
2787 strcpy(parking_con, "parkedcalls");
2788 strcpy(parking_con_dial, "park-dial");
2789 strcpy(parking_ext, "700");
2790 strcpy(pickup_ext, "*8");
2791 strcpy(parkmohclass, "default");
2792 courtesytone[0] = '\0';
2793 strcpy(xfersound, "beep");
2794 strcpy(xferfailsound, "pbx-invalid");
2795 parking_start = 701;
2799 comebacktoorigin = 1;
2801 parkedcalltransfers = 0;
2802 parkedcallreparking = 0;
2804 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
2805 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
2806 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
2807 atxferloopdelay = DEFAULT_ATXFER_LOOP_DELAY;
2808 atxferdropcall = DEFAULT_ATXFER_DROP_CALL;
2809 atxfercallbackretries = DEFAULT_ATXFER_CALLBACK_RETRIES;
2811 cfg = ast_config_load("features.conf");
2813 ast_log(LOG_WARNING,"Could not load features.conf\n");
2814 return AST_MODULE_LOAD_DECLINE;
2816 for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
2817 if (!strcasecmp(var->name, "parkext")) {
2818 ast_copy_string(parking_ext, var->value, sizeof(parking_ext));
2819 } else if (!strcasecmp(var->name, "context")) {
2820 ast_copy_string(parking_con, var->value, sizeof(parking_con));
2821 } else if (!strcasecmp(var->name, "parkingtime")) {
2822 if ((sscanf(var->value, "%d", &parkingtime) != 1) || (parkingtime < 1)) {
2823 ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value);
2824 parkingtime = DEFAULT_PARK_TIME;
2826 parkingtime = parkingtime * 1000;
2827 } else if (!strcasecmp(var->name, "parkpos")) {
2828 if (sscanf(var->value, "%d-%d", &start, &end) != 2) {
2829 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);
2831 parking_start = start;
2834 } else if (!strcasecmp(var->name, "findslot")) {
2835 parkfindnext = (!strcasecmp(var->value, "next"));
2836 } else if (!strcasecmp(var->name, "parkinghints")) {
2837 parkaddhints = ast_true(var->value);
2838 } else if (!strcasecmp(var->name, "parkedcalltransfers")) {
2839 if (!strcasecmp(var->value, "both"))
2840 parkedcalltransfers = AST_FEATURE_FLAG_BYBOTH;
2841 else if (!strcasecmp(var->value, "caller"))
2842 parkedcalltransfers = AST_FEATURE_FLAG_BYCALLER;
2843 else if (!strcasecmp(var->value, "callee"))
2844 parkedcalltransfers = AST_FEATURE_FLAG_BYCALLEE;
2845 } else if (!strcasecmp(var->name, "parkedcallreparking")) {
2846 if (!strcasecmp(var->value, "both"))
2847 parkedcalltransfers = AST_FEATURE_FLAG_BYBOTH;
2848 else if (!strcasecmp(var->value, "caller"))
2849 parkedcalltransfers = AST_FEATURE_FLAG_BYCALLER;
2850 else if (!strcasecmp(var->value, "callee"))
2851 parkedcalltransfers = AST_FEATURE_FLAG_BYCALLEE;
2852 } else if (!strcasecmp(var->name, "adsipark")) {
2853 adsipark = ast_true(var->value);
2854 } else if (!strcasecmp(var->name, "transferdigittimeout")) {
2855 if ((sscanf(var->value, "%d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) {
2856 ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value);
2857 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
2859 transferdigittimeout = transferdigittimeout * 1000;
2860 } else if (!strcasecmp(var->name, "featuredigittimeout")) {
2861 if ((sscanf(var->value, "%d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) {
2862 ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value);
2863 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
2865 } else if (!strcasecmp(var->name, "atxfernoanswertimeout")) {
2866 if ((sscanf(var->value, "%d", &atxfernoanswertimeout) != 1) || (atxfernoanswertimeout < 1)) {
2867 ast_log(LOG_WARNING, "%s is not a valid atxfernoanswertimeout\n", var->value);
2868 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
2870 atxfernoanswertimeout = atxfernoanswertimeout * 1000;
2871 } else if (!strcasecmp(var->name, "atxferloopdelay")) {
2872 if ((sscanf(var->value, "%u", &atxferloopdelay) != 1)) {
2873 ast_log(LOG_WARNING, "%s is not a valid atxferloopdelay\n", var->value);
2874 atxferloopdelay = DEFAULT_ATXFER_LOOP_DELAY;
2876 atxferloopdelay *= 1000;
2877 } else if (!strcasecmp(var->name, "atxferdropcall")) {
2878 atxferdropcall = ast_true(var->value);
2879 } else if (!strcasecmp(var->name, "atxfercallbackretries")) {
2880 if ((sscanf(var->value, "%u", &atxferloopdelay) != 1)) {
2881 ast_log(LOG_WARNING, "%s is not a valid atxfercallbackretries\n", var->value);
2882 atxfercallbackretries = DEFAULT_ATXFER_CALLBACK_RETRIES;
2884 } else if (!strcasecmp(var->name, "courtesytone")) {
2885 ast_copy_string(courtesytone, var->value, sizeof(courtesytone));
2886 } else if (!strcasecmp(var->name, "parkedplay")) {
2887 if (!strcasecmp(var->value, "both"))
2889 else if (!strcasecmp(var->value, "parked"))
2893 } else if (!strcasecmp(var->name, "xfersound")) {
2894 ast_copy_string(xfersound, var->value, sizeof(xfersound));
2895 } else if (!strcasecmp(var->name, "xferfailsound")) {
2896 ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound));
2897 } else if (!strcasecmp(var->name, "pickupexten")) {
2898 ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext));
2899 } else if (!strcasecmp(var->name, "comebacktoorigin")) {
2900 comebacktoorigin = ast_true(var->value);
2901 } else if (!strcasecmp(var->name, "parkedmusicclass")) {
2902 ast_copy_string(parkmohclass, var->value, sizeof(parkmohclass));
2907 for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) {
2908 if (remap_feature(var->name, var->value))
2909 ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name);
2912 /* Map a key combination to an application*/
2913 ast_unregister_features();
2914 for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) {
2915 char *tmp_val = ast_strdupa(var->value);
2916 char *exten, *activateon, *activatedby, *app, *app_args, *moh_class;
2917 struct ast_call_feature *feature;
2919 /* strsep() sets the argument to NULL if match not found, and it
2920 * is safe to use it with a NULL argument, so we don't check
2923 exten = strsep(&tmp_val,",");
2924 activatedby = strsep(&tmp_val,",");
2925 app = strsep(&tmp_val,",");
2926 app_args = strsep(&tmp_val,",");
2927 moh_class = strsep(&tmp_val,",");
2929 activateon = strsep(&activatedby, "/");
2931 /*! \todo XXX var_name or app_args ? */
2932 if (ast_strlen_zero(app) || ast_strlen_zero(exten) || ast_strlen_zero(activateon) || ast_strlen_zero(var->name)) {
2933 ast_log(LOG_NOTICE, "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n",
2934 app, exten, activateon, var->name);
2938 AST_LIST_LOCK(&feature_list);
2939 if ((feature = find_dynamic_feature(var->name))) {
2940 AST_LIST_UNLOCK(&feature_list);
2941 ast_log(LOG_WARNING, "Dynamic Feature '%s' specified more than once!\n", var->name);
2944 AST_LIST_UNLOCK(&feature_list);
2946 if (!(feature = ast_calloc(1, sizeof(*feature))))
2949 ast_copy_string(feature->sname, var->name, FEATURE_SNAME_LEN);
2950 ast_copy_string(feature->app, app, FEATURE_APP_LEN);
2951 ast_copy_string(feature->exten, exten, FEATURE_EXTEN_LEN);
2954 ast_copy_string(feature->app_args, app_args, FEATURE_APP_ARGS_LEN);
2957 ast_copy_string(feature->moh_class, moh_class, FEATURE_MOH_LEN);
2959 ast_copy_string(feature->exten, exten, sizeof(feature->exten));
2960 feature->operation = feature_exec_app;
2961 ast_set_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF);
2963 /* Allow caller and calle to be specified for backwards compatability */
2964 if (!strcasecmp(activateon, "self") || !strcasecmp(activateon, "caller"))