/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "str.h"
#include "safe-mkstemp.h"
#include "istream.h"
#include "istream-crlf.h"
#include "istream-seekable.h"
#include "istream-base64.h"
#include "istream-qp.h"
#include "istream-header-filter.h"
#include "ostream.h"
#include "message-binary-part.h"
#include "message-parser.h"
#include "message-decoder.h"
#include "mail-user.h"
#include "index-storage.h"
#include "index-mail.h"
struct binary_block {
unsigned int body_lines_count;
};
struct binary_ctx {
/* each block is its own input stream. basically each converted MIME
body has its own block and the parts between the MIME bodies are
unconverted blocks */
};
{
return;
}
static void
struct message_header_line *hdr,
{
strlen(cte_binary));
}
}
static int
bool include_hdr)
{
static const char *filter_headers[] = {
"Content-Transfer-Encoding",
};
int ret;
/* first parse the header to find c-t-e. */
}
if (message_parse_header_has_nuls(parser)) {
/* we're not converting NULs to 0x80 when doing a binary fetch,
even if they're in the message header. */
}
return -1;
}
if (cte == MESSAGE_CTE_UNKNOWN) {
"Unknown Content-Transfer-Encoding.");
return -1;
}
if (!include_hdr) {
/* body only */
} else if (IS_CONVERTED_CTE(cte)) {
/* write header with modified content-type */
if (ctx->copy_start_offset != 0)
} else {
/* copy everything as-is until the end of this header */
}
/* multipart */
return -1;
}
return 0;
}
/* no body */
return 0;
}
/* single part - write decoded data */
switch (cte) {
case MESSAGE_CTE_UNKNOWN:
i_unreached();
case MESSAGE_CTE_78BIT:
case MESSAGE_CTE_BINARY:
/* no conversion necessary */
break;
case MESSAGE_CTE_QP:
break;
case MESSAGE_CTE_BASE64:
break;
}
return 0;
}
{
int fd;
if (fd == -1) {
return -1;
}
/* we just want the fd, unlink it */
/* shouldn't happen.. */
i_close_fd(&fd);
return -1;
}
return fd;
}
{
}
static void
struct message_binary_part **msg_bin_parts)
{
unsigned int i, count;
bool found;
/* default to unchanged header */
for (i = 0; i < count; i++) {
continue;
if (blocks[i].converted_hdr)
else
}
if (found) {
struct message_binary_part, 1);
**msg_bin_parts = bin_part;
}
}
}
{
}
{
unsigned int i, count;
for (i = 0; i < count; i++) {
}
return streams;
}
static int
{
const unsigned char *data, *p;
cur_block_offset = 0;
block_idx = 0;
/* count the number of lines each block contains */
/* this is the last input for this block. the input
may also contain the next block's data, which we
don't want to include in this block's line count. */
}
data = p+1;
}
cur_block_offset += skip;
/* go to the next block */
if (++block_idx == block_count) {
ret = -1;
break;
}
cur_block++;
cur_block_offset = 0;
}
}
if (full_input->stream_errno != 0)
return -1;
return 0;
}
static int
const struct message_part *part,
bool include_hdr, const char *reason,
bool *binary_r, bool *converted_r)
{
return -1;
return -1;
}
fd_callback, _mail);
} else {
}
"<binary stream of mailbox %s UID %u>",
/* MIME part contains invalid data */
"Invalid data in MIME part");
} else {
}
i_stream_unref(&is);
return -1;
}
}
i_stream_seek(is, 0);
}
return 0;
}
{
const unsigned int field_idx =
int ret;
return TRUE;
if (ret <= 0)
return FALSE;
"Corrupted cached binary.parts data");
return FALSE;
}
return TRUE;
}
static struct message_part *
{
return part;
return child;
}
return NULL;
}
static int
{
unsigned int lines;
return -1;
/* first lookup from cache */
if (!get_cached_binary_parts(mail)) {
/* not found. parse the whole message */
return -1;
}
/* note that we assume here that binary translation doesn't change the
headers' line counts. this isn't true if the original message
contained duplicate Content-Transfer-Encoding lines, but since
that's invalid anyway we don't bother trying to handle it. */
/* either binary.parts or mime.parts is broken */
bin_part->physical_pos));
return -1;
}
}
}
if (!include_hdr) {
if (root_bin_part != NULL)
else
}
return 0;
}
const struct message_part *part,
{
}
/* current implementation doesn't bother implementing this,
because it's not needed by anything. */
/* FIXME: always put the header to temp file. skip it when needed. */
/* we have this cached already */
} else {
return -1;
}
if (!converted) {
/* don't keep this cached. it's exactly the same as
the original stream */
(include_hdr ? 0 :
} else {
}
return 0;
}