static void index_mail_cache_dates(struct index_mail *mail) { static enum index_cache_field date_fields[] = { MAIL_CACHE_RECEIVED_DATE, MAIL_CACHE_SAVE_DATE }; time_t dates[N_ELEMENTS(date_fields)]; unsigned int i; uint32_t t; dates[0] = mail->data.received_date; dates[1] = mail->data.save_date; for (i = 0; i < N_ELEMENTS(date_fields); i++) { if (dates[i] != (time_t)-1 && index_mail_want_cache(mail, date_fields[i])) { t = dates[i]; index_mail_cache_add(mail, date_fields[i], &t, sizeof(t)); } } if (mail->data.sent_date_parsed && index_mail_want_cache(mail, MAIL_CACHE_SENT_DATE)) (void)index_mail_cache_sent_date(mail); }
static int index_mail_cache_sent_date(struct index_mail *mail) { struct index_mail_data *data = &mail->data; const char *str; time_t t; int ret, tz; if (data->sent_date.time != (uint32_t)-1) return 0; if ((ret = mail_get_first_header(&mail->mail.mail, "Date", &str)) < 0) return ret; if (ret == 0 || !message_date_parse((const unsigned char *)str, strlen(str), &t, &tz)) { /* 0 = not found / invalid */ t = 0; tz = 0; } data->sent_date.time = t; data->sent_date.timezone = tz; index_mail_cache_add(mail, MAIL_CACHE_SENT_DATE, &data->sent_date, sizeof(data->sent_date)); return 0; }
static void index_mail_cache_sizes(struct index_mail *mail) { static enum index_cache_field size_fields[] = { MAIL_CACHE_VIRTUAL_FULL_SIZE, MAIL_CACHE_PHYSICAL_FULL_SIZE }; uoff_t sizes[N_ELEMENTS(size_fields)]; unsigned int i; sizes[0] = mail->data.virtual_size; sizes[1] = mail->data.physical_size; for (i = 0; i < N_ELEMENTS(size_fields); i++) { if (sizes[i] != (uoff_t)-1 && index_mail_want_cache(mail, size_fields[i])) { index_mail_cache_add(mail, size_fields[i], &sizes[i], sizeof(sizes[i])); } } }
static void index_mail_body_parsed_cache_bodystructure(struct index_mail *mail, enum index_cache_field field) { struct index_mail_data *data = &mail->data; unsigned int cache_field_parts = mail->ibox->cache_fields[MAIL_CACHE_MESSAGE_PARTS].idx; unsigned int cache_field_body = mail->ibox->cache_fields[MAIL_CACHE_IMAP_BODY].idx; unsigned int cache_field_bodystructure = mail->ibox->cache_fields[MAIL_CACHE_IMAP_BODYSTRUCTURE].idx; enum mail_cache_decision_type dec; string_t *str; bool bodystructure_cached = FALSE; bool plain_bodystructure = FALSE; bool cache_bodystructure, cache_body; if ((data->cache_flags & MAIL_CACHE_FLAG_TEXT_PLAIN_7BIT_ASCII) != 0) { if (data->messageparts_saved_to_cache || mail_cache_field_exists(mail->trans->cache_view, data->seq, cache_field_parts) > 0) { /* cached it as flag + message_parts */ plain_bodystructure = TRUE; } } if (!data->parsed_bodystructure) return; /* If BODY is fetched first but BODYSTRUCTURE is also wanted, we don't normally want to first cache BODY and then BODYSTRUCTURE. So check the wanted_fields also in here. */ if (plain_bodystructure) cache_bodystructure = FALSE; else if (field == MAIL_CACHE_IMAP_BODYSTRUCTURE || (mail->wanted_fields & MAIL_FETCH_IMAP_BODYSTRUCTURE) != 0) { cache_bodystructure = mail_cache_field_can_add(mail->trans->cache_trans, data->seq, cache_field_bodystructure); } else { cache_bodystructure = mail_cache_field_want_add(mail->trans->cache_trans, data->seq, cache_field_bodystructure); } if (cache_bodystructure) { str = str_new(mail->data_pool, 128); imap_bodystructure_write(data->parts, str, TRUE); data->bodystructure = str_c(str); index_mail_cache_add(mail, MAIL_CACHE_IMAP_BODYSTRUCTURE, str_c(str), str_len(str)+1); bodystructure_cached = TRUE; } else { bodystructure_cached = mail_cache_field_exists(mail->trans->cache_view, data->seq, cache_field_bodystructure) > 0; } /* normally don't cache both BODY and BODYSTRUCTURE, but do it if BODY is forced to be cached */ dec = mail_cache_field_get_decision(mail->mail.mail.box->cache, cache_field_body); if (plain_bodystructure || (bodystructure_cached && (dec != (MAIL_CACHE_DECISION_FORCED | MAIL_CACHE_DECISION_YES)))) cache_body = FALSE; else if (field == MAIL_CACHE_IMAP_BODY) { cache_body = mail_cache_field_can_add(mail->trans->cache_trans, data->seq, cache_field_body); } else { cache_body = mail_cache_field_want_add(mail->trans->cache_trans, data->seq, cache_field_body); } if (cache_body) { str = str_new(mail->data_pool, 128); imap_bodystructure_write(data->parts, str, FALSE); data->body = str_c(str); index_mail_cache_add(mail, MAIL_CACHE_IMAP_BODY, str_c(str), str_len(str)+1); } }
static int maildir_save_finish_real(struct mail_save_context *_ctx) { struct maildir_save_context *ctx = (struct maildir_save_context *)_ctx; struct mail_storage *storage = &ctx->mbox->storage->storage; const char *path; off_t real_size; uoff_t size; int output_errno; ctx->last_save_finished = TRUE; if (ctx->failed && ctx->fd == -1) { /* tmp file creation failed */ return -1; } path = t_strconcat(ctx->tmpdir, "/", ctx->file_last->tmp_name, NULL); if (!ctx->failed && o_stream_nfinish(_ctx->data.output) < 0) { if (!mail_storage_set_error_from_errno(storage)) { mail_storage_set_critical(storage, "write(%s) failed: %m", path); } ctx->failed = TRUE; } if (_ctx->data.save_date != (time_t)-1) { /* we can't change ctime, but we can add the date to cache */ struct index_mail *mail = (struct index_mail *)_ctx->dest_mail; uint32_t t = _ctx->data.save_date; index_mail_cache_add(mail, MAIL_CACHE_SAVE_DATE, &t, sizeof(t)); } if (maildir_save_finish_received_date(ctx, path) < 0) ctx->failed = TRUE; if (ctx->cur_dest_mail != NULL) { index_mail_cache_parse_deinit(ctx->cur_dest_mail, ctx->ctx.data.received_date, !ctx->failed); } i_stream_unref(&ctx->input); /* remember the size in case we want to add it to filename */ ctx->file_last->size = _ctx->data.output->offset; if (ctx->cur_dest_mail == NULL || mail_get_virtual_size(ctx->cur_dest_mail, &ctx->file_last->vsize) < 0) ctx->file_last->vsize = (uoff_t)-1; output_errno = _ctx->data.output->last_failed_errno; o_stream_destroy(&_ctx->data.output); if (storage->set->parsed_fsync_mode != FSYNC_MODE_NEVER && !ctx->failed) { if (fsync(ctx->fd) < 0) { if (!mail_storage_set_error_from_errno(storage)) { mail_storage_set_critical(storage, "fsync(%s) failed: %m", path); } ctx->failed = TRUE; } } real_size = lseek(ctx->fd, 0, SEEK_END); if (real_size == (off_t)-1) { mail_storage_set_critical(storage, "lseek(%s) failed: %m", path); } else if (real_size != (off_t)ctx->file_last->size && (!maildir_filename_get_size(ctx->file_last->dest_basename, MAILDIR_EXTRA_FILE_SIZE, &size) || size != ctx->file_last->size)) { /* e.g. zlib plugin was used. the "physical size" must be in the maildir filename, since stat() will return wrong size */ ctx->file_last->preserve_filename = FALSE; /* preserve the GUID if needed */ if (ctx->file_last->guid == NULL) ctx->file_last->guid = ctx->file_last->dest_basename; /* reset the base name as well, just in case there's a ,W=vsize */ ctx->file_last->dest_basename = ctx->file_last->tmp_name; } if (close(ctx->fd) < 0) { if (!mail_storage_set_error_from_errno(storage)) { mail_storage_set_critical(storage, "close(%s) failed: %m", path); } ctx->failed = TRUE; } ctx->fd = -1; if (ctx->failed) { /* delete the tmp file */ i_unlink_if_exists(path); errno = output_errno; if (ENOQUOTA(errno)) { mail_storage_set_error(storage, MAIL_ERROR_NOQUOTA, MAIL_ERRSTR_NO_QUOTA); } else if (errno != 0) { mail_storage_set_critical(storage, "write(%s) failed: %m", path); } maildir_save_remove_last_filename(ctx); return -1; } ctx->file_last = NULL; return 0; }