doveadm-mail-fetch.c revision e1ba963457988db73650fbf972398e1d0e2318b6
76b43e4417bab52e913da39b5f5bc2a130d3f149Timo Sirainen/* Copyright (c) 2010-2015 Dovecot authors, see the included COPYING file */
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include "lib.h"
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen#include "array.h"
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include "istream.h"
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include "ostream.h"
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include "str.h"
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include "message-address.h"
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen#include "message-size.h"
63a61b7a739ae0f3f520215137d9c50f94d0f34fTimo Sirainen#include "message-parser.h"
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include "message-header-decode.h"
18565c69efcd7db003dbf27cf625ed822e889fb1Timo Sirainen#include "message-decoder.h"
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include "imap-util.h"
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include "mail-user.h"
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include "mail-storage.h"
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include "mail-search.h"
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include "mail-namespace.h"
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen#include "doveadm-print.h"
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen#include "doveadm-mail.h"
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen#include "doveadm-mailbox-list-iter.h"
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen#include "doveadm-mail-iter.h"
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen#include <stdio.h>
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainenstruct fetch_cmd_context {
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen struct doveadm_mail_cmd_context ctx;
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen struct mail *mail;
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen ARRAY(struct fetch_field) fields;
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen ARRAY_TYPE(const_string) header_fields;
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen enum mail_fetch_field wanted_fields;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen const struct fetch_field *cur_field;
af1f4b17a92ca7b2661737e65c7849df289d3070Timo Sirainen};
af1f4b17a92ca7b2661737e65c7849df289d3070Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainenstruct fetch_field {
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen const char *name;
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen enum mail_fetch_field wanted_fields;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen int (*print)(struct fetch_cmd_context *ctx);
01cbf4ac5d44137ab434791be7f838d98d0fcf3bTimo Sirainen};
4b41116563110d00330896a568eff1078c382827Timo Sirainen
4b41116563110d00330896a568eff1078c382827Timo Sirainenstatic int fetch_user(struct fetch_cmd_context *ctx)
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen{
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen doveadm_print(ctx->ctx.cur_mail_user->username);
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen return 0;
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen}
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainenstatic int fetch_mailbox(struct fetch_cmd_context *ctx)
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen{
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen const char *value;
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen if (mail_get_special(ctx->mail, MAIL_FETCH_MAILBOX_NAME, &value) < 0)
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen return -1;
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen doveadm_print(value);
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen return 0;
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen}
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainenstatic int fetch_mailbox_guid(struct fetch_cmd_context *ctx)
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen{
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen struct mailbox_metadata metadata;
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen if (mailbox_get_metadata(ctx->mail->box, MAILBOX_METADATA_GUID,
d30da25fb6be1f1c667d93767c9194000194b618Timo Sirainen &metadata) < 0)
d30da25fb6be1f1c667d93767c9194000194b618Timo Sirainen return -1;
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen doveadm_print(guid_128_to_string(metadata.guid));
597dce34068d603fb759b4dff404b34049213e51Timo Sirainen return 0;
63a61b7a739ae0f3f520215137d9c50f94d0f34fTimo Sirainen}
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainenstatic int fetch_seq(struct fetch_cmd_context *ctx)
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen{
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen doveadm_print_num(ctx->mail->seq);
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen return 0;
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen}
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen
4b41116563110d00330896a568eff1078c382827Timo Sirainenstatic int fetch_uid(struct fetch_cmd_context *ctx)
910fa4e4204a73d3d24c03f3059dd24e727ca057Timo Sirainen{
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen doveadm_print_num(ctx->mail->uid);
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen return 0;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen}
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainenstatic int fetch_guid(struct fetch_cmd_context *ctx)
6060b7c8edf8fce73470d0df6a2479b69b01c537Timo Sirainen{
7f773564b94e6054a40d3785cb63c29f1e4d4deeTimo Sirainen const char *value;
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen
ccc895c0358108d2304239063e940b7d75f364abTimo Sirainen if (mail_get_special(ctx->mail, MAIL_FETCH_GUID, &value) < 0)
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen return -1;
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen doveadm_print(value);
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen return 0;
4b41116563110d00330896a568eff1078c382827Timo Sirainen}
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainenstatic int fetch_flags(struct fetch_cmd_context *ctx)
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen{
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen string_t *str = t_str_new(64);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen imap_write_flags(str, mail_get_flags(ctx->mail),
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen mail_get_keywords(ctx->mail));
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen doveadm_print(str_c(str));
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen return 0;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen}
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
4b41116563110d00330896a568eff1078c382827Timo Sirainenstatic int fetch_modseq(struct fetch_cmd_context *ctx)
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen{
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen doveadm_print_num(mail_get_modseq(ctx->mail));
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen return 0;
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen}
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainenstatic int fetch_hdr(struct fetch_cmd_context *ctx)
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen{
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen struct istream *input;
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen struct message_size hdr_size;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen int ret;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen if (mail_get_hdr_stream(ctx->mail, &hdr_size, &input) < 0)
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen return -1;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen input = i_stream_create_limit(input, hdr_size.physical_size);
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen ret = doveadm_print_istream(input);
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen i_stream_unref(&input);
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen return ret;
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen}
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainenstatic int fetch_hdr_field(struct fetch_cmd_context *ctx)
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen{
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen const char *const *value, *filter, *name = ctx->cur_field->name;
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen string_t *str = t_str_new(256);
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen bool add_lf = FALSE;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen filter = strchr(name, '.');
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen if (filter != NULL)
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen name = t_strdup_until(name, filter++);
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen if (filter != NULL && strcmp(filter, "utf8") == 0) {
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen if (mail_get_headers_utf8(ctx->mail, name, &value) < 0)
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen return -1;
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen } else {
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen if (mail_get_headers(ctx->mail, name, &value) < 0)
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen return -1;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen }
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen for (; *value != NULL; value++) {
4b41116563110d00330896a568eff1078c382827Timo Sirainen if (add_lf)
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen str_append_c(str, '\n');
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen str_append(str, *value);
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen add_lf = TRUE;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen }
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen if (filter == NULL || strcmp(filter, "utf8") == 0) {
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen /* print the header as-is */
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen } else if (strcmp(filter, "address") == 0 ||
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen strcmp(filter, "address_name") == 0 ||
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen strcmp(filter, "address_name.utf8") == 0) {
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen struct message_address *addr;
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen addr = message_address_parse(pool_datastack_create(),
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen str_data(str), str_len(str),
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen UINT_MAX, FALSE);
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen str_truncate(str, 0);
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen add_lf = FALSE;
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen for (; addr != NULL; addr = addr->next) {
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen if (add_lf)
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen str_append_c(str, '\n');
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen if (strcmp(filter, "address") == 0) {
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen if (addr->mailbox != NULL)
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen str_append(str, addr->mailbox);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen if (addr->domain != NULL) {
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen str_append_c(str, '@');
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen str_append(str, addr->domain);
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen }
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen } else if (addr->name != NULL) {
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen if (strcmp(filter, "address_name") == 0)
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen str_append(str, addr->name);
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen else {
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen message_header_decode_utf8(
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen (const void *)addr->name,
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen strlen(addr->name), str, NULL);
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen }
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen }
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen add_lf = TRUE;
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen }
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen } else {
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen i_fatal("Unknown header filter: %s", filter);
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen }
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen doveadm_print(str_c(str));
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen return 0;
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen}
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainenstatic int fetch_body(struct fetch_cmd_context *ctx)
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen{
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen struct istream *input;
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen struct message_size hdr_size;
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen if (mail_get_stream(ctx->mail, &hdr_size, NULL, &input) < 0)
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen return -1;
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen i_stream_skip(input, hdr_size.physical_size);
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen return doveadm_print_istream(input);
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen}
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainenstatic int fetch_body_snippet(struct fetch_cmd_context *ctx)
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen{
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen const char *value;
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen if (mail_get_special(ctx->mail, MAIL_FETCH_BODY_SNIPPET, &value) < 0)
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen return -1;
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen /* [0] contains the snippet algorithm, skip over it */
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen i_assert(value[0] != '\0');
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen doveadm_print(value + 1);
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen return 0;
d67fde1a8ebc1d85704c5986d8f93aae97eccef3Timo Sirainen}
d67fde1a8ebc1d85704c5986d8f93aae97eccef3Timo Sirainen
d67fde1a8ebc1d85704c5986d8f93aae97eccef3Timo Sirainenstatic int fetch_text(struct fetch_cmd_context *ctx)
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen{
aa215ab623706463cea1d047f975ffe51d3f0c05Timo Sirainen struct istream *input;
aa215ab623706463cea1d047f975ffe51d3f0c05Timo Sirainen
a5c8dc283ef673fcdae158513b8032e74b45f59aTimo Sirainen if (mail_get_stream(ctx->mail, NULL, NULL, &input) < 0)
d67fde1a8ebc1d85704c5986d8f93aae97eccef3Timo Sirainen return -1;
aa215ab623706463cea1d047f975ffe51d3f0c05Timo Sirainen return doveadm_print_istream(input);
aa215ab623706463cea1d047f975ffe51d3f0c05Timo Sirainen}
aa215ab623706463cea1d047f975ffe51d3f0c05Timo Sirainen
aa215ab623706463cea1d047f975ffe51d3f0c05Timo Sirainenstatic int fetch_text_utf8(struct fetch_cmd_context *ctx)
a5c8dc283ef673fcdae158513b8032e74b45f59aTimo Sirainen{
aa215ab623706463cea1d047f975ffe51d3f0c05Timo Sirainen struct istream *input;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen struct message_parser_ctx *parser;
a1808be0774cbcb28fec45341aabf803ec44bae5Timo Sirainen struct message_decoder_context *decoder;
d67fde1a8ebc1d85704c5986d8f93aae97eccef3Timo Sirainen struct message_block raw_block, block;
aa215ab623706463cea1d047f975ffe51d3f0c05Timo Sirainen struct message_part *parts;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen int ret = 0;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen if (mail_get_stream(ctx->mail, NULL, NULL, &input) < 0)
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen return -1;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen
1b5366b2234892f8930a29351da06b193e385150Timo Sirainen parser = message_parser_init(pool_datastack_create(), input,
1b5366b2234892f8930a29351da06b193e385150Timo Sirainen MESSAGE_HEADER_PARSER_FLAG_CLEAN_ONELINE,
1b5366b2234892f8930a29351da06b193e385150Timo Sirainen 0);
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen decoder = message_decoder_init(NULL, 0);
1b5366b2234892f8930a29351da06b193e385150Timo Sirainen
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen while ((ret = message_parser_parse_next_block(parser, &raw_block)) > 0) {
1b5366b2234892f8930a29351da06b193e385150Timo Sirainen if (!message_decoder_decode_next_block(decoder, &raw_block,
1b5366b2234892f8930a29351da06b193e385150Timo Sirainen &block))
1b5366b2234892f8930a29351da06b193e385150Timo Sirainen continue;
aa215ab623706463cea1d047f975ffe51d3f0c05Timo Sirainen
aa215ab623706463cea1d047f975ffe51d3f0c05Timo Sirainen if (block.hdr == NULL) {
d67fde1a8ebc1d85704c5986d8f93aae97eccef3Timo Sirainen if (block.size > 0)
aa215ab623706463cea1d047f975ffe51d3f0c05Timo Sirainen doveadm_print_stream(block.data, block.size);
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen } else if (block.hdr->eoh)
a5c8dc283ef673fcdae158513b8032e74b45f59aTimo Sirainen doveadm_print_stream("\n", 1);
a5c8dc283ef673fcdae158513b8032e74b45f59aTimo Sirainen else {
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen i_assert(block.hdr->name_len > 0);
d67fde1a8ebc1d85704c5986d8f93aae97eccef3Timo Sirainen doveadm_print_stream(block.hdr->name,
d67fde1a8ebc1d85704c5986d8f93aae97eccef3Timo Sirainen block.hdr->name_len);
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen doveadm_print_stream(": ", 2);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen if (block.hdr->full_value_len > 0) {
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen doveadm_print_stream(block.hdr->full_value,
b2ecd50bb98c44816cb07c17aa17fae2b425f941Timo Sirainen block.hdr->full_value_len);
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen }
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen doveadm_print_stream("\n", 1);
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen }
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen }
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen i_assert(ret != 0);
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen message_decoder_deinit(&decoder);
4b41116563110d00330896a568eff1078c382827Timo Sirainen (void)message_parser_deinit(&parser, &parts);
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen doveadm_print_stream("", 0);
f480b30abdddf6f1beb8a2c5b1ce4bf8999400dbTimo Sirainen if (input->stream_errno != 0) {
f480b30abdddf6f1beb8a2c5b1ce4bf8999400dbTimo Sirainen i_error("read(%s) failed: %s", i_stream_get_name(input),
f480b30abdddf6f1beb8a2c5b1ce4bf8999400dbTimo Sirainen i_stream_get_error(input));
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen return -1;
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen }
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen return 0;
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen}
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainenstatic int fetch_size_physical(struct fetch_cmd_context *ctx)
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen{
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen uoff_t size;
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen if (mail_get_physical_size(ctx->mail, &size) < 0)
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen return -1;
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen doveadm_print_num(size);
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen return 0;
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen}
8f017a40470ef2f4b530000d947a8bce44350a5eTimo Sirainen
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainenstatic int fetch_size_virtual(struct fetch_cmd_context *ctx)
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen{
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen uoff_t size;
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen if (mail_get_virtual_size(ctx->mail, &size) < 0)
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen return -1;
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen doveadm_print_num(size);
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen return 0;
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen}
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainenstatic int fetch_date_received(struct fetch_cmd_context *ctx)
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen{
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen time_t t;
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen if (mail_get_received_date(ctx->mail, &t) < 0)
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen return -1;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen doveadm_print(unixdate2str(t));
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen return 0;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen}
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainenstatic int fetch_date_sent(struct fetch_cmd_context *ctx)
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen{
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen time_t t;
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen int tz;
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen char chr;
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen if (mail_get_date(ctx->mail, &t, &tz) < 0)
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen return -1;
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen chr = tz < 0 ? '-' : '+';
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen if (tz < 0) tz = -tz;
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen doveadm_print(t_strdup_printf("%s (%c%02u%02u)", unixdate2str(t),
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen chr, tz/60, tz%60));
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen return 0;
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen}
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainenstatic int fetch_date_saved(struct fetch_cmd_context *ctx)
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen{
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen time_t t;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen
0d86aa0d47f7393c669c084b34c0537b193688adTimo Sirainen if (mail_get_save_date(ctx->mail, &t) < 0)
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen return -1;
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen doveadm_print(unixdate2str(t));
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen return 0;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen}
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainenstatic int fetch_imap_envelope(struct fetch_cmd_context *ctx)
a757f31393b9d6fc7760a9dec8363404ab3ae576Timo Sirainen{
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen const char *value;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen if (mail_get_special(ctx->mail, MAIL_FETCH_IMAP_ENVELOPE, &value) < 0)
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen return -1;
d67fde1a8ebc1d85704c5986d8f93aae97eccef3Timo Sirainen doveadm_print(value);
d67fde1a8ebc1d85704c5986d8f93aae97eccef3Timo Sirainen return 0;
87460b08cb97b31cde640d4975a6aa2c1d0e7226Timo Sirainen}
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
87460b08cb97b31cde640d4975a6aa2c1d0e7226Timo Sirainenstatic int fetch_imap_body(struct fetch_cmd_context *ctx)
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen{
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen const char *value;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen if (mail_get_special(ctx->mail, MAIL_FETCH_IMAP_BODY, &value) < 0)
838e367716bbd5e44b4a1691db9cbf72af53e9f0Timo Sirainen return -1;
01404d41657a104c5ea1c12bb87f9c321e9c1ac4Timo Sirainen doveadm_print(value);
01404d41657a104c5ea1c12bb87f9c321e9c1ac4Timo Sirainen return 0;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen}
static int fetch_imap_bodystructure(struct fetch_cmd_context *ctx)
{
const char *value;
if (mail_get_special(ctx->mail, MAIL_FETCH_IMAP_BODYSTRUCTURE, &value) < 0)
return -1;
doveadm_print(value);
return 0;
}
static int fetch_pop3_uidl(struct fetch_cmd_context *ctx)
{
const char *value;
if (mail_get_special(ctx->mail, MAIL_FETCH_UIDL_BACKEND, &value) < 0)
return -1;
doveadm_print(value);
return 0;
}
static int fetch_pop3_order(struct fetch_cmd_context *ctx)
{
const char *value;
if (mail_get_special(ctx->mail, MAIL_FETCH_POP3_ORDER, &value) < 0)
return -1;
doveadm_print(value);
return 0;
}
static int fetch_refcount(struct fetch_cmd_context *ctx)
{
const char *value;
if (mail_get_special(ctx->mail, MAIL_FETCH_REFCOUNT, &value) < 0)
return -1;
doveadm_print(value);
return 0;
}
static const struct fetch_field fetch_fields[] = {
{ "user", 0, fetch_user },
{ "mailbox", 0, fetch_mailbox },
{ "mailbox-guid", 0, fetch_mailbox_guid },
{ "seq", 0, fetch_seq },
{ "uid", 0, fetch_uid },
{ "guid", 0, fetch_guid },
{ "flags", MAIL_FETCH_FLAGS, fetch_flags },
{ "modseq", 0, fetch_modseq },
{ "hdr", MAIL_FETCH_STREAM_HEADER, fetch_hdr },
{ "body", MAIL_FETCH_STREAM_BODY, fetch_body },
{ "body.snippet", MAIL_FETCH_BODY_SNIPPET, fetch_body_snippet },
{ "text", MAIL_FETCH_STREAM_HEADER |
MAIL_FETCH_STREAM_BODY, fetch_text },
{ "text.utf8", MAIL_FETCH_STREAM_HEADER |
MAIL_FETCH_STREAM_BODY, fetch_text_utf8 },
{ "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 },
{ "imap.envelope", MAIL_FETCH_IMAP_ENVELOPE, fetch_imap_envelope },
{ "imap.body", MAIL_FETCH_IMAP_BODY, fetch_imap_body },
{ "imap.bodystructure", MAIL_FETCH_IMAP_BODYSTRUCTURE, fetch_imap_bodystructure },
{ "pop3.uidl", MAIL_FETCH_UIDL_BACKEND, fetch_pop3_uidl },
{ "pop3.order", MAIL_FETCH_POP3_ORDER, fetch_pop3_order },
{ "refcount", MAIL_FETCH_REFCOUNT, fetch_refcount }
};
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 print_fetch_fields(void)
{
unsigned int i;
fprintf(stderr, "Available fetch fields: %s", fetch_fields[0].name);
for (i = 1; i < N_ELEMENTS(fetch_fields); i++)
fprintf(stderr, " %s", fetch_fields[i].name);
fprintf(stderr, "\n");
}
static void parse_fetch_fields(struct fetch_cmd_context *ctx, const char *str)
{
const char *const *fields, *name;
const struct fetch_field *field;
struct fetch_field hdr_field;
memset(&hdr_field, 0, sizeof(hdr_field));
hdr_field.print = fetch_hdr_field;
t_array_init(&ctx->fields, 32);
t_array_init(&ctx->header_fields, 32);
fields = t_strsplit_spaces(str, " ");
for (; *fields != NULL; fields++) {
name = t_str_lcase(*fields);
doveadm_print_header_simple(name);
if (strncmp(name, "hdr.", 4) == 0) {
name += 4;
hdr_field.name = name;
array_append(&ctx->fields, &hdr_field, 1);
name = t_strcut(name, '.');
array_append(&ctx->header_fields, &name, 1);
} else {
field = fetch_field_find(name);
if (field == NULL) {
print_fetch_fields();
i_fatal("Unknown fetch field: %s", name);
}
ctx->wanted_fields |= field->wanted_fields;
array_append(&ctx->fields, field, 1);
}
}
array_append_zero(&ctx->header_fields);
}
static int cmd_fetch_mail(struct fetch_cmd_context *ctx)
{
const struct fetch_field *field;
struct mail *mail = ctx->mail;
int ret = 0;
array_foreach(&ctx->fields, field) {
ctx->cur_field = field;
if (field->print(ctx) < 0) {
i_error("fetch(%s) failed for box=%s uid=%u: %s",
field->name, mailbox_get_vname(mail->box),
mail->uid, mailbox_get_last_error(mail->box, NULL));
doveadm_mail_failed_mailbox(&ctx->ctx, mail->box);
ret = -1;
}
}
return ret;
}
static int
cmd_fetch_box(struct fetch_cmd_context *ctx, const struct mailbox_info *info)
{
struct doveadm_mail_iter *iter;
int ret = 0;
if (doveadm_mail_iter_init(&ctx->ctx, info, ctx->ctx.search_args,
ctx->wanted_fields,
array_idx(&ctx->header_fields, 0),
&iter) < 0)
return -1;
while (doveadm_mail_iter_next(iter, &ctx->mail)) {
T_BEGIN {
if (cmd_fetch_mail(ctx) < 0)
ret = -1;
} T_END;
}
if (doveadm_mail_iter_deinit(&iter) < 0)
ret = -1;
return ret;
}
static int
cmd_fetch_run(struct doveadm_mail_cmd_context *_ctx, struct mail_user *user)
{
struct fetch_cmd_context *ctx = (struct fetch_cmd_context *)_ctx;
const enum mailbox_list_iter_flags iter_flags =
MAILBOX_LIST_ITER_NO_AUTO_BOXES |
MAILBOX_LIST_ITER_RETURN_NO_FLAGS;
struct doveadm_mailbox_list_iter *iter;
const struct mailbox_info *info;
int ret = 0;
iter = doveadm_mailbox_list_iter_init(_ctx, user, _ctx->search_args,
iter_flags);
while ((info = doveadm_mailbox_list_iter_next(iter)) != NULL) T_BEGIN {
if (cmd_fetch_box(ctx, info) < 0)
ret = -1;
} T_END;
if (doveadm_mailbox_list_iter_deinit(&iter) < 0)
ret = -1;
return ret;
}
static void cmd_fetch_init(struct doveadm_mail_cmd_context *_ctx,
const char *const args[])
{
struct fetch_cmd_context *ctx = (struct fetch_cmd_context *)_ctx;
const char *fetch_fields = args[0];
if (fetch_fields == NULL || args[1] == NULL)
doveadm_mail_help_name("fetch");
parse_fetch_fields(ctx, fetch_fields);
_ctx->search_args = doveadm_mail_build_search_args(args + 1);
}
static struct doveadm_mail_cmd_context *cmd_fetch_alloc(void)
{
struct fetch_cmd_context *ctx;
ctx = doveadm_mail_cmd_alloc(struct fetch_cmd_context);
ctx->ctx.v.init = cmd_fetch_init;
ctx->ctx.v.run = cmd_fetch_run;
doveadm_print_init("pager");
return &ctx->ctx;
}
struct doveadm_mail_cmd cmd_fetch = {
cmd_fetch_alloc, "fetch", "<fields> <search query>"
};