bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2010-2018 Dovecot authors, see the included COPYING file */
2d7da70c0e6768afeb1200c95f3e1293f2e502c6Timo Sirainen /* if print() returns -1, log this error if non-NULL. otherwise log
2d7da70c0e6768afeb1200c95f3e1293f2e502c6Timo Sirainen the storage error. */
1631885636d15abaf0375304a17928c8c23782cdTimo Sirainenstatic int fetch_user(struct fetch_cmd_context *ctx)
c154a05c76d4d83de1cdf9746ce4e2da0869705dTimo Sirainen doveadm_print(ctx->ctx.cur_mail_user->username);
cf63dc8723b971cc80638fccbf494d961cbafc7fTimo Sirainenstatic int fetch_mailbox(struct fetch_cmd_context *ctx)
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen if (mail_get_special(ctx->mail, MAIL_FETCH_MAILBOX_NAME, &value) < 0)
cf63dc8723b971cc80638fccbf494d961cbafc7fTimo Sirainenstatic int fetch_mailbox_guid(struct fetch_cmd_context *ctx)
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen if (mailbox_get_metadata(ctx->mail->box, MAILBOX_METADATA_GUID,
de62ce819d59a529530da4b57be1b8d6dad13d6bTimo Sirainen doveadm_print(guid_128_to_string(metadata.guid));
cf63dc8723b971cc80638fccbf494d961cbafc7fTimo Sirainenstatic int fetch_seq(struct fetch_cmd_context *ctx)
cf63dc8723b971cc80638fccbf494d961cbafc7fTimo Sirainenstatic int fetch_uid(struct fetch_cmd_context *ctx)
cf63dc8723b971cc80638fccbf494d961cbafc7fTimo Sirainenstatic int fetch_guid(struct fetch_cmd_context *ctx)
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen if (mail_get_special(ctx->mail, MAIL_FETCH_GUID, &value) < 0)
cf63dc8723b971cc80638fccbf494d961cbafc7fTimo Sirainenstatic int fetch_flags(struct fetch_cmd_context *ctx)
c154a05c76d4d83de1cdf9746ce4e2da0869705dTimo Sirainen imap_write_flags(str, mail_get_flags(ctx->mail),
5e46f82843a13cc590900352d34c899cd5967de0Timo Sirainenstatic int fetch_modseq(struct fetch_cmd_context *ctx)
5e46f82843a13cc590900352d34c899cd5967de0Timo Sirainen doveadm_print_num(mail_get_modseq(ctx->mail));
2d7da70c0e6768afeb1200c95f3e1293f2e502c6Timo Sirainenfetch_set_istream_error(struct fetch_cmd_context *ctx, struct istream *input)
2d7da70c0e6768afeb1200c95f3e1293f2e502c6Timo Sirainen ctx->print_error = t_strdup_printf("read(%s) failed: %s",
2d7da70c0e6768afeb1200c95f3e1293f2e502c6Timo Sirainen i_stream_get_name(input), i_stream_get_error(input));
cf63dc8723b971cc80638fccbf494d961cbafc7fTimo Sirainenstatic int fetch_hdr(struct fetch_cmd_context *ctx)
6df0ab0c1ab91f06b6418cb30eff44405a1b8f02Timo Sirainen if (mail_get_hdr_stream(ctx->mail, &hdr_size, &input) < 0)
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen input = i_stream_create_limit(input, hdr_size.physical_size);
d38ca817bdcec666a3b91efb917064ab844c36a2Timo Sirainenstatic int fetch_hdr_field(struct fetch_cmd_context *ctx)
cf1c3e6833fc5031d89db48dad46ed025beda4e7Timo Sirainen const char *const *value, *filter, *name = ctx->cur_field->name;
b5ad250aeacc094b84cce08eeab227d0ec14fb14Timo Sirainen if (filter != NULL && strcmp(filter, "utf8") == 0) {
b5ad250aeacc094b84cce08eeab227d0ec14fb14Timo Sirainen if (mail_get_headers_utf8(ctx->mail, name, &value) < 0)
b5ad250aeacc094b84cce08eeab227d0ec14fb14Timo Sirainen if (mail_get_headers(ctx->mail, name, &value) < 0)
b5ad250aeacc094b84cce08eeab227d0ec14fb14Timo Sirainen if (filter == NULL || strcmp(filter, "utf8") == 0) {
cf1c3e6833fc5031d89db48dad46ed025beda4e7Timo Sirainen /* print the header as-is */
cf1c3e6833fc5031d89db48dad46ed025beda4e7Timo Sirainen addr = message_address_parse(pool_datastack_create(),
f24b245f49b030d7dba3bcb2463cbc05b98c9d1dTimo Sirainenstatic int fetch_body_field(struct fetch_cmd_context *ctx)
f24b245f49b030d7dba3bcb2463cbc05b98c9d1dTimo Sirainen i_unreached(); /* we already verified this was ok */
f24b245f49b030d7dba3bcb2463cbc05b98c9d1dTimo Sirainen if (imap_msgpart_open(ctx->mail, msgpart, &result) < 0) {
d9a7e950a9cd21f2b4a90ec7759fca9e8fcc7995Timo Sirainen if ((ret = doveadm_print_istream(result.input)) < 0)
cf63dc8723b971cc80638fccbf494d961cbafc7fTimo Sirainenstatic int fetch_body(struct fetch_cmd_context *ctx)
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen if (mail_get_stream(ctx->mail, &hdr_size, NULL, &input) < 0)
ed897f9e09ae8ad86a88955420bd275b46ee8231Timo Sirainenstatic int fetch_body_snippet(struct fetch_cmd_context *ctx)
ed897f9e09ae8ad86a88955420bd275b46ee8231Timo Sirainen if (mail_get_special(ctx->mail, MAIL_FETCH_BODY_SNIPPET, &value) < 0)
ed897f9e09ae8ad86a88955420bd275b46ee8231Timo Sirainen /* [0] contains the snippet algorithm, skip over it */
cf63dc8723b971cc80638fccbf494d961cbafc7fTimo Sirainenstatic int fetch_text(struct fetch_cmd_context *ctx)
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen if (mail_get_stream(ctx->mail, NULL, NULL, &input) < 0)
46d283ef537885386ab3fc72d1831054ea5f986bTimo Sirainenstatic int fetch_text_utf8(struct fetch_cmd_context *ctx)
46d283ef537885386ab3fc72d1831054ea5f986bTimo Sirainen if (mail_get_stream(ctx->mail, NULL, NULL, &input) < 0)
46d283ef537885386ab3fc72d1831054ea5f986bTimo Sirainen parser = message_parser_init(pool_datastack_create(), input,
46d283ef537885386ab3fc72d1831054ea5f986bTimo Sirainen while ((ret = message_parser_parse_next_block(parser, &raw_block)) > 0) {
46d283ef537885386ab3fc72d1831054ea5f986bTimo Sirainen if (!message_decoder_decode_next_block(decoder, &raw_block,
9f7a3d6bbc4601e293656295f2aa44dc67e1cb16Timo Sirainen i_error("read(%s) failed: %s", i_stream_get_name(input),
cf63dc8723b971cc80638fccbf494d961cbafc7fTimo Sirainenstatic int fetch_size_physical(struct fetch_cmd_context *ctx)
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen if (mail_get_physical_size(ctx->mail, &size) < 0)
cf63dc8723b971cc80638fccbf494d961cbafc7fTimo Sirainenstatic int fetch_size_virtual(struct fetch_cmd_context *ctx)
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen if (mail_get_virtual_size(ctx->mail, &size) < 0)
cf63dc8723b971cc80638fccbf494d961cbafc7fTimo Sirainenstatic int fetch_date_received(struct fetch_cmd_context *ctx)
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen if (mail_get_received_date(ctx->mail, &t) < 0)
cf63dc8723b971cc80638fccbf494d961cbafc7fTimo Sirainenstatic int fetch_date_sent(struct fetch_cmd_context *ctx)
c154a05c76d4d83de1cdf9746ce4e2da0869705dTimo Sirainen doveadm_print(t_strdup_printf("%s (%c%02u%02u)", unixdate2str(t),
cf63dc8723b971cc80638fccbf494d961cbafc7fTimo Sirainenstatic int fetch_date_saved(struct fetch_cmd_context *ctx)
7dd67cf142c243c735c00d640b7c85015b7da50aTimo Sirainenstatic int fetch_date_received_unixtime(struct fetch_cmd_context *ctx)
7dd67cf142c243c735c00d640b7c85015b7da50aTimo Sirainen if (mail_get_received_date(ctx->mail, &t) < 0)
7dd67cf142c243c735c00d640b7c85015b7da50aTimo Sirainenstatic int fetch_date_sent_unixtime(struct fetch_cmd_context *ctx)
7dd67cf142c243c735c00d640b7c85015b7da50aTimo Sirainenstatic int fetch_date_saved_unixtime(struct fetch_cmd_context *ctx)
c8ff6ff3a9b76f12b0e8269ca7bdd62d895f476bTimo Sirainenstatic int fetch_imap_envelope(struct fetch_cmd_context *ctx)
c8ff6ff3a9b76f12b0e8269ca7bdd62d895f476bTimo Sirainen if (mail_get_special(ctx->mail, MAIL_FETCH_IMAP_ENVELOPE, &value) < 0)
c8ff6ff3a9b76f12b0e8269ca7bdd62d895f476bTimo Sirainenstatic int fetch_imap_body(struct fetch_cmd_context *ctx)
c8ff6ff3a9b76f12b0e8269ca7bdd62d895f476bTimo Sirainen if (mail_get_special(ctx->mail, MAIL_FETCH_IMAP_BODY, &value) < 0)
c8ff6ff3a9b76f12b0e8269ca7bdd62d895f476bTimo Sirainenstatic int fetch_imap_bodystructure(struct fetch_cmd_context *ctx)
c8ff6ff3a9b76f12b0e8269ca7bdd62d895f476bTimo Sirainen if (mail_get_special(ctx->mail, MAIL_FETCH_IMAP_BODYSTRUCTURE, &value) < 0)
7f03bac2ef9fae720ce96536b1e936066f093de4Timo Sirainenstatic int fetch_pop3_uidl(struct fetch_cmd_context *ctx)
7f03bac2ef9fae720ce96536b1e936066f093de4Timo Sirainen if (mail_get_special(ctx->mail, MAIL_FETCH_UIDL_BACKEND, &value) < 0)
58f5b4641f4c0f91738ba4cb1246beb247f07da4Timo Sirainenstatic int fetch_pop3_order(struct fetch_cmd_context *ctx)
58f5b4641f4c0f91738ba4cb1246beb247f07da4Timo Sirainen if (mail_get_special(ctx->mail, MAIL_FETCH_POP3_ORDER, &value) < 0)
e1ba963457988db73650fbf972398e1d0e2318b6Timo Sirainenstatic int fetch_refcount(struct fetch_cmd_context *ctx)
e1ba963457988db73650fbf972398e1d0e2318b6Timo Sirainen if (mail_get_special(ctx->mail, MAIL_FETCH_REFCOUNT, &value) < 0)
7d56dc75f70aaea4369f4bfcffb0cd1b5abe1ca9Timo Sirainenstatic int fetch_storageid(struct fetch_cmd_context *ctx)
7d56dc75f70aaea4369f4bfcffb0cd1b5abe1ca9Timo Sirainen if (mail_get_special(ctx->mail, MAIL_FETCH_STORAGE_ID, &value) < 0)
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainenstatic const struct fetch_field fetch_fields[] = {
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen { "hdr", MAIL_FETCH_STREAM_HEADER, fetch_hdr },
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen { "body", MAIL_FETCH_STREAM_BODY, fetch_body },
ed897f9e09ae8ad86a88955420bd275b46ee8231Timo Sirainen { "body.snippet", MAIL_FETCH_BODY_SNIPPET, fetch_body_snippet },
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen { "size.physical", MAIL_FETCH_PHYSICAL_SIZE, fetch_size_physical },
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen { "size.virtual", MAIL_FETCH_VIRTUAL_SIZE, fetch_size_virtual },
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen { "date.received", MAIL_FETCH_RECEIVED_DATE, fetch_date_received },
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen { "date.sent", MAIL_FETCH_DATE, fetch_date_sent },
c8ff6ff3a9b76f12b0e8269ca7bdd62d895f476bTimo Sirainen { "date.saved", MAIL_FETCH_SAVE_DATE, fetch_date_saved },
7dd67cf142c243c735c00d640b7c85015b7da50aTimo Sirainen { "date.received.unixtime", MAIL_FETCH_RECEIVED_DATE, fetch_date_received_unixtime },
7dd67cf142c243c735c00d640b7c85015b7da50aTimo Sirainen { "date.sent.unixtime", MAIL_FETCH_DATE, fetch_date_sent_unixtime },
7dd67cf142c243c735c00d640b7c85015b7da50aTimo Sirainen { "date.saved.unixtime", MAIL_FETCH_SAVE_DATE, fetch_date_saved_unixtime },
c8ff6ff3a9b76f12b0e8269ca7bdd62d895f476bTimo Sirainen { "imap.envelope", MAIL_FETCH_IMAP_ENVELOPE, fetch_imap_envelope },
c8ff6ff3a9b76f12b0e8269ca7bdd62d895f476bTimo Sirainen { "imap.body", MAIL_FETCH_IMAP_BODY, fetch_imap_body },
7f03bac2ef9fae720ce96536b1e936066f093de4Timo Sirainen { "imap.bodystructure", MAIL_FETCH_IMAP_BODYSTRUCTURE, fetch_imap_bodystructure },
58f5b4641f4c0f91738ba4cb1246beb247f07da4Timo Sirainen { "pop3.uidl", MAIL_FETCH_UIDL_BACKEND, fetch_pop3_uidl },
e1ba963457988db73650fbf972398e1d0e2318b6Timo Sirainen { "pop3.order", MAIL_FETCH_POP3_ORDER, fetch_pop3_order },
7d56dc75f70aaea4369f4bfcffb0cd1b5abe1ca9Timo Sirainen { "refcount", MAIL_FETCH_REFCOUNT, fetch_refcount },
7d56dc75f70aaea4369f4bfcffb0cd1b5abe1ca9Timo Sirainen { "storageid", MAIL_FETCH_STORAGE_ID, fetch_storageid }
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainenstatic const struct fetch_field *fetch_field_find(const char *name)
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen unsigned int i;
cdf294e5cceee81d58c8477c7c28d9ad6b55c36aTimo Sirainen for (i = 0; i < N_ELEMENTS(fetch_fields); i++) {
7f098e28ddad259d9fbe76e18347c722bb005189Timo Sirainen unsigned int i;
f24b245f49b030d7dba3bcb2463cbc05b98c9d1dTimo Sirainen fprintf(stderr, "Available fetch fields: hdr.<name> body.<section> binary.<section> %s", fetch_fields[0].name);
7f098e28ddad259d9fbe76e18347c722bb005189Timo Sirainen for (i = 1; i < N_ELEMENTS(fetch_fields); i++)
cf63dc8723b971cc80638fccbf494d961cbafc7fTimo Sirainenstatic void parse_fetch_fields(struct fetch_cmd_context *ctx, const char *str)
0d16e4b4ba379b5d4c9b21e55173b291cac4d354Timo Sirainen if ((field = fetch_field_find(name)) != NULL) {
f24b245f49b030d7dba3bcb2463cbc05b98c9d1dTimo Sirainen bool binary = strncmp(name, "binary.", 7) == 0;
c001f4b968deb006f4f753af19db7843a2209ec5Timo Sirainen body_field.name = t_strarray_join(t_strsplit(name, ","), " ");
f24b245f49b030d7dba3bcb2463cbc05b98c9d1dTimo Sirainen ctx->wanted_fields |= imap_msgpart_get_fetch_data(msgpart);
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainenstatic int cmd_fetch_mail(struct fetch_cmd_context *ctx)
f23baa3b53b1dd4eb19729e99a43937fa3c7f309Timo Sirainen i_error("fetch(%s) failed for box=%s uid=%u: %s",
bf7dc750b95039981c0e9d728f313d50cf38a156Martti Rannanjärvi mailbox_get_last_internal_error(mail->box, NULL));
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen doveadm_mail_failed_mailbox(&ctx->ctx, mail->box);
cf63dc8723b971cc80638fccbf494d961cbafc7fTimo Sirainencmd_fetch_box(struct fetch_cmd_context *ctx, const struct mailbox_info *info)
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen if (doveadm_mail_iter_init(&ctx->ctx, info, ctx->ctx.search_args,
ec1fe002da484f4c06f0c072d673abac74b66b9eTimo Sirainen while (doveadm_mail_iter_next(iter, &ctx->mail)) {
cf63dc8723b971cc80638fccbf494d961cbafc7fTimo Sirainencmd_fetch_run(struct doveadm_mail_cmd_context *_ctx, struct mail_user *user)
cf63dc8723b971cc80638fccbf494d961cbafc7fTimo Sirainen struct fetch_cmd_context *ctx = (struct fetch_cmd_context *)_ctx;
8732bdd21579472feb40da8ffc99b8fd3b341417Timo Sirainen const enum mailbox_list_iter_flags iter_flags =
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen iter = doveadm_mailbox_list_iter_init(_ctx, user, _ctx->search_args,
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen while ((info = doveadm_mailbox_list_iter_next(iter)) != NULL) T_BEGIN {
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen if (doveadm_mailbox_list_iter_deinit(&iter) < 0)
23878bd03d1de531e3261a25598beec621351910Timo Sirainenstatic void cmd_fetch_init(struct doveadm_mail_cmd_context *_ctx,
23878bd03d1de531e3261a25598beec621351910Timo Sirainen const char *const args[])
23878bd03d1de531e3261a25598beec621351910Timo Sirainen struct fetch_cmd_context *ctx = (struct fetch_cmd_context *)_ctx;
1db62753d9e3b5d71018889c8ef0a3722a307455Timo Sirainen _ctx->search_args = doveadm_mail_build_search_args(args + 1);
23878bd03d1de531e3261a25598beec621351910Timo Sirainenstatic struct doveadm_mail_cmd_context *cmd_fetch_alloc(void)
23878bd03d1de531e3261a25598beec621351910Timo Sirainen ctx = doveadm_mail_cmd_alloc(struct fetch_cmd_context);
c45a841bee3f42ec6524b8f62c3fd457115c3f97Timo Sirainen .usage = DOVEADM_CMD_MAIL_USAGE_PREFIX"<fields> <search query>",
89d31290dab6e4bde08b8a118121f008154772e9Aki TuomiDOVEADM_CMD_PARAM('\0', "field", CMD_PARAM_ARRAY, 0)
89d31290dab6e4bde08b8a118121f008154772e9Aki TuomiDOVEADM_CMD_PARAM('\0', "fieldstr", CMD_PARAM_STR, CMD_PARAM_FLAG_POSITIONAL | CMD_PARAM_FLAG_DO_NOT_EXPOSE) /* FIXME: horrible hack, remove me when possible */