dovecot-2.2: IMAP BINARY extension supports now FETCH BINARY com...
dovecot at dovecot.org
dovecot at dovecot.org
Sat Aug 11 05:31:53 EEST 2012
details: http://hg.dovecot.org/dovecot-2.2/rev/f3ef88e19cd5
changeset: 14859:f3ef88e19cd5
user: Timo Sirainen <tss at iki.fi>
date: Sat Aug 11 05:31:46 2012 +0300
description:
IMAP BINARY extension supports now FETCH BINARY command.
diffstat:
src/doveadm/doveadm-mail.c | 1 +
src/imap/cmd-fetch.c | 18 +-
src/imap/imap-commands-util.c | 2 +
src/imap/imap-fetch-body.c | 108 ++++++++-
src/imap/imap-fetch.c | 1 +
src/imap/imap-fetch.h | 1 +
src/lib-imap-storage/imap-msgpart.c | 197 ++++++++++++---
src/lib-imap-storage/imap-msgpart.h | 14 +
src/lib-storage/fail-mail.c | 12 +
src/lib-storage/index/Makefile.am | 1 +
src/lib-storage/index/cydir/cydir-mail.c | 1 +
src/lib-storage/index/dbox-multi/mdbox-mail.c | 1 +
src/lib-storage/index/dbox-single/sdbox-mail.c | 1 +
src/lib-storage/index/imapc/imapc-mail.c | 1 +
src/lib-storage/index/index-mail-binary.c | 313 +++++++++++++++++++++++++
src/lib-storage/index/index-mail.h | 4 +
src/lib-storage/index/maildir/maildir-mail.c | 1 +
src/lib-storage/index/mbox/mbox-mail.c | 1 +
src/lib-storage/index/pop3c/pop3c-mail.c | 1 +
src/lib-storage/index/raw/raw-mail.c | 1 +
src/lib-storage/mail-error.h | 5 +-
src/lib-storage/mail-storage-private.h | 18 +
src/lib-storage/mail-storage.c | 12 +
src/lib-storage/mail-storage.h | 12 +
src/lib-storage/mail-user.c | 1 +
src/lib-storage/mail.c | 24 +
src/plugins/virtual/virtual-mail.c | 1 +
27 files changed, 701 insertions(+), 52 deletions(-)
diffs (truncated from 1199 to 300 lines):
diff -r ae5ad2935674 -r f3ef88e19cd5 src/doveadm/doveadm-mail.c
--- a/src/doveadm/doveadm-mail.c Sat Aug 11 05:29:05 2012 +0300
+++ b/src/doveadm/doveadm-mail.c Sat Aug 11 05:31:46 2012 +0300
@@ -46,6 +46,7 @@
break;
case MAIL_ERROR_NOTPOSSIBLE:
case MAIL_ERROR_EXISTS:
+ case MAIL_ERROR_CONVERSION:
exit_code = DOVEADM_EX_NOTPOSSIBLE;
break;
case MAIL_ERROR_PARAMS:
diff -r ae5ad2935674 -r f3ef88e19cd5 src/imap/cmd-fetch.c
--- a/src/imap/cmd-fetch.c Sat Aug 11 05:29:05 2012 +0300
+++ b/src/imap/cmd-fetch.c Sat Aug 11 05:31:46 2012 +0300
@@ -143,6 +143,7 @@
{
static const char *ok_message = "OK Fetch completed.";
const char *tagged_reply = ok_message;
+ enum mail_error error;
if (ctx->skipped_expunged_msgs) {
tagged_reply = "OK ["IMAP_RESP_CODE_EXPUNGEISSUED"] "
@@ -160,12 +161,17 @@
return TRUE;
}
- errstr = mailbox_get_last_error(cmd->client->mailbox, NULL);
-
- /* We never want to reply NO to FETCH requests,
- BYE is preferrable (see imap-ml for reasons). */
- client_disconnect_with_error(cmd->client, errstr);
- return TRUE;
+ errstr = mailbox_get_last_error(cmd->client->mailbox, &error);
+ if (error == MAIL_ERROR_CONVERSION) {
+ /* BINARY found unsupported Content-Transfer-Encoding */
+ tagged_reply = "NO ["IMAP_RESP_CODE_UNKNOWN_CTE"] "
+ "Unknown Content-Transfer-Encoding.";
+ } else {
+ /* We never want to reply NO to FETCH requests,
+ BYE is preferrable (see imap-ml for reasons). */
+ client_disconnect_with_error(cmd->client, errstr);
+ return TRUE;
+ }
}
return cmd_sync(cmd,
diff -r ae5ad2935674 -r f3ef88e19cd5 src/imap/imap-commands-util.c
--- a/src/imap/imap-commands-util.c Sat Aug 11 05:29:05 2012 +0300
+++ b/src/imap/imap-commands-util.c Sat Aug 11 05:31:46 2012 +0300
@@ -134,6 +134,8 @@
case MAIL_ERROR_INUSE:
resp_code = IMAP_RESP_CODE_INUSE;
break;
+ case MAIL_ERROR_CONVERSION:
+ break;
}
if (resp_code == NULL || *error_string == '[')
return t_strconcat("NO ", error_string, NULL);
diff -r ae5ad2935674 -r f3ef88e19cd5 src/imap/imap-fetch-body.c
--- a/src/imap/imap-fetch-body.c Sat Aug 11 05:29:05 2012 +0300
+++ b/src/imap/imap-fetch-body.c Sat Aug 11 05:31:46 2012 +0300
@@ -24,6 +24,8 @@
struct imap_msgpart *msgpart;
unsigned int partial:1;
+ unsigned int binary:1;
+ unsigned int binary_size:1;
};
static void fetch_read_error(struct imap_fetch_context *ctx)
@@ -40,7 +42,13 @@
string_t *str;
str = t_str_new(128);
- str_printfa(str, "BODY[%s]", body->section);
+ if (body->binary_size)
+ str_append(str, "BINARY.SIZE");
+ else if (body->binary)
+ str_append(str, "BINARY");
+ else
+ str_append(str, "BODY");
+ str_printfa(str, "[%s]", body->section);
if (body->partial) {
str_printfa(str, "<%"PRIuUOFF_T">",
imap_msgpart_get_partial_offset(body->msgpart));
@@ -130,6 +138,27 @@
return ctx->cont_handler(ctx);
}
+static int fetch_binary_size(struct imap_fetch_context *ctx, struct mail *mail,
+ const struct imap_fetch_body_data *body)
+{
+ string_t *str;
+ size_t size;
+
+ if (imap_msgpart_size(mail, body->msgpart, &size) < 0)
+ return -1;
+
+ str = t_str_new(128);
+ if (ctx->first)
+ ctx->first = FALSE;
+ else
+ str_append_c(str, ' ');
+ str_printfa(str, "%s %"PRIuUOFF_T, get_body_name(body), size);
+
+ if (o_stream_send(ctx->client->output, str_data(str), str_len(str)) < 0)
+ return -1;
+ return 1;
+}
+
/* Parse next digits in string into integer. Returns -1 if the integer
becomes too big and wraps. */
static int read_uoff_t(const char **p, uoff_t *value)
@@ -294,6 +323,83 @@
return TRUE;
}
+bool imap_fetch_binary_init(struct imap_fetch_init_context *ctx)
+{
+ struct imap_fetch_body_data *body;
+ const struct imap_arg *list_args;
+ unsigned int list_count;
+ const char *str, *p, *error;
+
+ i_assert(strncmp(ctx->name, "BINARY", 6) == 0);
+ p = ctx->name + 6;
+
+ body = p_new(ctx->fetch_ctx->pool, struct imap_fetch_body_data, 1);
+ body->binary = TRUE;
+
+ if (strncmp(p, ".SIZE", 5) == 0) {
+ /* fetch decoded size of the section */
+ p += 5;
+ body->binary_size = TRUE;
+ } else if (strncmp(p, ".PEEK", 5) == 0) {
+ p += 5;
+ } else {
+ ctx->fetch_ctx->flags_update_seen = TRUE;
+ }
+ if (*p != '[') {
+ ctx->error = "Invalid BINARY[..] parameter: Missing '['";
+ return FALSE;
+ }
+
+ if (imap_arg_get_list_full(&ctx->args[0], &list_args, &list_count)) {
+ /* BINARY[HEADER.FIELDS.. (headers list)] */
+ if (!imap_arg_get_atom(&ctx->args[1], &str) ||
+ str[0] != ']') {
+ ctx->error = "Invalid BINARY[..] parameter: Missing ']'";
+ return FALSE;
+ }
+ if (body_header_fields_parse(ctx, body, p+1,
+ list_args, list_count) < 0)
+ return FALSE;
+ p = str+1;
+ ctx->args += 2;
+ } else {
+ /* no headers list */
+ body->section = p+1;
+ p = strchr(body->section, ']');
+ if (p == NULL) {
+ ctx->error = "Invalid BINARY[..] parameter: Missing ']'";
+ return FALSE;
+ }
+ body->section = p_strdup_until(ctx->fetch_ctx->pool,
+ body->section, p);
+ p++;
+ }
+ if (imap_msgpart_parse(ctx->fetch_ctx->box, body->section,
+ &body->msgpart) < 0) {
+ ctx->error = "Invalid BINARY[..] section";
+ return -1;
+ }
+ imap_msgpart_set_decode_to_binary(body->msgpart);
+ ctx->fetch_ctx->fetch_data |=
+ imap_msgpart_get_fetch_data(body->msgpart);
+
+ if (!body->binary_size) {
+ if (body_parse_partial(body, p, &error) < 0) {
+ ctx->error = p_strdup_printf(ctx->fetch_ctx->pool,
+ "Invalid BINARY[..] parameter: %s", error);
+ return FALSE;
+ }
+ }
+
+ /* update the section name for the imap_fetch_add_handler() */
+ ctx->name = p_strdup(ctx->fetch_ctx->pool, get_body_name(body));
+ if (body->binary_size)
+ imap_fetch_add_handler(ctx, 0, "NIL", fetch_binary_size, body);
+ else
+ imap_fetch_add_handler(ctx, 0, "NIL", fetch_body_msgpart, body);
+ return TRUE;
+}
+
static int ATTR_NULL(3)
fetch_rfc822_size(struct imap_fetch_context *ctx, struct mail *mail,
void *context ATTR_UNUSED)
diff -r ae5ad2935674 -r f3ef88e19cd5 src/imap/imap-fetch.c
--- a/src/imap/imap-fetch.c Sat Aug 11 05:29:05 2012 +0300
+++ b/src/imap/imap-fetch.c Sat Aug 11 05:31:46 2012 +0300
@@ -860,6 +860,7 @@
static const struct imap_fetch_handler
imap_fetch_default_handlers[] = {
+ { "BINARY", imap_fetch_binary_init },
{ "BODY", fetch_body_init },
{ "BODYSTRUCTURE", fetch_bodystructure_init },
{ "ENVELOPE", fetch_envelope_init },
diff -r ae5ad2935674 -r f3ef88e19cd5 src/imap/imap-fetch.h
--- a/src/imap/imap-fetch.h Sat Aug 11 05:29:05 2012 +0300
+++ b/src/imap/imap-fetch.h Sat Aug 11 05:31:46 2012 +0300
@@ -125,6 +125,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);
void imap_fetch_handlers_init(void);
void imap_fetch_handlers_deinit(void);
diff -r ae5ad2935674 -r f3ef88e19cd5 src/lib-imap-storage/imap-msgpart.c
--- a/src/lib-imap-storage/imap-msgpart.c Sat Aug 11 05:29:05 2012 +0300
+++ b/src/lib-imap-storage/imap-msgpart.c Sat Aug 11 05:31:46 2012 +0300
@@ -5,8 +5,12 @@
#include "istream.h"
#include "istream-crlf.h"
#include "istream-nonuls.h"
+#include "istream-base64.h"
#include "istream-header-filter.h"
+#include "istream-qp.h"
+#include "ostream.h"
#include "message-parser.h"
+#include "message-decoder.h"
#include "mail-storage-private.h"
#include "mail-namespace.h"
#include "imap-parser.h"
@@ -37,6 +41,8 @@
/* which part of the message part to fetch (default: 0..(uoff_t)-1) */
uoff_t partial_offset, partial_size;
+
+ unsigned int decode_cte_to_binary:1;
};
struct imap_msgpart_open_ctx {
@@ -293,6 +299,11 @@
pool_unref(&msgpart->pool);
}
+void imap_msgpart_set_decode_to_binary(struct imap_msgpart *msgpart)
+{
+ msgpart->decode_cte_to_binary = TRUE;
+}
+
void imap_msgpart_set_partial(struct imap_msgpart *msgpart,
uoff_t offset, uoff_t size)
{
@@ -394,7 +405,7 @@
const struct imap_msgpart *msgpart)
{
struct mail_msgpart_partial_cache *cache = &mail->box->partial_cache;
- struct istream *nul_input, *crlf_input;
+ struct istream *crlf_input;
const unsigned char *data;
size_t size;
uoff_t physical_start = input->v_offset;
@@ -415,11 +426,6 @@
message parts. */
skip_using_parts(mail, input, &virtual_skip);
}
- if (!mail->has_no_nuls) {
- nul_input = i_stream_create_nonuls(input, 0x80);
- i_stream_unref(&input);
- input = nul_input;
- }
crlf_input = i_stream_create_crlf(input);
i_stream_unref(&input);
input = crlf_input;
@@ -445,6 +451,7 @@
static void
imap_msgpart_get_partial(struct mail *mail, const struct imap_msgpart *msgpart,
+ bool convert_nuls, bool use_partial_cache,
const struct message_size *part_size,
struct imap_msgpart_open_result *result)
{
@@ -468,6 +475,7 @@
} else {
/* input has LF linefeeds. it can be slow to seek to wanted
position, so try to do caching whenever possible */
+ i_assert(use_partial_cache);
result->input = imap_msgpart_crlf_seek(mail, result->input,
msgpart);
}
@@ -480,49 +488,73 @@
/* send all bytes */
result->size = bytes_left;
}
+
+ if (!mail->has_no_nuls && convert_nuls) {
+ /* IMAP literals must not contain NULs. change them to
More information about the dovecot-cvs
mailing list