bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2010-2018 Dovecot authors, see the included COPYING file */
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenstatic const char *index_attachment_dir_get(struct mail_storage *storage)
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainenstatic bool index_attachment_want(const struct istream_attachment_header *hdr,
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen apart.content_disposition = hdr->content_disposition;
cf64e39cef453f5a4704ea52b81b188ca411cb15Timo Sirainen /* don't treat text/ parts as attachments */
cf64e39cef453f5a4704ea52b81b188ca411cb15Timo Sirainen strncasecmp(hdr->content_type, "text/", 5) != 0;
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainenstatic int index_attachment_open_temp_fd(void *context)
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen struct mail_storage *storage = ctx->transaction->box->storage;
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);
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mailbox_set_critical(ctx->transaction->box,
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen "safe_mkstemp(%s) failed: %m", str_c(temp_path));
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mailbox_set_critical(ctx->transaction->box,
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainenindex_attachment_open_ostream(struct istream_attachment_info *info,
0482d891a6669537e10a1abc9866b45f2fc55fccTimo Sirainen const char **error_r ATTR_UNUSED, void *context)
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen struct mail_save_attachment *attach = ctx->data.attach;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen struct mail_storage *storage = ctx->transaction->box->storage;
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen const char *attachment_dir, *path, *digest = info->hash;
d11111fc5356108b6408a58b4ff1811d5b5678edTimo Sirainen if (storage->set->parsed_fsync_mode != FSYNC_MODE_NEVER)
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 attachment_dir = index_attachment_dir_get(storage);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen path = t_strdup_printf("%s/%c%c/%c%c/%s-%s", attachment_dir,
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen attach->cur_file = fs_file_init(attach->fs, path,
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen extref = array_append_space(&attach->extrefs);
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen extref->base64_blocks_per_line = info->base64_blocks_per_line;
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen extref->base64_have_crlf = info->base64_have_crlf;
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen *output_r = fs_write_stream(attach->cur_file);
0482d891a6669537e10a1abc9866b45f2fc55fccTimo Sirainenindex_attachment_close_ostream(struct ostream *output, bool success,
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen struct mail_save_attachment *attach = ctx->data.attach;
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",
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainenvoid index_attachment_save_begin(struct mail_save_context *ctx,
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen struct mail_storage *storage = ctx->transaction->box->storage;
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen if (*storage->set->mail_attachment_dir == '\0')
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen set.min_size = storage->set->mail_attachment_min_size;
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen if (hash_format_init(storage->set->mail_attachment_hash,
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen /* we already checked this when verifying settings */
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen i_panic("mail_attachment_hash=%s unexpectedly failed: %s",
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;
338088fe2875e8039d2b3df32cbd7a8396b24ea6Timo Sirainen pool = pool_alloconly_create("save attachment", 1024);
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen attach = p_new(pool, struct mail_save_attachment, 1);
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen attach->input = i_stream_create_attachment_extractor(input, &set, ctx);
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen p_array_init(&attach->extrefs, attach->pool, 8);
1260d509fa7122ddeee3b91e7d2b021d354102dcMartti Rannanjärvistatic int save_check_write_error(struct mail_save_context *ctx,
1260d509fa7122ddeee3b91e7d2b021d354102dcMartti Rannanjärvi struct mail_storage *storage = ctx->transaction->box->storage;
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 Sirainenint index_attachment_save_continue(struct mail_save_context *ctx)
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen struct mail_save_attachment *attach = ctx->data.attach;
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen data = i_stream_get_data(attach->input, &size);
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 */
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mail_set_critical(ctx->dest_mail, "read(%s) failed: %s",
1260d509fa7122ddeee3b91e7d2b021d354102dcMartti Rannanjärvi if (save_check_write_error(ctx, ctx->data.output) < 0)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenint index_attachment_save_finish(struct mail_save_context *ctx)
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen struct mail_save_attachment *attach = ctx->data.attach;
0482d891a6669537e10a1abc9866b45f2fc55fccTimo Sirainen return attach->input->stream_errno == 0 ? 0 : -1;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenvoid index_attachment_save_free(struct mail_save_context *ctx)
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen struct mail_save_attachment *attach = ctx->data.attach;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenindex_attachment_save_get_extrefs(struct mail_save_context *ctx)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenindex_attachment_delete_real(struct mail_storage *storage,
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);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen mail_storage_set_critical(storage, "%s", fs_last_error(fs));
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenint index_attachment_delete(struct mail_storage *storage,
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen ret = index_attachment_delete_real(storage, fs, name);
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainenvoid index_attachment_append_extrefs(string_t *str,
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen const ARRAY_TYPE(mail_attachment_extref) *extrefs)
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen str_printfa(str, "%"PRIuUOFF_T" %"PRIuUOFF_T" ",
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen str_append_c(str, MAIL_ATTACHMENT_DECODE_OPTION_CRLF);
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen /* make it clear there are no options */
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen str_append_c(str, MAIL_ATTACHMENT_DECODE_OPTION_NONE);
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen if (*str == MAIL_ATTACHMENT_DECODE_OPTION_NONE)
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainenbool index_attachment_parse_extrefs(const char *line, pool_t pool,
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen if (str_to_uoff(start_offset_str, &extref.start_offset) < 0 ||
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen !parse_extref_decode_options(decode_options, &extref))
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainenint index_attachment_stream_get(struct fs *fs, const char *attachment_dir,
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen ARRAY_TYPE(mail_attachment_extref) extrefs_arr;
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen if (!index_attachment_parse_extrefs(ext_refs, pool_datastack_create(),
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen conn = istream_attachment_connector_begin(*stream, full_size);
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen path = t_strdup_printf("%s/%s%s", attachment_dir,
fffb5431af081379c169d0d96aafe2a9a7352be2Timo Sirainen file = fs_file_init(fs, path, FS_OPEN_MODE_READONLY |
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen input = i_stream_create_fs_file(&file, IO_BLOCK_SIZE);
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen ret = istream_attachment_connector_add(conn, input,
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen input = istream_attachment_connector_finish(&conn);
08a4f9396a805b2ac70d55fd494637321ada6516Timo Sirainen "attachments-connector(%s)", i_stream_get_name(*stream)));