struct tm *tm;
uoff_t virtual_size;
time_t date;
- int timezone_offset;
+ int tz_offset;
+ bool have_tz_offset;
switch (arg->type) {
/* internal dates */
case SEARCH_BEFORE:
case SEARCH_ON:
case SEARCH_SINCE:
- if (mail_get_received_date(ctx->mail, &date) < 0)
- return -1;
+ have_tz_offset = FALSE; tz_offset = 0; date = (time_t)-1;
+ switch (arg->value.date_type) {
+ case MAIL_SEARCH_DATE_TYPE_SENT:
+ if (mail_get_date(ctx->mail, &date, &tz_offset) < 0)
+ return -1;
+ have_tz_offset = TRUE;
+ break;
+ case MAIL_SEARCH_DATE_TYPE_RECEIVED:
+ if (mail_get_received_date(ctx->mail, &date) < 0)
+ return -1;
+ break;
+ case MAIL_SEARCH_DATE_TYPE_SAVED:
+ if (mail_get_save_date(ctx->mail, &date) < 0)
+ return -1;
+ break;
+ }
if ((arg->value.search_flags &
MAIL_SEARCH_ARG_FLAG_USE_TZ) == 0) {
- tm = localtime(&date);
- date += utc_offset(tm, date)*60;
+ if (!have_tz_offset) {
+ tm = localtime(&date);
+ tz_offset = utc_offset(tm, date);
+ }
+ date += tz_offset * 60;
}
switch (arg->type) {
break;
}
- /* sent dates */
- case SEARCH_SENTBEFORE:
- case SEARCH_SENTON:
- case SEARCH_SENTSINCE:
- /* NOTE: RFC-3501 specifies that timezone is ignored
- in searches. date is returned as UTC, so change it. */
- if (mail_get_date(ctx->mail, &date, &timezone_offset) < 0)
- return -1;
-
- if ((arg->value.search_flags &
- MAIL_SEARCH_ARG_FLAG_USE_TZ) == 0)
- date += timezone_offset * 60;
-
- switch (arg->type) {
- case SEARCH_SENTBEFORE:
- return date < arg->value.time;
- case SEARCH_SENTON:
- return date >= arg->value.time &&
- date < arg->value.time + 3600*24;
- case SEARCH_SENTSINCE:
- return date >= arg->value.time;
- default:
- /* unreachable */
- break;
- }
-
/* sizes */
case SEARCH_SMALLER:
case SEARCH_LARGER:
sent_time += timezone_offset * 60;
switch (type) {
- case SEARCH_SENTBEFORE:
+ case SEARCH_BEFORE:
return sent_time < search_time;
- case SEARCH_SENTON:
+ case SEARCH_ON:
return sent_time >= search_time &&
sent_time < search_time + 3600*24;
- case SEARCH_SENTSINCE:
+ case SEARCH_SINCE:
return sent_time >= search_time;
default:
i_unreached();
/* first check that the field name matches to argument. */
switch (arg->type) {
- case SEARCH_SENTBEFORE:
- case SEARCH_SENTON:
- case SEARCH_SENTSINCE:
+ case SEARCH_BEFORE:
+ case SEARCH_ON:
+ case SEARCH_SINCE:
+ if (arg->value.date_type != MAIL_SEARCH_DATE_TYPE_SENT)
+ return;
+
/* date is handled differently than others */
if (strcasecmp(ctx->hdr->name, "Date") == 0) {
if (ctx->hdr->continues) {
void *context ATTR_UNUSED)
{
switch (arg->type) {
- case SEARCH_SENTBEFORE:
- case SEARCH_SENTON:
- case SEARCH_SENTSINCE:
+ case SEARCH_BEFORE:
+ case SEARCH_ON:
+ case SEARCH_SINCE:
+ if (arg->value.date_type != MAIL_SEARCH_DATE_TYPE_SENT)
+ break;
+
if (arg->not) {
/* date header not found, so we match only for
NOT searches */
case SEARCH_BEFORE:
case SEARCH_ON:
case SEARCH_SINCE:
- case SEARCH_SENTBEFORE:
- case SEARCH_SENTON:
- case SEARCH_SENTSINCE:
case SEARCH_SMALLER:
case SEARCH_LARGER:
case SEARCH_HEADER:
return TRUE;
}
-#define ARG_NEW_DATE(type) \
- arg_new_date(data, args, next_sarg, type)
+#define ARG_NEW_DATE(type, date_type) \
+ arg_new_date(data, args, next_sarg, type, date_type)
static bool
arg_new_date(struct search_build_data *data,
const struct imap_arg **args, struct mail_search_arg **next_sarg,
- enum mail_search_arg_type type)
+ enum mail_search_arg_type type,
+ enum mail_search_date_type date_type)
{
struct mail_search_arg *sarg;
const char *value;
data->error = "Invalid search date parameter";
return FALSE;
}
+ sarg->value.date_type = date_type;
return TRUE;
}
return ARG_NEW_STR(SEARCH_BODY);
} else if (strcmp(key, "BEFORE") == 0) {
/* <date> */
- return ARG_NEW_DATE(SEARCH_BEFORE);
+ return ARG_NEW_DATE(SEARCH_BEFORE,
+ MAIL_SEARCH_DATE_TYPE_RECEIVED);
} else if (strcmp(key, "BCC") == 0) {
/* <string> */
return ARG_NEW_HEADER(SEARCH_HEADER_ADDRESS, key);
return TRUE;
} if (strcmp(key, "ON") == 0) {
/* <date> */
- return ARG_NEW_DATE(SEARCH_ON);
+ return ARG_NEW_DATE(SEARCH_ON,
+ MAIL_SEARCH_DATE_TYPE_RECEIVED);
} if (strcmp(key, "OLD") == 0) {
/* OLD == NOT RECENT */
if (!ARG_NEW_FLAGS(MAIL_RECENT))
return ARG_NEW_HEADER(SEARCH_HEADER_COMPRESS_LWSP, key);
} else if (strcmp(key, "SENTBEFORE") == 0) {
/* <date> */
- return ARG_NEW_DATE(SEARCH_SENTBEFORE);
+ return ARG_NEW_DATE(SEARCH_BEFORE,
+ MAIL_SEARCH_DATE_TYPE_SENT);
} else if (strcmp(key, "SENTON") == 0) {
/* <date> */
- return ARG_NEW_DATE(SEARCH_SENTON);
+ return ARG_NEW_DATE(SEARCH_ON,
+ MAIL_SEARCH_DATE_TYPE_SENT);
} else if (strcmp(key, "SENTSINCE") == 0) {
/* <date> */
- return ARG_NEW_DATE(SEARCH_SENTSINCE);
+ return ARG_NEW_DATE(SEARCH_SINCE,
+ MAIL_SEARCH_DATE_TYPE_SENT);
} else if (strcmp(key, "SINCE") == 0) {
/* <date> */
- return ARG_NEW_DATE(SEARCH_SINCE);
+ return ARG_NEW_DATE(SEARCH_SINCE,
+ MAIL_SEARCH_DATE_TYPE_RECEIVED);
} else if (strcmp(key, "SMALLER") == 0) {
/* <n> */
return ARG_NEW_SIZE(SEARCH_SMALLER);
} else if (strcmp(key, "X-MAILBOX") == 0) {
/* <string> */
return ARG_NEW_STR(SEARCH_MAILBOX);
+ } else if (strcmp(key, "X-SAVEDBEFORE") == 0) {
+ /* <date> */
+ return ARG_NEW_DATE(SEARCH_BEFORE,
+ MAIL_SEARCH_DATE_TYPE_SAVED);
+ } else if (strcmp(key, "X-SAVEDON") == 0) {
+ /* <date> */
+ return ARG_NEW_DATE(SEARCH_ON,
+ MAIL_SEARCH_DATE_TYPE_SAVED);
+ } else if (strcmp(key, "X-SAVEDSINCE") == 0) {
+ /* <date> */
+ return ARG_NEW_DATE(SEARCH_SINCE,
+ MAIL_SEARCH_DATE_TYPE_SAVED);
}
break;
default:
case SEARCH_BEFORE:
case SEARCH_ON:
case SEARCH_SINCE:
- case SEARCH_SENTBEFORE:
- case SEARCH_SENTON:
- case SEARCH_SENTSINCE:
new_arg->value.time = arg->value.time;
+ new_arg->value.date_type = arg->value.date_type;
break;
case SEARCH_SMALLER:
case SEARCH_LARGER:
subarg = subarg->next;
}
break;
- case SEARCH_SENTBEFORE:
- case SEARCH_SENTON:
- case SEARCH_SENTSINCE:
- buffer_append(headers, &date_hdr, sizeof(const char *));
+ case SEARCH_BEFORE:
+ case SEARCH_ON:
+ case SEARCH_SINCE:
+ if (arg->value.date_type == MAIL_SEARCH_DATE_TYPE_SENT)
+ buffer_append(headers, &date_hdr, sizeof(const char *));
break;
case SEARCH_HEADER:
case SEARCH_HEADER_ADDRESS:
case SEARCH_BEFORE:
case SEARCH_ON:
case SEARCH_SINCE:
- case SEARCH_SENTBEFORE:
- case SEARCH_SENTON:
- case SEARCH_SENTSINCE:
- return arg1->value.time == arg2->value.time;
+ return arg1->value.time == arg2->value.time &&
+ arg1->value.date_type == arg2->value.date_type;
case SEARCH_SMALLER:
case SEARCH_LARGER:
SEARCH_FLAGS,
SEARCH_KEYWORDS,
- /* dates */
+ /* dates (date_type required) */
SEARCH_BEFORE,
SEARCH_ON, /* time must point to beginning of the day */
SEARCH_SINCE,
- SEARCH_SENTBEFORE,
- SEARCH_SENTON, /* time must point to beginning of the day */
- SEARCH_SENTSINCE,
/* sizes */
SEARCH_SMALLER,
SEARCH_MAILBOX
};
+enum mail_search_date_type {
+ MAIL_SEARCH_DATE_TYPE_SENT = 1,
+ MAIL_SEARCH_DATE_TYPE_RECEIVED,
+ MAIL_SEARCH_DATE_TYPE_SAVED
+};
+
enum mail_search_arg_flag {
- /* For (SENT)BEFORE/SINCE/ON searches: Don't drop timezone from
+ /* For BEFORE/SINCE/ON searches: Don't drop timezone from
comparisons */
MAIL_SEARCH_ARG_FLAG_USE_TZ = 0x01,
};
uoff_t size;
enum mail_flags flags;
enum mail_search_arg_flag search_flags;
+ enum mail_search_date_type date_type;
enum mail_thread_type thread_type;
struct mail_keywords *keywords;
struct mail_search_modseq *modseq;