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