mbox-save.c revision aeab2134d21723e782b788616b83b4f4e17626ef
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/* Copyright (c) 2002-2013 Dovecot authors, see the included COPYING file */
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainenstatic void write_error(struct mbox_save_context *ctx)
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainenstatic int mbox_seek_to_end(struct mbox_save_context *ctx, uoff_t *offset)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenstatic int mbox_append_lf(struct mbox_save_context *ctx)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (o_stream_send(ctx->output, "\n", 1) < 0) {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenstatic int write_from_line(struct mbox_save_context *ctx, time_t received_date,
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen strchr(storage->user->username, '@') != NULL ?
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen /* can't write empty envelope */
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen /* save in local timezone, no matter what it was given with */
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen line = mbox_from_create(from_envelope, received_date);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if ((ret = o_stream_send_str(ctx->output, line)) < 0)
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainenstatic int mbox_write_content_length(struct mbox_save_context *ctx)
303a87c31cb4aa198326694e231df53a043e63c7Timo Sirainen const char *str;
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen /* we can't seek, don't set Content-Length */
303a87c31cb4aa198326694e231df53a043e63c7Timo Sirainen /* write Content-Length headers */
303a87c31cb4aa198326694e231df53a043e63c7Timo Sirainen /* flush manually here so that we don't confuse seek() errors with
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen buffer flushing errors */
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen if (o_stream_seek(ctx->output, ctx->extra_hdr_offset +
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (o_stream_send(ctx->output, str, len) < 0 ||
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen if (o_stream_seek(ctx->output, end_offset) < 0) {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenstatic void mbox_save_init_sync(struct mailbox_transaction_context *t)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen struct mbox_mailbox *mbox = (struct mbox_mailbox *)t->box;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen struct mbox_save_context *ctx = (struct mbox_save_context *)t->save_ctx;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen /* open a new view to get the header. this is required if we just
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen synced the mailbox so we can get updated next_uid. */
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenstatic void status_flags_append(string_t *str, enum mail_flags flags,
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainenstatic void mbox_save_append_flag_headers(string_t *str, enum mail_flags flags)
ba5c8b0ae7460752adaf911901bf263788f62c72Phil Carmody /* write the Status: header always. It always gets added soon anyway. */
8039af9679af6fb56116b353fe44f7dd4c08f031Timo Sirainen status_flags_append(str, flags, mbox_status_flags);
06e72c658de3ce1252594b151313df90acf73271Timo Sirainen status_flags_append(str, flags, mbox_xstatus_flags);
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainenmbox_save_append_keyword_headers(struct mbox_save_context *ctx,
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen sizeof("Content-Length: \n")-1 + MAX_INT_STRLEN];
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen const ARRAY_TYPE(keywords) *keyword_names_list;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen const char *const *keyword_names;
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen keyword_names_list = mail_index_get_keywords(ctx->mbox->box.index);
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen keyword_names = array_get(keyword_names_list, &keyword_names_count);
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen count = keywords == NULL ? 0 : keywords->count;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen for (i = 0; i < count; i++) {
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen i_assert(keywords->idx[i] < keyword_names_count);
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen str_append(ctx->headers, keyword_names[keywords->idx[i]]);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen str_append_n(ctx->headers, space, sizeof(space));
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainenmbox_save_init_file(struct mbox_save_context *ctx,
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen struct mbox_transaction_context *t, bool want_mail)
07974f50bd55b06fd6d465f2c0e491794786e2faTimo Sirainen struct mailbox_transaction_context *_t = &t->t;
07974f50bd55b06fd6d465f2c0e491794786e2faTimo Sirainen struct mail_storage *storage = &mbox->storage->storage;
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen mail_storage_set_error(storage, MAIL_ERROR_PERM,
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen "Read-only mbox");
2d9644d34a78b24dc7769cd96497e700a0fb1cf1Timo Sirainen if ((_t->flags & MAILBOX_TRANSACTION_FLAG_ASSIGN_UIDS) != 0 ||
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen /* first appended mail in this transaction */
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen if (mbox_lock(mbox, F_WRLCK, &t->write_lock_id) <= 0)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen /* update mbox_sync_dirty state */
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen ret = mbox_sync_has_changed_full(mbox, TRUE, &empty);
7891195e3975d554df183670dba1fcecfa0a30c3Timo Sirainen /* we're not required to assign UIDs for the appended
7891195e3975d554df183670dba1fcecfa0a30c3Timo Sirainen mails immediately. do it only if it doesn't require
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen /* we'll need to assign UID for the mail immediately. */
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen /* the syncing above could have changed the append offset */
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (mbox_seek_to_end(ctx, &ctx->append_offset) < 0)
bd74402ca1a39ec303075fefb1212d7e18a71531Timo Sirainen ctx->output = o_stream_create_fd_file(mbox->mbox_fd,
270f00aeab7bede38764291e21a314211b884ab4Timo Sirainensave_header_callback(struct header_filter_istream *input ATTR_UNUSED,
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen /* we can't allow From_-lines in headers. there's no
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen legitimate reason for allowing them in any case,
ef11d3930c3602fc86349a4e3a53442df470b601Timo Sirainen so just drop them. */
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen ctx->mbox->md5_v.more(ctx->mbox_md5_ctx, hdr);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenstatic void mbox_save_x_delivery_id(struct mbox_save_context *ctx)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen buf = buffer_create_dynamic(pool_datastack_create(), 256);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen buffer_append(buf, &ioloop_time, sizeof(ioloop_time));
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen randbuf = buffer_append_space_unsafe(buf, MBOX_DELIVERY_ID_RAND_BYTES);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen random_fill_weak(randbuf, MBOX_DELIVERY_ID_RAND_BYTES);
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen md5_get_digest(buf->data, buf->used, md5_result);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen base64_encode(md5_result, sizeof(md5_result), str);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen ctx->x_delivery_id_header = i_strdup(str_c(str));
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenstatic struct istream *
270f00aeab7bede38764291e21a314211b884ab4Timo Sirainenmbox_save_get_input_stream(struct mbox_save_context *ctx, struct istream *input)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen struct istream *filter, *ret, *cache_input, *streams[3];
59714981ae172b5113be7ca9b8be518b759fc86dTimo Sirainen /* filter out unwanted headers and keep track of headers' MD5 sum */
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen filter = i_stream_create_header_filter(input, HEADER_FILTER_EXCLUDE |
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen /* we're using MD5 sums to generate POP3 UIDLs.
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen clients don't like it much if there are duplicates,
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen so make sure that there can't be any by appending
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen our own X-Delivery-ID header. */
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen const char *hdr;
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen streams[0] = i_stream_create_from_data(hdr, strlen(hdr));
8039af9679af6fb56116b353fe44f7dd4c08f031Timo Sirainen /* convert linefeeds to wanted format */
8039af9679af6fb56116b353fe44f7dd4c08f031Timo Sirainen ret = ctx->mbox->storage->storage.set->mail_save_crlf ?
a4bc2c3962b94f83c7bb7bebe7af364f4dee7883Timo Sirainen i_stream_create_crlf(filter) : i_stream_create_lf(filter);
a4bc2c3962b94f83c7bb7bebe7af364f4dee7883Timo Sirainen /* caching creates a tee stream */
23bdbb7b1831785c6ba6df190f6369da882d2b9dTimo Sirainen index_mail_cache_parse_init(ctx->ctx.dest_mail, ret);
8039af9679af6fb56116b353fe44f7dd4c08f031Timo Sirainenmbox_save_alloc(struct mailbox_transaction_context *t)
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen struct mbox_mailbox *mbox = (struct mbox_mailbox *)t->box;
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen i_assert((t->flags & MAILBOX_TRANSACTION_FLAG_EXTERNAL) != 0);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainenint mbox_save_begin(struct mail_save_context *_ctx, struct istream *input)
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen struct mbox_save_context *ctx = (struct mbox_save_context *)_ctx;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen (struct mbox_transaction_context *)_ctx->transaction;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen /* FIXME: we could write timezone_offset to From-line.. */
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen if (mbox_save_init_file(ctx, t, _ctx->dest_mail != NULL) < 0) {
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen /* we can use the wanted UID */
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen /* writing the first mail. Insert X-IMAPbase as well. */
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen str_printfa(ctx->headers, "X-IMAPbase: %u %010u\n",
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen str_printfa(ctx->headers, "X-UID: %u\n", ctx->next_uid);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen mail_index_append(ctx->trans, ctx->next_uid, &ctx->seq);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen mail_index_update_flags(ctx->trans, ctx->seq, MODIFY_REPLACE,
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen mail_index_update_keywords(ctx->trans, ctx->seq,
85ee28daca146e18a99a22f46c0d639e57a6ac95Timo Sirainen mail_index_update_modseq(ctx->trans, ctx->seq,
85ee28daca146e18a99a22f46c0d639e57a6ac95Timo Sirainen /* parse and cache the mail headers as we read it */
270f00aeab7bede38764291e21a314211b884ab4Timo Sirainen mail_set_seq_saving(_ctx->dest_mail, ctx->seq);
85ee28daca146e18a99a22f46c0d639e57a6ac95Timo Sirainen mbox_save_append_flag_headers(ctx->headers, save_flags);
85ee28daca146e18a99a22f46c0d639e57a6ac95Timo Sirainen mbox_save_append_keyword_headers(ctx, mdata->keywords);
85ee28daca146e18a99a22f46c0d639e57a6ac95Timo Sirainen i_assert(ctx->mbox->mbox_lock_type == F_WRLCK);
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen if (write_from_line(ctx, mdata->received_date, mdata->from_envelope) < 0)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen ctx->input = mbox_save_get_input_stream(ctx, input);
0b7651dc6ad21cce8579b5957252ae0daf972668Timo Sirainenstatic int mbox_save_body_input(struct mbox_save_context *ctx)
0b7651dc6ad21cce8579b5957252ae0daf972668Timo Sirainen const unsigned char *data;
c979eeda1f46483d9c963e265786b701d7683d77Timo Sirainen if (o_stream_send(ctx->output, data, size) < 0) {
10cfe8a2bdc5ccfc05380689c71c27209327538fTimo Sirainenstatic int mbox_save_body(struct mbox_save_context *ctx)
a54be2bd26d6f0860d194d3aeedfa6b7fc14d24cTimo Sirainen while ((ret = i_stream_read(ctx->input)) != -1) {
a54be2bd26d6f0860d194d3aeedfa6b7fc14d24cTimo Sirainen /* i_stream_read() may have returned 0 at EOF
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen because of this parser */
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen index_mail_cache_parse_continue(ctx->ctx.dest_mail);
88286b0527bcc0711e312e9db65ca121a45213e3Timo Sirainenstatic int mbox_save_finish_headers(struct mbox_save_context *ctx)
88286b0527bcc0711e312e9db65ca121a45213e3Timo Sirainen /* append our own headers and ending empty line */
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen if (o_stream_send(ctx->output, str_data(ctx->headers),
d42c9a8f362b76740418c4f9f9441eb7fc661e57Timo Sirainenint mbox_save_continue(struct mail_save_context *_ctx)
d42c9a8f362b76740418c4f9f9441eb7fc661e57Timo Sirainen struct mbox_save_context *ctx = (struct mbox_save_context *)_ctx;
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen const unsigned char *data;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen /* writing body */
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen while ((ret = i_stream_read(ctx->input)) > 0) {
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen index_mail_cache_parse_continue(ctx->ctx.dest_mail);
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen for (i = 0; i < size; i++) {
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen /* end of headers. we don't need to worry about
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen CRs because they're dropped */
88286b0527bcc0711e312e9db65ca121a45213e3Timo Sirainen /* found end of headers. write the rest of them
88286b0527bcc0711e312e9db65ca121a45213e3Timo Sirainen (not including the finishing empty line) */
88286b0527bcc0711e312e9db65ca121a45213e3Timo Sirainen if (o_stream_send(ctx->output, data, i) < 0) {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (o_stream_send(ctx->output, data, size) < 0) {
5735ada0f82788ee1b5228978d5bd8dad5a04219Timo Sirainen i_error("read(%s) failed: %m", i_stream_get_name(ctx->input));
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen hdr.middle = (const unsigned char *)hdr.name +
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen hdr.value_len = strlen((const char *)hdr.value);
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen ctx->mbox->md5_v.more(ctx->mbox_md5_ctx, &hdr);
88286b0527bcc0711e312e9db65ca121a45213e3Timo Sirainen ctx->mbox->md5_v.finish(ctx->mbox_md5_ctx, hdr_md5_sum);
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen /* write body */
1939d1843ee6c7ca5e5baa3967b0332341440005Timo Sirainen return ctx->input->eof ? 0 : mbox_save_body(ctx);
1939d1843ee6c7ca5e5baa3967b0332341440005Timo Sirainenint mbox_save_finish(struct mail_save_context *_ctx)
3419b088ffe531799bdb47b3ff3fce85c8b7569aTimo Sirainen struct mbox_save_context *ctx = (struct mbox_save_context *)_ctx;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen if (!ctx->failed && ctx->eoh_offset == (uoff_t)-1)
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen /* make sure everything is written */
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen index_mail_cache_parse_deinit(ctx->ctx.dest_mail,
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen if (ctx->failed && ctx->mail_offset != (uoff_t)-1) {
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen /* saving this mail failed - truncate back to beginning of it */
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen if (ftruncate(ctx->mbox->mbox_fd, (off_t)ctx->mail_offset) < 0)
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen mbox_set_syscall_error(ctx->mbox, "ftruncate()");
279b22f320f6139da5c1b0e2a5ead6692e7db947Timo Sirainen (void)o_stream_seek(ctx->output, ctx->mail_offset);
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen /* currently we can't just drop pending cache updates for this
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen one specific record, so we'll reset the whole cache
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen transaction. */
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen mail_cache_transaction_reset(ctx->ctx.transaction->cache_trans);
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainenvoid mbox_save_cancel(struct mail_save_context *_ctx)
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen struct mbox_save_context *ctx = (struct mbox_save_context *)_ctx;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainenstatic void mbox_transaction_save_deinit(struct mbox_save_context *ctx)
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainenstatic void mbox_save_truncate(struct mbox_save_context *ctx)
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen if (ctx->append_offset == (uoff_t)-1 || ctx->mbox->mbox_fd == -1)
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen i_assert(ctx->mbox->mbox_lock_type == F_WRLCK);
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen /* failed, truncate file back to original size. output stream needs to
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen be flushed before truncating so unref() won't write anything. */
b66d803de86bfb411165b3465b0d9ef64ecfe2a1Timo Sirainen if (ftruncate(ctx->mbox->mbox_fd, (off_t)ctx->append_offset) < 0)
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen mbox_set_syscall_error(ctx->mbox, "ftruncate()");
71caf493c651b8eab5adb170db0237f293928e92Timo Sirainenint mbox_transaction_save_commit_pre(struct mail_save_context *_ctx)
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen struct mbox_save_context *ctx = (struct mbox_save_context *)_ctx;
42507d758b053bb483de58fba55c73a9eb5d3fbaTimo Sirainen struct mailbox_transaction_context *_t = _ctx->transaction;
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen _t->changes->uid_validity = ctx->uid_validity;
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen &ctx->next_uid, sizeof(ctx->next_uid), FALSE);
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen if (ret == 0 && ctx->orig_atime != st.st_atime) {
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen /* try to set atime back to its original value.
1939d1843ee6c7ca5e5baa3967b0332341440005Timo Sirainen (it'll fail with EPERM for shared mailboxes where we aren't
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen the file's owner) */
1939d1843ee6c7ca5e5baa3967b0332341440005Timo Sirainen if (utime(mailbox_get_path(&mbox->box), &buf) < 0 &&
35283613d4c04ce18836e9fc431582c87b3710a0Timo Sirainen /* flush the final LF */
71caf493c651b8eab5adb170db0237f293928e92Timo Sirainen if (mbox->mbox_fd != -1 && !mbox->mbox_writeonly &&
71caf493c651b8eab5adb170db0237f293928e92Timo Sirainen mbox->storage->storage.set->parsed_fsync_mode != FSYNC_MODE_NEVER) {
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainenvoid mbox_transaction_save_commit_post(struct mail_save_context *_ctx,
5735ada0f82788ee1b5228978d5bd8dad5a04219Timo Sirainen struct mail_index_transaction_commit_result *result ATTR_UNUSED)
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen struct mbox_save_context *ctx = (struct mbox_save_context *)_ctx;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen i_assert(ctx->mbox->mbox_lock_type == F_WRLCK);
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen /* after saving mails with UIDs we need to update
279b22f320f6139da5c1b0e2a5ead6692e7db947Timo Sirainen the last-uid */
279b22f320f6139da5c1b0e2a5ead6692e7db947Timo Sirainenvoid mbox_transaction_save_rollback(struct mail_save_context *_ctx)
279b22f320f6139da5c1b0e2a5ead6692e7db947Timo Sirainen struct mbox_save_context *ctx = (struct mbox_save_context *)_ctx;