diff --git a/CHANGES b/CHANGES
index 6112c6a9318455282ec9ecd0c1087b3472e9759c..ada66405a864090510dcb59e93d1c48e1660809a 100644
--- a/CHANGES
+++ b/CHANGES
@@ -191,6 +191,12 @@ AlarmReceiver
  * Added configuration option no_group_meta. If enabled, grouping of metadata
    information in the AlarmReceiver log file will be skipped.
 
+Answer
+------------------
+ * It is now no longer possible to bypass updating the CDR on the channel
+   when answering. CDRs reflect the state of the channel and will always
+   reflect the time they were Answered.
+
 BridgeWait
 ------------------
  * A new application in Asterisk, this will place the calling channel
diff --git a/UPGRADE-12.txt b/UPGRADE-12.txt
index 6486f3e474dd6ee3eea34ed30825380de1e4ad1f..e65cedc215369db0f61fa64ab52a7148aa329845 100644
--- a/UPGRADE-12.txt
+++ b/UPGRADE-12.txt
@@ -101,10 +101,19 @@ AgentMonitorOutgoing
  - This application has been removed. It was a holdover from when
    AgentCallbackLogin was removed.
 
+Answer
+ - It is no longer possible to bypass updating the CDR when answering a
+   channel. CDRs are based on the channel state and will be updated when
+   the channel is Answered.
+
 ControlPlayback
  - The channel variable CPLAYBACKSTATUS may now return the value
    'REMOTESTOPPED' when playback is stopped by an external entity.
 
+DISA
+ - This application now has a dependency on the app_cdr module. It uses this
+   module to hide the CDR created prior to execution of the DISA application.
+
 DumpChan:
  - The output of DumpChan no longer includes the DirectBridge or IndirectBridge
    fields. Instead, if a channel is in a bridge, it includes a BridgeID field
diff --git a/apps/app_cdr.c b/apps/app_cdr.c
index 34fd45675b3d92f129d830fabba9967019624ce4..2793846f963e69fa5c69c25e929f787e81234e2d 100644
--- a/apps/app_cdr.c
+++ b/apps/app_cdr.c
@@ -36,6 +36,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/channel.h"
 #include "asterisk/module.h"
 #include "asterisk/app.h"
+#include "asterisk/stasis.h"
 
 /*** DOCUMENTATION
 	<application name="NoCDR" language="en_US">
@@ -112,43 +113,130 @@ AST_APP_OPTIONS(resetcdr_opts, {
 	AST_APP_OPTION('e', AST_CDR_FLAG_DISABLE_ALL),
 });
 
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(appcdr_message_type);
+
+/*! \internal \brief Payload for the Stasis message sent to manipulate a CDR */
+struct app_cdr_message_payload {
+	/*! The name of the channel to be manipulated */
+	const char *channel_name;
+	/*! Disable the CDR for this channel */
+	int disable:1;
+	/*! Re-enable the CDR for this channel */
+	int reenable:1;
+	/*! Reset the CDR */
+	int reset:1;
+	/*! If reseting the CDR, keep the variables */
+	int keep_variables:1;
+};
+
+static void appcdr_callback(void *data, struct stasis_subscription *sub, struct stasis_message *message)
+{
+	struct app_cdr_message_payload *payload;
+
+	if (stasis_message_type(message) != appcdr_message_type()) {
+		return;
+	}
+
+	payload = stasis_message_data(message);
+	if (!payload) {
+		return;
+	}
+
+	if (payload->disable) {
+		if (ast_cdr_set_property(payload->channel_name, AST_CDR_FLAG_DISABLE_ALL)) {
+			ast_log(AST_LOG_WARNING, "Failed to disable CDRs on channel %s\n",
+				payload->channel_name);
+		}
+	}
+
+	if (payload->reenable) {
+		if (ast_cdr_clear_property(payload->channel_name, AST_CDR_FLAG_DISABLE_ALL)) {
+			ast_log(AST_LOG_WARNING, "Failed to enable CDRs on channel %s\n",
+				payload->channel_name);
+		}
+	}
+
+	if (payload->reset) {
+		if (ast_cdr_reset(payload->channel_name, payload->keep_variables)) {
+			ast_log(AST_LOG_WARNING, "Failed to reset CDRs on channel %s\n",
+				payload->channel_name);
+		}
+	}
+}
+
+static int publish_app_cdr_message(struct ast_channel *chan, struct app_cdr_message_payload *payload)
+{
+	RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
+	RAII_VAR(struct stasis_subscription *, subscription, NULL, ao2_cleanup);
+
+	message = stasis_message_create(appcdr_message_type(), payload);
+	if (!message) {
+		ast_log(AST_LOG_WARNING, "Failed to manipulate CDR for channel %s: unable to create message\n",
+			payload->channel_name);
+		return -1;
+	}
+
+	subscription = stasis_subscribe(ast_channel_topic(chan), appcdr_callback, NULL);
+	if (!subscription) {
+		ast_log(AST_LOG_WARNING, "Failed to manipulate CDR for channel %s: unable to create subscription\n",
+			payload->channel_name);
+		return -1;
+	}
+
+	stasis_publish(ast_channel_topic(chan), message);
+
+	subscription = stasis_unsubscribe_and_join(subscription);
+	return 0;
+}
+
 static int resetcdr_exec(struct ast_channel *chan, const char *data)
 {
+	RAII_VAR(struct app_cdr_message_payload *, payload,
+		ao2_alloc(sizeof(*payload), NULL), ao2_cleanup);
 	char *args;
 	struct ast_flags flags = { 0 };
-	int res = 0;
+
+	if (!payload) {
+		return -1;
+	}
 
 	if (!ast_strlen_zero(data)) {
 		args = ast_strdupa(data);
 		ast_app_parse_options(resetcdr_opts, &flags, NULL, args);
 	}
 
+	payload->channel_name = ast_channel_name(chan);
+	payload->reset = 1;
+
 	if (ast_test_flag(&flags, AST_CDR_FLAG_DISABLE_ALL)) {
-		if (ast_cdr_clear_property(ast_channel_name(chan), AST_CDR_FLAG_DISABLE_ALL)) {
-			res = 1;
-		}
-	}
-	if (ast_cdr_reset(ast_channel_name(chan), &flags)) {
-		res = 1;
+		payload->reenable = 1;
 	}
 
-	if (res) {
-		ast_log(AST_LOG_WARNING, "Failed to reset CDR for channel %s\n", ast_channel_name(chan));
+	if (ast_test_flag(&flags, AST_CDR_FLAG_KEEP_VARS)) {
+		payload->keep_variables = 1;
 	}
-	return res;
+
+	return publish_app_cdr_message(chan, payload);
 }
 
 static int nocdr_exec(struct ast_channel *chan, const char *data)
 {
-	if (ast_cdr_set_property(ast_channel_name(chan), AST_CDR_FLAG_DISABLE_ALL)) {
-		ast_log(AST_LOG_WARNING, "Failed to disable CDR for channel %s\n", ast_channel_name(chan));
+	RAII_VAR(struct app_cdr_message_payload *, payload,
+		ao2_alloc(sizeof(*payload), NULL), ao2_cleanup);
+
+	if (!payload) {
+		return -1;
 	}
 
-	return 0;
+	payload->channel_name = ast_channel_name(chan);
+	payload->disable = 1;
+
+	return publish_app_cdr_message(chan, payload);
 }
 
 static int unload_module(void)
 {
+	STASIS_MESSAGE_TYPE_CLEANUP(appcdr_message_type);
 	ast_unregister_application(nocdr_app);
 	ast_unregister_application(resetcdr_app);
 	return 0;
@@ -158,6 +246,7 @@ static int load_module(void)
 {
 	int res = 0;
 
+	res |= STASIS_MESSAGE_TYPE_INIT(appcdr_message_type);
 	res |= ast_register_application_xml(nocdr_app, nocdr_exec);
 	res |= ast_register_application_xml(resetcdr_app, resetcdr_exec);
 
diff --git a/apps/app_disa.c b/apps/app_disa.c
index 9e74127179bacf13b77f90c5a4965ee5a78fb3d1..824e8fe55de5323f0c6c1c89cbae54e0fe76e41b 100644
--- a/apps/app_disa.c
+++ b/apps/app_disa.c
@@ -27,6 +27,7 @@
  */
 
 /*** MODULEINFO
+	<use type="module">app_cdr</use>
 	<support_level>core</support_level>
  ***/
 
@@ -362,7 +363,7 @@ static int disa_exec(struct ast_channel *chan, const char *data)
 
 	if (k == 3) {
 		int recheck = 0;
-		struct ast_flags cdr_flags = { AST_CDR_FLAG_DISABLE, };
+		struct ast_app *app_reset_cdr;
 
 		if (!ast_exists_extension(chan, args.context, exten, 1,
 			S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
@@ -387,10 +388,12 @@ static int disa_exec(struct ast_channel *chan, const char *data)
 				ast_channel_unlock(chan);
 			}
 
-			if (special_noanswer) {
-				ast_clear_flag(&cdr_flags, AST_CDR_FLAG_DISABLE);
+			app_reset_cdr = pbx_findapp("ResetCDR");
+			if (app_reset_cdr) {
+				pbx_exec(chan, app_reset_cdr, special_noanswer ? "" : "e");
+			} else {
+				ast_log(AST_LOG_NOTICE, "ResetCDR application not found; CDR will not be reset\n");
 			}
-			ast_cdr_reset(ast_channel_name(chan), &cdr_flags);
 			ast_explicit_goto(chan, args.context, exten, 1);
 			return 0;
 		}
diff --git a/apps/app_forkcdr.c b/apps/app_forkcdr.c
index 6231d381f7dad9635234c56605fbbe07ec7cee4c..af5ae6a1c3417173c4e5b056a61ff4293f033dee 100644
--- a/apps/app_forkcdr.c
+++ b/apps/app_forkcdr.c
@@ -40,6 +40,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/cdr.h"
 #include "asterisk/app.h"
 #include "asterisk/module.h"
+#include "asterisk/stasis.h"
 
 /*** DOCUMENTATION
 	<application name="ForkCDR" language="en_US">
@@ -102,8 +103,41 @@ AST_APP_OPTIONS(forkcdr_exec_options, {
 	AST_APP_OPTION('v', AST_CDR_FLAG_KEEP_VARS),
 });
 
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(forkcdr_message_type);
+
+/*! \internal \brief Message payload for the Stasis message sent to fork the CDR */
+struct fork_cdr_message_payload {
+	/*! The name of the channel whose CDR will be forked */
+	const char *channel_name;
+	/*! Option flags that control how the CDR will be forked */
+	struct ast_flags *flags;
+};
+
+static void forkcdr_callback(void *data, struct stasis_subscription *sub, struct stasis_message *message)
+{
+	struct fork_cdr_message_payload *payload;
+
+	if (stasis_message_type(message) != forkcdr_message_type()) {
+		return;
+	}
+
+	payload = stasis_message_data(message);
+	if (!payload) {
+		return;
+	}
+
+	if (ast_cdr_fork(payload->channel_name, payload->flags)) {
+		ast_log(AST_LOG_WARNING, "Failed to fork CDR for channel %s\n",
+			payload->channel_name);
+	}
+}
+
 static int forkcdr_exec(struct ast_channel *chan, const char *data)
 {
+	RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
+	RAII_VAR(struct fork_cdr_message_payload *, payload, ao2_alloc(sizeof(*payload), NULL), ao2_cleanup);
+	RAII_VAR(struct stasis_subscription *, subscription, NULL, ao2_cleanup);
+
 	char *parse;
 	struct ast_flags flags = { 0, };
 	AST_DECLARE_APP_ARGS(args,
@@ -118,21 +152,48 @@ static int forkcdr_exec(struct ast_channel *chan, const char *data)
 		ast_app_parse_options(forkcdr_exec_options, &flags, NULL, args.options);
 	}
 
-	if (ast_cdr_fork(ast_channel_name(chan), &flags)) {
-		ast_log(AST_LOG_WARNING, "Failed to fork CDR for channel %s\n", ast_channel_name(chan));
+	if (!payload) {
+		return -1;
+	}
+
+	payload->channel_name = ast_channel_name(chan);
+	payload->flags = &flags;
+	message = stasis_message_create(forkcdr_message_type(), payload);
+	if (!message) {
+		ast_log(AST_LOG_WARNING, "Failed to fork CDR for channel %s: unable to create message\n",
+			ast_channel_name(chan));
+		return -1;
+	}
+
+	subscription = stasis_subscribe(ast_channel_topic(chan), forkcdr_callback, NULL);
+	if (!subscription) {
+		ast_log(AST_LOG_WARNING, "Failed to fork CDR for channel %s: unable to create subscription\n",
+			payload->channel_name);
+		return -1;
 	}
 
+	stasis_publish(ast_channel_topic(chan), message);
+
+	subscription = stasis_unsubscribe_and_join(subscription);
+
 	return 0;
 }
 
 static int unload_module(void)
 {
+	STASIS_MESSAGE_TYPE_CLEANUP(forkcdr_message_type);
+
 	return ast_unregister_application(app);
 }
 
 static int load_module(void)
 {
-	return ast_register_application_xml(app, forkcdr_exec);
+	int res = 0;
+
+	res |= STASIS_MESSAGE_TYPE_INIT(forkcdr_message_type);
+	res |= ast_register_application_xml(app, forkcdr_exec);
+
+	return res;
 }
 
 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Fork The CDR into 2 separate entities");
diff --git a/funcs/func_cdr.c b/funcs/func_cdr.c
index 48df0a0928bf764404530b52a175c1419a8ba563..3f248168cbae873d070a17cd07d8236940896e10 100644
--- a/funcs/func_cdr.c
+++ b/funcs/func_cdr.c
@@ -39,6 +39,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/utils.h"
 #include "asterisk/app.h"
 #include "asterisk/cdr.h"
+#include "asterisk/stasis.h"
 
 /*** DOCUMENTATION
 	<function name="CDR" language="en_US">
@@ -201,45 +202,65 @@ AST_APP_OPTIONS(cdr_func_options, {
 	AST_APP_OPTION('u', OPT_UNPARSED),
 });
 
-static int cdr_read(struct ast_channel *chan, const char *cmd, char *parse,
-		    char *buf, size_t len)
+struct cdr_func_payload {
+	struct ast_channel *chan;
+	const char *cmd;
+	const char *arguments;
+	const char *value;
+};
+
+struct cdr_func_data {
+	char *buf;
+	size_t len;
+};
+
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(cdr_read_message_type);
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(cdr_write_message_type);
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(cdr_prop_write_message_type);
+
+static void cdr_read_callback(void *data, struct stasis_subscription *sub, struct stasis_message *message)
 {
+	struct cdr_func_data *output = data;
+	struct cdr_func_payload *payload = stasis_message_data(message);
+	char *info;
 	char *value = NULL;
 	struct ast_flags flags = { 0 };
 	char tempbuf[512];
-	char *info;
 	AST_DECLARE_APP_ARGS(args,
 		AST_APP_ARG(variable);
 		AST_APP_ARG(options);
 	);
 
-	buf[0] = '\0';/* Ensure the buffer is initialized. */
+	if (cdr_read_message_type() != stasis_message_type(message)) {
+		return;
+	}
 
-	if (!chan) {
-		return -1;
+	if (!payload || !output) {
+		return;
 	}
 
-	if (ast_strlen_zero(parse)) {
-		ast_log(AST_LOG_WARNING, "FUNC_CDR requires a variable (FUNC_CDR(variable[,option]))\n)");
-		return -1;
+	if (ast_strlen_zero(payload->arguments)) {
+		ast_log(AST_LOG_WARNING, "%s requires a variable (%s(variable[,option]))\n)",
+			payload->cmd, payload->cmd);
+		return;
 	}
-	info = ast_strdupa(parse);
+	info = ast_strdupa(payload->arguments);
 	AST_STANDARD_APP_ARGS(args, info);
 
 	if (!ast_strlen_zero(args.options)) {
 		ast_app_parse_options(cdr_func_options, &flags, NULL, args.options);
 	}
 
-	if (ast_strlen_zero(ast_channel_name(chan))) {
+	if (ast_strlen_zero(ast_channel_name(payload->chan))) {
 		/* Format request on a dummy channel */
-		ast_cdr_format_var(ast_channel_cdr(chan), args.variable, &value, tempbuf, sizeof(tempbuf), 0);
+		ast_cdr_format_var(ast_channel_cdr(payload->chan), args.variable, &value, tempbuf, sizeof(tempbuf), 0);
 		if (ast_strlen_zero(value)) {
-			return 0;
+			return;
 		}
 		ast_copy_string(tempbuf, value, sizeof(tempbuf));
 		ast_set_flag(&flags, OPT_UNPARSED);
-	} else if (ast_cdr_getvar(ast_channel_name(chan), args.variable, tempbuf, sizeof(tempbuf))) {
-		return 0;
+	} else if (ast_cdr_getvar(ast_channel_name(payload->chan), args.variable, tempbuf, sizeof(tempbuf))) {
+		return;
 	}
 
 	if (ast_test_flag(&flags, OPT_FLOAT)
@@ -249,8 +270,8 @@ static int cdr_read(struct ast_channel *chan, const char *cmd, char *parse,
 
 		if (sscanf(tempbuf, "%30ld", &ms) != 1) {
 			ast_log(AST_LOG_WARNING, "Unable to parse %s (%s) from the CDR for channel %s\n",
-				args.variable, tempbuf, ast_channel_name(chan));
-			return 0;
+				args.variable, tempbuf, ast_channel_name(payload->chan));
+			return;
 		}
 		dtime = (double)(ms / 1000.0);
 		snprintf(tempbuf, sizeof(tempbuf), "%lf", dtime);
@@ -265,8 +286,8 @@ static int cdr_read(struct ast_channel *chan, const char *cmd, char *parse,
 
 			if (sscanf(tempbuf, "%ld.%ld", &fmt_time.tv_sec, &tv_usec) != 2) {
 				ast_log(AST_LOG_WARNING, "Unable to parse %s (%s) from the CDR for channel %s\n",
-					args.variable, tempbuf, ast_channel_name(chan));
-				return 0;
+					args.variable, tempbuf, ast_channel_name(payload->chan));
+				return;
 			}
 			fmt_time.tv_usec = tv_usec;
 			ast_localtime(&fmt_time, &tm, NULL);
@@ -276,8 +297,8 @@ static int cdr_read(struct ast_channel *chan, const char *cmd, char *parse,
 
 			if (sscanf(tempbuf, "%8d", &disposition) != 1) {
 				ast_log(AST_LOG_WARNING, "Unable to parse %s (%s) from the CDR for channel %s\n",
-					args.variable, tempbuf, ast_channel_name(chan));
-				return 0;
+					args.variable, tempbuf, ast_channel_name(payload->chan));
+				return;
 			}
 			snprintf(tempbuf, sizeof(tempbuf), "%s", ast_cdr_disp2str(disposition));
 		} else if (!strcasecmp("amaflags", args.variable)) {
@@ -285,30 +306,45 @@ static int cdr_read(struct ast_channel *chan, const char *cmd, char *parse,
 
 			if (sscanf(tempbuf, "%8d", &amaflags) != 1) {
 				ast_log(AST_LOG_WARNING, "Unable to parse %s (%s) from the CDR for channel %s\n",
-					args.variable, tempbuf, ast_channel_name(chan));
-				return 0;
+					args.variable, tempbuf, ast_channel_name(payload->chan));
+				return;
 			}
 			snprintf(tempbuf, sizeof(tempbuf), "%s", ast_channel_amaflags2string(amaflags));
 		}
 	}
 
-	ast_copy_string(buf, tempbuf, len);
-	return 0;
+	ast_copy_string(output->buf, tempbuf, output->len);
 }
 
-static int cdr_write(struct ast_channel *chan, const char *cmd, char *parse,
-		     const char *value)
+static void cdr_write_callback(void *data, struct stasis_subscription *sub, struct stasis_message *message)
 {
+	struct cdr_func_payload *payload = stasis_message_data(message);
 	struct ast_flags flags = { 0 };
 	AST_DECLARE_APP_ARGS(args,
 		AST_APP_ARG(variable);
 		AST_APP_ARG(options);
 	);
+	char *parse;
 
-	if (ast_strlen_zero(parse) || !value || !chan) {
-		return -1;
+	if (cdr_write_message_type() != stasis_message_type(message)) {
+		return;
 	}
 
+	if (!payload) {
+		return;
+	}
+
+	if (ast_strlen_zero(payload->arguments)) {
+		ast_log(AST_LOG_WARNING, "%s requires a variable (%s(variable)=value)\n)",
+			payload->cmd, payload->cmd);
+		return;
+	}
+	if (ast_strlen_zero(payload->value)) {
+		ast_log(AST_LOG_WARNING, "%s requires a value (%s(variable)=value)\n)",
+			payload->cmd, payload->cmd);
+		return;
+	}
+	parse = ast_strdupa(payload->arguments);
 	AST_STANDARD_APP_ARGS(args, parse);
 
 	if (!ast_strlen_zero(args.options)) {
@@ -317,47 +353,61 @@ static int cdr_write(struct ast_channel *chan, const char *cmd, char *parse,
 
 	if (!strcasecmp(args.variable, "accountcode")) {
 		ast_log(AST_LOG_WARNING, "Using the CDR function to set 'accountcode' is deprecated. Please use the CHANNEL function instead.\n");
-		ast_channel_lock(chan);
-		ast_channel_accountcode_set(chan, value);
-		ast_channel_unlock(chan);
+		ast_channel_lock(payload->chan);
+		ast_channel_accountcode_set(payload->chan, payload->value);
+		ast_channel_unlock(payload->chan);
 	} else if (!strcasecmp(args.variable, "peeraccount")) {
 		ast_log(AST_LOG_WARNING, "The 'peeraccount' setting is not supported. Please set the 'accountcode' on the appropriate channel using the CHANNEL function.\n");
 	} else if (!strcasecmp(args.variable, "userfield")) {
-		ast_cdr_setuserfield(ast_channel_name(chan), value);
+		ast_cdr_setuserfield(ast_channel_name(payload->chan), payload->value);
 	} else if (!strcasecmp(args.variable, "amaflags")) {
 		ast_log(AST_LOG_WARNING, "Using the CDR function to set 'amaflags' is deprecated. Please use the CHANNEL function instead.\n");
-		if (isdigit(*value)) {
+		if (isdigit(*payload->value)) {
 			int amaflags;
-			sscanf(value, "%30d", &amaflags);
-			ast_channel_lock(chan);
-			ast_channel_amaflags_set(chan, amaflags);
-			ast_channel_unlock(chan);
+			sscanf(payload->value, "%30d", &amaflags);
+			ast_channel_lock(payload->chan);
+			ast_channel_amaflags_set(payload->chan, amaflags);
+			ast_channel_unlock(payload->chan);
 		} else {
-			ast_channel_lock(chan);
-			ast_channel_amaflags_set(chan, ast_channel_string2amaflag(value));
-			ast_channel_unlock(chan);
+			ast_channel_lock(payload->chan);
+			ast_channel_amaflags_set(payload->chan, ast_channel_string2amaflag(payload->value));
+			ast_channel_unlock(payload->chan);
 		}
 	} else {
-		ast_cdr_setvar(ast_channel_name(chan), args.variable, value);
+		ast_cdr_setvar(ast_channel_name(payload->chan), args.variable, payload->value);
 	}
-
-	return 0;
+	return;
 }
 
-static int cdr_prop_write(struct ast_channel *chan, const char *cmd, char *parse,
-		     const char *value)
+static void cdr_prop_write_callback(void *data, struct stasis_subscription *sub, struct stasis_message *message)
 {
+	struct cdr_func_payload *payload = stasis_message_data(message);
 	enum ast_cdr_options option;
-
+	char *parse;
 	AST_DECLARE_APP_ARGS(args,
 		AST_APP_ARG(variable);
 		AST_APP_ARG(options);
 	);
 
-	if (ast_strlen_zero(parse) || !value || !chan) {
-		return -1;
+	if (cdr_prop_write_message_type() != stasis_message_type(message)) {
+		return;
 	}
 
+	if (!payload) {
+		return;
+	}
+
+	if (ast_strlen_zero(payload->arguments)) {
+		ast_log(AST_LOG_WARNING, "%s requires a variable (%s(variable)=value)\n)",
+			payload->cmd, payload->cmd);
+		return;
+	}
+	if (ast_strlen_zero(payload->value)) {
+		ast_log(AST_LOG_WARNING, "%s requires a value (%s(variable)=value)\n)",
+			payload->cmd, payload->cmd);
+		return;
+	}
+	parse = ast_strdupa(payload->arguments);
 	AST_STANDARD_APP_ARGS(args, parse);
 
 	if (!strcasecmp("party_a", args.variable)) {
@@ -365,15 +415,139 @@ static int cdr_prop_write(struct ast_channel *chan, const char *cmd, char *parse
 	} else if (!strcasecmp("disable", args.variable)) {
 		option = AST_CDR_FLAG_DISABLE_ALL;
 	} else {
-		ast_log(AST_LOG_WARNING, "Unknown option %s used with CDR_PROP\n", args.variable);
-		return 0;
+		ast_log(AST_LOG_WARNING, "Unknown option %s used with %s\n", args.variable, payload->cmd);
+		return;
 	}
 
-	if (ast_true(value)) {
-		ast_cdr_set_property(ast_channel_name(chan), option);
+	if (ast_true(payload->value)) {
+		ast_cdr_set_property(ast_channel_name(payload->chan), option);
 	} else {
-		ast_cdr_clear_property(ast_channel_name(chan), option);
+		ast_cdr_clear_property(ast_channel_name(payload->chan), option);
+	}
+}
+
+
+static int cdr_read(struct ast_channel *chan, const char *cmd, char *parse,
+		    char *buf, size_t len)
+{
+	RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
+	RAII_VAR(struct cdr_func_payload *, payload,
+		ao2_alloc(sizeof(*payload), NULL), ao2_cleanup);
+	struct cdr_func_data output = { 0, };
+
+	if (!payload) {
+		return -1;
 	}
+	payload->chan = chan;
+	payload->cmd = cmd;
+	payload->arguments = parse;
+
+	buf[0] = '\0';/* Ensure the buffer is initialized. */
+	output.buf = buf;
+	output.len = len;
+
+	message = stasis_message_create(cdr_read_message_type(), payload);
+	if (!message) {
+		ast_log(AST_LOG_WARNING, "Failed to manipulate CDR for channel %s: unable to create message\n",
+			ast_channel_name(chan));
+		return -1;
+	}
+
+	/* If this is a request on a dummy channel, we're doing post-processing on an
+	 * already dispatched CDR. Simply call the callback to calculate the value and
+	 * return, instead of posting to Stasis as we would for a running channel.
+	 */
+	if (ast_strlen_zero(ast_channel_name(chan))) {
+		cdr_read_callback(NULL, NULL, message);
+	} else {
+		RAII_VAR(struct stasis_subscription *, subscription, NULL, ao2_cleanup);
+
+		subscription = stasis_subscribe(ast_channel_topic(chan), cdr_read_callback, &output);
+		if (!subscription) {
+			ast_log(AST_LOG_WARNING, "Failed to manipulate CDR for channel %s: unable to create subscription\n",
+				ast_channel_name(chan));
+			return -1;
+		}
+
+		stasis_publish(ast_channel_topic(chan), message);
+
+		subscription = stasis_unsubscribe_and_join(subscription);
+	}
+
+	return 0;
+}
+
+static int cdr_write(struct ast_channel *chan, const char *cmd, char *parse,
+		     const char *value)
+{
+	RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
+	RAII_VAR(struct cdr_func_payload *, payload,
+		ao2_alloc(sizeof(*payload), NULL), ao2_cleanup);
+	RAII_VAR(struct stasis_subscription *, subscription, NULL, ao2_cleanup);
+
+	if (!payload) {
+		return -1;
+	}
+	payload->chan = chan;
+	payload->cmd = cmd;
+	payload->arguments = parse;
+	payload->value = value;
+
+	message = stasis_message_create(cdr_write_message_type(), payload);
+	if (!message) {
+		ast_log(AST_LOG_WARNING, "Failed to manipulate CDR for channel %s: unable to create message\n",
+			ast_channel_name(chan));
+		return -1;
+	}
+
+	subscription = stasis_subscribe(ast_channel_topic(chan), cdr_write_callback, NULL);
+	if (!subscription) {
+		ast_log(AST_LOG_WARNING, "Failed to manipulate CDR for channel %s: unable to create subscription\n",
+			ast_channel_name(chan));
+		return -1;
+	}
+
+	stasis_publish(ast_channel_topic(chan), message);
+
+	subscription = stasis_unsubscribe_and_join(subscription);
+
+	return 0;
+}
+
+static int cdr_prop_write(struct ast_channel *chan, const char *cmd, char *parse,
+		     const char *value)
+{
+	RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
+	RAII_VAR(struct cdr_func_payload *, payload,
+		ao2_alloc(sizeof(*payload), NULL), ao2_cleanup);
+	RAII_VAR(struct stasis_subscription *, subscription, NULL, ao2_cleanup);
+
+	if (!payload) {
+		return -1;
+	}
+	payload->chan = chan;
+	payload->cmd = cmd;
+	payload->arguments = parse;
+	payload->value = value;
+
+	message = stasis_message_create(cdr_prop_write_message_type(), payload);
+	if (!message) {
+		ast_log(AST_LOG_WARNING, "Failed to manipulate CDR for channel %s: unable to create message\n",
+			ast_channel_name(chan));
+		return -1;
+	}
+
+	subscription = stasis_subscribe(ast_channel_topic(chan), cdr_prop_write_callback, NULL);
+	if (!subscription) {
+		ast_log(AST_LOG_WARNING, "Failed to manipulate CDR for channel %s: unable to create subscription\n",
+			ast_channel_name(chan));
+		return -1;
+	}
+
+	stasis_publish(ast_channel_topic(chan), message);
+
+	subscription = stasis_unsubscribe_and_join(subscription);
+
 	return 0;
 }
 
@@ -393,6 +567,9 @@ static int unload_module(void)
 {
 	int res = 0;
 
+	STASIS_MESSAGE_TYPE_CLEANUP(cdr_read_message_type);
+	STASIS_MESSAGE_TYPE_CLEANUP(cdr_write_message_type);
+	STASIS_MESSAGE_TYPE_CLEANUP(cdr_prop_write_message_type);
 	res |= ast_custom_function_unregister(&cdr_function);
 	res |= ast_custom_function_unregister(&cdr_prop_function);
 
@@ -403,6 +580,9 @@ static int load_module(void)
 {
 	int res = 0;
 
+	res |= STASIS_MESSAGE_TYPE_INIT(cdr_read_message_type);
+	res |= STASIS_MESSAGE_TYPE_INIT(cdr_write_message_type);
+	res |= STASIS_MESSAGE_TYPE_INIT(cdr_prop_write_message_type);
 	res |= ast_custom_function_register(&cdr_function);
 	res |= ast_custom_function_register(&cdr_prop_function);
 
diff --git a/include/asterisk/cdr.h b/include/asterisk/cdr.h
index 801b1b4989d9800689877149d5b7a6d7f3ab9e7d..ad7e5cc69d091baf8993f5508a333f82177fbb62 100644
--- a/include/asterisk/cdr.h
+++ b/include/asterisk/cdr.h
@@ -431,17 +431,13 @@ int ast_cdr_clear_property(const char *channel_name, enum ast_cdr_options option
 /*!
  * \brief Reset the detail record
  * \param channel_name The channel that the CDR is associated with
- * \param options Options that control what the reset operation does.
- *
- * Valid options are:
- * \ref AST_CDR_FLAG_KEEP_VARS - keep the variables during the reset
- * \ref AST_CDR_FLAG_DISABLE_ALL - when used with \ref ast_cdr_reset, re-enables
- * the CDR
+ * \param keep_variables Keep the variables during the reset. If zero,
+ *        variables are discarded during the reset.
  *
  * \retval 0 on success
  * \retval -1 on failure
  */
-int ast_cdr_reset(const char *channel_name, struct ast_flags *options);
+int ast_cdr_reset(const char *channel_name, int keep_variables);
 
 /*!
  * \brief Serializes all the data and variables for a current CDR record
diff --git a/main/cdr.c b/main/cdr.c
index 63648361db88e84ff31bfd493983ebfc15b39df5..593f4715278359e3ad7c0647840ba149eb54c355 100644
--- a/main/cdr.c
+++ b/main/cdr.c
@@ -3269,7 +3269,7 @@ int ast_cdr_clear_property(const char *channel_name, enum ast_cdr_options option
 	return 0;
 }
 
-int ast_cdr_reset(const char *channel_name, struct ast_flags *options)
+int ast_cdr_reset(const char *channel_name, int keep_variables)
 {
 	RAII_VAR(struct cdr_object *, cdr, cdr_object_get_by_name(channel_name), ao2_cleanup);
 	struct ast_var_t *vardata;
@@ -3282,7 +3282,7 @@ int ast_cdr_reset(const char *channel_name, struct ast_flags *options)
 	ao2_lock(cdr);
 	for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
 		/* clear variables */
-		if (!ast_test_flag(options, AST_CDR_FLAG_KEEP_VARS)) {
+		if (!keep_variables) {
 			while ((vardata = AST_LIST_REMOVE_HEAD(&it_cdr->party_a.variables, entries))) {
 				ast_var_delete(vardata);
 			}
diff --git a/main/pbx.c b/main/pbx.c
index 1e6a246251b653467326ab0aabcf21b49e93d062..c5eb5f116aea4b6315e6cd9228b5c594e5555d0d 100644
--- a/main/pbx.c
+++ b/main/pbx.c
@@ -104,10 +104,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 				<para>Asterisk will wait this number of milliseconds before returning to
 				the dialplan after answering the call.</para>
 			</parameter>
-			<parameter name="nocdr">
-				<para>Asterisk will send an answer signal to the calling phone, but will not
-				set the disposition or answer time in the CDR for this call.</para>
-			</parameter>
 		</syntax>
 		<description>
 			<para>If the call has not been answered, this application will
@@ -10727,9 +10723,7 @@ static int pbx_builtin_answer(struct ast_channel *chan, const char *data)
 	}
 
 	if (!ast_strlen_zero(args.answer_cdr) && !strcasecmp(args.answer_cdr, "nocdr")) {
-		if (ast_cdr_set_property(ast_channel_name(chan), AST_CDR_FLAG_DISABLE_ALL)) {
-			ast_log(AST_LOG_WARNING, "Failed to disable CDR on %s\n", ast_channel_name(chan));
-		}
+		ast_log(AST_LOG_WARNING, "The nocdr option for the Answer application has been removed and is no longer supported.\n");
 	}
 
 	return __ast_answer(chan, delay);