imap-fetch-body.c revision defeb23b40f1c1af0535a84529383825e5ef8dfe
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/* Copyright (c) 2002-2015 Dovecot authors, see the included COPYING file */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "imap-common.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "buffer.h"
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen#include "str.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "strescape.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "istream.h"
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen#include "ostream.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "istream-header-filter.h"
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen#include "message-parser.h"
436adac819e7cbeef04af08dcc6a4f3ecd4a1d9eMartti Rannanjärvi#include "mail-storage-private.h"
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen#include "imap-quote.h"
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen#include "imap-parser.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "imap-msgpart.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen#include "imap-fetch.h"
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen#include <stdlib.h>
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen#include <ctype.h>
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen#include <unistd.h>
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainenstruct imap_fetch_body_data {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const char *section; /* NOTE: always uppercased */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen struct imap_msgpart *msgpart;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen unsigned int partial:1;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen unsigned int binary:1;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen unsigned int binary_size:1;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen};
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic void fetch_read_error(struct imap_fetch_context *ctx,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const char **disconnect_reason_r)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen{
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen struct imap_fetch_state *state = &ctx->state;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (state->cur_input->stream_errno == ENOENT) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (state->cur_mail->expunged) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen *disconnect_reason_r = "Mail expunged while it was being FETCHed";
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen return;
5948e3e120c5dcaf0aeb44405566381045fa82d6Timo Sirainen }
7fc0ca6c1f664de6506afa816200d115f9f80391Timo Sirainen }
7fc0ca6c1f664de6506afa816200d115f9f80391Timo Sirainen mail_storage_set_critical(state->cur_mail->box->storage,
7fc0ca6c1f664de6506afa816200d115f9f80391Timo Sirainen "read(%s) failed: %s (FETCH %s for mailbox %s UID %u)",
5948e3e120c5dcaf0aeb44405566381045fa82d6Timo Sirainen i_stream_get_name(state->cur_input),
5948e3e120c5dcaf0aeb44405566381045fa82d6Timo Sirainen i_stream_get_error(state->cur_input),
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen state->cur_human_name,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen mailbox_get_vname(state->cur_mail->box), state->cur_mail->uid);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen *disconnect_reason_r = "FETCH read() failed";
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen}
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainenstatic const char *get_body_name(const struct imap_fetch_body_data *body)
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen{
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen string_t *str;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
5b7ff90a6c078b07406bce434c719017a0f51825Timo Sirainen str = t_str_new(128);
5b7ff90a6c078b07406bce434c719017a0f51825Timo Sirainen if (body->binary_size)
5b7ff90a6c078b07406bce434c719017a0f51825Timo Sirainen str_append(str, "BINARY.SIZE");
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen else if (body->binary)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen str_append(str, "BINARY");
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen else
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen str_append(str, "BODY");
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen str_printfa(str, "[%s]", body->section);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (body->partial) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen str_printfa(str, "<%"PRIuUOFF_T">",
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen imap_msgpart_get_partial_offset(body->msgpart));
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return str_c(str);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen}
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic string_t *get_prefix(struct imap_fetch_state *state,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const struct imap_fetch_body_data *body,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen uoff_t size, bool has_nuls)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen{
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen string_t *str;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen str = t_str_new(128);
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen if (state->cur_first)
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen state->cur_first = FALSE;
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen else
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen str_append_c(str, ' ');
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen str_append(str, get_body_name(body));
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (size == (uoff_t)-1)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen str_append(str, " NIL");
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen else if (has_nuls && body->binary)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen str_printfa(str, " ~{%"PRIuUOFF_T"}\r\n", size);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen else
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen str_printfa(str, " {%"PRIuUOFF_T"}\r\n", size);
84ed9f8f3d0e5ed47607ef417618e49e4f865557Timo Sirainen return str;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen}
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
7fc0ca6c1f664de6506afa816200d115f9f80391Timo Sirainenstatic int fetch_stream_continue(struct imap_fetch_context *ctx)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen{
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen struct imap_fetch_state *state = &ctx->state;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const char *disconnect_reason;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen off_t ret;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen o_stream_set_max_buffer_size(ctx->client->output, 0);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ret = o_stream_send_istream(ctx->client->output, state->cur_input);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen o_stream_set_max_buffer_size(ctx->client->output, (size_t)-1);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (ret > 0) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen state->cur_offset += ret;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (ctx->state.cur_stats_sizep != NULL)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen *ctx->state.cur_stats_sizep += ret;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (state->cur_offset != state->cur_size) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen /* unfinished */
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (state->cur_input->stream_errno != 0) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen fetch_read_error(ctx, &disconnect_reason);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen client_disconnect(ctx->client, disconnect_reason);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return -1;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen }
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (!i_stream_have_bytes_left(state->cur_input)) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen /* Input stream gave less data than expected */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_error("read(%s): FETCH %s for mailbox %s UID %u "
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen "got too little data: "
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen "%"PRIuUOFF_T" vs %"PRIuUOFF_T,
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainen i_stream_get_name(state->cur_input),
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainen state->cur_human_name,
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen mailbox_get_vname(state->cur_mail->box),
7a24bdc1a5e2d5368c2569b4852192f2bdb5a31fTimo Sirainen state->cur_mail->uid,
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen state->cur_offset, state->cur_size);
7a24bdc1a5e2d5368c2569b4852192f2bdb5a31fTimo Sirainen mail_set_cache_corrupted(state->cur_mail,
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen state->cur_size_field);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen client_disconnect(ctx->client, "FETCH failed");
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return -1;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen }
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen if (ret < 0) {
d85a1a9d9af4a36ded4d30cb277905c807de2ec5Timo Sirainen /* client probably disconnected */
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen return -1;
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen }
d85a1a9d9af4a36ded4d30cb277905c807de2ec5Timo Sirainen
d85a1a9d9af4a36ded4d30cb277905c807de2ec5Timo Sirainen o_stream_set_flush_pending(ctx->client->output, TRUE);
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen return 0;
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen }
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen return 1;
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen}
d85a1a9d9af4a36ded4d30cb277905c807de2ec5Timo Sirainen
8f90ef65db62946aabe1969755edcdefb4eb430aTimo Sirainenstatic const char *
8f90ef65db62946aabe1969755edcdefb4eb430aTimo Sirainenget_body_human_name(pool_t pool, struct imap_fetch_body_data *body)
8f90ef65db62946aabe1969755edcdefb4eb430aTimo Sirainen{
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen string_t *str;
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen uoff_t partial_offset, partial_size;
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen
d85a1a9d9af4a36ded4d30cb277905c807de2ec5Timo Sirainen str = t_str_new(64);
d85a1a9d9af4a36ded4d30cb277905c807de2ec5Timo Sirainen if (body->binary)
d85a1a9d9af4a36ded4d30cb277905c807de2ec5Timo Sirainen str_append(str, "BINARY[");
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen else
d85a1a9d9af4a36ded4d30cb277905c807de2ec5Timo Sirainen str_append(str, "BODY[");
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen str_append(str, body->section);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen str_append_c(str, ']');
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen partial_offset = imap_msgpart_get_partial_offset(body->msgpart);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen partial_size = imap_msgpart_get_partial_size(body->msgpart);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (partial_offset != 0 || partial_size != (uoff_t)-1) {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen str_printfa(str, "<%"PRIuUOFF_T, partial_offset);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (partial_size != (uoff_t)-1)
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen str_printfa(str, ".%"PRIuUOFF_T, partial_size);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen str_append_c(str, '>');
504337186520df7012315687fc0f88c945775471Timo Sirainen }
504337186520df7012315687fc0f88c945775471Timo Sirainen return p_strdup(pool, str_c(str));
d85a1a9d9af4a36ded4d30cb277905c807de2ec5Timo Sirainen}
d85a1a9d9af4a36ded4d30cb277905c807de2ec5Timo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainenstatic void fetch_state_update_stats(struct imap_fetch_context *ctx,
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen const struct imap_msgpart *msgpart)
d85a1a9d9af4a36ded4d30cb277905c807de2ec5Timo Sirainen{
d85a1a9d9af4a36ded4d30cb277905c807de2ec5Timo Sirainen if (!imap_msgpart_contains_body(msgpart)) {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen ctx->client->fetch_hdr_count++;
d85a1a9d9af4a36ded4d30cb277905c807de2ec5Timo Sirainen ctx->state.cur_stats_sizep = &ctx->client->fetch_hdr_bytes;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen } else {
6d6c1517ef20e340a3aace406724fc8916f2d13fTimo Sirainen ctx->client->fetch_body_count++;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen ctx->state.cur_stats_sizep = &ctx->client->fetch_body_bytes;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen }
d85a1a9d9af4a36ded4d30cb277905c807de2ec5Timo Sirainen}
7e209b78ca757294dbbc15604c88673b3a6b0c39Timo Sirainen
d85a1a9d9af4a36ded4d30cb277905c807de2ec5Timo Sirainenstatic int fetch_body_msgpart(struct imap_fetch_context *ctx, struct mail *mail,
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen struct imap_fetch_body_data *body)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen{
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen struct imap_msgpart_open_result result;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen string_t *str;
825b0e819a7c48a366ddca23ec78b87e8c30e9b4Aki Tuomi
825b0e819a7c48a366ddca23ec78b87e8c30e9b4Aki Tuomi if (mail == NULL) {
825b0e819a7c48a366ddca23ec78b87e8c30e9b4Aki Tuomi imap_msgpart_free(&body->msgpart);
825b0e819a7c48a366ddca23ec78b87e8c30e9b4Aki Tuomi return 1;
825b0e819a7c48a366ddca23ec78b87e8c30e9b4Aki Tuomi }
825b0e819a7c48a366ddca23ec78b87e8c30e9b4Aki Tuomi
825b0e819a7c48a366ddca23ec78b87e8c30e9b4Aki Tuomi if (imap_msgpart_open(mail, body->msgpart, &result) < 0)
d85a1a9d9af4a36ded4d30cb277905c807de2ec5Timo Sirainen return -1;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen ctx->state.cur_input = result.input;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen ctx->state.cur_size = result.size;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen ctx->state.cur_size_field = result.size_field;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen ctx->state.cur_human_name = get_body_human_name(ctx->ctx_pool, body);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
939a0d82523538b2de38a02bc9f790a67b7ebf47Timo Sirainen fetch_state_update_stats(ctx, body->msgpart);
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen str = get_prefix(&ctx->state, body, ctx->state.cur_size,
d85a1a9d9af4a36ded4d30cb277905c807de2ec5Timo Sirainen result.binary_decoded_input_has_nuls);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen o_stream_nsend(ctx->client->output, str_data(str), str_len(str));
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen ctx->state.cont_handler = fetch_stream_continue;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return ctx->state.cont_handler(ctx);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen}
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainenstatic int fetch_binary_size(struct imap_fetch_context *ctx, struct mail *mail,
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen struct imap_fetch_body_data *body)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen{
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen string_t *str;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen uoff_t size;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
939a0d82523538b2de38a02bc9f790a67b7ebf47Timo Sirainen if (mail == NULL) {
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen imap_msgpart_free(&body->msgpart);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return 1;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen }
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (imap_msgpart_size(mail, body->msgpart, &size) < 0)
939a0d82523538b2de38a02bc9f790a67b7ebf47Timo Sirainen return -1;
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen str = t_str_new(128);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (ctx->state.cur_first)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen ctx->state.cur_first = FALSE;
939a0d82523538b2de38a02bc9f790a67b7ebf47Timo Sirainen else
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen str_append_c(str, ' ');
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen str_printfa(str, "%s %"PRIuUOFF_T, get_body_name(body), size);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (o_stream_send(ctx->client->output, str_data(str), str_len(str)) < 0)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return -1;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return 1;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen}
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen/* Parse next digits in string into integer. Returns -1 if the integer
d85a1a9d9af4a36ded4d30cb277905c807de2ec5Timo Sirainen becomes too big and wraps. */
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainenstatic int read_uoff_t(const char **p, uoff_t *value)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen{
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen return str_parse_uoff(*p, value, p);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen}
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainenstatic int
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainenbody_header_fields_parse(struct imap_fetch_init_context *ctx,
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen struct imap_fetch_body_data *body, const char *prefix,
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen const struct imap_arg *args, unsigned int args_count)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen{
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen string_t *str;
6d6c1517ef20e340a3aace406724fc8916f2d13fTimo Sirainen const char *value;
6d6c1517ef20e340a3aace406724fc8916f2d13fTimo Sirainen size_t i;
6d6c1517ef20e340a3aace406724fc8916f2d13fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen str = str_new(ctx->pool, 128);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen str_append(str, prefix);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen str_append(str, " (");
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen for (i = 0; i < args_count; i++) {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (!imap_arg_get_astring(&args[i], &value)) {
939a0d82523538b2de38a02bc9f790a67b7ebf47Timo Sirainen ctx->error = "Invalid BODY[..] parameter: "
d85a1a9d9af4a36ded4d30cb277905c807de2ec5Timo Sirainen "Header list contains non-strings";
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen return -1;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen }
d85a1a9d9af4a36ded4d30cb277905c807de2ec5Timo Sirainen value = t_str_ucase(value);
939a0d82523538b2de38a02bc9f790a67b7ebf47Timo Sirainen
d85a1a9d9af4a36ded4d30cb277905c807de2ec5Timo Sirainen if (i != 0)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen str_append_c(str, ' ');
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
d85a1a9d9af4a36ded4d30cb277905c807de2ec5Timo Sirainen if (args[i].type == IMAP_ARG_ATOM)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen str_append(str, value);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen else
d85a1a9d9af4a36ded4d30cb277905c807de2ec5Timo Sirainen imap_append_quoted(str, value);
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen }
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen str_append_c(str, ')');
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen body->section = str_c(str);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return 0;
d85a1a9d9af4a36ded4d30cb277905c807de2ec5Timo Sirainen}
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainenstatic int body_parse_partial(struct imap_fetch_body_data *body,
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen const char *p, const char **error_r)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen{
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen uoff_t offset, size = (uoff_t)-1;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (*p == '\0')
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return 0;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen /* <start.end> */
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (*p != '<') {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen *error_r = "Unexpected data after ']'";
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return -1;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen }
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen p++;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen body->partial = TRUE;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch if (read_uoff_t(&p, &offset) < 0 || offset > OFF_T_MAX) {
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch /* wrapped */
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen *error_r = "Too big partial start";
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return -1;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen }
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
7e209b78ca757294dbbc15604c88673b3a6b0c39Timo Sirainen if (*p == '.') {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen p++;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (read_uoff_t(&p, &size) < 0 || size > OFF_T_MAX) {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen /* wrapped */
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen *error_r = "Too big partial end";
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return -1;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen }
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen }
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (*p != '>') {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen *error_r = "Missing '>' in partial";
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return -1;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen }
6d6c1517ef20e340a3aace406724fc8916f2d13fTimo Sirainen if (p[1] != '\0') {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen *error_r = "Unexpected data after '>'";
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return -1;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen }
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen imap_msgpart_set_partial(body->msgpart, offset, size);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return 0;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen}
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainenbool imap_fetch_body_section_init(struct imap_fetch_init_context *ctx)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen{
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen struct imap_fetch_body_data *body;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen const struct imap_arg *list_args;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen unsigned int list_count;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen const char *str, *p, *error;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen i_assert(strncmp(ctx->name, "BODY", 4) == 0);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen p = ctx->name + 4;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen body = p_new(ctx->pool, struct imap_fetch_body_data, 1);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (strncmp(p, ".PEEK", 5) == 0)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen p += 5;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen else
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen ctx->fetch_ctx->flags_update_seen = TRUE;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (*p != '[') {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen ctx->error = "Invalid BODY[..] parameter: Missing '['";
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return FALSE;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen }
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (imap_arg_get_list_full(&ctx->args[0], &list_args, &list_count)) {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen /* BODY[HEADER.FIELDS.. (headers list)] */
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (!imap_arg_get_atom(&ctx->args[1], &str) ||
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen str[0] != ']') {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen ctx->error = "Invalid BODY[..] parameter: Missing ']'";
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return FALSE;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen }
a406615fbcef37b1d12f0be95a70abf23238c5efTimo Sirainen if (body_header_fields_parse(ctx, body, p+1,
a406615fbcef37b1d12f0be95a70abf23238c5efTimo Sirainen list_args, list_count) < 0)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return FALSE;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen p = str+1;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ctx->args += 2;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen } else {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* no headers list */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen body->section = p+1;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen p = strchr(body->section, ']');
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (p == NULL) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ctx->error = "Invalid BODY[..] parameter: Missing ']'";
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return FALSE;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen body->section = p_strdup_until(ctx->pool, body->section, p);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen p++;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (imap_msgpart_parse(body->section, &body->msgpart) < 0) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ctx->error = "Invalid BODY[..] section";
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return FALSE;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ctx->fetch_ctx->fetch_data |=
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen imap_msgpart_get_fetch_data(body->msgpart);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen imap_msgpart_get_wanted_headers(body->msgpart, &ctx->fetch_ctx->all_headers);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
a406615fbcef37b1d12f0be95a70abf23238c5efTimo Sirainen if (body_parse_partial(body, p, &error) < 0) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ctx->error = p_strdup_printf(ctx->pool,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen "Invalid BODY[..] parameter: %s", error);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return FALSE;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
03010dbaa74ec70f062994dfe3cd39bedc99a28bTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* update the section name for the imap_fetch_add_handler() */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ctx->name = p_strdup(ctx->pool, get_body_name(body));
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen imap_fetch_add_handler(ctx, IMAP_FETCH_HANDLER_FLAG_WANT_DEINIT,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen "NIL", fetch_body_msgpart, body);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return TRUE;
a406615fbcef37b1d12f0be95a70abf23238c5efTimo Sirainen}
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen
a406615fbcef37b1d12f0be95a70abf23238c5efTimo Sirainenbool imap_fetch_binary_init(struct imap_fetch_init_context *ctx)
a406615fbcef37b1d12f0be95a70abf23238c5efTimo Sirainen{
a406615fbcef37b1d12f0be95a70abf23238c5efTimo Sirainen struct imap_fetch_body_data *body;
a406615fbcef37b1d12f0be95a70abf23238c5efTimo Sirainen const struct imap_arg *list_args;
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen unsigned int list_count;
212e9e43a7d49242446331fd43ba519eda936d60Timo Sirainen const char *str, *p, *error;
a406615fbcef37b1d12f0be95a70abf23238c5efTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_assert(strncmp(ctx->name, "BINARY", 6) == 0);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen p = ctx->name + 6;
42270b2d8d9bb0d04b16e0ead727154b32399a3fTimo Sirainen
42270b2d8d9bb0d04b16e0ead727154b32399a3fTimo Sirainen body = p_new(ctx->pool, struct imap_fetch_body_data, 1);
42270b2d8d9bb0d04b16e0ead727154b32399a3fTimo Sirainen body->binary = TRUE;
42270b2d8d9bb0d04b16e0ead727154b32399a3fTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (strncmp(p, ".SIZE", 5) == 0) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* fetch decoded size of the section */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen p += 5;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen body->binary_size = TRUE;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen } else if (strncmp(p, ".PEEK", 5) == 0) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen p += 5;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen } else {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ctx->fetch_ctx->flags_update_seen = TRUE;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (*p != '[') {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ctx->error = "Invalid BINARY[..] parameter: Missing '['";
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return FALSE;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (imap_arg_get_list_full(&ctx->args[0], &list_args, &list_count)) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* BINARY[HEADER.FIELDS.. (headers list)] */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (!imap_arg_get_atom(&ctx->args[1], &str) ||
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen str[0] != ']') {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ctx->error = "Invalid BINARY[..] parameter: Missing ']'";
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return FALSE;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (body_header_fields_parse(ctx, body, p+1,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen list_args, list_count) < 0)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return FALSE;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen p = str+1;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ctx->args += 2;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen } else {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* no headers list */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen body->section = p+1;
4182d8cd818e76856a5a1e25b343fe5ddf69fd8eTimo Sirainen p = strchr(body->section, ']');
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (p == NULL) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ctx->error = "Invalid BINARY[..] parameter: Missing ']'";
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return FALSE;
a406615fbcef37b1d12f0be95a70abf23238c5efTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen body->section = p_strdup_until(ctx->pool, body->section, p);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen p++;
a406615fbcef37b1d12f0be95a70abf23238c5efTimo Sirainen }
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (imap_msgpart_parse(body->section, &body->msgpart) < 0) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen ctx->error = "Invalid BINARY[..] section";
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return FALSE;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen }
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen imap_msgpart_set_decode_to_binary(body->msgpart);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen ctx->fetch_ctx->fetch_data |=
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen imap_msgpart_get_fetch_data(body->msgpart);
a406615fbcef37b1d12f0be95a70abf23238c5efTimo Sirainen
a406615fbcef37b1d12f0be95a70abf23238c5efTimo Sirainen if (!body->binary_size) {
a406615fbcef37b1d12f0be95a70abf23238c5efTimo Sirainen if (body_parse_partial(body, p, &error) < 0) {
a406615fbcef37b1d12f0be95a70abf23238c5efTimo Sirainen ctx->error = p_strdup_printf(ctx->pool,
a406615fbcef37b1d12f0be95a70abf23238c5efTimo Sirainen "Invalid BINARY[..] parameter: %s", error);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return FALSE;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen }
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
d22301419109ed4a38351715e6760011421dadecTimo Sirainen /* update the section name for the imap_fetch_add_handler() */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ctx->name = p_strdup(ctx->pool, get_body_name(body));
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (body->binary_size) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen imap_fetch_add_handler(ctx, IMAP_FETCH_HANDLER_FLAG_WANT_DEINIT,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen "0", fetch_binary_size, body);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen } else {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen imap_fetch_add_handler(ctx, IMAP_FETCH_HANDLER_FLAG_WANT_DEINIT,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen "NIL", fetch_body_msgpart, body);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return TRUE;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen}
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic int ATTR_NULL(3)
817d027593510c3ba70ad542ce0011f5f6916d1eTimo Sirainenfetch_rfc822_size(struct imap_fetch_context *ctx, struct mail *mail,
817d027593510c3ba70ad542ce0011f5f6916d1eTimo Sirainen void *context ATTR_UNUSED)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen{
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen uoff_t size;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (mail_get_virtual_size(mail, &size) < 0)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return -1;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen str_printfa(ctx->state.cur_str, "RFC822.SIZE %"PRIuUOFF_T" ", size);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return 1;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen}
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic int
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenfetch_and_free_msgpart(struct imap_fetch_context *ctx,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen struct mail *mail, struct imap_msgpart **_msgpart)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen{
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen struct imap_msgpart_open_result result;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen int ret;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ret = imap_msgpart_open(mail, *_msgpart, &result);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen imap_msgpart_free(_msgpart);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (ret < 0)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return -1;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ctx->state.cur_input = result.input;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ctx->state.cur_size = result.size;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ctx->state.cur_size_field = result.size_field;
3e1d94509fd76c56f2eb54f98ea02ade9ac2d44aTimo Sirainen ctx->state.cont_handler = fetch_stream_continue;
3e1d94509fd76c56f2eb54f98ea02ade9ac2d44aTimo Sirainen return 0;
3e1d94509fd76c56f2eb54f98ea02ade9ac2d44aTimo Sirainen}
3e1d94509fd76c56f2eb54f98ea02ade9ac2d44aTimo Sirainen
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainenstatic int ATTR_NULL(3)
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainenfetch_rfc822(struct imap_fetch_context *ctx, struct mail *mail,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen void *context ATTR_UNUSED)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen{
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen struct imap_msgpart *msgpart;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen const char *str;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen msgpart = imap_msgpart_full();
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (fetch_and_free_msgpart(ctx, mail, &msgpart) < 0)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return -1;
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen str = t_strdup_printf(" RFC822 {%"PRIuUOFF_T"}\r\n",
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen ctx->state.cur_size);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (ctx->state.cur_first) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen str++; ctx->state.cur_first = FALSE;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen }
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen o_stream_nsend_str(ctx->client->output, str);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen fetch_state_update_stats(ctx, msgpart);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ctx->state.cur_human_name = "RFC822";
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return ctx->state.cont_handler(ctx);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen}
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainenstatic int ATTR_NULL(3)
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainenfetch_rfc822_header(struct imap_fetch_context *ctx,
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen struct mail *mail, void *context ATTR_UNUSED)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen{
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen struct imap_msgpart *msgpart;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen const char *str;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen msgpart = imap_msgpart_header();
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (fetch_and_free_msgpart(ctx, mail, &msgpart) < 0)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return -1;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen str = t_strdup_printf(" RFC822.HEADER {%"PRIuUOFF_T"}\r\n",
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen ctx->state.cur_size);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (ctx->state.cur_first) {
e3736b5d480878031c386ac55d201fcf08e68766Timo Sirainen str++; ctx->state.cur_first = FALSE;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen }
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen o_stream_nsend_str(ctx->client->output, str);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen fetch_state_update_stats(ctx, msgpart);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen ctx->state.cur_human_name = "RFC822.HEADER";
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return ctx->state.cont_handler(ctx);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen}
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainenstatic int ATTR_NULL(3)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainenfetch_rfc822_text(struct imap_fetch_context *ctx, struct mail *mail,
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen void *context ATTR_UNUSED)
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen{
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen struct imap_msgpart *msgpart;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen const char *str;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen msgpart = imap_msgpart_body();
e3736b5d480878031c386ac55d201fcf08e68766Timo Sirainen if (fetch_and_free_msgpart(ctx, mail, &msgpart) < 0)
e3736b5d480878031c386ac55d201fcf08e68766Timo Sirainen return -1;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen str = t_strdup_printf(" RFC822.TEXT {%"PRIuUOFF_T"}\r\n",
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen ctx->state.cur_size);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (ctx->state.cur_first) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen str++; ctx->state.cur_first = FALSE;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen }
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen o_stream_nsend_str(ctx->client->output, str);
e3736b5d480878031c386ac55d201fcf08e68766Timo Sirainen fetch_state_update_stats(ctx, msgpart);
e3736b5d480878031c386ac55d201fcf08e68766Timo Sirainen
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen ctx->state.cur_human_name = "RFC822.TEXT";
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen return ctx->state.cont_handler(ctx);
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen}
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainenbool imap_fetch_rfc822_init(struct imap_fetch_init_context *ctx)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen{
fb7dd075cf883e5e7defbc0c8fb8326e30bdccdeTimo Sirainen const char *name = ctx->name;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (name[6] == '\0') {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen ctx->fetch_ctx->fetch_data |= MAIL_FETCH_STREAM_HEADER |
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen MAIL_FETCH_STREAM_BODY;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen ctx->fetch_ctx->flags_update_seen = TRUE;
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen imap_fetch_add_handler(ctx, 0, "NIL",
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen fetch_rfc822, (void *)NULL);
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen return TRUE;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen }
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (strcmp(name+6, ".SIZE") == 0) {
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen ctx->fetch_ctx->fetch_data |= MAIL_FETCH_VIRTUAL_SIZE;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen imap_fetch_add_handler(ctx, IMAP_FETCH_HANDLER_FLAG_BUFFERED,
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen "0", fetch_rfc822_size, (void *)NULL);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return TRUE;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen }
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen if (strcmp(name+6, ".HEADER") == 0) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen ctx->fetch_ctx->fetch_data |= MAIL_FETCH_STREAM_HEADER;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen imap_fetch_add_handler(ctx, 0, "NIL",
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen fetch_rfc822_header, (void *)NULL);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return TRUE;
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen }
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen if (strcmp(name+6, ".TEXT") == 0) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen ctx->fetch_ctx->fetch_data |= MAIL_FETCH_STREAM_BODY;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen ctx->fetch_ctx->flags_update_seen = TRUE;
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen imap_fetch_add_handler(ctx, 0, "NIL",
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen fetch_rfc822_text, (void *)NULL);
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen return TRUE;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen }
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen ctx->error = t_strconcat("Unknown parameter ", name, NULL);
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen return FALSE;
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen}
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen