dovecot-2.0: doveadm fetch: Added "fields to fetch" parameter.

dovecot at dovecot.org dovecot at dovecot.org
Wed Apr 28 23:15:53 EEST 2010


details:   http://hg.dovecot.org/dovecot-2.0/rev/c8981561c5f2
changeset: 11206:c8981561c5f2
user:      Timo Sirainen <tss at iki.fi>
date:      Wed Apr 28 23:13:12 2010 +0300
description:
doveadm fetch: Added "fields to fetch" parameter.

diffstat:

 src/doveadm/doveadm-mail-fetch.c |  292 +++++++++++++++++++++++++++++++++++++----
 src/doveadm/doveadm-mail.c       |    2 +-
 2 files changed, 264 insertions(+), 30 deletions(-)

diffs (truncated from 373 to 300 lines):

diff -r dab4fb9f8140 -r c8981561c5f2 src/doveadm/doveadm-mail-fetch.c
--- a/src/doveadm/doveadm-mail-fetch.c	Wed Apr 28 22:26:15 2010 +0300
+++ b/src/doveadm/doveadm-mail-fetch.c	Wed Apr 28 23:13:12 2010 +0300
@@ -1,11 +1,14 @@
 /* Copyright (c) 2010 Dovecot authors, see the included COPYING file */
 
 #include "lib.h"
+#include "array.h"
 #include "istream.h"
 #include "ostream.h"
 #include "base64.h"
 #include "randgen.h"
 #include "str.h"
+#include "message-size.h"
+#include "imap-util.h"
 #include "mail-namespace.h"
 #include "mail-storage.h"
 #include "mail-search-build.h"
@@ -16,9 +19,208 @@
 struct fetch_context {
 	struct mail_search_args *search_args;
 	struct ostream *output;
+	struct mail *mail;
 
-	string_t *prefix;
-	unsigned int prefix_len;
+	ARRAY_DEFINE(fields, const struct fetch_field);
+	enum mail_fetch_field wanted_fields;
+
+	string_t *hdr;
+	const char *prefix;
+};
+
+static int fetch_mailbox(struct fetch_context *ctx)
+{
+	const char *value;
+
+	if (mail_get_special(ctx->mail, MAIL_FETCH_MAILBOX_NAME, &value) < 0)
+		return -1;
+	str_append(ctx->hdr, value);
+	return 0;
+}
+
+static int fetch_seq(struct fetch_context *ctx)
+{
+	str_printfa(ctx->hdr, "%u", ctx->mail->seq);
+	return 0;
+}
+
+static int fetch_uid(struct fetch_context *ctx)
+{
+	str_printfa(ctx->hdr, "%u", ctx->mail->seq);
+	return 0;
+}
+
+static int fetch_guid(struct fetch_context *ctx)
+{
+	const char *value;
+
+	if (mail_get_special(ctx->mail, MAIL_FETCH_GUID, &value) < 0)
+		return -1;
+	str_append(ctx->hdr, value);
+	return 0;
+}
+
+static int fetch_flags(struct fetch_context *ctx)
+{
+	imap_write_flags(ctx->hdr, mail_get_flags(ctx->mail),
+			 mail_get_keywords(ctx->mail));
+	return 0;
+}
+
+static void flush_hdr(struct fetch_context *ctx)
+{
+	o_stream_send(ctx->output, str_data(ctx->hdr), str_len(ctx->hdr));
+	str_truncate(ctx->hdr, 0);
+}
+
+static int fetch_hdr(struct fetch_context *ctx)
+{
+	struct istream *input;
+	struct message_size hdr_size;
+	int ret = 0;
+
+	if (mail_get_stream(ctx->mail, &hdr_size, NULL, &input) < 0)
+		return -1;
+
+	str_append_c(ctx->hdr, '\n');
+	flush_hdr(ctx);
+	input = i_stream_create_limit(input, hdr_size.physical_size);
+	while (!i_stream_is_eof(input)) {
+		if (o_stream_send_istream(ctx->output, input) <= 0)
+			i_fatal("write(stdout) failed: %m");
+	}
+	if (input->stream_errno != 0) {
+		i_error("read() failed: %m");
+		ret = -1;
+	}
+	i_stream_unref(&input);
+	o_stream_flush(ctx->output);
+	return ret;
+}
+
+static int fetch_body(struct fetch_context *ctx)
+{
+	struct istream *input;
+	struct message_size hdr_size;
+	int ret = 0;
+
+	if (mail_get_stream(ctx->mail, &hdr_size, NULL, &input) < 0)
+		return -1;
+
+	str_append_c(ctx->hdr, '\n');
+	flush_hdr(ctx);
+	i_stream_skip(input, hdr_size.physical_size);
+	while (!i_stream_is_eof(input)) {
+		if (o_stream_send_istream(ctx->output, input) <= 0)
+			i_fatal("write(stdout) failed: %m");
+	}
+	if (input->stream_errno != 0) {
+		i_error("read() failed: %m");
+		ret = -1;
+	}
+	o_stream_flush(ctx->output);
+	return ret;
+}
+
+static int fetch_text(struct fetch_context *ctx)
+{
+	struct istream *input;
+	int ret = 0;
+
+	if (mail_get_stream(ctx->mail, NULL, NULL, &input) < 0)
+		return -1;
+
+	str_append_c(ctx->hdr, '\n');
+	flush_hdr(ctx);
+	while (!i_stream_is_eof(input)) {
+		if (o_stream_send_istream(ctx->output, input) <= 0)
+			i_fatal("write(stdout) failed: %m");
+	}
+	if (input->stream_errno != 0) {
+		i_error("read() failed: %m");
+		ret = -1;
+	}
+	o_stream_flush(ctx->output);
+	return ret;
+}
+
+static int fetch_size_physical(struct fetch_context *ctx)
+{
+	uoff_t size;
+
+	if (mail_get_physical_size(ctx->mail, &size) < 0)
+		return -1;
+	str_printfa(ctx->hdr, "%"PRIuUOFF_T, size);
+	return 0;
+}
+
+static int fetch_size_virtual(struct fetch_context *ctx)
+{
+	uoff_t size;
+
+	if (mail_get_virtual_size(ctx->mail, &size) < 0)
+		return -1;
+	str_printfa(ctx->hdr, "%"PRIuUOFF_T, size);
+	return 0;
+}
+
+static int fetch_date_received(struct fetch_context *ctx)
+{
+	time_t t;
+
+	if (mail_get_received_date(ctx->mail, &t) < 0)
+		return -1;
+	str_printfa(ctx->hdr, "%s", unixdate2str(t));
+	return 0;
+}
+
+static int fetch_date_sent(struct fetch_context *ctx)
+{
+	time_t t;
+	int tz;
+	char chr;
+
+	if (mail_get_date(ctx->mail, &t, &tz) < 0)
+		return -1;
+
+	chr = tz < 0 ? '-' : '+';
+	if (tz < 0) tz = -tz;
+	str_printfa(ctx->hdr, "%s (%c%02u%02u)", unixdate2str(t),
+		    chr, tz/60, tz%60);
+	return 0;
+}
+
+static int fetch_date_saved(struct fetch_context *ctx)
+{
+	time_t t;
+
+	if (mail_get_save_date(ctx->mail, &t) < 0)
+		return -1;
+	str_printfa(ctx->hdr, "%s", unixdate2str(t));
+	return 0;
+}
+
+struct fetch_field {
+	const char *name;
+	enum mail_fetch_field wanted_fields;
+	int (*print)(struct fetch_context *ctx);
+};
+
+static const struct fetch_field fetch_fields[] = {
+	{ "mailbox",       0,                        fetch_mailbox },
+	{ "seq",           0,                        fetch_seq },
+	{ "uid",           0,                        fetch_uid },
+	{ "guid",          0,                        fetch_guid },
+	{ "flags",         MAIL_FETCH_FLAGS,         fetch_flags },
+	{ "hdr",           MAIL_FETCH_STREAM_HEADER, fetch_hdr },
+	{ "body",          MAIL_FETCH_STREAM_BODY,   fetch_body },
+	{ "text",          MAIL_FETCH_STREAM_HEADER |
+	                   MAIL_FETCH_STREAM_BODY,   fetch_text },
+	{ "size.physical", MAIL_FETCH_PHYSICAL_SIZE, fetch_size_physical },
+	{ "size.virtual",  MAIL_FETCH_VIRTUAL_SIZE,  fetch_size_virtual },
+	{ "date.received", MAIL_FETCH_RECEIVED_DATE, fetch_date_received },
+	{ "date.sent",     MAIL_FETCH_DATE,          fetch_date_sent },
+	{ "date.saved",    MAIL_FETCH_SAVE_DATE,     fetch_date_saved }
 };
 
 static struct mail_search_args *build_search_args(const char *const args[])
@@ -35,6 +237,36 @@
 	return sargs;
 }
 
+static const struct fetch_field *fetch_field_find(const char *name)
+{
+	unsigned int i;
+
+	for (i = 0; i < N_ELEMENTS(fetch_fields); i++) {
+		if (strcmp(fetch_fields[i].name, name) == 0)
+			return &fetch_fields[i];
+	}
+	return NULL;
+}
+
+static void parse_fetch_fields(struct fetch_context *ctx, const char *str)
+{
+	const char *const *fields, *name;
+	const struct fetch_field *field;
+
+	t_array_init(&ctx->fields, 32);
+	fields = t_strsplit_spaces(str, " ");
+	for (; *fields != NULL; fields++) {
+		name = t_str_lcase(*fields);
+
+		field = fetch_field_find(name);
+		if (field == NULL)
+			i_fatal("Unknown fetch field: %s", name);
+		ctx->wanted_fields |= field->wanted_fields;
+
+		array_append(&ctx->fields, field, 1);
+	}
+}
+
 static void
 cmd_fetch_box(struct fetch_context *ctx, struct mailbox *box)
 {
@@ -42,7 +274,7 @@
 	struct mailbox_transaction_context *t;
 	struct mail_search_context *search_ctx;
 	struct mail *mail;
-	struct istream *input;
+	const struct fetch_field *field;
 
 	if (mailbox_sync(box, MAILBOX_SYNC_FLAG_FULL_READ) < 0) {
 		i_error("Syncing mailbox %s failed: %s", mailbox_get_vname(box),
@@ -53,25 +285,24 @@
 	mail_search_args_init(ctx->search_args, box, FALSE, NULL);
 	t = mailbox_transaction_begin(box, 0);
 	search_ctx = mailbox_search_init(t, ctx->search_args, NULL);
-	mail = mail_alloc(t, 0, NULL);
+	mail = mail_alloc(t, ctx->wanted_fields, NULL);
 	while (mailbox_search_next(search_ctx, mail)) {
-		if (mail_get_stream(mail, NULL, NULL, &input) < 0) {
-			i_error("Couldn't open mail uid=%u: %s", mail->uid,
-				mail_storage_get_last_error(storage, NULL));
-			continue;
+		str_truncate(ctx->hdr, 0);
+		str_append(ctx->hdr, ctx->prefix);
+
+		ctx->mail = mail;
+		array_foreach(&ctx->fields, field) {
+			str_printfa(ctx->hdr, "%s: ", field->name);
+			if (field->print(ctx) < 0) {
+				i_error("fetch(%s) failed for box=%s uid=%u: %s",
+					field->name, mailbox_get_vname(box),
+					mail->uid, mail_storage_get_last_error(storage, NULL));
+			}
+			str_append_c(ctx->hdr, '\n');
 		}
+		flush_hdr(ctx);


More information about the dovecot-cvs mailing list