From f386bd2c452ba5133a167f4f7566a4291729c610 Mon Sep 17 00:00:00 2001 From: Josef 'Jeff' Sipek Date: Thu, 4 Jan 2018 12:44:16 -0500 Subject: [PATCH] imap: support for FETCH SNIPPET --- configure.ac | 2 +- src/imap/imap-fetch-body.c | 89 ++++++++++++++++++++++++++++++++++++++ src/imap/imap-fetch.c | 1 + src/imap/imap-fetch.h | 1 + 4 files changed, 92 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 11c4ff1456..c39e2498cd 100644 --- a/configure.ac +++ b/configure.ac @@ -2953,7 +2953,7 @@ dnl ** 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]) diff --git a/src/imap/imap-fetch-body.c b/src/imap/imap-fetch-body.c index b17e24b94b..5b8203d8df 100644 --- a/src/imap/imap-fetch-body.c +++ b/src/imap/imap-fetch-body.c @@ -587,3 +587,92 @@ bool imap_fetch_rfc822_init(struct imap_fetch_init_context *ctx) 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; +} diff --git a/src/imap/imap-fetch.c b/src/imap/imap-fetch.c index 9744f7b70b..2fda83c44b 100644 --- a/src/imap/imap-fetch.c +++ b/src/imap/imap-fetch.c @@ -997,6 +997,7 @@ imap_fetch_default_handlers[] = { { "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 }, diff --git a/src/imap/imap-fetch.h b/src/imap/imap-fetch.h index 0bd6b3a4ec..5d26b28672 100644 --- a/src/imap/imap-fetch.h +++ b/src/imap/imap-fetch.h @@ -154,6 +154,7 @@ bool imap_fetch_uid_init(struct imap_fetch_init_context *ctx); 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);