41 #include "asterisk/stasis_message_router.h"
197 enum cdr_option_flags {
198 OPT_UNPARSED = (1 << 1),
199 OPT_FLOAT = (1 << 2),
210 const char *arguments;
224 static struct timeval cdr_retrieve_time(struct
ast_channel *chan,
const char *time_name)
226 struct timeval time = { 0 };
232 if (ast_strlen_zero(ast_channel_name(chan))) {
234 ast_cdr_format_var(ast_channel_cdr(chan), time_name, &value, tempbuf,
sizeof(tempbuf), 1);
236 ast_cdr_getvar(ast_channel_name(chan), time_name, tempbuf,
sizeof(tempbuf));
240 if (sscanf(tempbuf,
"%ld.%ld", &tv_sec, &tv_usec) == 2) {
241 time.tv_sec = tv_sec;
242 time.tv_usec = tv_usec;
244 ast_log(AST_LOG_WARNING,
"Failed to fully extract '%s' from CDR\n", time_name);
267 ast_assert(payload != NULL);
268 output = payload->data;
269 ast_assert(output != NULL);
271 if (ast_strlen_zero(payload->arguments)) {
272 ast_log(AST_LOG_WARNING,
"%s requires a variable (%s(variable[,option]))\n)",
273 payload->cmd, payload->cmd);
279 if (!ast_strlen_zero(args.options)) {
283 if (ast_strlen_zero(ast_channel_name(payload->chan))) {
285 ast_cdr_format_var(ast_channel_cdr(payload->chan), args.variable, &value, tempbuf,
sizeof(tempbuf), ast_test_flag(&flags, OPT_UNPARSED));
286 if (ast_strlen_zero(value)) {
290 ast_set_flag(&flags, OPT_UNPARSED);
291 }
else if (
ast_cdr_getvar(ast_channel_name(payload->chan), args.variable, tempbuf,
sizeof(tempbuf))) {
295 if (ast_test_flag(&flags, OPT_FLOAT)
296 && (!strcasecmp(
"billsec", args.variable) || !strcasecmp(
"duration", args.variable))) {
297 struct timeval start = cdr_retrieve_time(payload->chan, !strcasecmp(
"billsec", args.variable) ?
"answer" :
"start");
298 struct timeval finish = cdr_retrieve_time(payload->chan,
"end");
310 snprintf(tempbuf,
sizeof(tempbuf),
"%lf", delta);
312 }
else if (!ast_test_flag(&flags, OPT_UNPARSED)) {
313 if (!strcasecmp(
"start", args.variable)
314 || !strcasecmp(
"end", args.variable)
315 || !strcasecmp(
"answer", args.variable)) {
316 struct timeval fmt_time;
322 if (sscanf(tempbuf,
"%ld.%ld", &tv_sec, &tv_usec) != 2) {
323 ast_log(AST_LOG_WARNING,
"Unable to parse %s (%s) from the CDR for channel %s\n",
324 args.variable, tempbuf, ast_channel_name(payload->chan));
328 fmt_time.tv_sec = tv_sec;
329 fmt_time.tv_usec = tv_usec;
331 ast_strftime(tempbuf,
sizeof(tempbuf),
"%Y-%m-%d %T", &tm);
335 }
else if (!strcasecmp(
"disposition", args.variable)) {
338 if (sscanf(tempbuf,
"%8d", &disposition) != 1) {
339 ast_log(AST_LOG_WARNING,
"Unable to parse %s (%s) from the CDR for channel %s\n",
340 args.variable, tempbuf, ast_channel_name(payload->chan));
344 }
else if (!strcasecmp(
"amaflags", args.variable)) {
347 if (sscanf(tempbuf,
"%8d", &amaflags) != 1) {
348 ast_log(AST_LOG_WARNING,
"Unable to parse %s (%s) from the CDR for channel %s\n",
349 args.variable, tempbuf, ast_channel_name(payload->chan));
376 if (ast_strlen_zero(payload->arguments)
377 || !payload->value) {
386 if (!ast_strlen_zero(args.options)) {
391 ast_assert(strcasecmp(args.variable,
"accountcode")
392 && strcasecmp(args.variable,
"peeraccount")
393 && strcasecmp(args.variable,
"amaflags"));
395 if (!strcasecmp(args.variable,
"userfield")) {
398 ast_cdr_setvar(ast_channel_name(payload->chan), args.variable, payload->value);
420 if (ast_strlen_zero(payload->arguments)) {
421 ast_log(AST_LOG_WARNING,
"%s requires a variable (%s(variable)=value)\n)",
422 payload->cmd, payload->cmd);
425 if (ast_strlen_zero(payload->value)) {
426 ast_log(AST_LOG_WARNING,
"%s requires a value (%s(variable)=value)\n)",
427 payload->cmd, payload->cmd);
433 if (!strcasecmp(
"party_a", args.variable)) {
435 }
else if (!strcasecmp(
"disable", args.variable)) {
438 ast_log(AST_LOG_WARNING,
"Unknown option %s used with %s\n", args.variable, payload->cmd);
450 static int cdr_read(
struct ast_channel *chan,
const char *cmd,
char *parse,
451 char *buf,
size_t len)
458 ast_log(LOG_WARNING,
"No channel was provided to %s function.\n", cmd);
462 if (!cdr_read_message_type()) {
463 ast_log(AST_LOG_WARNING,
"Failed to manipulate CDR for channel %s: message type not available\n",
464 ast_channel_name(chan));
468 payload = ao2_alloc(
sizeof(*payload), NULL);
472 payload->chan = chan;
474 payload->arguments = parse;
475 payload->data = &output;
483 ast_log(AST_LOG_WARNING,
"Failed to manipulate CDR for channel %s: unable to create message\n",
484 ast_channel_name(chan));
492 if (ast_strlen_zero(ast_channel_name(chan))) {
493 cdr_read_callback(NULL, NULL, message);
498 ast_log(AST_LOG_WARNING,
"Failed to manipulate CDR for channel %s: no message router\n",
499 ast_channel_name(chan));
508 static int cdr_write(
struct ast_channel *chan,
const char *cmd,
char *arguments,
521 ast_log(LOG_WARNING,
"No channel was provided to %s function.\n", cmd);
524 if (ast_strlen_zero(arguments)) {
525 ast_log(LOG_WARNING,
"%s requires a variable (%s(variable)=value)\n)",
530 ast_log(LOG_WARNING,
"%s requires a value (%s(variable)=value)\n)",
539 if (!strcasecmp(args.variable,
"accountcode")) {
540 ast_log(LOG_WARNING,
"Using the %s function to set 'accountcode' is deprecated. Please use the CHANNEL function instead.\n",
542 ast_channel_lock(chan);
543 ast_channel_accountcode_set(chan, value);
544 ast_channel_unlock(chan);
547 if (!strcasecmp(args.variable,
"amaflags")) {
550 ast_log(LOG_WARNING,
"Using the %s function to set 'amaflags' is deprecated. Please use the CHANNEL function instead.\n",
552 if (isdigit(*value)) {
553 if (sscanf(value,
"%30d", &amaflags) != 1) {
554 amaflags = AST_AMA_NONE;
559 ast_channel_lock(chan);
561 ast_channel_unlock(chan);
564 if (!strcasecmp(args.variable,
"peeraccount")) {
565 ast_log(LOG_WARNING,
"The 'peeraccount' setting is not supported. Please set the 'accountcode' on the appropriate channel using the CHANNEL function.\n");
570 if (!cdr_write_message_type()) {
571 ast_log(LOG_WARNING,
"Failed to manipulate CDR for channel %s: message type not available\n",
572 ast_channel_name(chan));
576 payload = ao2_alloc(
sizeof(*payload), NULL);
580 payload->chan = chan;
582 payload->arguments = arguments;
583 payload->value = value;
588 ast_log(LOG_WARNING,
"Failed to manipulate CDR for channel %s: unable to create message\n",
589 ast_channel_name(chan));
594 ast_log(LOG_WARNING,
"Failed to manipulate CDR for channel %s: no message router\n",
595 ast_channel_name(chan));
606 static int cdr_prop_write(
struct ast_channel *chan,
const char *cmd,
char *parse,
614 ast_log(LOG_WARNING,
"No channel was provided to %s function.\n", cmd);
619 ast_log(AST_LOG_WARNING,
"Failed to manipulate CDR for channel %s: no message router\n",
620 ast_channel_name(chan));
624 if (!cdr_prop_write_message_type()) {
625 ast_log(AST_LOG_WARNING,
"Failed to manipulate CDR for channel %s: message type not available\n",
626 ast_channel_name(chan));
630 payload = ao2_alloc(
sizeof(*payload), NULL);
634 payload->chan = chan;
636 payload->arguments = parse;
637 payload->value = value;
641 ast_log(AST_LOG_WARNING,
"Failed to manipulate CDR for channel %s: unable to create message\n",
642 ast_channel_name(chan));
659 .write = cdr_prop_write,
662 static int unload_module(
void)
681 static int load_module(
void)
696 cdr_prop_write_callback, NULL);
698 cdr_write_callback, NULL);
700 cdr_read_callback, NULL);
709 AST_MODULE_INFO(
ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT,
"Call Detail Record (CDR) dialplan functions",
710 .support_level = AST_MODULE_SUPPORT_CORE,
712 .unload = unload_module,
Main Channel structure associated with a channel.
int ast_cdr_setvar(const char *channel_name, const char *name, const char *value)
Set a variable on a CDR.
Asterisk main include file. File version handling, generic pbx functions.
int stasis_message_router_add(struct stasis_message_router *router, struct stasis_message_type *message_type, stasis_subscription_cb callback, void *data)
Add a route to a message router.
int ast_cdr_getvar(const char *channel_name, const char *name, char *value, size_t length)
Retrieve a CDR variable from a channel's current CDR.
#define STASIS_MESSAGE_TYPE_INIT(name)
Boiler-plate messaging macro for initializing message types.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
Stasis Message Bus API. See Stasis Message Bus API for detailed documentation.
struct ast_tm * ast_localtime(const struct timeval *timep, struct ast_tm *p_tm, const char *zone)
Timezone-independent version of localtime_r(3).
int ast_tvzero(const struct timeval t)
Returns true if the argument is 0,0.
#define STASIS_MESSAGE_TYPE_CLEANUP(name)
Boiler-plate messaging macro for cleaning up message types.
struct stasis_message_type * stasis_message_type(const struct stasis_message *msg)
Get the message type for a stasis_message.
const char * ast_channel_amaflags2string(enum ama_flags flags)
Convert the enum representation of an AMA flag to a string representation.
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
ast_cdr_options
CDR manipulation options. Certain function calls will manipulate the state of a CDR object based on t...
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
#define AST_APP_OPTIONS(holder, options...)
Declares an array of options for an application.
enum ama_flags ast_channel_string2amaflag(const char *flag)
Convert a string to a detail record AMA flag.
void ast_cdr_format_var(struct ast_cdr *cdr, const char *name, char **ret, char *workspace, int workspacelen, int raw)
Format a CDR variable from an already posted CDR.
struct stasis_message_router * ast_cdr_message_router(void)
Return the message router for the CDR engine.
General Asterisk PBX channel definitions.
#define ast_strdupa(s)
duplicate a string in memory from the stack
Data structure associated with a custom dialplan function.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
void ast_channel_amaflags_set(struct ast_channel *chan, enum ama_flags value)
int ast_app_parse_options(const struct ast_app_option *options, struct ast_flags *flags, char **args, char *optstr)
Parses a string containing application options and sets flags/arguments.
Core PBX routines and definitions.
int ast_cdr_set_property(const char *channel_name, enum ast_cdr_options option)
Set a property on a CDR for a channel.
const char * ast_cdr_disp2str(int disposition)
Disposition to a string.
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
struct stasis_message * stasis_message_create(struct stasis_message_type *type, void *data)
Create a new message.
void stasis_message_router_remove(struct stasis_message_router *router, struct stasis_message_type *message_type)
Remove a route from a message router.
Module has failed to load, may be in an inconsistent state.
int ast_strftime(char *buf, size_t len, const char *format, const struct ast_tm *tm)
Special version of strftime(3) that handles fractions of a second. Takes the same arguments as strfti...
void ast_cdr_setuserfield(const char *channel_name, const char *userfield)
Set CDR user field for channel (stored in CDR)
Structure used to handle boolean flags.
STASIS_MESSAGE_TYPE_DEFN_LOCAL(cdr_sync_message_type)
A message type used to synchronize with the CDR topic.
void stasis_message_router_publish_sync(struct stasis_message_router *router, struct stasis_message *message)
Publish a message to a message router's subscription synchronously.
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
int ast_cdr_clear_property(const char *channel_name, enum ast_cdr_options option)
Clear a property on a CDR for a channel.
int64_t ast_tvdiff_us(struct timeval end, struct timeval start)
Computes the difference (in microseconds) between two struct timeval instances.
#define AST_APP_OPTION(option, flagno)
Declares an application option that does not accept an argument.
#define ASTERISK_GPL_KEY
The text the key() function should return.
Asterisk module definitions.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
#define ast_custom_function_register(acf)
Register a custom function.
#define AST_APP_ARG(name)
Define an application argument.