dovecot-2.2: lib-storage: Added mail_search_args_to_imap()

dovecot at dovecot.org dovecot at dovecot.org
Thu Apr 23 16:29:40 UTC 2015


details:   http://hg.dovecot.org/dovecot-2.2/rev/fdd0f4d50256
changeset: 18456:fdd0f4d50256
user:      Timo Sirainen <tss at iki.fi>
date:      Thu Apr 23 19:24:50 2015 +0300
description:
lib-storage: Added mail_search_args_to_imap()
Useful for writing IMAP SEARCH parameters from struct mail_search_arg.

diffstat:

 src/lib-storage/Makefile.am                  |   10 +
 src/lib-storage/mail-search-args-imap.c      |  304 +++++++++++++++++++++++++++
 src/lib-storage/mail-search.h                |    9 +
 src/lib-storage/test-mail-search-args-imap.c |  133 +++++++++++
 4 files changed, 456 insertions(+), 0 deletions(-)

diffs (truncated from 498 to 300 lines):

diff -r 3d7b8a09d85d -r fdd0f4d50256 src/lib-storage/Makefile.am
--- a/src/lib-storage/Makefile.am	Thu Apr 23 19:20:00 2015 +0300
+++ b/src/lib-storage/Makefile.am	Thu Apr 23 19:24:50 2015 +0300
@@ -28,6 +28,7 @@
 	mail-error.c \
 	mail-namespace.c \
 	mail-search.c \
+	mail-search-args-imap.c \
 	mail-search-build.c \
 	mail-search-parser.c \
 	mail-search-parser-imap.c \
@@ -96,6 +97,7 @@
 libdovecot_storage_la_LDFLAGS = -export-dynamic
 
 test_programs = \
+	test-mail-search-args-imap \
 	test-mailbox-get
 
 noinst_PROGRAMS = $(test_programs)
@@ -104,6 +106,14 @@
 	$(top_builddir)/src/lib-test/libtest.la \
 	$(top_builddir)/src/lib/liblib.la
 
+test_mail_search_args_imap_SOURCES = test-mail-search-args-imap.c
+test_mail_search_args_imap_LDADD = \
+	$(LIBDOVECOT_STORAGE) \
+	$(LIBDOVECOT)
+test_mail_search_args_imap_DEPENDENCIES = \
+	libstorage.la \
+	$(LIBDOVECOT_DEPS)
+
 test_mailbox_get_SOURCES = test-mailbox-get.c
 test_mailbox_get_LDADD = mailbox-get.lo $(test_libs)
 test_mailbox_get_DEPENDENCIES = $(noinst_LTLIBRARIES) $(test_libs)
diff -r 3d7b8a09d85d -r fdd0f4d50256 src/lib-storage/mail-search-args-imap.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib-storage/mail-search-args-imap.c	Thu Apr 23 19:24:50 2015 +0300
@@ -0,0 +1,304 @@
+/* Copyright (c) 2015 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "ioloop.h"
+#include "array.h"
+#include "str.h"
+#include "utc-offset.h"
+#include "mail-index.h"
+#include "imap-date.h"
+#include "imap-util.h"
+#include "imap-quote.h"
+#include "mail-search.h"
+
+#include <time.h>
+
+static bool
+mail_search_subargs_to_imap(string_t *dest, const struct mail_search_arg *args,
+			    const char *prefix, const char **error_r)
+{
+	const struct mail_search_arg *arg;
+
+	str_append_c(dest, '(');
+	for (arg = args; arg != NULL; arg = arg->next) {
+		if (arg->next != NULL)
+			str_append(dest, prefix);
+		if (!mail_search_arg_to_imap(dest, arg, error_r))
+			return FALSE;
+		if (arg->next != NULL)
+			str_append_c(dest, ' ');
+	}
+	str_append_c(dest, ')');
+	return TRUE;
+}
+
+static bool
+mail_search_arg_to_imap_date(string_t *dest, const struct mail_search_arg *arg)
+{
+	time_t timestamp = arg->value.time;
+	const char *str;
+
+	if ((arg->value.search_flags &
+	     MAIL_SEARCH_ARG_FLAG_USE_TZ) == 0) {
+		struct tm *tm = localtime(&timestamp);
+		int tz_offset = utc_offset(tm, timestamp);
+		timestamp -= tz_offset * 60;
+	}
+	if (!imap_to_date(timestamp, &str))
+		return FALSE;
+	str_printfa(dest, " \"%s\"", str);
+	return TRUE;
+}
+
+bool mail_search_arg_to_imap(string_t *dest, const struct mail_search_arg *arg,
+			     const char **error_r)
+{
+	unsigned int start_pos;
+
+	if (arg->match_not)
+		str_append(dest, "NOT ");
+	start_pos = str_len(dest);
+	switch (arg->type) {
+	case SEARCH_OR:
+		if (!mail_search_subargs_to_imap(dest, arg->value.subargs,
+						 "OR ", error_r))
+			return FALSE;
+		break;
+	case SEARCH_SUB:
+		if (!mail_search_subargs_to_imap(dest, arg->value.subargs,
+						 "", error_r))
+			return FALSE;
+		break;
+	case SEARCH_ALL:
+		str_append(dest, "ALL");
+		break;
+	case SEARCH_SEQSET:
+		imap_write_seq_range(dest, &arg->value.seqset);
+		break;
+	case SEARCH_UIDSET:
+		str_append(dest, "UID ");
+		imap_write_seq_range(dest, &arg->value.seqset);
+		break;
+	case SEARCH_FLAGS:
+		i_assert((arg->value.flags & MAIL_FLAGS_MASK) != 0);
+		str_append_c(dest, '(');
+		if ((arg->value.flags & MAIL_ANSWERED) != 0)
+			str_append(dest, "ANSWERED ");
+		if ((arg->value.flags & MAIL_FLAGGED) != 0)
+			str_append(dest, "FLAGGED ");
+		if ((arg->value.flags & MAIL_DELETED) != 0)
+			str_append(dest, "DELETED ");
+		if ((arg->value.flags & MAIL_SEEN) != 0)
+			str_append(dest, "SEEN ");
+		if ((arg->value.flags & MAIL_DRAFT) != 0)
+			str_append(dest, "DRAFT ");
+		if ((arg->value.flags & MAIL_RECENT) != 0)
+			str_append(dest, "RECENT ");
+		str_truncate(dest, str_len(dest)-1);
+		str_append_c(dest, ')');
+		break;
+	case SEARCH_KEYWORDS: {
+		const struct mail_keywords *kw = arg->value.keywords;
+		const ARRAY_TYPE(keywords) *names_arr;
+		const char *const *namep;
+		unsigned int i;
+
+		if (kw == NULL) {
+			/* uninitialized */
+			str_printfa(dest, "KEYWORD %s", arg->value.str);
+			break;
+		}
+
+		names_arr = mail_index_get_keywords(kw->index);
+
+		str_append_c(dest, '(');
+		for (i = 0; i < kw->count; i++) {
+			namep = array_idx(names_arr, kw->idx[i]);
+			if (i > 0)
+				str_append_c(dest, ' ');
+			str_printfa(dest, "KEYWORD %s", *namep);
+		}
+		str_append_c(dest, ')');
+		break;
+	}
+
+	case SEARCH_BEFORE:
+		switch (arg->value.date_type) {
+		case MAIL_SEARCH_DATE_TYPE_SENT:
+			str_append(dest, "SENTBEFORE");
+			break;
+		case MAIL_SEARCH_DATE_TYPE_RECEIVED:
+			str_append(dest, "BEFORE");
+			break;
+		case MAIL_SEARCH_DATE_TYPE_SAVED:
+			str_append(dest, "X-SAVEDBEFORE");
+			break;
+		}
+		if (mail_search_arg_to_imap_date(dest, arg))
+			;
+		else if (arg->value.date_type != MAIL_SEARCH_DATE_TYPE_RECEIVED ||
+			 arg->value.time > ioloop_time) {
+			*error_r = t_strdup_printf(
+				"SEARCH_BEFORE can't be written as IMAP for timestamp %ld (type=%d, use_tz=%d)",
+				(long)arg->value.time, arg->value.date_type,
+				(arg->value.search_flags & MAIL_SEARCH_ARG_FLAG_USE_TZ) != 0);
+			return FALSE;
+		} else {
+			str_truncate(dest, start_pos);
+			str_printfa(dest, "OLDER %u",
+				    (unsigned int)(ioloop_time - arg->value.time + 1));
+		}
+		break;
+	case SEARCH_ON:
+		switch (arg->value.date_type) {
+		case MAIL_SEARCH_DATE_TYPE_SENT:
+			str_append(dest, "SENTON");
+			break;
+		case MAIL_SEARCH_DATE_TYPE_RECEIVED:
+			str_append(dest, "ON");
+			break;
+		case MAIL_SEARCH_DATE_TYPE_SAVED:
+			str_append(dest, "X-SAVEDON");
+			break;
+		}
+		if (!mail_search_arg_to_imap_date(dest, arg)) {
+			*error_r = t_strdup_printf(
+				"SEARCH_ON can't be written as IMAP for timestamp %ld (type=%d, use_tz=%d)",
+				(long)arg->value.time, arg->value.date_type,
+				(arg->value.search_flags & MAIL_SEARCH_ARG_FLAG_USE_TZ) != 0);
+			return FALSE;
+		}
+		break;
+	case SEARCH_SINCE:
+		switch (arg->value.date_type) {
+		case MAIL_SEARCH_DATE_TYPE_SENT:
+			str_append(dest, "SENTSINCE");
+			break;
+		case MAIL_SEARCH_DATE_TYPE_RECEIVED:
+			str_append(dest, "SINCE");
+			break;
+		case MAIL_SEARCH_DATE_TYPE_SAVED:
+			str_append(dest, "X-SAVEDSINCE");
+			break;
+		}
+		if (mail_search_arg_to_imap_date(dest, arg))
+			;
+		else if (arg->value.date_type != MAIL_SEARCH_DATE_TYPE_RECEIVED ||
+			 arg->value.time >= ioloop_time) {
+			*error_r = t_strdup_printf(
+				"SEARCH_SINCE can't be written as IMAP for timestamp %ld (type=%d, use_tz=%d)",
+				(long)arg->value.time, arg->value.date_type,
+				(arg->value.search_flags & MAIL_SEARCH_ARG_FLAG_USE_TZ) != 0);
+			return FALSE;
+		} else {
+			str_truncate(dest, start_pos);
+			str_printfa(dest, "YOUNGER %u",
+				    (unsigned int)(ioloop_time - arg->value.time));
+		}
+		break;
+	case SEARCH_SMALLER:
+		str_printfa(dest, "SMALLER %llu", (unsigned long long)arg->value.size);
+		break;
+	case SEARCH_LARGER:
+		str_printfa(dest, "LARGER %llu", (unsigned long long)arg->value.size);
+		break;
+	case SEARCH_HEADER:
+	case SEARCH_HEADER_ADDRESS:
+	case SEARCH_HEADER_COMPRESS_LWSP:
+		if (strcasecmp(arg->hdr_field_name, "From") == 0 ||
+		    strcasecmp(arg->hdr_field_name, "To") == 0 ||
+		    strcasecmp(arg->hdr_field_name, "Cc") == 0 ||
+		    strcasecmp(arg->hdr_field_name, "Bcc") == 0 ||
+		    strcasecmp(arg->hdr_field_name, "Subject") == 0)
+			str_append(dest, t_str_ucase(arg->hdr_field_name));
+		else {
+			str_append(dest, "HEADER ");
+			imap_append_astring(dest, arg->hdr_field_name);
+		}
+		str_append_c(dest, ' ');
+		imap_append_astring(dest, arg->value.str);
+		break;
+
+	case SEARCH_BODY:
+		str_append(dest, "BODY ");
+		imap_append_astring(dest, arg->value.str);
+		break;
+	case SEARCH_TEXT:
+		str_append(dest, "TEXT ");
+		imap_append_astring(dest, arg->value.str);
+		break;
+
+	/* extensions */
+	case SEARCH_MODSEQ: {
+		bool extended_output = FALSE;
+
+		str_append(dest, "MODSEQ ");
+		if (arg->value.str != NULL) {
+			str_printfa(dest, "/flags/%s", arg->value.str);
+			extended_output = TRUE;
+		} else if (arg->value.flags != 0) {
+			str_append(dest, "/flags/");
+			imap_write_flags(dest, arg->value.flags, NULL);
+			extended_output = TRUE;
+		}
+		if (extended_output) {
+			str_append_c(dest, ' ');
+			switch (arg->value.modseq->type) {
+			case MAIL_SEARCH_MODSEQ_TYPE_ANY:
+				str_append(dest, "all");
+				break;
+			case MAIL_SEARCH_MODSEQ_TYPE_PRIVATE:
+				str_append(dest, "priv");
+				break;
+			case MAIL_SEARCH_MODSEQ_TYPE_SHARED:
+				str_append(dest, "shared");
+				break;
+			}
+			str_append_c(dest, ' ');
+		}
+		str_printfa(dest, "%llu", (unsigned long long)arg->value.modseq->modseq);
+		break;
+	}
+	case SEARCH_INTHREAD:


More information about the dovecot-cvs mailing list