aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGES7
-rw-r--r--apps/app_dial.c63
-rw-r--r--configs/features.conf.sample6
-rw-r--r--include/asterisk/global_datastores.h11
-rw-r--r--main/features.c281
-rw-r--r--main/global_datastores.c27
6 files changed, 279 insertions, 116 deletions
diff --git a/CHANGES b/CHANGES
index 5989eba8f..bcfc1b693 100644
--- a/CHANGES
+++ b/CHANGES
@@ -706,6 +706,13 @@ AEL Changes
Call Features (res_features) Changes
------------------------------------
* Added the parkedcalltransfers option to features.conf
+ * Added parkedcallparking option to control one touch parking w/ parking
+ pickup
+ * Added parkedcallhangup option to control disconnect feature w/ parking
+ pickup
+ * Added parkedcallrecording option to control one-touch record w/ parking
+ pickup
+ * Added BRIDGE_FEATURES variable to set available features for a channel
* The built-in method for doing attended transfers has been updated to
include some new options that allow you to have the transferee sent
back to the person that did the transfer if the transfer is not successful.
diff --git a/apps/app_dial.c b/apps/app_dial.c
index 2e0b5f4c8..1759fefe9 100644
--- a/apps/app_dial.c
+++ b/apps/app_dial.c
@@ -1249,19 +1249,6 @@ static int setup_privacy_args(struct privacy_args *pa,
return 1; /* success */
}
-static void set_dial_features(struct ast_flags64 *opts, struct ast_dial_features *features)
-{
- struct ast_flags64 perm_opts = {.flags = 0};
-
- ast_copy_flags64(&perm_opts, opts,
- OPT_CALLER_TRANSFER | OPT_CALLER_PARK | OPT_CALLER_MONITOR | OPT_CALLER_MIXMONITOR | OPT_CALLER_HANGUP |
- OPT_CALLEE_TRANSFER | OPT_CALLEE_PARK | OPT_CALLEE_MONITOR | OPT_CALLEE_MIXMONITOR | OPT_CALLEE_HANGUP);
-
- memset(features->options, 0, sizeof(features->options));
-
- ast_app_options2str64(dial_exec_options, &perm_opts, features->options, sizeof(features->options));
-}
-
static void end_bridge_callback(void *data)
{
char buf[80];
@@ -1325,9 +1312,6 @@ static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags
struct ast_flags64 opts = { 0, };
char *opt_args[OPT_ARG_ARRAY_SIZE];
struct ast_datastore *datastore = NULL;
- struct ast_datastore *ds_caller_features = NULL;
- struct ast_datastore *ds_callee_features = NULL;
- struct ast_dial_features *caller_features;
int fulldial = 0, num_dialed = 0;
/* Reset all DIAL variables back to blank, to prevent confusion (in case we don't reset all of them). */
@@ -1411,28 +1395,6 @@ static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags
ast_channel_unlock(chan);
ast_copy_flags64(peerflags, &opts, OPT_DTMF_EXIT | OPT_GO_ON | OPT_ORIGINAL_CLID | OPT_CALLER_HANGUP | OPT_IGNORE_FORWARDING);
- /* Create datastore for channel dial features for caller */
- if (!(ds_caller_features = ast_datastore_alloc(&dial_features_info, NULL))) {
- ast_log(LOG_WARNING, "Unable to create channel datastore for dial features. Aborting!\n");
- goto out;
- }
-
- if (!(caller_features = ast_malloc(sizeof(*caller_features)))) {
- ast_log(LOG_WARNING, "Unable to allocate memory for feature flags. Aborting!\n");
- goto out;
- }
-
- ast_copy_flags(&(caller_features->features_callee), &(config.features_caller), AST_FLAGS_ALL);
- caller_features->is_caller = 1;
- set_dial_features(&opts, caller_features);
-
- ds_caller_features->inheritance = DATASTORE_INHERIT_FOREVER;
- ds_caller_features->data = caller_features;
-
- ast_channel_lock(chan);
- ast_channel_datastore_add(chan, ds_caller_features);
- ast_channel_unlock(chan);
-
/* loop through the list of dial destinations */
rest = args.peers;
while ((cur = strsep(&rest, "&")) ) {
@@ -1444,7 +1406,6 @@ static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags
char *tech = strsep(&number, "/");
/* find if we already dialed this interface */
struct ast_dialed_interface *di;
- struct ast_dial_features *callee_features;
AST_LIST_HEAD(, ast_dialed_interface) *dialed_interfaces;
num_dialed++;
if (!number) {
@@ -1580,30 +1541,6 @@ static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags
else
ast_copy_string(tc->exten, chan->exten, sizeof(tc->exten));
- /* Save callee features */
- if (!(ds_callee_features = ast_datastore_alloc(&dial_features_info, NULL))) {
- ast_log(LOG_WARNING, "Unable to create channel datastore for dial features. Aborting!\n");
- ast_free(tmp);
- goto out;
- }
-
- if (!(callee_features = ast_malloc(sizeof(*callee_features)))) {
- ast_log(LOG_WARNING, "Unable to allocate memory for feature flags. Aborting!\n");
- ast_free(tmp);
- goto out;
- }
-
- ast_copy_flags(&(callee_features->features_callee), &(config.features_callee), AST_FLAGS_ALL);
- callee_features->is_caller = 0;
- set_dial_features(&opts, callee_features);
-
- ds_callee_features->inheritance = DATASTORE_INHERIT_FOREVER;
- ds_callee_features->data = callee_features;
-
- ast_channel_lock(chan);
- ast_channel_datastore_add(tc, ds_callee_features);
- ast_channel_unlock(chan);
-
res = ast_call(tc, numsubst, 0); /* Place the call, but don't wait on the answer */
/* Save the info in cdr's that we called them */
diff --git a/configs/features.conf.sample b/configs/features.conf.sample
index 90faa1236..3fd118322 100644
--- a/configs/features.conf.sample
+++ b/configs/features.conf.sample
@@ -23,6 +23,12 @@ context => parkedcalls ; Which context parked calls are in (default parking lot
; one of: callee, caller, both, no (default is no)
;parkedcallreparking = caller ; Enables or disables DTMF based parking when picking up a parked call.
; one of: callee, caller, both, no (default is no)
+;parkedcallparking = caller ; Enables or disables DTMF based one-touch parking when picking up a parked call.
+ ; one of: callee, caller, both, no (default is no)
+;parkedcallhangup = caller ; Enables or disables DTMF based hangups when picking up a parked call.
+ ; one of: callee, caller, both, no (default is no)
+;parkedcallrecording = caller ; Enables or disables DTMF based one-touch recording when picking up a parked call.
+ ; one of: callee, caller, both, no (default is no)
;adsipark = yes ; if you want ADSI parking announcements
;findslot => next ; Continue to the 'next' free parking space.
; Defaults to 'first' available
diff --git a/include/asterisk/global_datastores.h b/include/asterisk/global_datastores.h
index 510034b0d..72edabac5 100644
--- a/include/asterisk/global_datastores.h
+++ b/include/asterisk/global_datastores.h
@@ -26,22 +26,11 @@
#include "asterisk/channel.h"
-#define MAX_DIAL_FEATURE_OPTIONS 30
-
extern const struct ast_datastore_info dialed_interface_info;
-extern const struct ast_datastore_info dial_features_info;
-
struct ast_dialed_interface {
AST_LIST_ENTRY(ast_dialed_interface) list;
char interface[1];
};
-struct ast_dial_features {
- struct ast_flags features_caller;
- struct ast_flags features_callee;
- char options[MAX_DIAL_FEATURE_OPTIONS];
- int is_caller;
-};
-
#endif
diff --git a/main/features.c b/main/features.c
index 64c17e364..f6024f19a 100644
--- a/main/features.c
+++ b/main/features.c
@@ -66,6 +66,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#define DEFAULT_ATXFER_CALLBACK_RETRIES 2
#define AST_MAX_WATCHERS 256
+#define MAX_DIAL_FEATURE_OPTIONS 30
struct feature_group_exten {
AST_LIST_ENTRY(feature_group_exten) entry;
@@ -122,6 +123,8 @@ struct ast_parkinglot {
int parkaddhints; /*!< Add parking hints automatically */
int parkedcalltransfers; /*!< Enable DTMF based transfers on bridge when picking up parked calls */
int parkedcallreparking; /*!< Enable DTMF based parking on bridge when picking up parked calls */
+ int parkedcallhangup; /*!< Enable DTMF based hangup on a bridge when pickup up parked calls */
+ int parkedcallrecording; /*!< Enable DTMF based recording on a bridge when picking up parked calls */
AST_LIST_HEAD(parkinglot_parklist, parkeduser) parkings; /*!< List of active parkings in this parkinglot */
};
@@ -195,7 +198,39 @@ static struct ast_app *stopmixmonitor_app = NULL;
static int stopmixmonitor_ok = 1;
static pthread_t parking_thread;
+struct ast_dial_features {
+ struct ast_flags features_caller;
+ struct ast_flags features_callee;
+ int is_caller;
+};
+static void *dial_features_duplicate(void *data)
+{
+ struct ast_dial_features *df = data, *df_copy;
+
+ if (!(df_copy = ast_calloc(1, sizeof(*df)))) {
+ return NULL;
+ }
+
+ memcpy(df_copy, df, sizeof(*df));
+
+ return df_copy;
+ }
+
+ static void dial_features_destroy(void *data)
+ {
+ struct ast_dial_features *df = data;
+ if (df) {
+ ast_free(df);
+ }
+ }
+
+ const struct ast_datastore_info dial_features_info = {
+ .type = "dial-features",
+ .destroy = dial_features_destroy,
+ .duplicate = dial_features_duplicate,
+ };
+
/* Forward declarations */
static struct ast_parkinglot *parkinglot_addref(struct ast_parkinglot *parkinglot);
static void parkinglot_unref(struct ast_parkinglot *parkinglot);
@@ -301,7 +336,7 @@ static struct ast_channel *ast_feature_request_and_dial(struct ast_channel *call
* bridge call, check if we're going back to dialplan
* if not hangup both legs of the call
*/
-static void *ast_bridge_call_thread(void *data)
+static void *ast_bridge_call_thread(void *data)
{
struct ast_bridge_thread_obj *tobj = data;
int res;
@@ -813,7 +848,6 @@ static int builtin_parkcall(struct ast_channel *chan, struct ast_channel *peer,
}
return res;
-
}
/*! \brief Play message to both caller and callee in bridged call, plays synchronously, autoservicing the
@@ -1126,7 +1160,7 @@ static int builtin_blindtransfer(struct ast_channel *chan, struct ast_channel *p
ast_indicate(transferee, AST_CONTROL_HOLD);
memset(xferto, 0, sizeof(xferto));
-
+
/* Transfer */
res = ast_stream_and_wait(transferer, "pbx-transfer", AST_DIGIT_ANY);
if (res < 0) {
@@ -1256,6 +1290,8 @@ static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, st
struct ast_bridge_config bconfig;
struct ast_frame *f;
int l;
+ struct ast_datastore *features_datastore;
+ struct ast_dial_features *dialfeatures = NULL;
ast_debug(1, "Executing Attended Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense);
set_peers(&transferer, &transferee, peer, chan, sense);
@@ -1296,6 +1332,13 @@ static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, st
return AST_FEATURE_RETURN_SUCCESS;
}
+ /* If we are attended transfering to parking, just use builtin_parkcall instead of trying to track all of
+ * the different variables for handling this properly with a builtin_atxfer */
+ if (!strcmp(xferto, ast_parking_ext())) {
+ finishup(transferee);
+ return builtin_parkcall(chan, peer, config, code, sense, data);
+ }
+
l = strlen(xferto);
snprintf(xferto + l, sizeof(xferto) - l, "@%s/n", transferer_real_context); /* append context */
@@ -1385,6 +1428,30 @@ static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, st
ast_hangup(newchan);
return -1;
}
+
+ ast_channel_lock(newchan);
+ if ((features_datastore = ast_channel_datastore_find(newchan, &dial_features_info, NULL))) {
+ dialfeatures = features_datastore->data;
+ }
+ ast_channel_unlock(newchan);
+
+ if (dialfeatures) {
+ /* newchan should always be the callee and shows up as callee in dialfeatures, but for some reason
+ I don't currently understand, the abilities of newchan seem to be stored on the caller side */
+ ast_copy_flags(&(config->features_callee), &(dialfeatures->features_caller), AST_FLAGS_ALL);
+ dialfeatures = NULL;
+ }
+
+ ast_channel_lock(xferchan);
+ if ((features_datastore = ast_channel_datastore_find(xferchan, &dial_features_info, NULL))) {
+ dialfeatures = features_datastore->data;
+ }
+ ast_channel_unlock(xferchan);
+
+ if (dialfeatures) {
+ ast_copy_flags(&(config->features_caller), &(dialfeatures->features_caller), AST_FLAGS_ALL);
+ }
+
tobj->chan = newchan;
tobj->peer = xferchan;
tobj->bconfig = *config;
@@ -2132,6 +2199,92 @@ static struct ast_cdr *pick_unlocked_cdr(struct ast_cdr *cdr)
return cdr_orig; /* everybody LOCKED or some other weirdness, like a NULL */
}
+static void set_bridge_features_on_config(struct ast_bridge_config *config, const char *features)
+{
+ const char *feature;
+
+ if (ast_strlen_zero(features)) {
+ return;
+ }
+
+ for (feature = features; *feature; feature++) {
+ switch (*feature) {
+ case 'T' :
+ case 't' :
+ ast_set_flag(&(config->features_caller), AST_FEATURE_REDIRECT);
+ break;
+ case 'K' :
+ case 'k' :
+ ast_set_flag(&(config->features_caller), AST_FEATURE_PARKCALL);
+ break;
+ case 'H' :
+ case 'h' :
+ ast_set_flag(&(config->features_caller), AST_FEATURE_DISCONNECT);
+ break;
+ case 'W' :
+ case 'w' :
+ ast_set_flag(&(config->features_caller), AST_FEATURE_AUTOMON);
+ break;
+ default :
+ ast_log(LOG_WARNING, "Skipping unknown feature code '%c'\n", *feature);
+ }
+ }
+}
+
+static void add_features_datastores(struct ast_channel *caller, struct ast_channel *callee, struct ast_bridge_config *config)
+{
+ struct ast_datastore *ds_callee_features = NULL, *ds_caller_features = NULL;
+ struct ast_dial_features *callee_features = NULL, *caller_features = NULL;
+
+ ast_channel_lock(caller);
+ ds_caller_features = ast_channel_datastore_find(caller, &dial_features_info, NULL);
+ ast_channel_unlock(caller);
+ if (!ds_caller_features) {
+ if (!(ds_caller_features = ast_datastore_alloc(&dial_features_info, NULL))) {
+ ast_log(LOG_WARNING, "Unable to create channel datastore for caller features. Aborting!\n");
+ return;
+ }
+ if (!(caller_features = ast_calloc(1, sizeof(*caller_features)))) {
+ ast_log(LOG_WARNING, "Unable to allocate memory for callee feature flags. Aborting!\n");
+ ast_datastore_free(ds_caller_features);
+ return;
+ }
+ ds_caller_features->inheritance = DATASTORE_INHERIT_FOREVER;
+ caller_features->is_caller = 1;
+ ast_copy_flags(&(caller_features->features_callee), &(config->features_callee), AST_FLAGS_ALL);
+ ast_copy_flags(&(caller_features->features_caller), &(config->features_caller), AST_FLAGS_ALL);
+ ds_caller_features->data = caller_features;
+ ast_channel_lock(caller);
+ ast_channel_datastore_add(caller, ds_caller_features);
+ ast_channel_unlock(caller);
+ }
+
+ ast_channel_lock(callee);
+ ds_callee_features = ast_channel_datastore_find(callee, &dial_features_info, NULL);
+ ast_channel_unlock(callee);
+ if (!ds_callee_features) {
+ if (!(ds_callee_features = ast_datastore_alloc(&dial_features_info, NULL))) {
+ ast_log(LOG_WARNING, "Unable to create channel datastore for callee features. Aborting!\n");
+ return;
+ }
+ if (!(callee_features = ast_calloc(1, sizeof(*callee_features)))) {
+ ast_log(LOG_WARNING, "Unable to allocate memory for callee feature flags. Aborting!\n");
+ ast_datastore_free(ds_callee_features);
+ return;
+ }
+ ds_callee_features->inheritance = DATASTORE_INHERIT_FOREVER;
+ callee_features->is_caller = 0;
+ ast_copy_flags(&(callee_features->features_callee), &(config->features_caller), AST_FLAGS_ALL);
+ ast_copy_flags(&(callee_features->features_caller), &(config->features_callee), AST_FLAGS_ALL);
+ ds_callee_features->data = callee_features;
+ ast_channel_lock(callee);
+ ast_channel_datastore_add(callee, ds_callee_features);
+ ast_channel_unlock(callee);
+ }
+
+ return;
+}
+
/*!
* \brief bridge the call and set CDR
* \param chan,peer,config
@@ -2176,6 +2329,9 @@ int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast
pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
}
+ set_bridge_features_on_config(config, pbx_builtin_getvar_helper(chan, "BRIDGE_FEATURES"));
+ add_features_datastores(chan, peer, config);
+
/* This is an interesting case. One example is if a ringing channel gets redirected to
* an extension that picks up a parked call. This will make sure that the call taken
* out of parking gets told that the channel it just got bridged to is still ringing. */
@@ -2199,7 +2355,7 @@ int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast
pbx_exec(src, monitor_app, tmp);
}
}
-
+
set_config_flags(chan, peer, config);
config->firstpass = 1;
@@ -2266,7 +2422,7 @@ int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast
}
for (;;) {
struct ast_channel *other; /* used later */
-
+
res = ast_channel_bridge(chan, peer, config, &f, &who);
if (config->feature_timer) {
@@ -2608,6 +2764,50 @@ static void post_manager_event(const char *s, struct parkeduser *pu)
);
}
+static char *callback_dialoptions(struct ast_flags *features_callee, struct ast_flags *features_caller, char *options, size_t len)
+{
+ int i = 0;
+ enum {
+ OPT_CALLEE_REDIRECT = 't',
+ OPT_CALLER_REDIRECT = 'T',
+ OPT_CALLEE_AUTOMON = 'w',
+ OPT_CALLER_AUTOMON = 'W',
+ OPT_CALLEE_DISCONNECT = 'h',
+ OPT_CALLER_DISCONNECT = 'H',
+ OPT_CALLEE_PARKCALL = 'k',
+ OPT_CALLER_PARKCALL = 'K',
+ };
+
+ memset(options, 0, len);
+ if (ast_test_flag(features_caller, AST_FEATURE_REDIRECT) && i < len) {
+ options[i++] = OPT_CALLER_REDIRECT;
+ }
+ if (ast_test_flag(features_caller, AST_FEATURE_AUTOMON) && i < len) {
+ options[i++] = OPT_CALLER_AUTOMON;
+ }
+ if (ast_test_flag(features_caller, AST_FEATURE_DISCONNECT) && i < len) {
+ options[i++] = OPT_CALLER_DISCONNECT;
+ }
+ if (ast_test_flag(features_caller, AST_FEATURE_PARKCALL) && i < len) {
+ options[i++] = OPT_CALLER_PARKCALL;
+ }
+
+ if (ast_test_flag(features_callee, AST_FEATURE_REDIRECT) && i < len) {
+ options[i++] = OPT_CALLEE_REDIRECT;
+ }
+ if (ast_test_flag(features_callee, AST_FEATURE_AUTOMON) && i < len) {
+ options[i++] = OPT_CALLEE_AUTOMON;
+ }
+ if (ast_test_flag(features_callee, AST_FEATURE_DISCONNECT) && i < len) {
+ options[i++] = OPT_CALLEE_DISCONNECT;
+ }
+ if (ast_test_flag(features_callee, AST_FEATURE_PARKCALL) && i < len) {
+ options[i++] = OPT_CALLEE_PARKCALL;
+ }
+
+ return options;
+}
+
/*! \brief Run management on parkinglots, called once per parkinglot */
int manage_parkinglot(struct ast_parkinglot *curlot, fd_set *rfds, fd_set *efds, fd_set *nrfds, fd_set *nefds, int *ms, int *max)
{
@@ -2665,10 +2865,13 @@ int manage_parkinglot(struct ast_parkinglot *curlot, fd_set *rfds, fd_set *efds,
peername += 7;
}
- if (dialfeatures)
- snprintf(returnexten, sizeof(returnexten), "%s,,%s", peername, dialfeatures->options);
- else /* Existing default */
- snprintf(returnexten, sizeof(returnexten), "%s,,t", peername);
+ if (dialfeatures) {
+ char buf[MAX_DIAL_FEATURE_OPTIONS] = {0,};
+ snprintf(returnexten, sizeof(returnexten), "%s|30|%s", peername, callback_dialoptions(&(dialfeatures->features_callee), &(dialfeatures->features_caller), buf, sizeof(buf)));
+ } else { /* Existing default */
+ ast_log(LOG_WARNING, "Dialfeatures not found on %s, using default!\n", chan->name);
+ snprintf(returnexten, sizeof(returnexten), "%s|30|t", peername);
+ }
ast_add_extension2(con, 1, peername_flat, 1, NULL, NULL, "Dial", ast_strdup(returnexten), ast_free_ptr, registrar);
}
@@ -2988,8 +3191,11 @@ static int park_exec_full(struct ast_channel *chan, void *data, struct ast_parki
//ASTOBJ_UNLOCK(parkinglot);
if (peer) {
+ struct ast_datastore *features_datastore;
+ struct ast_dial_features *dialfeatures = NULL;
+
/* Play a courtesy to the source(s) configured to prefix the bridge connecting */
-
+
if (!ast_strlen_zero(courtesytone)) {
int error = 0;
ast_indicate(peer, AST_CONTROL_UNHOLD);
@@ -3014,7 +3220,7 @@ static int park_exec_full(struct ast_channel *chan, void *data, struct ast_parki
return -1;
}
} else
- ast_indicate(peer, AST_CONTROL_UNHOLD);
+ ast_indicate(peer, AST_CONTROL_UNHOLD);
res = ast_channel_make_compatible(chan, peer);
if (res < 0) {
@@ -3029,14 +3235,43 @@ static int park_exec_full(struct ast_channel *chan, void *data, struct ast_parki
pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
ast_cdr_setdestchan(chan->cdr, peer->name);
memset(&config, 0, sizeof(struct ast_bridge_config));
- if ((parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH))
+
+ /* Get datastore for peer and apply it's features to the callee side of the bridge config */
+ ast_channel_lock(peer);
+ if ((features_datastore = ast_channel_datastore_find(peer, &dial_features_info, NULL))) {
+ dialfeatures = features_datastore->data;
+ }
+ ast_channel_unlock(peer);
+
+ if (dialfeatures) {
+ ast_copy_flags(&(config.features_callee), dialfeatures->is_caller ? &(dialfeatures->features_caller) : &(dialfeatures->features_callee), AST_FLAGS_ALL);
+ }
+
+ if ((parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) {
ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
- if ((parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH))
+ }
+ if ((parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) {
ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
- if ((parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYBOTH))
+ }
+ if ((parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) {
ast_set_flag(&(config.features_callee), AST_FEATURE_PARKCALL);
- if ((parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYBOTH))
+ }
+ if ((parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) {
ast_set_flag(&(config.features_caller), AST_FEATURE_PARKCALL);
+ }
+ if ((parkinglot->parkedcallhangup == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) {
+ ast_set_flag(&(config.features_callee), AST_FEATURE_DISCONNECT);
+ }
+ if ((parkinglot->parkedcallhangup == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) {
+ ast_set_flag(&(config.features_caller), AST_FEATURE_DISCONNECT);
+ }
+ if ((parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) {
+ ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON);
+ }
+ if ((parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) {
+ ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON);
+ }
+
res = ast_bridge_call(chan, peer, &config);
pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
@@ -3283,6 +3518,8 @@ static int load_config(void)
default_parkinglot->parkaddhints = 0;
default_parkinglot->parkedcalltransfers = 0;
default_parkinglot->parkedcallreparking = 0;
+ default_parkinglot->parkedcallrecording = 0;
+ default_parkinglot->parkedcallhangup = 0;
transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
@@ -3334,6 +3571,20 @@ static int load_config(void)
default_parkinglot->parkedcallreparking = AST_FEATURE_FLAG_BYCALLER;
else if (!strcasecmp(var->value, "callee"))
default_parkinglot->parkedcallreparking = AST_FEATURE_FLAG_BYCALLEE;
+ } else if (!strcasecmp(var->name, "parkedcallhangup")) {
+ if (!strcasecmp(var->value, "both"))
+ default_parkinglot->parkedcallhangup = AST_FEATURE_FLAG_BYBOTH;
+ else if (!strcasecmp(var->value, "caller"))
+ default_parkinglot->parkedcallhangup = AST_FEATURE_FLAG_BYCALLER;
+ else if (!strcasecmp(var->value, "callee"))
+ default_parkinglot->parkedcallhangup = AST_FEATURE_FLAG_BYCALLEE;
+ } else if (!strcasecmp(var->name, "parkedcallrecording")) {
+ if (!strcasecmp(var->value, "both"))
+ default_parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYBOTH;
+ else if (!strcasecmp(var->value, "caller"))
+ default_parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYCALLER;
+ else if (!strcasecmp(var->value, "callee"))
+ default_parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYCALLEE;
} else if (!strcasecmp(var->name, "adsipark")) {
adsipark = ast_true(var->value);
} else if (!strcasecmp(var->name, "transferdigittimeout")) {
diff --git a/main/global_datastores.c b/main/global_datastores.c
index ca04a0fe9..5b9630257 100644
--- a/main/global_datastores.c
+++ b/main/global_datastores.c
@@ -79,35 +79,8 @@ static void *dialed_interface_duplicate(void *data)
return new_list;
}
-
-static void *dial_features_duplicate(void *data)
-{
- struct ast_dial_features *df = data, *df_copy;
-
- if (!(df_copy = ast_calloc(1, sizeof(*df)))) {
- return NULL;
- }
-
- memcpy(df_copy, df, sizeof(*df));
-
- return df_copy;
-}
-
-static void dial_features_destroy(void *data) {
- struct ast_dial_features *df = data;
- if (df) {
- ast_free(df);
- }
-}
-
const struct ast_datastore_info dialed_interface_info = {
.type = "dialed-interface",
.destroy = dialed_interface_destroy,
.duplicate = dialed_interface_duplicate,
};
-
-const struct ast_datastore_info dial_features_info = {
- .type = "dial-features",
- .destroy = dial_features_destroy,
- .duplicate = dial_features_duplicate,
-};