maildir-mail.c revision f6f021c133f680cf3d559187524fd9abcbaae9b9
bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2003-2010 Dovecot authors, see the included COPYING file */
c150beda11da6fbbb1a936829550945d5e884f68Josef 'Jeff' Sipekdo_open(struct maildir_mailbox *mbox, const char *path,
d22301419109ed4a38351715e6760011421dadecTimo Sirainen mail_storage_set_critical(&mbox->storage->storage, "%s",
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen mail_storage_set_critical(&mbox->storage->storage,
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainendo_stat(struct maildir_mailbox *mbox, const char *path, struct stat *st)
b12a6d0e54318273acf0d0fb8b3f4c29f67b62b0Timo Sirainen mail_storage_set_critical(&mbox->storage->storage, "%s",
b12a6d0e54318273acf0d0fb8b3f4c29f67b62b0Timo Sirainen mail_storage_set_critical(&mbox->storage->storage,
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainenstatic struct istream *
86c6b2546b0bbfce326583f14d05f59674a6d861Timo Sirainenmaildir_open_mail(struct maildir_mailbox *mbox, struct mail *mail,
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen struct mail_private *p = (struct mail_private *)mail;
86c6b2546b0bbfce326583f14d05f59674a6d861Timo Sirainen if (maildir_file_do(mbox, mail->uid, do_open, &ctx) < 0)
73247459cf41eb1e5ae5bc61354db46d3b05ee75Timo Sirainen path = maildir_save_file_get_path(mail->transaction, mail->seq);
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen if (maildir_lose_unexpected_dir(&mbox->storage->storage,
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainenstatic int maildir_mail_stat(struct mail *mail, struct stat *st)
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)mail->box;
4b41116563110d00330896a568eff1078c382827Timo Sirainen struct index_mail *imail = (struct index_mail *)mail;
87490012895b4f371635ded00add04c9107dcfefJosef 'Jeff' Sipek if (mail->lookup_abort == MAIL_LOOKUP_ABORT_NOT_IN_CACHE)
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen if (imail->data.access_part != 0 && imail->data.stream == NULL) {
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen /* we're going to open the mail anyway */
4b41116563110d00330896a568eff1078c382827Timo Sirainen (void)mail_get_stream(mail, NULL, NULL, &input);
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen stp = i_stream_stat(imail->data.stream, FALSE);
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen ret = maildir_file_do(mbox, mail->uid, do_stat, st);
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen path = maildir_save_file_get_path(mail->transaction, mail->seq);
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainenstatic int maildir_mail_get_received_date(struct mail *_mail, time_t *date_r)
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen if (index_mail_get_received_date(_mail, date_r) == 0)
fc22ecbb03396eda9270472446a6065a986a43e0Timo Sirainenstatic int maildir_mail_get_save_date(struct mail *_mail, time_t *date_r)
5f44975ec6c5755dd74bcd4c47a123a7242ecab3Timo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
fc22ecbb03396eda9270472446a6065a986a43e0Timo Sirainen if (index_mail_get_save_date(_mail, date_r) == 0)
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainenmaildir_mail_get_fname(struct maildir_mailbox *mbox, struct mail *mail,
4b41116563110d00330896a568eff1078c382827Timo Sirainen ret = maildir_uidlist_lookup(mbox->uidlist, mail->uid, &flags, fname_r);
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen /* file exists in index file, but not in dovecot-uidlist anymore. */
fc22ecbb03396eda9270472446a6065a986a43e0Timo Sirainen /* one reason this could happen is if we delayed opening
fc22ecbb03396eda9270472446a6065a986a43e0Timo Sirainen dovecot-uidlist and we're trying to open a mail that got recently
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen expunged. Let's test this theory first: */
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen exists = mail_index_lookup_seq(view, mail->uid, &seq);
36f4f01d56ec9156ab75bc2047a8388192df3178Timo Sirainen /* the message still exists in index. this means there's some
36f4f01d56ec9156ab75bc2047a8388192df3178Timo Sirainen kind of a desync, which doesn't get fixed if cur/ mtime is
36f4f01d56ec9156ab75bc2047a8388192df3178Timo Sirainen the same as in index. fix this by forcing a resync. */
36f4f01d56ec9156ab75bc2047a8388192df3178Timo Sirainen (void)maildir_storage_sync_force(mbox, mail->uid);
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainenstatic int maildir_get_pop3_state(struct index_mail *mail)
cbcde6379f1b0b27bdefc4b11eec93ad69e459d4Timo Sirainen struct index_mailbox_context *ibox = INDEX_STORAGE_CONTEXT(box);
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen /* if this mail itself has non-pop3 fields we know we're not
fc22ecbb03396eda9270472446a6065a986a43e0Timo Sirainen allowed_pop3_fields = MAIL_FETCH_FLAGS | MAIL_FETCH_STREAM_HEADER |
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen MAIL_FETCH_STREAM_BODY | MAIL_FETCH_UIDL_FILE_NAME |
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen (mail->wanted_fields & ~allowed_pop3_fields) != 0)
915bb1572a406d30013ed3ee83fba7082a6d1baePhil Carmody /* get vsize decisions */
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen psize_idx = ibox->cache_fields[MAIL_CACHE_PHYSICAL_FULL_SIZE].idx;
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen vsize_idx = ibox->cache_fields[MAIL_CACHE_VIRTUAL_FULL_SIZE].idx;
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen vsize_dec = mail_cache_field_get_decision(box->cache,
5abb33fdc94c081ccd3213bf7d0fa9d0367b4bfdTimo Sirainen /* also check if there are any non-[pv]size cached fields */
7bd301fdbfefe7cef3576d19ece29c75ebe53bafTimo Sirainen fields = mail_cache_register_get_list(box->cache,
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen for (i = 0; i < count; i++) {
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen dec = fields[i].decision & ~MAIL_CACHE_DECISION_FORCED;
690bafa70767e3f6e98bbfd62ad4a26be2387ea9Timo Sirainen /* either nothing is cached, or only vsize is cached. */
d22301419109ed4a38351715e6760011421dadecTimo Sirainen } else if (vsize_dec != MAIL_CACHE_DECISION_YES &&
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen (box->flags & MAILBOX_FLAG_POP3_SESSION) == 0) {
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen /* if virtual size isn't cached permanently,
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen POP3 isn't being used */
767cd7e92a46ca7c0dc4823936750b2bf2eb99e3Timo Sirainen /* possibly a mixed pop3/imap */
767cd7e92a46ca7c0dc4823936750b2bf2eb99e3Timo Sirainenstatic int maildir_quick_size_lookup(struct index_mail *mail, bool vsize,
690bafa70767e3f6e98bbfd62ad4a26be2387ea9Timo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)_mail->box;
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen if (maildir_mail_get_fname(mbox, _mail, &fname) <= 0)
87490012895b4f371635ded00add04c9107dcfefJosef 'Jeff' Sipek path = maildir_save_file_get_path(_mail->transaction,
d67fde1a8ebc1d85704c5986d8f93aae97eccef3Timo Sirainen /* size can be included in filename */
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen /* size can be included in uidlist entry */
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi value = maildir_uidlist_lookup_ext(mbox->uidlist, _mail->uid,
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen if (value != NULL && str_to_uoff(value, size_r) == 0)
1b5366b2234892f8930a29351da06b193e385150Timo Sirainenmaildir_handle_size_caching(struct index_mail *mail, bool quick_check,
3063bd8ff05d3d8cd33156f4366b36890e501436Timo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)box;
aa215ab623706463cea1d047f975ffe51d3f0c05Timo Sirainen field = vsize ? MAIL_FETCH_VIRTUAL_SIZE : MAIL_FETCH_PHYSICAL_SIZE;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen if ((mail->data.dont_cache_fetch_fields & field) != 0)
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen if (quick_check && maildir_quick_size_lookup(mail, vsize, &size) > 0) {
d67fde1a8ebc1d85704c5986d8f93aae97eccef3Timo Sirainen /* already in filename / uidlist. don't add it anywhere,
d67fde1a8ebc1d85704c5986d8f93aae97eccef3Timo Sirainen including to the uidlist if it's already in filename.
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen do some extra checks here to catch potential cache bugs. */
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen if (vsize && mail->data.virtual_size != size) {
b2ecd50bb98c44816cb07c17aa17fae2b425f941Timo Sirainen "Corrupted virtual size for uid=%u: "
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen } else if (!vsize && mail->data.physical_size != size) {
5abb33fdc94c081ccd3213bf7d0fa9d0367b4bfdTimo Sirainen "Corrupted physical size for uid=%u: "
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen /* 1 = pop3-only, 0 = mixed, -1 = no pop3 */
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen if (pop3_state >= 0 && mail->mail.mail.uid != 0) {
3063bd8ff05d3d8cd33156f4366b36890e501436Timo Sirainen /* if size is wanted permanently, store it to uidlist
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi so that in case cache file gets lost we can get it quickly */
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mail->data.dont_cache_fetch_fields |= field;
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen maildir_uidlist_set_ext(mbox->uidlist, mail->mail.mail.uid,
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainenstatic int maildir_mail_get_virtual_size(struct mail *_mail, uoff_t *size_r)
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
677b75f90d81eafe742896d6570a2f63ce501d05Josef 'Jeff' Sipek struct index_mail_data *data = &mail->data;
6df0ab0c1ab91f06b6418cb30eff44405a1b8f02Timo Sirainen if (index_mail_get_cached_virtual_size(mail, size_r)) {
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen i_assert(mail->data.virtual_size != (uoff_t)-1);
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen maildir_handle_size_caching(mail, TRUE, TRUE);
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen if (maildir_quick_size_lookup(mail, TRUE, &data->virtual_size) < 0)
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen data->dont_cache_fetch_fields |= MAIL_FETCH_VIRTUAL_SIZE;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen /* fallback to reading the file */
7631f16156aca373004953fe6b01a7f343fb47e0Timo Sirainen old_offset = data->stream == NULL ? 0 : data->stream->v_offset;
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen if (mail_get_stream(_mail, &hdr_size, &body_size, &input) < 0)
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen maildir_handle_size_caching(mail, FALSE, TRUE);
87490012895b4f371635ded00add04c9107dcfefJosef 'Jeff' Sipekstatic int maildir_mail_get_physical_size(struct mail *_mail, uoff_t *size_r)
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)_mail->box;
0d86aa0d47f7393c669c084b34c0537b193688adTimo Sirainen if (index_mail_get_physical_size(_mail, size_r) == 0) {
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen i_assert(mail->data.physical_size != (uoff_t)-1);
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen maildir_handle_size_caching(mail, TRUE, FALSE);
421d30619384e72a27e2a5d13ff6525aff4d17feTimo Sirainen if (maildir_quick_size_lookup(mail, FALSE, &data->physical_size) < 0)
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen data->dont_cache_fetch_fields |= MAIL_FETCH_PHYSICAL_SIZE;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen ret = maildir_file_do(mbox, _mail->uid, do_stat, &st);
87460b08cb97b31cde640d4975a6aa2c1d0e7226Timo Sirainen /* saved mail which hasn't been committed yet */
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen path = maildir_save_file_get_path(_mail->transaction,
21aaa6affb9f134112b75b5db737309fc35ef1cfMartti Rannanjärvi mail_storage_set_critical(_mail->box->storage,
6564208826b0f46a00f010d1b5711d85944c3c88Timo Sirainen maildir_handle_size_caching(mail, FALSE, FALSE);
const char **value_r)
switch (field) {
case MAIL_FETCH_GUID:
case MAIL_FETCH_UIDL_BACKEND:
bool deleted;
if (deleted)
const char *fname;
&fname) == 0 &&
const char *fname;
int ret;
if (ret <= 0)
&size)) {
const char *subdir =
NULL);