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);