changeset 22768:15f548f4d144

imap: support for FETCH SNIPPET
author Josef 'Jeff' Sipek <jeff.sipek@dovecot.fi>
date Thu, 04 Jan 2018 12:44:16 -0500
parents 90e946ef71f8
children e6a9ff4a07d5
files configure.ac src/imap/imap-fetch-body.c src/imap/imap-fetch.c src/imap/imap-fetch.h
diffstat 4 files changed, 92 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/configure.ac	Tue Nov 21 13:27:18 2017 +0200
+++ b/configure.ac	Thu Jan 04 12:44:16 2018 -0500
@@ -2953,7 +2953,7 @@
 dnl IDLE doesn't really belong to banner. It's there just to make Blackberries
 dnl happy, because otherwise BIS server disables push email.
 capability_banner="IMAP4rev1 LITERAL+ SASL-IR LOGIN-REFERRALS ID ENABLE IDLE"
-capability="$capability_banner SORT SORT=DISPLAY THREAD=REFERENCES THREAD=REFS THREAD=ORDEREDSUBJECT MULTIAPPEND URL-PARTIAL CATENATE UNSELECT CHILDREN NAMESPACE UIDPLUS LIST-EXTENDED I18NLEVEL=1 CONDSTORE QRESYNC ESEARCH ESORT SEARCHRES WITHIN CONTEXT=SEARCH LIST-STATUS BINARY MOVE"
+capability="$capability_banner SORT SORT=DISPLAY THREAD=REFERENCES THREAD=REFS THREAD=ORDEREDSUBJECT MULTIAPPEND URL-PARTIAL CATENATE UNSELECT CHILDREN NAMESPACE UIDPLUS LIST-EXTENDED I18NLEVEL=1 CONDSTORE QRESYNC ESEARCH ESORT SEARCHRES WITHIN CONTEXT=SEARCH LIST-STATUS BINARY MOVE SNIPPET=FUZZY"
 AC_DEFINE_UNQUOTED(CAPABILITY_STRING, "$capability", [IMAP capabilities])
 AC_DEFINE_UNQUOTED(CAPABILITY_BANNER_STRING, "$capability_banner", [IMAP capabilities advertised in banner])
 
--- a/src/imap/imap-fetch-body.c	Tue Nov 21 13:27:18 2017 +0200
+++ b/src/imap/imap-fetch-body.c	Thu Jan 04 12:44:16 2018 -0500
@@ -587,3 +587,92 @@
 	ctx->error = t_strconcat("Unknown parameter ", name, NULL);
 	return FALSE;
 }
+
+static int ATTR_NULL(3)
+fetch_snippet(struct imap_fetch_context *ctx, struct mail *mail,
+	      void *context)
+{
+	const bool lazy = context != NULL;
+	enum mail_lookup_abort temp_lookup_abort = lazy ? MAIL_LOOKUP_ABORT_NOT_IN_CACHE : mail->lookup_abort;
+	enum mail_lookup_abort orig_lookup_abort = mail->lookup_abort;
+	const char *snippet;
+	const char *str;
+	int ret;
+
+	mail->lookup_abort = temp_lookup_abort;
+	ret = mail_get_special(mail, MAIL_FETCH_BODY_SNIPPET, &snippet);
+	mail->lookup_abort = orig_lookup_abort;
+
+	if (ret == 0) {
+		/* got it => nothing to do */
+		snippet++; /* skip over snippet version byte */
+	} else if (mailbox_get_last_mail_error(mail->box) != MAIL_ERROR_LOOKUP_ABORTED) {
+		/* actual error => bail */
+		return -1;
+	} else if (lazy) {
+		/* not in cache && lazy => give up */
+		return 1;
+	} else {
+		/*
+		 * not in cache && !lazy => someone higher up set
+		 * MAIL_LOOKUP_ABORT_NOT_IN_CACHE and so even though we got
+		 * a non-lazy request we failed the cache lookup.
+		 *
+		 * This is not an error, but since the scenario is
+		 * sufficiently convoluted this else branch serves to
+		 * document it.
+		 */
+		return 1;
+	}
+
+	str = t_strdup_printf(" SNIPPET FUZZY {%"PRIuSIZE_T"}\r\n", strlen(snippet));
+	if (ctx->state.cur_first) {
+		str++;
+		ctx->state.cur_first = FALSE;
+	}
+	o_stream_nsend_str(ctx->client->output, str);
+	o_stream_nsend_str(ctx->client->output, snippet);
+
+	return 1;
+}
+
+bool imap_fetch_snippet_init(struct imap_fetch_init_context *ctx)
+{
+	const struct imap_arg *list_args;
+	unsigned int list_count;
+	bool lazy;
+
+	lazy = FALSE;
+
+	if (imap_arg_get_list_full(&ctx->args[0], &list_args, &list_count)) {
+		unsigned int i;
+
+		for (i = 0; i < list_count; i++) {
+			const char *str;
+
+			if (!imap_arg_get_atom(&list_args[i], &str)) {
+				ctx->error = "Invalid SNIPPET algorithm/modifier";
+				return FALSE;
+			}
+
+			if (strcasecmp(str, "LAZY") == 0 ||
+			    strcasecmp(str, "LAZY=FUZZY") == 0) {
+				lazy = TRUE;
+			} else if (strcasecmp(str, "FUZZY") == 0) {
+				/* nothing to do */
+			} else {
+				ctx->error = t_strdup_printf("'%s' is not a "
+							     "supported SNIPPET algorithm/modifier",
+							     str);
+				return FALSE;
+			}
+		}
+
+		ctx->args += list_count;
+	}
+
+	ctx->fetch_ctx->fetch_data |= MAIL_FETCH_BODY_SNIPPET;
+	ctx->fetch_ctx->flags_update_seen = TRUE;
+	imap_fetch_add_handler(ctx, 0, "NIL", fetch_snippet, (void *) lazy);
+	return TRUE;
+}
--- a/src/imap/imap-fetch.c	Tue Nov 21 13:27:18 2017 +0200
+++ b/src/imap/imap-fetch.c	Thu Jan 04 12:44:16 2018 -0500
@@ -997,6 +997,7 @@
 	{ "INTERNALDATE", fetch_internaldate_init },
 	{ "MODSEQ", imap_fetch_modseq_init },
 	{ "RFC822", imap_fetch_rfc822_init },
+	{ "SNIPPET", imap_fetch_snippet_init },
 	{ "UID", imap_fetch_uid_init },
 	{ "X-GUID", fetch_guid_init },
 	{ "X-MAILBOX", fetch_x_mailbox_init },
--- a/src/imap/imap-fetch.h	Tue Nov 21 13:27:18 2017 +0200
+++ b/src/imap/imap-fetch.h	Thu Jan 04 12:44:16 2018 -0500
@@ -154,6 +154,7 @@
 bool imap_fetch_body_section_init(struct imap_fetch_init_context *ctx);
 bool imap_fetch_rfc822_init(struct imap_fetch_init_context *ctx);
 bool imap_fetch_binary_init(struct imap_fetch_init_context *ctx);
+bool imap_fetch_snippet_init(struct imap_fetch_init_context *ctx);
 
 void imap_fetch_handlers_init(void);
 void imap_fetch_handlers_deinit(void);