From: Alan T. DeKok Date: Tue, 14 Jun 2022 22:00:52 +0000 (-0500) Subject: Allow %{date:+%A} to mean "Monday" X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=93005cbb12b961384505df1e85e075fa60ab3948;p=thirdparty%2Ffreeradius-server.git Allow %{date:+%A} to mean "Monday" which mirrors the "date +%A" command on Unix. Also update the documentation and add examples. --- diff --git a/raddb/mods-available/date b/raddb/mods-available/date index 9030460fc6e..8cc67ede6b0 100644 --- a/raddb/mods-available/date +++ b/raddb/mods-available/date @@ -7,64 +7,34 @@ # # = Date Module # -# The `date` module xlat does convert time formats. +# The `date` module parses dates, and prints them. # - +# The server will normally print dates in its own pre-defined format. +# It will also parse dates in a few limited formats. However, these +# operations are for full dates (e.g. January 1, 2020 12:34pm). The +# server does not print dates in other formats, and does not parse +# dates in other formats. # -# ## Configuration Settings +# The `date` module adds that functionality. It allows you to print +# dates in almost any format you want. It allows you to parse dates +# in almost any format, so long as you know what the fields are, and +# how they are defined. # # -# ### Simple date +# ## Configuration Settings # date { # - # format:: - # - # The `xlat` performs in three modes depending on the input it - # is passed. - # - # The input string can be: - # - # - an expanded date or integer attribute; - # - an expanded string attribute; - # - the fixed strings `request` or `now`. - # - # ."Attribute" mode: - # - # If the given attribute is of `date` or `integer` type, the date - # xlat will convert it to a `time` string in the format of the - # format config item. + # format:: Formatting of the output string. # - # If the given attribute is a `string` type, the `xlat` will attempt - # to parse it in the format specified by the format config item, - # and will expand to a Unix timestamp (seconds since the epoch). - # - # ."Get time" mode: - # - # If the input is the string `request`, the `xlat` will format the - # time the current request packet arrived according to the format - # string, and return it as a string. - # - # If the input is the string `now`, the `xlat` will behave as - # above, for the current time. - # - # See also the core provided expansions which are equivalent to - # `request` and `now`, but return numerical values: - # - # [options="header,autowidth"] - # |=== - # | Parameter | Description - # | %l | request time in seconds since the epoch. - # | %M | request time microsecond component. - # | %c | current time in seconds since the epoch. - # | %C | current time microsecond component. - # |=== + # The format arguments are the same as for the system + # `strftime` call. See `man strftime` for documentation. # format = "%b %e %Y %H:%M:%S %Z" # - # utc:: + # utc:: Whether conversions are in UTC or local time. # # If `utc` is enabled then any conversions will be made # as UTC, not localtime. @@ -87,3 +57,58 @@ date date_iso { format = "%Y-%m-%dT%H:%M:%SZ" utc = yes } + +# +# ### xlat expansions +# +# The `date` module defines an expansion `%{date:}` When the +# expansion is not passed an argument, it returns the current date +# printed according to the `format` string defined above. +# +# ."Attribute" mode: +# +# If the argument to `%{date:...}` is an attribute of `date` or +# `integer` type, the date used will be the time given by the +# relevant attribute. +# +# For example, `%{date:&Event-Timestamp}` will use the date from the +# `Event-Timestamp` attribute as the source of the date for printing. +# +# ."Get time" mode: +# +# If the input is the string `request`, the `xlat` will format the +# time the current request packet arrived according to the format +# string, and return it as a string. +# +# If the input is the string `now`, the `xlat` will behave as +# above, for the current time. +# +# If the input string begins with `+`, then the remainder of the +# string is interpreted as if the string had been given in the +# `format` configuration item. +# +# For example `%{date:'+%A'}` will return `Monday` if today is Monday. +# +# Note that the `%` character is special for xlat expansions, and therefore +# either has to be "protected" by string quotation, or the `%` character has +# to be escaped itself, as in `%{date:+%%A}` +# +# ."Integer output" +# +# In some cases, it is useful for the module to parse dates instead +# of printing them. In this mode, the format string is ignored. +# Instead, the input arguments are parsed, and the output is an +# integer containg the requested value. +# +# The following expansions return integer numbers: +# +# [options="header,autowidth"] +# |=== +# | Parameter | Description +# | %l | request time in seconds since the epoch. +# | %M | request time microsecond component. +# | %c | current time in seconds since the epoch. +# | %C | current time microsecond component. +# | &Attribute-Name | for string attributes, parse the string according to `format`, and return the integer value as a Unix timestamp. +# |=== +# diff --git a/src/modules/rlm_date/rlm_date.c b/src/modules/rlm_date/rlm_date.c index 4e8fd27acfa..ce51a2423ee 100644 --- a/src/modules/rlm_date/rlm_date.c +++ b/src/modules/rlm_date/rlm_date.c @@ -107,7 +107,7 @@ static xlat_action_t date_convert_string(TALLOC_CTX *ctx, fr_dcursor_t *out, req } static xlat_action_t date_encode_strftime(TALLOC_CTX *ctx, fr_dcursor_t *out, rlm_date_t const *inst, - request_t *request, time_t date) + request_t *request, char const *fmt, time_t date) { struct tm tminfo; char buff[64]; @@ -125,7 +125,7 @@ static xlat_action_t date_encode_strftime(TALLOC_CTX *ctx, fr_dcursor_t *out, rl } } - if (strftime(buff, sizeof(buff), inst->fmt, &tminfo) == 0) return XLAT_ACTION_FAIL; + if (strftime(buff, sizeof(buff), fmt, &tminfo) == 0) return XLAT_ACTION_FAIL; MEM(vb = fr_value_box_alloc_null(ctx)); MEM(fr_value_box_strdup(ctx, vb, NULL, buff, false) == 0); @@ -182,13 +182,20 @@ static xlat_action_t xlat_date_convert(TALLOC_CTX *ctx, fr_dcursor_t *out, */ if (arg->type == FR_TYPE_STRING) { if (strcmp(arg->vb_strvalue, "request") == 0) { - return date_encode_strftime(ctx, out, inst, request, + return date_encode_strftime(ctx, out, inst, request, inst->fmt, fr_time_to_sec(request->packet->timestamp)); } if (strcmp(arg->vb_strvalue, "now") == 0) { now: - return date_encode_strftime(ctx, out, inst, request, fr_time_to_sec(fr_time())); + return date_encode_strftime(ctx, out, inst, request, inst->fmt, fr_time_to_sec(fr_time())); + } + + /* + * %{date:'+%A'} == "Monday", to mirror the behavior of the `date` command. + */ + if (arg->vb_strvalue[0] == '+') { + return date_encode_strftime(ctx, out, inst, request, arg->vb_strvalue + 1, fr_time_to_sec(fr_time())); } } @@ -199,13 +206,13 @@ static xlat_action_t xlat_date_convert(TALLOC_CTX *ctx, fr_dcursor_t *out, * format as a string. */ case FR_TYPE_DATE: - return date_encode_strftime(ctx, out, inst, request, fr_unix_time_to_sec(arg->vb_date)); + return date_encode_strftime(ctx, out, inst, request, inst->fmt, fr_unix_time_to_sec(arg->vb_date)); case FR_TYPE_UINT32: - return date_encode_strftime(ctx, out, inst, request, (time_t) arg->vb_uint32); + return date_encode_strftime(ctx, out, inst, request, inst->fmt, (time_t) arg->vb_uint32); case FR_TYPE_UINT64: - return date_encode_strftime(ctx, out, inst, request, (time_t) arg->vb_uint64); + return date_encode_strftime(ctx, out, inst, request, inst->fmt, (time_t) arg->vb_uint64); /* * These are 'from' types, i.e. we'll convert the input string