bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2010-2018 Dovecot authors, see the included COPYING file */
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen#include "lib.h"
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen#include "safe-mkstemp.h"
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen#include "fs-api.h"
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen#include "istream.h"
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen#include "ostream.h"
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen#include "base64.h"
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen#include "hash-format.h"
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen#include "str.h"
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen#include "message-parser.h"
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen#include "rfc822-parser.h"
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen#include "fs-api.h"
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen#include "istream-fs-file.h"
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen#include "istream-attachment-connector.h"
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen#include "istream-attachment-extractor.h"
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen#include "mail-user.h"
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen#include "index-mail.h"
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen#include "index-attachment.h"
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainenenum mail_attachment_decode_option {
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen MAIL_ATTACHMENT_DECODE_OPTION_NONE = '-',
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen MAIL_ATTACHMENT_DECODE_OPTION_BASE64 = 'B',
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen MAIL_ATTACHMENT_DECODE_OPTION_CRLF = 'C'
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen};
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenstruct mail_save_attachment {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen pool_t pool;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen struct fs *fs;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen struct istream *input;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen struct fs_file *cur_file;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen ARRAY_TYPE(mail_attachment_extref) extrefs;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen};
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenstatic const char *index_attachment_dir_get(struct mail_storage *storage)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen{
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen return mail_user_home_expand(storage->user,
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen storage->set->mail_attachment_dir);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen}
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainenstatic bool index_attachment_want(const struct istream_attachment_header *hdr,
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen void *context)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen{
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen struct mail_save_context *ctx = context;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen struct mail_attachment_part apart;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&apart);
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen apart.part = hdr->part;
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen apart.content_type = hdr->content_type;
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen apart.content_disposition = hdr->content_disposition;
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen
cf64e39cef453f5a4704ea52b81b188ca411cb15Timo Sirainen if (ctx->part_is_attachment != NULL)
cf64e39cef453f5a4704ea52b81b188ca411cb15Timo Sirainen return ctx->part_is_attachment(ctx, &apart);
cf64e39cef453f5a4704ea52b81b188ca411cb15Timo Sirainen
cf64e39cef453f5a4704ea52b81b188ca411cb15Timo Sirainen /* don't treat text/ parts as attachments */
cf64e39cef453f5a4704ea52b81b188ca411cb15Timo Sirainen return hdr->content_type != NULL &&
cf64e39cef453f5a4704ea52b81b188ca411cb15Timo Sirainen strncasecmp(hdr->content_type, "text/", 5) != 0;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen}
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainenstatic int index_attachment_open_temp_fd(void *context)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen{
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen struct mail_save_context *ctx = context;
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen struct mail_storage *storage = ctx->transaction->box->storage;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen string_t *temp_path;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen int fd;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen temp_path = t_str_new(256);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen mail_user_set_get_temp_prefix(temp_path, storage->user->set);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen fd = safe_mkstemp_hostpid(temp_path, 0600, (uid_t)-1, (gid_t)-1);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (fd == -1) {
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mailbox_set_critical(ctx->transaction->box,
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen "safe_mkstemp(%s) failed: %m", str_c(temp_path));
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen return -1;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen }
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (unlink(str_c(temp_path)) < 0) {
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mailbox_set_critical(ctx->transaction->box,
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen "unlink(%s) failed: %m", str_c(temp_path));
4307c886579381dbb1897ea1388ae6978c96f560Timo Sirainen i_close_fd(&fd);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen return -1;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen }
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen return fd;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen}
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainenstatic int
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainenindex_attachment_open_ostream(struct istream_attachment_info *info,
0482d891a6669537e10a1abc9866b45f2fc55fccTimo Sirainen struct ostream **output_r,
0482d891a6669537e10a1abc9866b45f2fc55fccTimo Sirainen const char **error_r ATTR_UNUSED, void *context)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen{
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen struct mail_save_context *ctx = context;
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen struct mail_save_attachment *attach = ctx->data.attach;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen struct mail_storage *storage = ctx->transaction->box->storage;
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen struct mail_attachment_extref *extref;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen enum fs_open_flags flags = 0;
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen const char *attachment_dir, *path, *digest = info->hash;
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen guid_128_t guid_128;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen i_assert(attach->cur_file == NULL);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
d11111fc5356108b6408a58b4ff1811d5b5678edTimo Sirainen if (storage->set->parsed_fsync_mode != FSYNC_MODE_NEVER)
d11111fc5356108b6408a58b4ff1811d5b5678edTimo Sirainen flags |= FS_OPEN_FLAG_FSYNC;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (strlen(digest) < 4) {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen /* make sure we can access first 4 bytes without accessing
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen out of bounds memory */
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen digest = t_strconcat(digest, "\0\0\0\0", NULL);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen }
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
de62ce819d59a529530da4b57be1b8d6dad13d6bTimo Sirainen guid_128_generate(guid_128);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen attachment_dir = index_attachment_dir_get(storage);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen path = t_strdup_printf("%s/%c%c/%c%c/%s-%s", attachment_dir,
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen digest[0], digest[1],
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen digest[2], digest[3], digest,
de62ce819d59a529530da4b57be1b8d6dad13d6bTimo Sirainen guid_128_to_string(guid_128));
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen attach->cur_file = fs_file_init(attach->fs, path,
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen FS_OPEN_MODE_REPLACE | flags);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen extref = array_append_space(&attach->extrefs);
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen extref->start_offset = info->start_offset;
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen extref->size = info->encoded_size;
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen extref->path = p_strdup(attach->pool,
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen path + strlen(attachment_dir) + 1);
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen extref->base64_blocks_per_line = info->base64_blocks_per_line;
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen extref->base64_have_crlf = info->base64_have_crlf;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen *output_r = fs_write_stream(attach->cur_file);
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen return 0;
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen}
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainenstatic int
0482d891a6669537e10a1abc9866b45f2fc55fccTimo Sirainenindex_attachment_close_ostream(struct ostream *output, bool success,
2d349bb70f5345887bd14973540ffa7528be2677Timo Sirainen const char **error, void *context)
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen{
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen struct mail_save_context *ctx = context;
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen struct mail_save_attachment *attach = ctx->data.attach;
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen int ret = success ? 0 : -1;
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen i_assert(attach->cur_file != NULL);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (ret < 0)
2d349bb70f5345887bd14973540ffa7528be2677Timo Sirainen fs_write_stream_abort_error(attach->cur_file, &output, "%s", *error);
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen else if (fs_write_stream_finish(attach->cur_file, &output) < 0) {
2d349bb70f5345887bd14973540ffa7528be2677Timo Sirainen *error = t_strdup_printf("Couldn't create attachment %s: %s",
2d349bb70f5345887bd14973540ffa7528be2677Timo Sirainen fs_file_path(attach->cur_file),
2d349bb70f5345887bd14973540ffa7528be2677Timo Sirainen fs_file_last_error(attach->cur_file));
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen ret = -1;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen }
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs_file_deinit(&attach->cur_file);
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen if (ret < 0) {
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen array_delete(&attach->extrefs,
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen array_count(&attach->extrefs)-1, 1);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen }
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen return ret;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen}
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainenvoid index_attachment_save_begin(struct mail_save_context *ctx,
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen struct fs *fs, struct istream *input)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen{
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen struct mail_storage *storage = ctx->transaction->box->storage;
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen struct mail_save_attachment *attach;
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen struct istream_attachment_settings set;
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen const char *error;
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen pool_t pool;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen i_assert(ctx->data.attach == NULL);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen if (*storage->set->mail_attachment_dir == '\0')
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen return;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&set);
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen set.min_size = storage->set->mail_attachment_min_size;
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen if (hash_format_init(storage->set->mail_attachment_hash,
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen &set.hash_format, &error) < 0) {
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen /* we already checked this when verifying settings */
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen i_panic("mail_attachment_hash=%s unexpectedly failed: %s",
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen storage->set->mail_attachment_hash, error);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen }
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen set.want_attachment = index_attachment_want;
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen set.open_temp_fd = index_attachment_open_temp_fd;
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen set.open_attachment_ostream = index_attachment_open_ostream;
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen set.close_attachment_ostream = index_attachment_close_ostream;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen pool = pool_alloconly_create("save attachment", 1024);
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen attach = p_new(pool, struct mail_save_attachment, 1);
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen attach->pool = pool;
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen attach->fs = fs;
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen attach->input = i_stream_create_attachment_extractor(input, &set, ctx);
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen p_array_init(&attach->extrefs, attach->pool, 8);
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen ctx->data.attach = attach;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen}
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
1260d509fa7122ddeee3b91e7d2b021d354102dcMartti Rannanjärvistatic int save_check_write_error(struct mail_save_context *ctx,
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen struct ostream *output)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen{
1260d509fa7122ddeee3b91e7d2b021d354102dcMartti Rannanjärvi struct mail_storage *storage = ctx->transaction->box->storage;
1260d509fa7122ddeee3b91e7d2b021d354102dcMartti Rannanjärvi
f988b93c2ef773987bcdcbfb4cca39b955e3a392Timo Sirainen if (output->stream_errno == 0)
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen return 0;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen if (!mail_storage_set_error_from_errno(storage)) {
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mail_set_critical(ctx->dest_mail, "write(%s) failed: %s",
0f3d4fbcf88e2ffd674893aed8cc1288fe17d290Timo Sirainen o_stream_get_name(output), o_stream_get_error(output));
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen }
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen return -1;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen}
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenint index_attachment_save_continue(struct mail_save_context *ctx)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen{
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen struct mail_save_attachment *attach = ctx->data.attach;
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen const unsigned char *data;
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen size_t size;
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen ssize_t ret;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
0482d891a6669537e10a1abc9866b45f2fc55fccTimo Sirainen if (attach->input->stream_errno != 0)
0482d891a6669537e10a1abc9866b45f2fc55fccTimo Sirainen return -1;
0482d891a6669537e10a1abc9866b45f2fc55fccTimo Sirainen
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen do {
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen ret = i_stream_read(attach->input);
7f74811b78f8915e73dffc88bb49009e98b6846dTimo Sirainen if (ret > 0 || ret == -2) {
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen data = i_stream_get_data(attach->input, &size);
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen o_stream_nsend(ctx->data.output, data, size);
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen i_stream_skip(attach->input, size);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen }
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen index_mail_cache_parse_continue(ctx->dest_mail);
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen if (ret == 0 && !i_stream_attachment_extractor_can_retry(attach->input)) {
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen /* need more input */
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen return 0;
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen }
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen } while (ret != -1);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
0482d891a6669537e10a1abc9866b45f2fc55fccTimo Sirainen if (attach->input->stream_errno != 0) {
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mail_set_critical(ctx->dest_mail, "read(%s) failed: %s",
0482d891a6669537e10a1abc9866b45f2fc55fccTimo Sirainen i_stream_get_name(attach->input),
0482d891a6669537e10a1abc9866b45f2fc55fccTimo Sirainen i_stream_get_error(attach->input));
0482d891a6669537e10a1abc9866b45f2fc55fccTimo Sirainen return -1;
0482d891a6669537e10a1abc9866b45f2fc55fccTimo Sirainen }
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen if (ctx->data.output != NULL) {
1260d509fa7122ddeee3b91e7d2b021d354102dcMartti Rannanjärvi if (save_check_write_error(ctx, ctx->data.output) < 0)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen return -1;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen }
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen return 0;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen}
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenint index_attachment_save_finish(struct mail_save_context *ctx)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen{
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen struct mail_save_attachment *attach = ctx->data.attach;
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen (void)i_stream_read(attach->input);
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen i_assert(attach->input->eof);
0482d891a6669537e10a1abc9866b45f2fc55fccTimo Sirainen return attach->input->stream_errno == 0 ? 0 : -1;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen}
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenvoid index_attachment_save_free(struct mail_save_context *ctx)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen{
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen struct mail_save_attachment *attach = ctx->data.attach;
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen if (attach != NULL) {
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen i_stream_unref(&attach->input);
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen pool_unref(&attach->pool);
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen ctx->data.attach = NULL;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen }
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen}
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenconst ARRAY_TYPE(mail_attachment_extref) *
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenindex_attachment_save_get_extrefs(struct mail_save_context *ctx)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen{
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen return ctx->data.attach == NULL ? NULL :
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen &ctx->data.attach->extrefs;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen}
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenstatic int
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenindex_attachment_delete_real(struct mail_storage *storage,
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen struct fs *fs, const char *name)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen{
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen struct fs_file *file;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen const char *path;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen int ret;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen path = t_strdup_printf("%s/%s", index_attachment_dir_get(storage), name);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen file = fs_file_init(fs, path, FS_OPEN_MODE_READONLY);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen if ((ret = fs_delete(file)) < 0)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen mail_storage_set_critical(storage, "%s", fs_last_error(fs));
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs_file_deinit(&file);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen return ret;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen}
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenint index_attachment_delete(struct mail_storage *storage,
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen struct fs *fs, const char *name)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen{
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen int ret;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen T_BEGIN {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen ret = index_attachment_delete_real(storage, fs, name);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen } T_END;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen return ret;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen}
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainenvoid index_attachment_append_extrefs(string_t *str,
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen const ARRAY_TYPE(mail_attachment_extref) *extrefs)
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen{
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen const struct mail_attachment_extref *extref;
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen bool add_space = FALSE;
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen unsigned int startpos;
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen array_foreach(extrefs, extref) {
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen if (!add_space)
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen add_space = TRUE;
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen else
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen str_append_c(str, ' ');
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen str_printfa(str, "%"PRIuUOFF_T" %"PRIuUOFF_T" ",
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen extref->start_offset, extref->size);
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen startpos = str_len(str);
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen if (extref->base64_have_crlf)
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen str_append_c(str, MAIL_ATTACHMENT_DECODE_OPTION_CRLF);
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen if (extref->base64_blocks_per_line > 0) {
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen str_printfa(str, "%c%u",
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen MAIL_ATTACHMENT_DECODE_OPTION_BASE64,
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen extref->base64_blocks_per_line * 4);
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen }
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen if (startpos == str_len(str)) {
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen /* make it clear there are no options */
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen str_append_c(str, MAIL_ATTACHMENT_DECODE_OPTION_NONE);
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen }
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen str_append_c(str, ' ');
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen str_append(str, extref->path);
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen }
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen}
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainenstatic bool
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainenparse_extref_decode_options(const char *str,
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen struct mail_attachment_extref *extref)
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen{
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen unsigned int num;
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen if (*str == MAIL_ATTACHMENT_DECODE_OPTION_NONE)
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen return str[1] == '\0';
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen while (*str != '\0') {
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen switch (*str) {
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen case MAIL_ATTACHMENT_DECODE_OPTION_BASE64:
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen str++; num = 0;
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen while (*str >= '0' && *str <= '9') {
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen num = num*10 + (*str-'0');
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen str++;
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen }
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen if (num == 0 || num % 4 != 0)
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen return FALSE;
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen extref->base64_blocks_per_line = num/4;
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen break;
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen case MAIL_ATTACHMENT_DECODE_OPTION_CRLF:
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen extref->base64_have_crlf = TRUE;
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen str++;
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen break;
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen default:
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen return FALSE;
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen }
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen }
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen return TRUE;
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen}
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainenbool index_attachment_parse_extrefs(const char *line, pool_t pool,
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen ARRAY_TYPE(mail_attachment_extref) *extrefs)
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen{
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen struct mail_attachment_extref extref;
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen const char *const *args;
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen unsigned int i, len;
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen uoff_t last_voffset;
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen args = t_strsplit(line, " ");
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen len = str_array_length(args);
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen if ((len % 4) != 0)
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen return FALSE;
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen last_voffset = 0;
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen for (i = 0; args[i] != NULL; i += 4) {
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen const char *start_offset_str = args[i+0];
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen const char *size_str = args[i+1];
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen const char *decode_options = args[i+2];
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen const char *path = args[i+3];
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&extref);
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen if (str_to_uoff(start_offset_str, &extref.start_offset) < 0 ||
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen str_to_uoff(size_str, &extref.size) < 0 ||
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen extref.start_offset < last_voffset ||
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen !parse_extref_decode_options(decode_options, &extref))
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen return FALSE;
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen last_voffset += extref.size +
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen (extref.start_offset - last_voffset);
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen extref.path = p_strdup(pool, path);
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen array_append(extrefs, &extref, 1);
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen }
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen return TRUE;
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen}
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainenint index_attachment_stream_get(struct fs *fs, const char *attachment_dir,
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen const char *path_suffix,
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen struct istream **stream, uoff_t full_size,
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen const char *ext_refs, const char **error_r)
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen{
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen ARRAY_TYPE(mail_attachment_extref) extrefs_arr;
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen const struct mail_attachment_extref *extref;
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen struct istream_attachment_connector *conn;
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen struct istream *input;
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen struct fs_file *file;
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen const char *path;
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen int ret;
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen *error_r = NULL;
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen t_array_init(&extrefs_arr, 16);
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen if (!index_attachment_parse_extrefs(ext_refs, pool_datastack_create(),
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen &extrefs_arr)) {
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen *error_r = "Broken ext-refs string";
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen return -1;
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen }
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen conn = istream_attachment_connector_begin(*stream, full_size);
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen array_foreach(&extrefs_arr, extref) {
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen path = t_strdup_printf("%s/%s%s", attachment_dir,
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen extref->path, path_suffix);
fffb5431af081379c169d0d96aafe2a9a7352be2Timo Sirainen file = fs_file_init(fs, path, FS_OPEN_MODE_READONLY |
fffb5431af081379c169d0d96aafe2a9a7352be2Timo Sirainen FS_OPEN_FLAG_SEEKABLE);
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen input = i_stream_create_fs_file(&file, IO_BLOCK_SIZE);
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen ret = istream_attachment_connector_add(conn, input,
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen extref->start_offset, extref->size,
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen extref->base64_blocks_per_line,
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen extref->base64_have_crlf, error_r);
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen i_stream_unref(&input);
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen if (ret < 0) {
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen istream_attachment_connector_abort(&conn);
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen return -1;
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen }
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen }
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen input = istream_attachment_connector_finish(&conn);
08a4f9396a805b2ac70d55fd494637321ada6516Timo Sirainen i_stream_set_name(input, t_strdup_printf(
08a4f9396a805b2ac70d55fd494637321ada6516Timo Sirainen "attachments-connector(%s)", i_stream_get_name(*stream)));
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen i_stream_unref(stream);
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen *stream = input;
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen return 0;
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen}