index-attachment.c revision 4307c886579381dbb1897ea1388ae6978c96f560
/* Copyright (c) 2010-2012 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "safe-mkstemp.h"
#include "fs-api.h"
#include "istream.h"
#include "ostream.h"
#include "base64.h"
#include "hash-format.h"
#include "str.h"
#include "message-parser.h"
#include "rfc822-parser.h"
#include "mail-user.h"
#include "index-mail.h"
#include "index-attachment.h"
#define BASE64_ATTACHMENT_MAX_EXTRA_BYTES 1024
enum mail_attachment_state {
};
enum base64_state {
BASE64_STATE_0 = 0,
};
struct mail_save_attachment_part {
char *content_type, *content_disposition;
enum mail_attachment_state state;
/* start offset of the message part in the original input stream */
/* for saving attachments base64-decoded: */
enum base64_state base64_state;
unsigned int base64_line_blocks, cur_base64_blocks;
bool base64_have_crlf; /* CRLF linefeeds */
bool base64_failed;
int temp_fd;
struct hash_format *part_hash;
};
struct mail_save_attachment {
struct message_parser_ctx *parser;
/* per-MIME part data */
struct mail_save_attachment_part part;
struct message_part *prev_part;
};
{
}
{
return;
}
const struct message_header_line *hdr)
{
struct rfc822_parser_context parser;
T_BEGIN {
}
} T_END;
}
static void
const struct message_header_line *hdr)
{
/* just pass it as-is to backend. */
}
struct message_header_line *hdr)
{
return;
}
if (!hdr->no_newline) {
if (hdr->crlf_newline)
else
}
}
struct message_part *part)
{
struct mail_attachment_part apart;
/* multiparts may contain attachments as children,
but they're never themselves */
return FALSE;
}
return TRUE;
}
{
int fd;
if (fd == -1) {
return -1;
}
i_close_fd(&fd);
return -1;
}
return fd;
}
static struct hash_format *
{
struct hash_format *format;
const char *error;
/* we already checked this when verifying settings */
i_panic("mail_attachment_hash=%s unexpectedly failed: %s",
}
return format;
}
{
int fd;
if (fd == -1)
return -1;
return 0;
}
{
if (o_stream_nfinish(output) == 0)
return 0;
if (!mail_storage_set_error_from_errno(storage)) {
}
return -1;
}
{
struct hash_format *hash;
const unsigned char *data;
int outfd;
/* only a small part of the MIME part is base64-encoded. */
return -1;
}
if (part->base64_line_blocks == 0) {
/* only one line of base64 */
}
/* decode base64 data and write it to another temp file */
if (outfd == -1)
return -1;
buffer_set_used_size(buf, 0);
"Attachment base64 data unexpectedly broke");
break;
}
}
if (ret != -1) {
} else if (base64_input->stream_errno != 0) {
"read(attachment-temp) failed: %m");
}
buffer_free(&buf);
/* write the rest of the data to the message stream */
}
if (input->stream_errno != 0) {
"read(attachment-temp) failed: %m");
}
}
if (failed) {
"close(attachment-temp) failed: %m");
}
return -1;
}
/* successfully wrote it. switch to using it. */
"close(attachment-decoded-temp) failed: %m");
}
}
return 0;
}
{
const unsigned char *data;
int ret = 0;
return -1;
if (!part->base64_failed) {
part->base64_bytes > 0) {
/* there is no trailing LF or '=' characters,
but it's not completely empty */
}
/* base64 data looks ok. */
if (index_attachment_base64_decode(ctx) < 0)
} else {
}
}
/* open the attachment destination file */
/* make sure we can access first 4 bytes without accessing
out of bounds memory */
}
return -1;
}
/* copy data to it from temp file */
}
if (input->stream_errno != 0) {
ret = -1;
}
if (ret < 0)
ret = -1;
}
if (ret == 0) {
struct mail_attachment_extref *extref;
}
return ret;
}
static int
{
switch (part->base64_state) {
case BASE64_STATE_0:
if (base64_is_valid_char(chr))
part->base64_state++;
else if (chr == '\r')
else if (chr == '\n') {
if (part->cur_base64_blocks <
/* last line */
return 0;
} else if (part->base64_line_blocks == 0) {
/* first line */
if (part->cur_base64_blocks == 0)
return -1;
} else if (part->cur_base64_blocks ==
/* line is ok */
} else {
return -1;
}
part->cur_base64_blocks = 0;
} else {
return -1;
}
break;
case BASE64_STATE_1:
if (!base64_is_valid_char(chr))
return -1;
part->base64_state++;
break;
case BASE64_STATE_2:
if (base64_is_valid_char(chr))
part->base64_state++;
else if (chr == '=')
else
return -1;
break;
case BASE64_STATE_3:
if (base64_is_valid_char(chr)) {
} else if (chr == '=') {
return 0;
} else {
return -1;
}
break;
case BASE64_STATE_CR:
if (chr != '\n')
return -1;
break;
case BASE64_STATE_EOB:
if (chr != '=')
return -1;
return 0;
case BASE64_STATE_EOM:
i_unreached();
}
return 1;
}
static void
{
size_t i;
int ret;
return;
for (i = 0; i < size; i++) {
(char)data[i]);
if (ret <= 0) {
if (ret < 0)
break;
}
}
}
const struct message_block *block)
{
case MAIL_ATTACHMENT_STATE_NO:
break;
}
break;
}
/* attachment is large enough. we'll first write it to
temp file. */
if (index_attachment_save_temp_open(ctx) < 0) {
/* failed, fallback to just saving it inline */
break;
}
/* fall through */
break;
}
}
{
"close(attachment-temp) failed: %m");
}
}
static int
{
int ret = 0;
/* body part changed. we're now parsing the end of a
boundary, possibly followed by message epilogue */
case MAIL_ATTACHMENT_STATE_NO:
break;
/* body part wasn't large enough. write to main file. */
}
break;
if (index_attachment_save_finish_part(ctx) < 0)
ret = -1;
break;
}
return ret;
}
{
struct message_block block;
int ret;
if (index_attachment_save_body_part_changed(ctx) < 0)
return -1;
}
/* end of headers */
}
} else {
/* body */
}
if (output->last_failed_errno != 0)
break;
}
if (ret == 0)
return 0;
return -1;
}
return -1;
}
return -1;
}
return 0;
}
{
struct message_part *parts;
if (index_attachment_save_body_part_changed(ctx) < 0)
ret = -1;
}
return ret;
}
{
}
}
const ARRAY_TYPE(mail_attachment_extref) *
{
}
static int
{
const char *path, *p, *attachment_dir;
int ret;
/* if the directory is now empty, rmdir it and its parents
until it fails */
break;
/* success, continue to parent */
/* there are other entries in this directory */
break;
} else {
fs_last_error(fs));
break;
}
}
return ret;
}
{
int ret;
T_BEGIN {
} T_END;
return ret;
}