135
135
ctx->newdir = p_strconcat(pool, path, "/new", NULL);
136
136
ctx->curdir = p_strconcat(pool, path, "/cur", NULL);
138
buffer_create_const_data(&ctx->keywords_buffer, NULL, 0);
138
buffer_create_from_const_data(&ctx->keywords_buffer, "", 0);
139
139
array_create_from_buffer(&ctx->keywords_array, &ctx->keywords_buffer,
140
140
sizeof(unsigned int));
141
141
ctx->last_save_finished = TRUE;
156
157
/* allow caller to specify recent flag only when uid is specified
157
158
(we're replicating, converting, etc.). */
159
_ctx->flags |= MAIL_RECENT;
160
else if ((_ctx->flags & MAIL_RECENT) == 0 &&
161
ctx->last_nonrecent_uid < _ctx->uid)
162
ctx->last_nonrecent_uid = _ctx->uid;
160
mdata->flags |= MAIL_RECENT;
161
else if ((mdata->flags & MAIL_RECENT) == 0 &&
162
ctx->last_nonrecent_uid < mdata->uid)
163
ctx->last_nonrecent_uid = mdata->uid;
164
165
/* now, we want to be able to rollback the whole append session,
165
166
so we'll just store the name of this temp file and move it later
166
167
into new/ or cur/. */
168
keyword_count = _ctx->keywords == NULL ? 0 : _ctx->keywords->count;
169
keyword_count = mdata->keywords == NULL ? 0 : mdata->keywords->count;
169
170
mf = p_malloc(ctx->pool, sizeof(*mf) +
170
171
sizeof(unsigned int) * keyword_count);
171
172
mf->tmp_name = mf->dest_basename = p_strdup(ctx->pool, tmp_fname);
172
mf->flags = _ctx->flags;
173
mf->flags = mdata->flags;
173
174
mf->size = (uoff_t)-1;
174
175
mf->vsize = (uoff_t)-1;
179
180
ctx->files_tail = &mf->next;
180
181
ctx->files_count++;
182
if (_ctx->keywords != NULL) {
183
if (mdata->keywords != NULL) {
184
185
mf->keywords_count = keyword_count;
185
memcpy(mf + 1, _ctx->keywords->idx,
186
memcpy(mf + 1, mdata->keywords->idx,
186
187
sizeof(unsigned int) * keyword_count);
187
188
ctx->have_keywords = TRUE;
189
if (_ctx->pop3_uidl != NULL)
190
mf->pop3_uidl = p_strdup(ctx->pool, _ctx->pop3_uidl);
191
mf->pop3_order = _ctx->pop3_order;
190
if (mdata->pop3_uidl != NULL)
191
mf->pop3_uidl = p_strdup(ctx->pool, mdata->pop3_uidl);
192
mf->pop3_order = mdata->pop3_order;
193
194
/* insert into index */
194
mail_index_append(ctx->trans, _ctx->uid, &ctx->seq);
195
mail_index_append(ctx->trans, mdata->uid, &ctx->seq);
195
196
mail_index_update_flags(ctx->trans, ctx->seq,
196
MODIFY_REPLACE, _ctx->flags & ~MAIL_RECENT);
197
if (_ctx->keywords != NULL) {
197
MODIFY_REPLACE, mdata->flags & ~MAIL_RECENT);
198
if (mdata->keywords != NULL) {
198
199
mail_index_update_keywords(ctx->trans, ctx->seq,
199
MODIFY_REPLACE, _ctx->keywords);
200
MODIFY_REPLACE, mdata->keywords);
201
if (_ctx->min_modseq != 0) {
202
if (mdata->min_modseq != 0) {
202
203
mail_index_update_modseq(ctx->trans, ctx->seq,
206
207
if (ctx->first_seq == 0) {
275
*fname_r = maildir_filename_flags_set(NULL, basename,
276
mf->flags & MAIL_FLAGS_MASK, NULL);
276
*fname_r = maildir_filename_flags_set(basename,
277
mf->flags & MAIL_FLAGS_MASK);
280
281
i_assert(ctx->keywords_sync_ctx != NULL || mf->keywords_count == 0);
281
buffer_create_const_data(&ctx->keywords_buffer, mf + 1,
282
mf->keywords_count * sizeof(unsigned int));
283
*fname_r = maildir_filename_flags_set(ctx->keywords_sync_ctx, basename,
284
mf->flags & MAIL_FLAGS_MASK,
285
&ctx->keywords_array);
282
buffer_create_from_const_data(&ctx->keywords_buffer, mf + 1,
283
mf->keywords_count * sizeof(unsigned int));
284
*fname_r = maildir_filename_flags_kw_set(ctx->keywords_sync_ctx,
286
mf->flags & MAIL_FLAGS_MASK,
287
&ctx->keywords_array);
412
414
ctx->input = i_stream_create_lf(input);
413
415
mf = maildir_save_add(_ctx, fname, NULL);
414
if (_ctx->guid != NULL) {
416
if (_ctx->data.guid != NULL) {
415
417
maildir_save_set_dest_basename(_ctx, mf,
421
423
if (!ctx->failed) {
422
_ctx->output = o_stream_create_fd_file(ctx->fd, 0, FALSE);
423
o_stream_cork(_ctx->output);
424
_ctx->data.output = o_stream_create_fd_file(ctx->fd, 0, FALSE);
425
o_stream_cork(_ctx->data.output);
424
426
ctx->last_save_finished = FALSE;
426
428
return ctx->failed ? -1 : 0;
438
if (o_stream_send_istream(_ctx->output, ctx->input) < 0) {
440
if (o_stream_send_istream(_ctx->data.output, ctx->input) < 0) {
439
441
if (!mail_storage_set_error_from_errno(storage)) {
440
442
mail_storage_set_critical(storage,
441
443
"o_stream_send_istream(%s/%s) "
462
464
struct utimbuf buf;
465
if (ctx->ctx.received_date != (time_t)-1) {
467
if (ctx->ctx.data.received_date != (time_t)-1) {
466
468
/* set the received_date by modifying mtime */
467
469
buf.actime = ioloop_time;
468
buf.modtime = ctx->ctx.received_date;
470
buf.modtime = ctx->ctx.data.received_date;
470
472
if (utime(path, &buf) < 0) {
471
473
mail_storage_set_critical(storage,
475
477
} else if (ctx->fd != -1) {
476
478
if (fstat(ctx->fd, &st) == 0)
477
ctx->ctx.received_date = st.st_mtime;
479
ctx->ctx.data.received_date = st.st_mtime;
479
481
mail_storage_set_critical(storage,
480
482
"fstat(%s) failed: %m", path);
485
487
if (stat(path, &st) == 0)
486
ctx->ctx.received_date = st.st_mtime;
488
ctx->ctx.data.received_date = st.st_mtime;
488
490
mail_storage_set_critical(storage,
489
491
"stat(%s) failed: %m", path);
530
532
path = t_strconcat(ctx->tmpdir, "/", ctx->file_last->tmp_name, NULL);
531
if (!ctx->failed && o_stream_flush(_ctx->output) < 0) {
533
if (!ctx->failed && o_stream_nfinish(_ctx->data.output) < 0) {
532
534
if (!mail_storage_set_error_from_errno(storage)) {
533
535
mail_storage_set_critical(storage,
534
"o_stream_flush(%s) failed: %m", path);
536
"write(%s) failed: %m", path);
536
538
ctx->failed = TRUE;
539
if (_ctx->save_date != (time_t)-1) {
541
if (_ctx->data.save_date != (time_t)-1) {
540
542
/* we can't change ctime, but we can add the date to cache */
541
543
struct index_mail *mail = (struct index_mail *)_ctx->dest_mail;
542
uint32_t t = _ctx->save_date;
544
uint32_t t = _ctx->data.save_date;
544
546
index_mail_cache_add(mail, MAIL_CACHE_SAVE_DATE, &t, sizeof(t));
550
552
if (ctx->cur_dest_mail != NULL) {
551
553
index_mail_cache_parse_deinit(ctx->cur_dest_mail,
552
ctx->ctx.received_date,
554
ctx->ctx.data.received_date,
555
557
i_stream_unref(&ctx->input);
557
559
/* remember the size in case we want to add it to filename */
558
ctx->file_last->size = _ctx->output->offset;
560
ctx->file_last->size = _ctx->data.output->offset;
559
561
if (ctx->cur_dest_mail == NULL ||
560
562
mail_get_virtual_size(ctx->cur_dest_mail,
561
563
&ctx->file_last->vsize) < 0)
562
564
ctx->file_last->vsize = (uoff_t)-1;
564
output_errno = _ctx->output->stream_errno;
565
o_stream_destroy(&_ctx->output);
566
output_errno = _ctx->data.output->last_failed_errno;
567
o_stream_destroy(&_ctx->data.output);
567
569
if (storage->set->parsed_fsync_mode != FSYNC_MODE_NEVER &&
819
if (!ctx->locked_uidlist_refresh) {
821
if (!ctx->locked_uidlist_refresh && ctx->locked) {
820
822
(void)maildir_uidlist_refresh(ctx->mbox->uidlist);
821
823
ctx->locked_uidlist_refresh = TRUE;
824
if ((prev_mf != NULL && maildir_filename_has_conflict(mf, prev_mf)) ||
826
if (!ctx->locked_uidlist_refresh ||
827
(prev_mf != NULL && maildir_filename_has_conflict(mf, prev_mf)) ||
825
828
maildir_uidlist_get_full_filename(ctx->mbox->uidlist,
826
829
mf->dest_basename) != NULL) {
827
830
/* file already exists. give it another name.
852
855
maildir_save_move_files_to_newcur(struct maildir_save_context *ctx)
854
ARRAY_DEFINE(files, struct maildir_filename *);
857
ARRAY(struct maildir_filename *) files;
855
858
struct maildir_filename *mf, *const *mfp, *prev_mf;
856
859
bool newdir, new_changed, cur_changed;
947
950
enum maildir_uidlist_sync_flags sync_flags;
950
i_assert(_ctx->output == NULL);
953
i_assert(_ctx->data.output == NULL);
951
954
i_assert(ctx->last_save_finished);
953
956
if (ctx->files_count == 0) {
1064
1067
struct maildir_save_context *ctx = (struct maildir_save_context *)_ctx;
1066
i_assert(_ctx->output == NULL);
1069
i_assert(_ctx->data.output == NULL);
1068
1071
if (!ctx->last_save_finished)
1069
1072
maildir_save_cancel(&ctx->ctx);