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
574 * Setup channel, set return exten,priority to 's,1'
575 * answer chan, sleep chan, park call
577 static int builtin_parkcall(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
579 struct ast_channel *parker;
580 struct ast_channel *parkee;
582 struct ast_module_user *u;
584 u = ast_module_user_add(chan);
586 set_peers(&parker, &parkee, peer, chan, sense);
587 /* Setup the exten/priority to be s/1 since we don't know
588 where this call should return */
589 strcpy(chan->exten, "s");
591 if (chan->_state != AST_STATE_UP)
592 res = ast_answer(chan);
594 res = ast_safe_sleep(chan, 1000);
596 res = ast_park_call(parkee, parker, 0, NULL);
598 ast_module_user_remove(u);
601 if (sense == FEATURE_SENSE_CHAN)
602 res = AST_PBX_NO_HANGUP_PEER;
604 res = AST_PBX_KEEPALIVE;
611 * \brief Monitor a channel by DTMF
612 * \param chan channel requesting monitor
613 * \param peer channel to be monitored
618 * Check monitor app enabled, setup channels, both caller/callee chans not null
619 * get TOUCH_MONITOR variable for filename if exists, exec monitor app.
620 * \retval FEATURE_RETURN_SUCCESS on success.
621 * \retval -1 on error.
623 static int builtin_automonitor(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
625 char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL;
628 struct ast_channel *caller_chan, *callee_chan;
631 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
635 if (!monitor_app && !(monitor_app = pbx_findapp("Monitor"))) {
637 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
641 set_peers(&caller_chan, &callee_chan, peer, chan, sense);
643 if (!ast_strlen_zero(courtesytone)) {
644 if (ast_autoservice_start(callee_chan))
646 if (ast_stream_and_wait(caller_chan, courtesytone, "")) {
647 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
648 ast_autoservice_stop(callee_chan);
651 if (ast_autoservice_stop(callee_chan))
655 if (callee_chan->monitor) {
656 ast_verb(4, "User hit '%s' to stop recording call.\n", code);
657 ast_monitor_stop(callee_chan, 1);
658 return FEATURE_RETURN_SUCCESS;
661 if (caller_chan && callee_chan) {
662 const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT");
663 const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR");
666 touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT");
669 touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR");
672 len = strlen(touch_monitor) + 50;
674 touch_filename = alloca(len);
675 snprintf(touch_filename, len, "auto-%ld-%s", (long)time(NULL), touch_monitor);
676 snprintf(args, len, "%s|%s|m", (touch_format) ? touch_format : "wav", touch_filename);
678 caller_chan_id = ast_strdupa(S_OR(caller_chan->cid.cid_num, caller_chan->name));
679 callee_chan_id = ast_strdupa(S_OR(callee_chan->cid.cid_num, callee_chan->name));
680 len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50;
682 touch_filename = alloca(len);
683 snprintf(touch_filename, len, "auto-%ld-%s-%s", (long)time(NULL), caller_chan_id, callee_chan_id);
684 snprintf(args, len, "%s|%s|m", S_OR(touch_format, "wav"), touch_filename);
687 for(x = 0; x < strlen(args); x++) {
692 ast_verb(4, "User hit '%s' to record call. filename: %s\n", code, args);
694 pbx_exec(callee_chan, monitor_app, args);
695 pbx_builtin_setvar_helper(callee_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
696 pbx_builtin_setvar_helper(caller_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
698 return FEATURE_RETURN_SUCCESS;
701 ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n");
705 static int builtin_disconnect(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
707 ast_verb(4, "User hit '%s' to disconnect call.\n", code);
708 return FEATURE_RETURN_HANGUP;
711 static int finishup(struct ast_channel *chan)
713 ast_indicate(chan, AST_CONTROL_UNHOLD);
715 return ast_autoservice_stop(chan);
719 * \brief Find the context for the transfer
722 * Grab the TRANSFER_CONTEXT, if fails try grabbing macrocontext.
723 * \return a context string
725 static const char *real_ctx(struct ast_channel *transferer, struct ast_channel *transferee)
727 const char *s = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT");
728 if (ast_strlen_zero(s))
729 s = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT");
730 if (ast_strlen_zero(s)) /* Use the non-macro context to transfer the call XXX ? */
731 s = transferer->macrocontext;
732 if (ast_strlen_zero(s))
733 s = transferer->context;
738 * \brief Blind transfer user to another extension
739 * \param chan channel initiated blind transfer
740 * \param peer channel to be transfered
745 * Place peer on hold, check if tranfered to parkinglot extension,
746 * otherwise check extension exists and transfer caller.
747 * \retval FEATURE_RETURN_SUCCESS.
748 * \retval -1 on failure.
750 static int builtin_blindtransfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
752 struct ast_channel *transferer;
753 struct ast_channel *transferee;
754 const char *transferer_real_context;
758 set_peers(&transferer, &transferee, peer, chan, sense);
759 transferer_real_context = real_ctx(transferer, transferee);
760 /* Start autoservice on chan while we talk to the originator */
761 ast_autoservice_start(transferee);
762 ast_indicate(transferee, AST_CONTROL_HOLD);
764 memset(xferto, 0, sizeof(xferto));
767 res = ast_stream_and_wait(transferer, "pbx-transfer", AST_DIGIT_ANY);
769 finishup(transferee);
770 return -1; /* error ? */
772 if (res > 0) /* If they've typed a digit already, handle it */
773 xferto[0] = (char) res;
775 ast_stopstream(transferer);
776 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
777 if (res < 0) { /* hangup, would be 0 for invalid and 1 for valid */
778 finishup(transferee);
781 if (!strcmp(xferto, ast_parking_ext())) {
782 res = finishup(transferee);
785 else if (!ast_park_call(transferee, transferer, 0, NULL)) { /* success */
786 /* We return non-zero, but tell the PBX not to hang the channel when
787 the thread dies -- We have to be careful now though. We are responsible for
788 hanging up the channel, else it will never be hung up! */
790 return (transferer == peer) ? AST_PBX_KEEPALIVE : AST_PBX_NO_HANGUP_PEER;
792 ast_log(LOG_WARNING, "Unable to park call %s\n", transferee->name);
794 /*! \todo XXX Maybe we should have another message here instead of invalid extension XXX */
795 } else if (ast_exists_extension(transferee, transferer_real_context, xferto, 1, transferer->cid.cid_num)) {
796 pbx_builtin_setvar_helper(peer, "BLINDTRANSFER", transferee->name);
797 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", peer->name);
798 res=finishup(transferee);
799 if (!transferer->cdr) {
800 transferer->cdr=ast_cdr_alloc();
802 ast_cdr_init(transferer->cdr, transferer); /* initilize our channel's cdr */
803 ast_cdr_start(transferer->cdr);
806 if (transferer->cdr) {
807 ast_cdr_setdestchan(transferer->cdr, transferee->name);
808 ast_cdr_setapp(transferer->cdr, "BLINDTRANSFER","");
810 if (!transferee->pbx) {
811 /* Doh! Use our handy async_goto functions */
812 if (option_verbose > 2)
813 ast_verbose(VERBOSE_PREFIX_3 "Transferring %s to '%s' (context %s) priority 1\n"
814 ,transferee->name, xferto, transferer_real_context);
815 if (ast_async_goto(transferee, transferer_real_context, xferto, 1))
816 ast_log(LOG_WARNING, "Async goto failed :-(\n");
818 /* Set the channel's new extension, since it exists, using transferer context */
819 set_c_e_p(transferee, transferer_real_context, xferto, 0);
821 check_goto_on_transfer(transferer);
824 ast_verb(3, "Unable to find extension '%s' in context '%s'\n", xferto, transferer_real_context);
826 if (ast_stream_and_wait(transferer, xferfailsound, AST_DIGIT_ANY) < 0) {
827 finishup(transferee);
830 ast_stopstream(transferer);
831 res = finishup(transferee);
833 ast_verb(2, "Hungup during autoservice stop on '%s'\n", transferee->name);
836 return FEATURE_RETURN_SUCCESS;
840 * \brief make channels compatible
843 * \retval 0 on success.
844 * \retval -1 on failure.
846 static int check_compat(struct ast_channel *c, struct ast_channel *newchan)
848 if (ast_channel_make_compatible(c, newchan) < 0) {
849 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n",
850 c->name, newchan->name);
858 * \brief Attended transfer
865 * Get extension to transfer to, if you cannot generate channel (or find extension)
866 * return to host channel. After called channel answered wait for hangup of transferer,
867 * bridge call between transfer peer (taking them off hold) to attended transfer channel.
868 * \return -1 means what failure/success both?
870 static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
872 struct ast_channel *transferer;
873 struct ast_channel *transferee;
874 const char *transferer_real_context;
875 char xferto[256] = "";
876 char callbackto[256] = "";
879 struct ast_channel *newchan;
880 struct ast_channel *xferchan;
881 struct ast_bridge_thread_obj *tobj;
882 struct ast_bridge_config bconfig;
886 ast_debug(1, "Executing Attended Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense);
887 set_peers(&transferer, &transferee, peer, chan, sense);
888 transferer_real_context = real_ctx(transferer, transferee);
889 /* Start autoservice on chan while we talk to the originator */
890 ast_autoservice_start(transferee);
891 ast_indicate(transferee, AST_CONTROL_HOLD);
894 res = ast_stream_and_wait(transferer, "pbx-transfer", AST_DIGIT_ANY);
896 finishup(transferee);
899 if (res > 0) /* If they've typed a digit already, handle it */
900 xferto[0] = (char) res;
902 /* this is specific of atxfer */
903 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
904 if (res < 0) { /* hangup, would be 0 for invalid and 1 for valid */
905 finishup(transferee);
909 ast_log(LOG_WARNING, "Did not read data.\n");
910 finishup(transferee);
911 if (ast_stream_and_wait(transferer, "beeperr", ""))
913 return FEATURE_RETURN_SUCCESS;
916 /* valid extension, res == 1 */
917 if (!ast_exists_extension(transferer, transferer_real_context, xferto, 1, transferer->cid.cid_num)) {
918 ast_log(LOG_WARNING, "Extension %s does not exist in context %s\n",xferto,transferer_real_context);
919 finishup(transferee);
920 if (ast_stream_and_wait(transferer, "beeperr", ""))
922 return FEATURE_RETURN_SUCCESS;
926 snprintf(xferto + l, sizeof(xferto) - l, "@%s/n", transferer_real_context); /* append context */
927 newchan = ast_feature_request_and_dial(transferer, transferee, "Local", ast_best_codec(transferer->nativeformats),
928 xferto, atxfernoanswertimeout, &outstate, transferer->cid.cid_num, transferer->cid.cid_name, 1);
930 if (!ast_check_hangup(transferer)) {
931 /* Transferer is up - old behaviour */
932 ast_indicate(transferer, -1);
934 finishup(transferee);
935 /* any reason besides user requested cancel and busy triggers the failed sound */
936 if (outstate != AST_CONTROL_UNHOLD && outstate != AST_CONTROL_BUSY &&
937 ast_stream_and_wait(transferer, xferfailsound, ""))
939 if (ast_stream_and_wait(transferer, xfersound, ""))
940 ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
941 return FEATURE_RETURN_SUCCESS;
944 if (check_compat(transferer, newchan))
946 memset(&bconfig,0,sizeof(struct ast_bridge_config));
947 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
948 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
949 res = ast_bridge_call(transferer, newchan, &bconfig);
950 if (ast_check_hangup(newchan) || !ast_check_hangup(transferer)) {
952 if (ast_stream_and_wait(transferer, xfersound, ""))
953 ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
954 finishup(transferee);
955 transferer->_softhangup = 0;
956 return FEATURE_RETURN_SUCCESS;
958 if (check_compat(transferee, newchan))
960 ast_indicate(transferee, AST_CONTROL_UNHOLD);
962 if ((ast_autoservice_stop(transferee) < 0)
963 || (ast_waitfordigit(transferee, 100) < 0)
964 || (ast_waitfordigit(newchan, 100) < 0)
965 || ast_check_hangup(transferee)
966 || ast_check_hangup(newchan)) {
970 xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Transfered/%s", transferee->name);
975 /* Make formats okay */
976 xferchan->readformat = transferee->readformat;
977 xferchan->writeformat = transferee->writeformat;
978 ast_channel_masquerade(xferchan, transferee);
979 ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority);
980 xferchan->_state = AST_STATE_UP;
981 ast_clear_flag(xferchan, AST_FLAGS_ALL);
982 xferchan->_softhangup = 0;
983 if ((f = ast_read(xferchan)))
985 newchan->_state = AST_STATE_UP;
986 ast_clear_flag(newchan, AST_FLAGS_ALL);
987 newchan->_softhangup = 0;
988 if (!(tobj = ast_calloc(1, sizeof(*tobj)))) {
989 ast_hangup(xferchan);
993 tobj->chan = xferchan;
994 tobj->peer = newchan;
995 tobj->bconfig = *config;
997 if (ast_stream_and_wait(newchan, xfersound, ""))
998 ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
999 ast_bridge_call_thread_launch(tobj);
1000 return -1; /* XXX meaning the channel is bridged ? */
1001 } else if (!ast_check_hangup(transferee)) {
1002 /* act as blind transfer */
1003 if (ast_autoservice_stop(transferee) < 0) {
1004 ast_hangup(newchan);
1009 unsigned int tries = 0;
1011 /* newchan wasn't created - we should callback to transferer */
1012 if (!ast_exists_extension(transferer, transferer_real_context, transferer->cid.cid_num, 1, transferee->cid.cid_num)) {
1013 ast_log(LOG_WARNING, "Extension %s does not exist in context %s - callback failed\n",transferer->cid.cid_num,transferer_real_context);
1014 if (ast_stream_and_wait(transferee, "beeperr", ""))
1016 return FEATURE_RETURN_SUCCESS;
1018 snprintf(callbackto, sizeof(callbackto), "%s@%s/n", transferer->cid.cid_num, transferer_real_context); /* append context */
1020 newchan = ast_feature_request_and_dial(transferee, NULL, "Local", ast_best_codec(transferee->nativeformats),
1021 callbackto, atxfernoanswertimeout, &outstate, transferee->cid.cid_num, transferee->cid.cid_name, 0);
1022 while (!newchan && !atxferdropcall && tries < atxfercallbackretries) {
1023 /* Trying to transfer again */
1024 ast_autoservice_start(transferee);
1025 ast_indicate(transferee, AST_CONTROL_HOLD);
1027 newchan = ast_feature_request_and_dial(transferer, transferee, "Local", ast_best_codec(transferer->nativeformats),
1028 xferto, atxfernoanswertimeout, &outstate, transferer->cid.cid_num, transferer->cid.cid_name, 1);
1029 if (ast_autoservice_stop(transferee) < 0) {
1030 ast_hangup(newchan);
1034 /* Transfer failed, sleeping */
1035 ast_debug(1, "Sleeping for %d ms before callback.\n", atxferloopdelay);
1036 ast_safe_sleep(transferee, atxferloopdelay);
1037 ast_debug(1, "Trying to callback...\n");
1038 newchan = ast_feature_request_and_dial(transferee, NULL, "Local", ast_best_codec(transferee->nativeformats),
1039 callbackto, atxfernoanswertimeout, &outstate, transferee->cid.cid_num, transferee->cid.cid_name, 0);
1047 /* newchan is up, we should prepare transferee and bridge them */
1048 if (check_compat(transferee, newchan))
1050 ast_indicate(transferee, AST_CONTROL_UNHOLD);
1052 if ((ast_waitfordigit(transferee, 100) < 0)
1053 || (ast_waitfordigit(newchan, 100) < 0)
1054 || ast_check_hangup(transferee)
1055 || ast_check_hangup(newchan)) {
1056 ast_hangup(newchan);
1060 xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Transfered/%s", transferee->name);
1062 ast_hangup(newchan);
1065 /* Make formats okay */
1066 xferchan->readformat = transferee->readformat;
1067 xferchan->writeformat = transferee->writeformat;
1068 ast_channel_masquerade(xferchan, transferee);
1069 ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority);
1070 xferchan->_state = AST_STATE_UP;
1071 ast_clear_flag(xferchan, AST_FLAGS_ALL);
1072 xferchan->_softhangup = 0;
1073 if ((f = ast_read(xferchan)))
1075 newchan->_state = AST_STATE_UP;
1076 ast_clear_flag(newchan, AST_FLAGS_ALL);
1077 newchan->_softhangup = 0;
1078 if (!(tobj = ast_calloc(1, sizeof(*tobj)))) {
1079 ast_hangup(xferchan);
1080 ast_hangup(newchan);
1083 tobj->chan = xferchan;
1084 tobj->peer = newchan;
1085 tobj->bconfig = *config;
1087 if (ast_stream_and_wait(newchan, xfersound, ""))
1088 ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
1089 ast_bridge_call_thread_launch(tobj);
1090 return -1; /* XXX meaning the channel is bridged ? */
1092 /* Transferee hung up */
1093 finishup(transferee);
1098 /* add atxfer and automon as undefined so you can only use em if you configure them */
1099 #define FEATURES_COUNT ARRAY_LEN(builtin_features)
1101 AST_RWLOCK_DEFINE_STATIC(features_lock);
1103 static struct ast_call_feature builtin_features[] =
1105 { AST_FEATURE_REDIRECT, "Blind Transfer", "blindxfer", "#", "#", builtin_blindtransfer, AST_FEATURE_FLAG_NEEDSDTMF, "" },
1106 { AST_FEATURE_REDIRECT, "Attended Transfer", "atxfer", "", "", builtin_atxfer, AST_FEATURE_FLAG_NEEDSDTMF, "" },
1107 { AST_FEATURE_AUTOMON, "One Touch Monitor", "automon", "", "", builtin_automonitor, AST_FEATURE_FLAG_NEEDSDTMF, "" },
1108 { AST_FEATURE_DISCONNECT, "Disconnect Call", "disconnect", "*", "*", builtin_disconnect, AST_FEATURE_FLAG_NEEDSDTMF, "" },
1109 { AST_FEATURE_PARKCALL, "Park Call", "parkcall", "", "", builtin_parkcall, AST_FEATURE_FLAG_NEEDSDTMF, "" },
1113 static AST_LIST_HEAD_STATIC(feature_list,ast_call_feature);
1115 /*! \brief register new feature into feature_list*/
1116 void ast_register_feature(struct ast_call_feature *feature)
1119 ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
1123 AST_LIST_LOCK(&feature_list);
1124 AST_LIST_INSERT_HEAD(&feature_list,feature,feature_entry);
1125 AST_LIST_UNLOCK(&feature_list);
1127 ast_verb(2, "Registered Feature '%s'\n",feature->sname);
1131 * \brief Add new feature group
1132 * \param fgname feature group name
1133 * Add new feature group to the feature group list insert at head of list.
1134 * \note This function MUST be called while feature_groups is locked.
1136 static struct feature_group* register_group(const char *fgname)
1138 struct feature_group *fg;
1141 ast_log(LOG_NOTICE, "You didn't pass a new group name!\n");
1145 if (!(fg = ast_calloc(1, sizeof(*fg))))
1148 if (ast_string_field_init(fg, 128)) {
1153 ast_string_field_set(fg, gname, fgname);
1155 AST_LIST_INSERT_HEAD(&feature_groups, fg, entry);
1157 ast_verb(2, "Registered group '%s'\n", fg->gname);
1163 * \brief Add feature to group
1164 * \param fg feature group
1166 * \param feature feature to add
1167 * Check fg and feature specified, add feature to list
1168 * \note This function MUST be called while feature_groups is locked.
1170 static void register_group_feature(struct feature_group *fg, const char *exten, struct ast_call_feature *feature)
1172 struct feature_group_exten *fge;
1174 if (!(fge = ast_calloc(1, sizeof(*fge))))
1177 if (ast_string_field_init(fge, 128)) {
1183 ast_log(LOG_NOTICE, "You didn't pass a group!\n");
1188 ast_log(LOG_NOTICE, "You didn't pass a feature!\n");
1192 ast_string_field_set(fge, exten, (ast_strlen_zero(exten) ? feature->exten : exten));
1194 fge->feature = feature;
1196 AST_LIST_INSERT_HEAD(&fg->features, fge, entry);
1198 ast_verb(2, "Registered feature '%s' for group '%s' at exten '%s'\n",
1199 feature->sname, fg->gname, exten);
1202 void ast_unregister_feature(struct ast_call_feature *feature)
1207 AST_LIST_LOCK(&feature_list);
1208 AST_LIST_REMOVE(&feature_list,feature,feature_entry);
1209 AST_LIST_UNLOCK(&feature_list);
1213 /*! \brief Remove all features in the list */
1214 static void ast_unregister_features(void)
1216 struct ast_call_feature *feature;
1218 AST_LIST_LOCK(&feature_list);
1219 while ((feature = AST_LIST_REMOVE_HEAD(&feature_list,feature_entry)))
1221 AST_LIST_UNLOCK(&feature_list);
1224 /*! \brief find a call feature by name */
1225 static struct ast_call_feature *find_dynamic_feature(const char *name)
1227 struct ast_call_feature *tmp;
1229 AST_LIST_TRAVERSE(&feature_list, tmp, feature_entry) {
1230 if (!strcasecmp(tmp->sname, name))
1237 /*! \brief Remove all feature groups in the list */
1238 static void ast_unregister_groups(void)
1240 struct feature_group *fg;
1241 struct feature_group_exten *fge;
1243 AST_RWLIST_WRLOCK(&feature_groups);
1244 while ((fg = AST_LIST_REMOVE_HEAD(&feature_groups, entry))) {
1245 while ((fge = AST_LIST_REMOVE_HEAD(&fg->features, entry))) {
1246 ast_string_field_free_all(fge);
1250 ast_string_field_free_all(fg);
1253 AST_RWLIST_UNLOCK(&feature_groups);
1257 * \brief Find a group by name
1258 * \param name feature name
1259 * \retval feature group on success.
1260 * \retval NULL on failure.
1262 static struct feature_group *find_group(const char *name) {
1263 struct feature_group *fg = NULL;
1265 AST_LIST_TRAVERSE(&feature_groups, fg, entry) {
1266 if (!strcasecmp(fg->gname, name))
1274 * \brief Find a feature extension
1276 * \retval feature group extension on success.
1277 * \retval NULL on failure.
1279 static struct feature_group_exten *find_group_exten(struct feature_group *fg, const char *code) {
1280 struct feature_group_exten *fge = NULL;
1282 AST_LIST_TRAVERSE(&fg->features, fge, entry) {
1283 if(!strcasecmp(fge->exten, code))
1290 void ast_rdlock_call_features(void)
1292 ast_rwlock_rdlock(&features_lock);
1295 void ast_unlock_call_features(void)
1297 ast_rwlock_unlock(&features_lock);
1300 struct ast_call_feature *ast_find_call_feature(const char *name)
1303 for (x = 0; x < FEATURES_COUNT; x++) {
1304 if (!strcasecmp(name, builtin_features[x].sname))
1305 return &builtin_features[x];
1311 * \brief exec an app by feature
1312 * \param chan,peer,config,code,sense
1313 * Find a feature, determine which channel activated
1314 * \retval FEATURE_RETURN_PBX_KEEPALIVE,FEATURE_RETURN_NO_HANGUP_PEER
1316 * \retval -2 when an application cannot be found.
1318 static int feature_exec_app(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
1320 struct ast_app *app;
1321 struct ast_call_feature *feature = data;
1322 struct ast_channel *work, *idle;
1325 if (!feature) { /* shouldn't ever happen! */
1326 ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n");
1330 if (sense == FEATURE_SENSE_CHAN) {
1331 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
1332 return FEATURE_RETURN_PASSDIGITS;
1333 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
1341 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
1342 return FEATURE_RETURN_PASSDIGITS;
1343 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
1352 if (!(app = pbx_findapp(feature->app))) {
1353 ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app);
1357 ast_autoservice_start(idle);
1359 if (!ast_strlen_zero(feature->moh_class))
1360 ast_moh_start(idle, feature->moh_class, NULL);
1362 res = pbx_exec(work, app, feature->app_args);
1364 if (!ast_strlen_zero(feature->moh_class))
1367 ast_autoservice_stop(idle);
1369 if (res == AST_PBX_KEEPALIVE)
1370 return FEATURE_RETURN_PBX_KEEPALIVE;
1371 else if (res == AST_PBX_NO_HANGUP_PEER)
1372 return FEATURE_RETURN_NO_HANGUP_PEER;
1374 return FEATURE_RETURN_SUCCESSBREAK;
1376 return FEATURE_RETURN_SUCCESS; /*! \todo XXX should probably return res */
1379 static void unmap_features(void)
1383 ast_rwlock_wrlock(&features_lock);
1384 for (x = 0; x < FEATURES_COUNT; x++)
1385 strcpy(builtin_features[x].exten, builtin_features[x].default_exten);
1386 ast_rwlock_unlock(&features_lock);
1389 static int remap_feature(const char *name, const char *value)
1393 ast_rwlock_wrlock(&features_lock);
1394 for (x = 0; x < FEATURES_COUNT; x++) {
1395 if (strcasecmp(builtin_features[x].sname, name))
1398 ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten));
1402 ast_rwlock_unlock(&features_lock);
1408 * \brief Check the dynamic features
1409 * \param chan,peer,config,code,sense
1410 * Lock features list, browse for code, unlock list
1411 * \retval res on success.
1412 * \retval -1 on failure.
1414 static int ast_feature_interpret(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
1417 struct ast_flags features;
1418 int res = FEATURE_RETURN_PASSDIGITS;
1419 struct ast_call_feature *feature;
1420 struct feature_group *fg = NULL;
1421 struct feature_group_exten *fge;
1422 const char *dynamic_features=pbx_builtin_getvar_helper(chan,"DYNAMIC_FEATURES");
1425 if (sense == FEATURE_SENSE_CHAN)
1426 ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);
1428 ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL);
1429 ast_debug(3, "Feature interpret: chan=%s, peer=%s, sense=%d, features=%d\n", chan->name, peer->name, sense, features.flags);
1431 ast_rwlock_rdlock(&features_lock);
1432 for (x = 0; x < FEATURES_COUNT; x++) {
1433 if ((ast_test_flag(&features, builtin_features[x].feature_mask)) &&
1434 !ast_strlen_zero(builtin_features[x].exten)) {
1435 /* Feature is up for consideration */
1436 if (!strcmp(builtin_features[x].exten, code)) {
1437 res = builtin_features[x].operation(chan, peer, config, code, sense, NULL);
1439 } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) {
1440 if (res == FEATURE_RETURN_PASSDIGITS)
1441 res = FEATURE_RETURN_STOREDIGITS;
1445 ast_rwlock_unlock(&features_lock);
1447 if (ast_strlen_zero(dynamic_features))
1450 tmp = ast_strdupa(dynamic_features);
1452 while ((tok = strsep(&tmp, "#"))) {
1453 AST_RWLIST_RDLOCK(&feature_groups);
1455 fg = find_group(tok);
1457 if (fg && (fge = find_group_exten(fg, code))) {
1458 res = fge->feature->operation(chan, peer, config, code, sense, fge->feature);
1459 AST_RWLIST_UNLOCK(&feature_groups);
1463 AST_RWLIST_UNLOCK(&feature_groups);
1464 AST_LIST_LOCK(&feature_list);
1466 if(!(feature = find_dynamic_feature(tok))) {
1467 AST_LIST_UNLOCK(&feature_list);
1471 /* Feature is up for consideration */
1472 if (!strcmp(feature->exten, code)) {
1473 ast_verb(3, " Feature Found: %s exten: %s\n",feature->sname, tok);
1474 res = feature->operation(chan, peer, config, code, sense, feature);
1475 AST_LIST_UNLOCK(&feature_list);
1477 } else if (!strncmp(feature->exten, code, strlen(code)))
1478 res = FEATURE_RETURN_STOREDIGITS;
1480 AST_LIST_UNLOCK(&feature_list);
1486 static void set_config_flags(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
1490 ast_clear_flag(config, AST_FLAGS_ALL);
1492 ast_rwlock_rdlock(&features_lock);
1493 for (x = 0; x < FEATURES_COUNT; x++) {
1494 if (!ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF))
1497 if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask))
1498 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
1500 if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask))
1501 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
1503 ast_rwlock_unlock(&features_lock);
1505 if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) {
1506 const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
1508 if (dynamic_features) {
1509 char *tmp = ast_strdupa(dynamic_features);
1511 struct ast_call_feature *feature;
1513 /* while we have a feature */
1514 while ((tok = strsep(&tmp, "#"))) {
1515 AST_LIST_LOCK(&feature_list);
1516 if ((feature = find_dynamic_feature(tok)) && ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) {
1517 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
1518 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
1519 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
1520 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
1522 AST_LIST_UNLOCK(&feature_list);
1530 * \param caller,transferee,type,format,data,timeout,outstate,cid_num,cid_name,igncallerstate
1531 * Request channel, set channel variables, initiate call,check if they want to disconnect
1532 * go into loop, check if timeout has elapsed, check if person to be transfered hung up,
1533 * check for answer break loop, set cdr return channel.
1534 * \todo XXX Check - this is very similar to the code in channel.c
1535 * \return always a channel
1537 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)
1542 struct ast_channel *chan;
1543 struct ast_channel *monitor_chans[2];
1544 struct ast_channel *active_channel;
1545 int res = 0, ready = 0;
1547 if ((chan = ast_request(type, format, data, &cause))) {
1548 ast_set_callerid(chan, cid_num, cid_name, cid_num);
1549 ast_channel_inherit_variables(caller, chan);
1550 pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", caller->name);
1552 chan->cdr=ast_cdr_alloc();
1554 ast_cdr_init(chan->cdr, chan); /* initilize our channel's cdr */
1555 ast_cdr_start(chan->cdr);
1559 if (!ast_call(chan, data, timeout)) {
1560 struct timeval started;
1562 char *disconnect_code = NULL, *dialed_code = NULL;
1564 ast_indicate(caller, AST_CONTROL_RINGING);
1565 /* support dialing of the featuremap disconnect code while performing an attended tranfer */
1566 ast_rwlock_rdlock(&features_lock);
1567 for (x = 0; x < FEATURES_COUNT; x++) {
1568 if (strcasecmp(builtin_features[x].sname, "disconnect"))
1571 disconnect_code = builtin_features[x].exten;
1572 len = strlen(disconnect_code) + 1;
1573 dialed_code = alloca(len);
1574 memset(dialed_code, 0, len);
1577 ast_rwlock_unlock(&features_lock);
1579 started = ast_tvnow();
1582 ast_poll_channel_add(caller, chan);
1584 while (!((transferee && ast_check_hangup(transferee)) && (!igncallerstate && ast_check_hangup(caller))) && timeout && (chan->_state != AST_STATE_UP)) {
1585 struct ast_frame *f = NULL;
1587 monitor_chans[0] = caller;
1588 monitor_chans[1] = chan;
1589 active_channel = ast_waitfor_n(monitor_chans, 2, &to);
1591 /* see if the timeout has been violated */
1592 if(ast_tvdiff_ms(ast_tvnow(), started) > timeout) {
1593 state = AST_CONTROL_UNHOLD;
1594 ast_log(LOG_NOTICE, "We exceeded our AT-timeout\n");
1595 break; /*doh! timeout*/
1598 if (!active_channel)
1601 if (chan && (chan == active_channel)){
1603 if (f == NULL) { /*doh! where'd he go?*/
1604 state = AST_CONTROL_HANGUP;
1609 if (f->frametype == AST_FRAME_CONTROL || f->frametype == AST_FRAME_DTMF || f->frametype == AST_FRAME_TEXT) {
1610 if (f->subclass == AST_CONTROL_RINGING) {
1611 state = f->subclass;
1612 ast_verb(3, "%s is ringing\n", chan->name);
1613 ast_indicate(caller, AST_CONTROL_RINGING);
1614 } else if ((f->subclass == AST_CONTROL_BUSY) || (f->subclass == AST_CONTROL_CONGESTION)) {
1615 state = f->subclass;
1616 ast_verb(3, "%s is busy\n", chan->name);
1617 ast_indicate(caller, AST_CONTROL_BUSY);
1621 } else if (f->subclass == AST_CONTROL_ANSWER) {
1622 /* This is what we are hoping for */
1623 state = f->subclass;
1628 } else if (f->subclass == -1) {
1629 if (option_verbose > 2)
1630 ast_verbose( VERBOSE_PREFIX_3 "%s stopped sounds\n", chan->name);
1631 ast_indicate(caller, -1);
1636 ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass);
1638 /* else who cares */
1641 } else if (caller && (active_channel == caller)) {
1642 f = ast_read(caller);
1643 if (f == NULL) { /*doh! where'd he go?*/
1644 if (!igncallerstate) {
1645 if (ast_check_hangup(caller) && !ast_check_hangup(chan)) {
1646 /* make this a blind transfer */
1650 state = AST_CONTROL_HANGUP;
1656 if (f->frametype == AST_FRAME_DTMF) {
1657 dialed_code[x++] = f->subclass;
1658 dialed_code[x] = '\0';
1659 if (strlen(dialed_code) == len) {
1661 } else if (x && strncmp(dialed_code, disconnect_code, x)) {
1663 dialed_code[x] = '\0';
1665 if (*dialed_code && !strcmp(dialed_code, disconnect_code)) {
1666 /* Caller Canceled the call */
1667 state = AST_CONTROL_UNHOLD;
1679 ast_poll_channel_del(caller, chan);
1682 ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data);
1684 ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
1686 case AST_CAUSE_BUSY:
1687 state = AST_CONTROL_BUSY;
1689 case AST_CAUSE_CONGESTION:
1690 state = AST_CONTROL_CONGESTION;
1695 ast_indicate(caller, -1);
1696 if (chan && ready) {
1697 if (chan->_state == AST_STATE_UP)
1698 state = AST_CONTROL_ANSWER;
1711 if (chan && res <= 0) {
1712 if (chan->cdr || (chan->cdr = ast_cdr_alloc())) {
1714 ast_cdr_init(chan->cdr, chan);
1715 snprintf(tmp, 256, "%s/%s", type, (char *)data);
1716 ast_cdr_setapp(chan->cdr,"Dial",tmp);
1717 ast_cdr_update(chan);
1718 ast_cdr_start(chan->cdr);
1719 ast_cdr_end(chan->cdr);
1720 /* If the cause wasn't handled properly */
1721 if (ast_cdr_disposition(chan->cdr,chan->hangupcause))
1722 ast_cdr_failed(chan->cdr);
1724 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
1732 * \brief bridge the call and set CDR
1733 * \param chan,peer,config
1734 * Set start time, check for two channels,check if monitor on
1735 * check for feature activation, create new CDR
1736 * \retval res on success.
1737 * \retval -1 on failure to bridge.
1739 int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast_bridge_config *config)
1741 /* Copy voice back and forth between the two channels. Give the peer
1742 the ability to transfer calls with '#<extension' syntax. */
1743 struct ast_frame *f;
1744 struct ast_channel *who;
1745 char chan_featurecode[FEATURE_MAX_LEN + 1]="";
1746 char peer_featurecode[FEATURE_MAX_LEN + 1]="";
1751 struct ast_option_header *aoh;
1752 struct ast_bridge_config backup_config;
1753 struct ast_cdr *bridge_cdr;
1755 memset(&backup_config, 0, sizeof(backup_config));
1757 config->start_time = ast_tvnow();
1760 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
1761 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
1763 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
1766 const char *monitor_exec;
1767 struct ast_channel *src = NULL;
1769 if (!(monitor_app = pbx_findapp("Monitor")))
1772 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR")))
1774 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
1776 if (monitor_app && src) {
1777 char *tmp = ast_strdupa(monitor_exec);
1778 pbx_exec(src, monitor_app, tmp);
1782 set_config_flags(chan, peer, config);
1783 config->firstpass = 1;
1785 /* Answer if need be */
1786 if (ast_answer(chan))
1788 peer->appl = "Bridged Call";
1789 peer->data = chan->name;
1791 /* copy the userfield from the B-leg to A-leg if applicable */
1792 if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) {
1794 if (!ast_strlen_zero(chan->cdr->userfield)) {
1795 snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield);
1796 ast_cdr_appenduserfield(chan, tmp);
1798 ast_cdr_setuserfield(chan, peer->cdr->userfield);
1799 /* free the peer's cdr without ast_cdr_free complaining */
1800 ast_free(peer->cdr);
1805 struct ast_channel *other; /* used later */
1807 res = ast_channel_bridge(chan, peer, config, &f, &who);
1809 if (config->feature_timer) {
1810 /* Update time limit for next pass */
1811 diff = ast_tvdiff_ms(ast_tvnow(), config->start_time);
1812 config->feature_timer -= diff;
1814 /* Running on backup config, meaning a feature might be being
1815 activated, but that's no excuse to keep things going
1817 if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) {
1818 ast_debug(1, "Timed out, realtime this time!\n");
1819 config->feature_timer = 0;
1825 } else if (config->feature_timer <= 0) {
1826 /* Not *really* out of time, just out of time for
1827 digits to come in for features. */
1828 ast_debug(1, "Timed out for feature!\n");
1829 if (!ast_strlen_zero(peer_featurecode)) {
1830 ast_dtmf_stream(chan, peer, peer_featurecode, 0, 0);
1831 memset(peer_featurecode, 0, sizeof(peer_featurecode));
1833 if (!ast_strlen_zero(chan_featurecode)) {
1834 ast_dtmf_stream(peer, chan, chan_featurecode, 0, 0);
1835 memset(chan_featurecode, 0, sizeof(chan_featurecode));
1839 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
1841 /* Restore original (possibly time modified) bridge config */
1842 memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
1843 memset(&backup_config, 0, sizeof(backup_config));
1845 hadfeatures = hasfeatures;
1846 /* Continue as we were */
1849 /* The bridge returned without a frame and there is a feature in progress.
1850 * However, we don't think the feature has quite yet timed out, so just
1851 * go back into the bridge. */
1855 if (config->feature_timer <=0) {
1856 /* We ran out of time */
1857 config->feature_timer = 0;
1867 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
1871 if (!f || (f->frametype == AST_FRAME_CONTROL &&
1872 (f->subclass == AST_CONTROL_HANGUP || f->subclass == AST_CONTROL_BUSY ||
1873 f->subclass == AST_CONTROL_CONGESTION))) {
1877 /* many things should be sent to the 'other' channel */
1878 other = (who == chan) ? peer : chan;
1879 if (f->frametype == AST_FRAME_CONTROL) {
1880 switch (f->subclass) {
1881 case AST_CONTROL_RINGING:
1882 case AST_CONTROL_FLASH:
1884 ast_indicate(other, f->subclass);
1886 case AST_CONTROL_HOLD:
1887 case AST_CONTROL_UNHOLD:
1888 ast_indicate_data(other, f->subclass, f->data, f->datalen);
1890 case AST_CONTROL_OPTION:
1892 /* Forward option Requests */
1893 if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) {
1894 ast_channel_setoption(other, ntohs(aoh->option), aoh->data,
1895 f->datalen - sizeof(struct ast_option_header), 0);
1899 } else if (f->frametype == AST_FRAME_DTMF_BEGIN) {
1901 } else if (f->frametype == AST_FRAME_DTMF) {
1905 hadfeatures = hasfeatures;
1906 /* This cannot overrun because the longest feature is one shorter than our buffer */
1908 sense = FEATURE_SENSE_CHAN;
1909 featurecode = chan_featurecode;
1911 sense = FEATURE_SENSE_PEER;
1912 featurecode = peer_featurecode;
1914 /*! append the event to featurecode. we rely on the string being zero-filled, and
1915 * not overflowing it.
1916 * \todo XXX how do we guarantee the latter ?
1918 featurecode[strlen(featurecode)] = f->subclass;
1919 /* Get rid of the frame before we start doing "stuff" with the channels */
1922 config->feature_timer = backup_config.feature_timer;
1923 res = ast_feature_interpret(chan, peer, config, featurecode, sense);
1925 case FEATURE_RETURN_PASSDIGITS:
1926 ast_dtmf_stream(other, who, featurecode, 0, 0);
1928 case FEATURE_RETURN_SUCCESS:
1929 memset(featurecode, 0, sizeof(chan_featurecode));
1932 if (res >= FEATURE_RETURN_PASSDIGITS) {
1936 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
1937 if (hadfeatures && !hasfeatures) {
1938 /* Restore backup */
1939 memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
1940 memset(&backup_config, 0, sizeof(struct ast_bridge_config));
1941 } else if (hasfeatures) {
1943 /* Backup configuration */
1944 memcpy(&backup_config, config, sizeof(struct ast_bridge_config));
1945 /* Setup temporary config options */
1946 config->play_warning = 0;
1947 ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
1948 ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
1949 config->warning_freq = 0;
1950 config->warning_sound = NULL;
1951 config->end_sound = NULL;
1952 config->start_sound = NULL;
1953 config->firstpass = 0;
1955 config->start_time = ast_tvnow();
1956 config->feature_timer = featuredigittimeout;
1957 ast_debug(1, "Set time limit to %ld\n", config->feature_timer);
1964 /* arrange the cdrs */
1965 bridge_cdr = ast_cdr_alloc();
1967 if (chan->cdr && peer->cdr) { /* both of them? merge */
1968 ast_cdr_init(bridge_cdr,chan); /* seems more logicaller to use the destination as a base, but, really, it's random */
1969 ast_cdr_start(bridge_cdr); /* now is the time to start */
1971 /* absorb the channel cdr */
1972 ast_cdr_merge(bridge_cdr, chan->cdr);
1973 if (!ast_test_flag(chan->cdr, AST_CDR_FLAG_LOCKED))
1974 ast_cdr_discard(chan->cdr); /* if locked cdrs are in chan, they are taken over in the merge */
1976 /* absorb the peer cdr */
1977 ast_cdr_merge(bridge_cdr, peer->cdr);
1978 if (ast_test_flag(peer->cdr, AST_CDR_FLAG_LOCKED))
1979 ast_cdr_discard(peer->cdr); /* if locked cdrs are in peer, they are taken over in the merge */
1982 chan->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */
1983 } else if (chan->cdr) {
1984 /* take the cdr from the channel - literally */
1985 ast_cdr_init(bridge_cdr,chan);
1986 /* absorb this data */
1987 ast_cdr_merge(bridge_cdr, chan->cdr);
1988 if (!ast_test_flag(chan->cdr, AST_CDR_FLAG_LOCKED))
1989 ast_cdr_discard(chan->cdr); /* if locked cdrs are in chan, they are taken over in the merge */
1990 chan->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */
1991 } else if (peer->cdr) {
1992 /* take the cdr from the peer - literally */
1993 ast_cdr_init(bridge_cdr,peer);
1994 /* absorb this data */
1995 ast_cdr_merge(bridge_cdr, peer->cdr);
1996 if (!ast_test_flag(peer->cdr, AST_CDR_FLAG_LOCKED))
1997 ast_cdr_discard(peer->cdr); /* if locked cdrs are in chan, they are taken over in the merge */
1999 peer->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */
2001 /* make up a new cdr */
2002 ast_cdr_init(bridge_cdr,chan); /* eh, just pick one of them */
2003 chan->cdr = bridge_cdr; /* */
2005 if (ast_strlen_zero(bridge_cdr->dstchannel)) {
2006 if (strcmp(bridge_cdr->channel, peer->name) != 0)
2007 ast_cdr_setdestchan(bridge_cdr, peer->name);
2009 ast_cdr_setdestchan(bridge_cdr, chan->name);
2015 /*! \brief Output parking event to manager */
2016 static void post_manager_event(const char *s, struct parkeduser *pu)
2018 manager_event(EVENT_FLAG_CALL, s,
2021 "CallerIDNum: %s\r\n"
2022 "CallerIDName: %s\r\n\r\n",
2025 S_OR(pu->chan->cid.cid_num, "<unknown>"),
2026 S_OR(pu->chan->cid.cid_name, "<unknown>")
2031 * \brief Take care of parked calls and unpark them if needed
2032 * \param ignore unused var
2033 * Start inf loop, lock parking lot, check if any parked channels have gone above timeout
2034 * if so, remove channel from parking lot and return it to the extension that parked it.
2035 * Check if parked channel decided to hangup, wait until next FD via select().
2037 static void *do_parking_thread(void *ignore)
2039 char parkingslot[AST_MAX_EXTENSION];
2040 fd_set rfds, efds; /* results from previous select, to be preserved across loops. */
2046 struct parkeduser *pu;
2047 int ms = -1; /* select timeout, uninitialized */
2048 int max = -1; /* max fd, none there yet */
2049 fd_set nrfds, nefds; /* args for the next select */
2053 AST_LIST_LOCK(&parkinglot);
2054 AST_LIST_TRAVERSE_SAFE_BEGIN(&parkinglot, pu, list) {
2055 struct ast_channel *chan = pu->chan; /* shorthand */
2056 int tms; /* timeout for this item */
2057 int x; /* fd index in channel */
2058 struct ast_context *con;
2060 if (pu->notquiteyet) /* Pretend this one isn't here yet */
2062 tms = ast_tvdiff_ms(ast_tvnow(), pu->start);
2063 if (tms > pu->parkingtime) {
2064 ast_indicate(chan, AST_CONTROL_UNHOLD);
2065 /* Get chan, exten from derived kludge */
2066 if (pu->peername[0]) {
2067 char *peername = ast_strdupa(pu->peername);
2068 char *cp = strrchr(peername, '-');
2071 con = ast_context_find(parking_con_dial);
2073 con = ast_context_create(NULL, parking_con_dial, registrar);
2075 ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial);
2078 char returnexten[AST_MAX_EXTENSION];
2079 snprintf(returnexten, sizeof(returnexten), "%s,,t", peername);
2080 ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", ast_strdup(returnexten), ast_free, registrar);
2082 if (comebacktoorigin) {
2083 set_c_e_p(chan, parking_con_dial, peername, 1);
2085 ast_log(LOG_WARNING, "now going to parkedcallstimeout,s,1 | ps is %d\n",pu->parkingnum);
2086 snprintf(parkingslot, sizeof(parkingslot), "%d", pu->parkingnum);
2087 pbx_builtin_setvar_helper(pu->chan, "PARKINGSLOT", parkingslot);
2088 set_c_e_p(chan, "parkedcallstimeout", peername, 1);
2091 /* They've been waiting too long, send them back to where they came. Theoretically they
2092 should have their original extensions and such, but we copy to be on the safe side */
2093 set_c_e_p(chan, pu->context, pu->exten, pu->priority);
2096 post_manager_event("ParkedCallTimeOut", pu);
2098 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);
2099 /* Start up the PBX, or hang them up */
2100 if (ast_pbx_start(chan)) {
2101 ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", chan->name);
2104 /* And take them out of the parking lot */
2105 AST_LIST_REMOVE_CURRENT(&parkinglot, list);
2106 con = ast_context_find(parking_con);
2108 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL))
2109 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
2111 notify_metermaids(pu->parkingexten, parking_con, AST_DEVICE_NOT_INUSE);
2113 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
2115 } else { /* still within parking time, process descriptors */
2116 for (x = 0; x < AST_MAX_FDS; x++) {
2117 struct ast_frame *f;
2119 if (chan->fds[x] == -1 || (!FD_ISSET(chan->fds[x], &rfds) && !FD_ISSET(chan->fds[x], &efds)))
2120 continue; /* nothing on this descriptor */
2122 if (FD_ISSET(chan->fds[x], &efds))
2123 ast_set_flag(chan, AST_FLAG_EXCEPTION);
2125 ast_clear_flag(chan, AST_FLAG_EXCEPTION);
2128 /* See if they need servicing */
2130 if (!f || (f->frametype == AST_FRAME_CONTROL && f->subclass == AST_CONTROL_HANGUP)) {
2133 post_manager_event("ParkedCallGiveUp", pu);
2135 /* There's a problem, hang them up*/
2136 ast_verb(2, "%s got tired of being parked\n", chan->name);
2138 /* And take them out of the parking lot */
2139 AST_LIST_REMOVE_CURRENT(&parkinglot, list);
2140 con = ast_context_find(parking_con);
2142 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL))
2143 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
2145 notify_metermaids(pu->parkingexten, parking_con, AST_DEVICE_NOT_INUSE);
2147 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
2151 /*! \todo XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
2153 if (pu->moh_trys < 3 && !chan->generatordata) {
2154 ast_debug(1, "MOH on parked call stopped by outside source. Restarting.\n");
2155 ast_indicate_data(chan, AST_CONTROL_HOLD,
2156 S_OR(parkmohclass, NULL),
2157 !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
2160 goto std; /*! \todo XXX Ick: jumping into an else statement??? XXX */
2164 if (x >= AST_MAX_FDS) {
2165 std: for (x=0; x<AST_MAX_FDS; x++) { /* mark fds for next round */
2166 if (chan->fds[x] > -1) {
2167 FD_SET(chan->fds[x], &nrfds);
2168 FD_SET(chan->fds[x], &nefds);
2169 if (chan->fds[x] > max)
2173 /* Keep track of our shortest wait */
2174 if (tms < ms || ms < 0)
2179 AST_LIST_TRAVERSE_SAFE_END
2180 AST_LIST_UNLOCK(&parkinglot);
2184 struct timeval tv = ast_samp2tv(ms, 1000);
2185 /* Wait for something to happen */
2186 ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL);
2188 pthread_testcancel();
2190 return NULL; /* Never reached */
2193 /*! \brief Park a call */
2194 static int park_call_exec(struct ast_channel *chan, void *data)
2196 /* Data is unused at the moment but could contain a parking
2197 lot context eventually */
2199 struct ast_module_user *u;
2201 u = ast_module_user_add(chan);
2203 /* Setup the exten/priority to be s/1 since we don't know
2204 where this call should return */
2205 strcpy(chan->exten, "s");
2207 /* Answer if call is not up */
2208 if (chan->_state != AST_STATE_UP)
2209 res = ast_answer(chan);
2210 /* Sleep to allow VoIP streams to settle down */
2212 res = ast_safe_sleep(chan, 1000);
2215 res = ast_park_call(chan, chan, 0, NULL);
2217 ast_module_user_remove(u);
2219 return !res ? AST_PBX_KEEPALIVE : res;
2222 /*! \brief Pickup parked call */
2223 static int park_exec(struct ast_channel *chan, void *data)
2226 struct ast_module_user *u;
2227 struct ast_channel *peer=NULL;
2228 struct parkeduser *pu;
2229 struct ast_context *con;
2232 struct ast_bridge_config config;
2235 ast_log(LOG_WARNING, "Parkedcall requires an argument (extension number)\n");
2239 u = ast_module_user_add(chan);
2241 park = atoi((char *)data);
2243 AST_LIST_LOCK(&parkinglot);
2244 AST_LIST_TRAVERSE_SAFE_BEGIN(&parkinglot, pu, list) {
2245 if (pu->parkingnum == park) {
2246 AST_LIST_REMOVE_CURRENT(&parkinglot, list);
2250 AST_LIST_TRAVERSE_SAFE_END
2251 AST_LIST_UNLOCK(&parkinglot);
2255 con = ast_context_find(parking_con);
2257 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL))
2258 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
2260 notify_metermaids(pu->parkingexten, parking_con, AST_DEVICE_NOT_INUSE);
2262 ast_log(LOG_WARNING, "Whoa, no parking context?\n");
2264 manager_event(EVENT_FLAG_CALL, "UnParkedCall",
2268 "CallerIDNum: %s\r\n"
2269 "CallerIDName: %s\r\n",
2270 pu->parkingexten, pu->chan->name, chan->name,
2271 S_OR(pu->chan->cid.cid_num, "<unknown>"),
2272 S_OR(pu->chan->cid.cid_name, "<unknown>")
2277 /* JK02: it helps to answer the channel if not already up */
2278 if (chan->_state != AST_STATE_UP)
2282 /* Play a courtesy to the source(s) configured to prefix the bridge connecting */
2284 if (!ast_strlen_zero(courtesytone)) {
2286 ast_indicate(peer, AST_CONTROL_UNHOLD);
2287 if (parkedplay == 0) {
2288 error = ast_stream_and_wait(chan, courtesytone, "");
2289 } else if (parkedplay == 1) {
2290 error = ast_stream_and_wait(peer, courtesytone, "");
2291 } else if (parkedplay == 2) {
2292 if (!ast_streamfile(chan, courtesytone, chan->language) &&
2293 !ast_streamfile(peer, courtesytone, chan->language)) {
2294 /*! \todo XXX we would like to wait on both! */
2295 res = ast_waitstream(chan, "");
2297 res = ast_waitstream(peer, "");
2303 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
2308 ast_indicate(peer, AST_CONTROL_UNHOLD);
2310 res = ast_channel_make_compatible(chan, peer);
2312 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
2316 /* This runs sorta backwards, since we give the incoming channel control, as if it
2317 were the person called. */
2318 ast_verb(3, "Channel %s connected to parked call %d\n", chan->name, park);
2320 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
2321 ast_cdr_setdestchan(chan->cdr, peer->name);
2322 memset(&config, 0, sizeof(struct ast_bridge_config));
2323 if ((parkedcalltransfers == AST_FEATURE_FLAG_BYCALLEE) || (parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH))
2324 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
2325 if ((parkedcalltransfers == AST_FEATURE_FLAG_BYCALLER) || (parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH))
2326 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
2327 if ((parkedcallreparking == AST_FEATURE_FLAG_BYCALLEE) || (parkedcallreparking == AST_FEATURE_FLAG_BYBOTH))
2328 ast_set_flag(&(config.features_callee), AST_FEATURE_PARKCALL);
2329 if ((parkedcallreparking == AST_FEATURE_FLAG_BYCALLER) || (parkedcallreparking == AST_FEATURE_FLAG_BYBOTH))
2330 ast_set_flag(&(config.features_caller), AST_FEATURE_PARKCALL);
2331 res = ast_bridge_call(chan, peer, &config);
2333 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
2334 ast_cdr_setdestchan(chan->cdr, peer->name);
2336 /* Simulate the PBX hanging up */
2337 if (res != AST_PBX_NO_HANGUP_PEER)
2341 /*! \todo XXX Play a message XXX */
2342 if (ast_stream_and_wait(chan, "pbx-invalidpark", ""))
2343 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
2344 ast_verb(3, "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park);
2348 ast_module_user_remove(u);
2353 static int handle_showfeatures(int fd, int argc, char *argv[])
2356 struct ast_call_feature *feature;
2357 char format[] = "%-25s %-7s %-7s\n";
2359 ast_cli(fd, format, "Builtin Feature", "Default", "Current");
2360 ast_cli(fd, format, "---------------", "-------", "-------");
2362 ast_cli(fd, format, "Pickup", "*8", ast_pickup_ext()); /* default hardcoded above, so we'll hardcode it here */
2364 ast_rwlock_rdlock(&features_lock);
2365 for (i = 0; i < FEATURES_COUNT; i++)
2366 ast_cli(fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
2367 ast_rwlock_unlock(&features_lock);
2370 ast_cli(fd, format, "Dynamic Feature", "Default", "Current");
2371 ast_cli(fd, format, "---------------", "-------", "-------");
2372 if (AST_LIST_EMPTY(&feature_list))
2373 ast_cli(fd, "(none)\n");
2375 AST_LIST_LOCK(&feature_list);
2376 AST_LIST_TRAVERSE(&feature_list, feature, feature_entry)
2377 ast_cli(fd, format, feature->sname, "no def", feature->exten);
2378 AST_LIST_UNLOCK(&feature_list);
2380 ast_cli(fd, "\nCall parking\n");
2381 ast_cli(fd, "------------\n");
2382 ast_cli(fd,"%-20s: %s\n", "Parking extension", parking_ext);
2383 ast_cli(fd,"%-20s: %s\n", "Parking context", parking_con);
2384 ast_cli(fd,"%-20s: %d-%d\n", "Parked call extensions", parking_start, parking_stop);
2387 return RESULT_SUCCESS;
2390 static char mandescr_bridge[] =
2391 "Description: Bridge together two channels already in the PBX\n"
2392 "Variables: ( Headers marked with * are required )\n"
2393 " *Channel1: Channel to Bridge to Channel2\n"
2394 " *Channel2: Channel to Bridge to Channel1\n"
2395 " Tone: (Yes|No) Play courtesy tone to Channel 2\n"
2399 * \brief Actual bridge
2402 * Stop hold music, lock both channels, masq channels,
2403 * after bridge return channel to next priority.
2405 static void do_bridge_masquerade(struct ast_channel *chan, struct ast_channel *tmpchan)
2408 ast_mutex_lock(&chan->lock);
2409 ast_setstate(tmpchan, chan->_state);
2410 tmpchan->readformat = chan->readformat;
2411 tmpchan->writeformat = chan->writeformat;
2412 ast_channel_masquerade(tmpchan, chan);
2413 ast_mutex_lock(&tmpchan->lock);
2414 ast_do_masquerade(tmpchan);
2415 /* when returning from bridge, the channel will continue at the next priority */
2416 ast_explicit_goto(tmpchan, chan->context, chan->exten, chan->priority + 1);
2417 ast_mutex_unlock(&tmpchan->lock);
2418 ast_mutex_unlock(&chan->lock);
2422 * \brief Bridge channels together
2425 * Make sure valid channels were specified,
2426 * send errors if any of the channels could not be found/locked, answer channels if needed,
2427 * create the placeholder channels and grab the other channels
2428 * make the channels compatible, send error if we fail doing so
2429 * setup the bridge thread object and start the bridge.
2430 * \retval 0 on success or on incorrect use.
2431 * \retval 1 on failure to bridge channels.
2433 static int action_bridge(struct mansession *s, const struct message *m)
2435 const char *channela = astman_get_header(m, "Channel1");
2436 const char *channelb = astman_get_header(m, "Channel2");
2437 const char *playtone = astman_get_header(m, "Tone");
2438 struct ast_channel *chana = NULL, *chanb = NULL;
2439 struct ast_channel *tmpchana = NULL, *tmpchanb = NULL;
2440 struct ast_bridge_thread_obj *tobj = NULL;
2442 /* make sure valid channels were specified */
2443 if (!ast_strlen_zero(channela) && !ast_strlen_zero(channelb)) {
2444 chana = ast_get_channel_by_name_prefix_locked(channela, strlen(channela));
2445 chanb = ast_get_channel_by_name_prefix_locked(channelb, strlen(channelb));
2447 ast_mutex_unlock(&chana->lock);
2449 ast_mutex_unlock(&chanb->lock);
2451 /* send errors if any of the channels could not be found/locked */
2454 snprintf(buf, sizeof(buf), "Channel1 does not exists: %s", channela);
2455 astman_send_error(s, m, buf);
2460 snprintf(buf, sizeof(buf), "Channel2 does not exists: %s", channelb);
2461 astman_send_error(s, m, buf);
2465 astman_send_error(s, m, "Missing channel parameter in request");
2469 /* Answer the channels if needed */
2470 if (chana->_state != AST_STATE_UP)
2472 if (chanb->_state != AST_STATE_UP)
2475 /* create the placeholder channels and grab the other channels */
2476 if (!(tmpchana = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
2477 NULL, NULL, 0, "Bridge/%s", chana->name))) {
2478 astman_send_error(s, m, "Unable to create temporary channel!");
2482 if (!(tmpchanb = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
2483 NULL, NULL, 0, "Bridge/%s", chanb->name))) {
2484 astman_send_error(s, m, "Unable to create temporary channels!");
2485 ast_channel_free(tmpchana);
2489 do_bridge_masquerade(chana, tmpchana);
2490 do_bridge_masquerade(chanb, tmpchanb);
2492 /* make the channels compatible, send error if we fail doing so */
2493 if (ast_channel_make_compatible(tmpchana, tmpchanb)) {
2494 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for manager bridge\n", tmpchana->name, tmpchanb->name);
2495 astman_send_error(s, m, "Could not make channels compatible for manager bridge");
2496 ast_hangup(tmpchana);
2497 ast_hangup(tmpchanb);
2501 /* setup the bridge thread object and start the bridge */
2502 if (!(tobj = ast_calloc(1, sizeof(*tobj)))) {
2503 ast_log(LOG_WARNING, "Unable to spawn a new bridge thread on %s and %s: %s\n", tmpchana->name, tmpchanb->name, strerror(errno));
2504 astman_send_error(s, m, "Unable to spawn a new bridge thread");
2505 ast_hangup(tmpchana);
2506 ast_hangup(tmpchanb);
2510 tobj->chan = tmpchana;
2511 tobj->peer = tmpchanb;
2512 tobj->return_to_pbx = 1;
2514 if (ast_true(playtone)) {
2515 if (!ast_strlen_zero(xfersound) && !ast_streamfile(tmpchanb, xfersound, tmpchanb->language)) {
2516 if (ast_waitstream(tmpchanb, "") < 0)
2517 ast_log(LOG_WARNING, "Failed to play a courtesy tone on chan %s\n", tmpchanb->name);
2521 ast_bridge_call_thread_launch(tobj);
2523 astman_send_ack(s, m, "Launched bridge thread with success");
2528 static char showfeatures_help[] =
2529 "Usage: feature list\n"
2530 " Lists currently configured features.\n";
2533 * \brief CLI command to list parked calls
2537 * Check right usage, lock parking lot, display parked calls, unlock parking lot list.
2538 * \retval CLI_SUCCESS on success.
2539 * \retval CLI_SHOWUSAGE on incorrect number of arguements.
2540 * \retval NULL when tab completion is used.
2542 static char *handle_parkedcalls(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2544 struct parkeduser *cur;
2549 e->command = "parkedcalls show";
2551 "Usage: parkedcalls show\n"
2552 " List currently parked calls\n";
2558 if (a->argc > e->args)
2559 return CLI_SHOWUSAGE;
2561 ast_cli(a->fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
2562 , "Context", "Extension", "Pri", "Timeout");
2564 AST_LIST_LOCK(&parkinglot);
2565 AST_LIST_TRAVERSE(&parkinglot, cur, list) {
2566 ast_cli(a->fd, "%-10.10s %25s (%-15s %-12s %-4d) %6lds\n"
2567 ,cur->parkingexten, cur->chan->name, cur->context, cur->exten
2568 ,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL));
2572 AST_LIST_UNLOCK(&parkinglot);
2573 ast_cli(a->fd, "%d parked call%s.\n", numparked, ESS(numparked));
2579 static char *handle_parkedcalls_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2581 char *res = handle_parkedcalls(e, cmd, a);
2582 if (cmd == CLI_INIT)
2583 e->command = "show parkedcalls";
2587 static struct ast_cli_entry cli_show_parkedcalls_deprecated = NEW_CLI(handle_parkedcalls_deprecated, "List currently parked calls.");
2589 static struct ast_cli_entry cli_features[] = {
2590 { { "feature", "show", NULL },
2591 handle_showfeatures, "Lists configured features",
2592 showfeatures_help },
2594 NEW_CLI(handle_parkedcalls, "List currently parked calls", .deprecate_cmd = &cli_show_parkedcalls_deprecated),
2598 * \brief Dump parking lot status
2601 * Lock parking lot, iterate list and append parked calls status, unlock parking lot.
2602 * \return Always RESULT_SUCCESS
2604 static int manager_parking_status(struct mansession *s, const struct message *m)
2606 struct parkeduser *cur;
2607 const char *id = astman_get_header(m, "ActionID");
2608 char idText[256] = "";
2610 if (!ast_strlen_zero(id))
2611 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
2613 astman_send_ack(s, m, "Parked calls will follow");
2615 AST_LIST_LOCK(&parkinglot);
2617 AST_LIST_TRAVERSE(&parkinglot, cur, list) {
2618 astman_append(s, "Event: ParkedCall\r\n"
2623 "CallerIDNum: %s\r\n"
2624 "CallerIDName: %s\r\n"
2627 cur->parkingnum, cur->chan->name, cur->peername,
2628 (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL),
2629 S_OR(cur->chan->cid.cid_num, ""), /* XXX in other places it is <unknown> */
2630 S_OR(cur->chan->cid.cid_name, ""),
2635 "Event: ParkedCallsComplete\r\n"
2639 AST_LIST_UNLOCK(&parkinglot);
2641 return RESULT_SUCCESS;
2644 static char mandescr_park[] =
2645 "Description: Park a channel.\n"
2646 "Variables: (Names marked with * are required)\n"
2647 " *Channel: Channel name to park\n"
2648 " *Channel2: Channel to announce park info to (and return to if timeout)\n"
2649 " Timeout: Number of milliseconds to wait before callback.\n";
2652 * \brief Create manager event for parked calls
2655 * Get channels involved in park, create event.
2658 static int manager_park(struct mansession *s, const struct message *m)
2660 const char *channel = astman_get_header(m, "Channel");
2661 const char *channel2 = astman_get_header(m, "Channel2");
2662 const char *timeout = astman_get_header(m, "Timeout");
2667 struct ast_channel *ch1, *ch2;
2669 if (ast_strlen_zero(channel)) {
2670 astman_send_error(s, m, "Channel not specified");
2674 if (ast_strlen_zero(channel2)) {
2675 astman_send_error(s, m, "Channel2 not specified");
2679 ch1 = ast_get_channel_by_name_locked(channel);
2681 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel);
2682 astman_send_error(s, m, buf);
2686 ch2 = ast_get_channel_by_name_locked(channel2);
2688 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2);
2689 astman_send_error(s, m, buf);
2690 ast_channel_unlock(ch1);
2694 if (!ast_strlen_zero(timeout)) {
2695 sscanf(timeout, "%d", &to);
2698 res = ast_masq_park_call(ch1, ch2, to, &parkExt);
2700 ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT);
2701 astman_send_ack(s, m, "Park successful");
2703 astman_send_error(s, m, "Park failure");
2706 ast_channel_unlock(ch1);
2707 ast_channel_unlock(ch2);
2713 * \brief Pickup a call
2714 * \param chan channel that initiated pickup
2715 * Walk list of channels, checking it is not itself, channel is pbx one,
2716 * check that the callgroup for both channels are the same and the channel is ringing.
2717 * Answer calling channel, flag channel as answered on queue, masq channels together.
2719 int ast_pickup_call(struct ast_channel *chan)
2721 struct ast_channel *cur = NULL;
2724 while ((cur = ast_channel_walk_locked(cur)) != NULL) {
2727 (chan->pickupgroup & cur->callgroup) &&
2728 ((cur->_state == AST_STATE_RINGING) ||
2729 (cur->_state == AST_STATE_RING))) {
2732 ast_channel_unlock(cur);
2735 ast_debug(1, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
2736 res = ast_answer(chan);
2738 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
2739 res = ast_queue_control(chan, AST_CONTROL_ANSWER);
2741 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
2742 res = ast_channel_masquerade(cur, chan);
2744 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name); /* Done */
2745 ast_channel_unlock(cur);
2747 ast_debug(1, "No call pickup possible...\n");
2753 * \brief Add parking hints for all defined parking lots
2755 * \param start starting parkinglot number
2756 * \param stop ending parkinglot number
2758 static void park_add_hints(char *context, int start, int stop)
2761 char device[AST_MAX_EXTENSION];
2764 for (numext = start; numext <= stop; numext++) {
2765 snprintf(exten, sizeof(exten), "%d", numext);
2766 snprintf(device, sizeof(device), "park:%s@%s", exten, context);
2767 ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar);
2772 static int load_config(void)
2774 int start = 0, end = 0;
2777 struct ast_context *con = NULL;
2778 struct ast_config *cfg = NULL;
2779 struct ast_variable *var = NULL;
2780 struct feature_group *fg = NULL;
2781 struct ast_flags config_flags = { 0 };
2782 char old_parking_ext[AST_MAX_EXTENSION];
2783 char old_parking_con[AST_MAX_EXTENSION] = "";
2785 static const char *categories[] = {
2786 /* Categories in features.conf that are not
2787 * to be parsed as group categories
2794 if (!ast_strlen_zero(parking_con)) {
2795 strcpy(old_parking_ext, parking_ext);
2796 strcpy(old_parking_con, parking_con);
2799 /* Reset to defaults */
2800 strcpy(parking_con, "parkedcalls");
2801 strcpy(parking_con_dial, "park-dial");
2802 strcpy(parking_ext, "700");
2803 strcpy(pickup_ext, "*8");
2804 strcpy(parkmohclass, "default");
2805 courtesytone[0] = '\0';
2806 strcpy(xfersound, "beep");
2807 strcpy(xferfailsound, "pbx-invalid");
2808 parking_start = 701;
2812 comebacktoorigin = 1;
2814 parkedcalltransfers = 0;
2815 parkedcallreparking = 0;
2817 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
2818 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
2819 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
2820 atxferloopdelay = DEFAULT_ATXFER_LOOP_DELAY;
2821 atxferdropcall = DEFAULT_ATXFER_DROP_CALL;
2822 atxfercallbackretries = DEFAULT_ATXFER_CALLBACK_RETRIES;
2824 cfg = ast_config_load("features.conf", config_flags);
2826 ast_log(LOG_WARNING,"Could not load features.conf\n");
2827 return AST_MODULE_LOAD_DECLINE;
2829 for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
2830 if (!strcasecmp(var->name, "parkext")) {
2831 ast_copy_string(parking_ext, var->value, sizeof(parking_ext));
2832 } else if (!strcasecmp(var->name, "context")) {
2833 ast_copy_string(parking_con, var->value, sizeof(parking_con));
2834 } else if (!strcasecmp(var->name, "parkingtime")) {
2835 if ((sscanf(var->value, "%d", &parkingtime) != 1) || (parkingtime < 1)) {
2836 ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value);
2837 parkingtime = DEFAULT_PARK_TIME;
2839 parkingtime = parkingtime * 1000;
2840 } else if (!strcasecmp(var->name, "parkpos")) {
2841 if (sscanf(var->value, "%d-%d", &start, &end) != 2) {
2842 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);
2844 parking_start = start;
2847 } else if (!strcasecmp(var->name, "findslot")) {
2848 parkfindnext = (!strcasecmp(var->value, "next"));
2849 } else if (!strcasecmp(var->name, "parkinghints")) {
2850 parkaddhints = ast_true(var->value);
2851 } else if (!strcasecmp(var->name, "parkedcalltransfers")) {
2852 if (!strcasecmp(var->value, "both"))
2853 parkedcalltransfers = AST_FEATURE_FLAG_BYBOTH;
2854 else if (!strcasecmp(var->value, "caller"))
2855 parkedcalltransfers = AST_FEATURE_FLAG_BYCALLER;
2856 else if (!strcasecmp(var->value, "callee"))
2857 parkedcalltransfers = AST_FEATURE_FLAG_BYCALLEE;
2858 } else if (!strcasecmp(var->name, "parkedcallreparking")) {
2859 if (!strcasecmp(var->value, "both"))
2860 parkedcalltransfers = AST_FEATURE_FLAG_BYBOTH;
2861 else if (!strcasecmp(var->value, "caller"))
2862 parkedcalltransfers = AST_FEATURE_FLAG_BYCALLER;
2863 else if (!strcasecmp(var->value, "callee"))
2864 parkedcalltransfers = AST_FEATURE_FLAG_BYCALLEE;
2865 } else if (!strcasecmp(var->name, "adsipark")) {
2866 adsipark = ast_true(var->value);
2867 } else if (!strcasecmp(var->name, "transferdigittimeout")) {
2868 if ((sscanf(var->value, "%d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) {
2869 ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value);
2870 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
2872 transferdigittimeout = transferdigittimeout * 1000;
2873 } else if (!strcasecmp(var->name, "featuredigittimeout")) {
2874 if ((sscanf(var->value, "%d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) {
2875 ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value);
2876 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
2878 } else if (!strcasecmp(var->name, "atxfernoanswertimeout")) {
2879 if ((sscanf(var->value, "%d", &atxfernoanswertimeout) != 1) || (atxfernoanswertimeout < 1)) {
2880 ast_log(LOG_WARNING, "%s is not a valid atxfernoanswertimeout\n", var->value);
2881 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
2883 atxfernoanswertimeout = atxfernoanswertimeout * 1000;
2884 } else if (!strcasecmp(var->name, "atxferloopdelay")) {
2885 if ((sscanf(var->value, "%u", &atxferloopdelay) != 1)) {
2886 ast_log(LOG_WARNING, "%s is not a valid atxferloopdelay\n", var->value);
2887 atxferloopdelay = DEFAULT_ATXFER_LOOP_DELAY;
2889 atxferloopdelay *= 1000;
2890 } else if (!strcasecmp(var->name, "atxferdropcall")) {
2891 atxferdropcall = ast_true(var->value);
2892 } else if (!strcasecmp(var->name, "atxfercallbackretries")) {
2893 if ((sscanf(var->value, "%u", &atxferloopdelay) != 1)) {
2894 ast_log(LOG_WARNING, "%s is not a valid atxfercallbackretries\n", var->value);
2895 atxfercallbackretries = DEFAULT_ATXFER_CALLBACK_RETRIES;
2897 } else if (!strcasecmp(var->name, "courtesytone")) {
2898 ast_copy_string(courtesytone, var->value, sizeof(courtesytone));
2899 } else if (!strcasecmp(var->name, "parkedplay")) {
2900 if (!strcasecmp(var->value, "both"))
2902 else if (!strcasecmp(var->value, "parked"))
2906 } else if (!strcasecmp(var->name, "xfersound")) {
2907 ast_copy_string(xfersound, var->value, sizeof(xfersound));
2908 } else if (!strcasecmp(var->name, "xferfailsound")) {
2909 ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound));
2910 } else if (!strcasecmp(var->name, "pickupexten")) {
2911 ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext));
2912 } else if (!strcasecmp(var->name, "comebacktoorigin")) {
2913 comebacktoorigin = ast_true(var->value);
2914 } else if (!strcasecmp(var->name, "parkedmusicclass")) {
2915 ast_copy_string(parkmohclass, var->value, sizeof(parkmohclass));
2920 for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) {
2921 if (remap_feature(var->name, var->value))
2922 ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name);
2925 /* Map a key combination to an application*/
2926 ast_unregister_features();
2927 for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) {
2928 char *tmp_val = ast_strdupa(var->value);
2929 char *exten, *activateon, *activatedby, *app, *app_args, *moh_class;
2930 struct ast_call_feature *feature;
2932 /* strsep() sets the argument to NULL if match not found, and it
2933 * is safe to use it with a NULL argument, so we don't check
2936 exten = strsep(&tmp_val,",");
2937 activatedby = strsep(&tmp_val,",");
2938 app = strsep(&tmp_val,",");
2939 app_args = strsep(&tmp_val,",");
2940 moh_class = strsep(&tmp_val,",");
2942 activateon = strsep(&activatedby, "/");
2944 /*! \todo XXX var_name or app_args ? */
2945 if (ast_strlen_zero(app) || ast_strlen_zero(exten) || ast_strlen_zero(activateon) || ast_strlen_zero(var->name)) {
2946 ast_log(LOG_NOTICE, "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n",
2947 app, exten, activateon, var->name);
2951 AST_LIST_LOCK(&feature_list);
2952 if ((feature = find_dynamic_feature(var->name))) {
2953 AST_LIST_UNLOCK(&feature_list);
2954 ast_log(LOG_WARNING, "Dynamic Feature '%s' specified more than once!\n", var->name);
2957 AST_LIST_UNLOCK(&feature_list);