From f33ead8f667fdc27d25c2b15458d35b74e4038e9 Mon Sep 17 00:00:00 2001 From: Timo Sirainen Date: Fri, 4 Nov 2016 12:04:11 +0200 Subject: [PATCH] lib-storage: Fix doveadm search query parsing to use timezones correctly. When using a date string, e.g. "senton 25-Mar-2007" it should work the same way as IMAP does and show all mails whose sent date is on 25th, ignoring whatever the timezone is in the Date header (or in case of received/saved-date it would be using the timestamps in server's local timezone, again just like IMAP). When search with an exact UNIX timestamp or a time interval (e.g. "3 days"), it should be using UTC times for doing all comparisons. --- src/doveadm/doveadm-dsync.c | 5 +++-- src/lib-storage/mail-search-register-human.c | 7 ++++--- src/lib-storage/mail-storage.c | 7 ++++++- src/lib-storage/mail-storage.h | 15 +++++++++++---- 4 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/doveadm/doveadm-dsync.c b/src/doveadm/doveadm-dsync.c index a0db38d53c..48648db17c 100644 --- a/src/doveadm/doveadm-dsync.c +++ b/src/doveadm/doveadm-dsync.c @@ -964,6 +964,7 @@ cmd_mailbox_dsync_parse_arg(struct doveadm_mail_cmd_context *_ctx, int c) { struct dsync_cmd_context *ctx = (struct dsync_cmd_context *)_ctx; const char *str, *error; + bool utc; switch (c) { case '1': @@ -1043,11 +1044,11 @@ cmd_mailbox_dsync_parse_arg(struct doveadm_mail_cmd_context *_ctx, int c) ctx->state_input = optarg; break; case 't': - if (mail_parse_human_timestamp(optarg, &ctx->sync_since_timestamp) < 0) + if (mail_parse_human_timestamp(optarg, &ctx->sync_since_timestamp, &utc) < 0) i_fatal("Invalid -t parameter: %s", optarg); break; case 'e': - if (mail_parse_human_timestamp(optarg, &ctx->sync_until_timestamp) < 0) + if (mail_parse_human_timestamp(optarg, &ctx->sync_until_timestamp, &utc) < 0) i_fatal("Invalid -e parameter: %s", optarg); break; case 'I': diff --git a/src/lib-storage/mail-search-register-human.c b/src/lib-storage/mail-search-register-human.c index f192fe2ae7..7379e8e4ba 100644 --- a/src/lib-storage/mail-search-register-human.c +++ b/src/lib-storage/mail-search-register-human.c @@ -35,15 +35,16 @@ arg_new_human_date(struct mail_search_build_context *ctx, { struct mail_search_arg *sarg; const char *value; + bool utc; sarg = mail_search_build_new(ctx, type); if (mail_search_parse_string(ctx->parser, &value) < 0) return NULL; - if (mail_parse_human_timestamp(value, &sarg->value.time) < 0) + if (mail_parse_human_timestamp(value, &sarg->value.time, &utc) < 0) sarg->value.time = (time_t)-1; - - sarg->value.search_flags = MAIL_SEARCH_ARG_FLAG_USE_TZ; + if (utc) + sarg->value.search_flags = MAIL_SEARCH_ARG_FLAG_USE_TZ; if (sarg->value.time == (time_t)-1) { ctx->_error = p_strconcat(ctx->pool, diff --git a/src/lib-storage/mail-storage.c b/src/lib-storage/mail-storage.c index 8a6b6afcc1..151ef477b0 100644 --- a/src/lib-storage/mail-storage.c +++ b/src/lib-storage/mail-storage.c @@ -2524,7 +2524,8 @@ mail_storage_settings_to_index_flags(const struct mail_storage_settings *set) return index_flags; } -int mail_parse_human_timestamp(const char *str, time_t *timestamp_r) +int mail_parse_human_timestamp(const char *str, time_t *timestamp_r, + bool *utc_r) { struct tm tm; unsigned int secs; @@ -2541,15 +2542,19 @@ int mail_parse_human_timestamp(const char *str, time_t *timestamp_r) tm.tm_mon = (str[5]-'0') * 10 + (str[6]-'0') - 1; tm.tm_mday = (str[8]-'0') * 10 + (str[9]-'0'); *timestamp_r = mktime(&tm); + *utc_r = FALSE; return 0; } else if (imap_parse_date(str, timestamp_r)) { /* imap date */ + *utc_r = FALSE; return 0; } else if (str_to_time(str, timestamp_r) == 0) { /* unix timestamp */ + *utc_r = TRUE; return 0; } else if (settings_get_time(str, &secs, &error) == 0) { *timestamp_r = ioloop_time - secs; + *utc_r = TRUE; return 0; } else { return -1; diff --git a/src/lib-storage/mail-storage.h b/src/lib-storage/mail-storage.h index b13fce5d53..db089580b7 100644 --- a/src/lib-storage/mail-storage.h +++ b/src/lib-storage/mail-storage.h @@ -923,9 +923,16 @@ void mail_set_cache_corrupted_reason(struct mail *mail, 128 bits are returned. */ void mail_generate_guid_128_hash(const char *guid, guid_128_t guid_128_r); -/* Parse a human-writable string into a timestamp. Returns 0 and timestamp on - success, -1 if the string couldn't be parsed. Currently supported string - formats: yyyy-mm-dd, imap date, unix timestamp, interval (e.g. n days). */ -int mail_parse_human_timestamp(const char *str, time_t *timestamp_r); +/* Parse a human-writable string into a timestamp. utc_r controls whether + the returned timestamp should be treated as an exact UTC time (TRUE), or + whether this is a human-given date where the timestamp could be adjusted + by the matched mails' timezones (see MAIL_SEARCH_ARG_FLAG_USE_TZ). + + Returns 0 and timestamp on success, -1 if the string couldn't be parsed. + Currently supported string formats: yyyy-mm-dd (utc=FALSE), + imap date (utc=FALSE), unix timestamp (utc=TRUE), interval (e.g. n days, + utc=TRUE). */ +int mail_parse_human_timestamp(const char *str, time_t *timestamp_r, + bool *utc_r); #endif -- 2.47.3