maildir-mail.c revision b19a1420da0618a10edf67c2cfd13c8c8633057a
c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen/* Copyright (c) 2003-2008 Dovecot authors, see the included COPYING file */
8c909e451d14075c05d90382cf8eebc4e354f569Timo Sirainendo_open(struct maildir_mailbox *mbox, const char *path, int *fd)
1a5573ebc32fae2fe576ec544e1781323c1db609Timo Sirainen mail_storage_set_critical(&mbox->storage->storage,
8049d5792631981b50b0ad226a03298445e305c7Timo Sirainendo_stat(struct maildir_mailbox *mbox, const char *path, struct stat *st)
b42817ce16a8660cbcc4adfc8bccc3db1c6d00c7Timo Sirainen mail_storage_set_critical(&mbox->storage->storage,
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainenstatic struct istream *
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainenmaildir_open_mail(struct maildir_mailbox *mbox, struct mail *mail,
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (maildir_file_do(mbox, mail->uid, do_open, &fd) < 0)
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen path = maildir_save_file_get_path(mail->transaction, mail->seq);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen return i_stream_create_fd(fd, MAIL_READ_BLOCK_SIZE, TRUE);
82d1fe3d5d04fb11e3e89cce03dc4de191e58f75Timo Sirainenstatic int maildir_mail_stat(struct mail *mail, struct stat *st)
857c471c13ca215f4be9dd4b336b742b8d434e31Timo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)mail->box;
82d1fe3d5d04fb11e3e89cce03dc4de191e58f75Timo Sirainen struct index_mail_data *data = &((struct index_mail *)mail)->data;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen if (data->access_part != 0 && data->stream == NULL) {
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen /* we're going to open the mail anyway */
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen (void)mail_get_stream(mail, NULL, NULL, &input);
4ba9a1d3facc515b3feb5238a16bcf91f76fac61Timo Sirainen mail_storage_set_critical(&mbox->storage->storage,
4ba9a1d3facc515b3feb5238a16bcf91f76fac61Timo Sirainen "fstat(maildir) failed: %m");
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen ret = maildir_file_do(mbox, mail->uid, do_stat, st);
d46a1e3f999dda802dc5137e883adcd7a6629cd3Timo Sirainen path = maildir_save_file_get_path(mail->transaction, mail->seq);
08e9fd42eb8007e1f9db62c088eef74f906114a5Josef 'Jeff' Sipekstatic int maildir_mail_get_received_date(struct mail *_mail, time_t *date_r)
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
306b3f41b05da642d87e7ca7a1496efce9f5902fTimo Sirainen if (index_mail_get_received_date(_mail, date_r) == 0)
97ae33602db7d5bc8eede82512a965d49ab8853bTimo Sirainenstatic int maildir_mail_get_save_date(struct mail *_mail, time_t *date_r)
30d50c7e8706f2d750215e009504109ca19cd485Timo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
57a8c6a95e4bce3eeaba36985adb81c07dd683ffTimo Sirainen if (index_mail_get_save_date(_mail, date_r) == 0)
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainenmaildir_mail_get_fname(struct maildir_mailbox *mbox, struct mail *mail,
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen const char **fname_r)
eecb235c14b49c01774134ea593c266f2d2c2be1Timo Sirainen *fname_r = maildir_uidlist_lookup(mbox->uidlist, mail->uid, &flags);
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen /* file exists in index file, but not in dovecot-uidlist anymore. */
98c217499d578495e982ea6010ebff831e9669aeMartti Rannanjärvi /* one reason this could happen is if we delayed opening
98c217499d578495e982ea6010ebff831e9669aeMartti Rannanjärvi dovecot-uidlist and we're trying to open a mail that got recently
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen expunged. Let's test this theory first: */
97ae33602db7d5bc8eede82512a965d49ab8853bTimo Sirainen view = mail_index_view_open(mbox->ibox.index);
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen exists = mail_index_lookup_seq(view, mail->uid, &seq);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen /* the message still exists in index. this means there's some
ccc895c0358108d2304239063e940b7d75f364abTimo Sirainen kind of a desync, which doesn't get fixed if cur/ mtime is
8d630c15a8ed6f85553467c3a231a273defca5f6Timo Sirainen the same as in index. fix this by forcing a resync. */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (void)maildir_storage_sync_force(mbox, mail->uid);
9fd2181788a61500641c66aec0f8c746b19bf830Timo Sirainenstatic int maildir_get_pop3_state(struct index_mail *mail)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* if this mail itself has non-pop3 fields we know we're not
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen allowed_pop3_fields = MAIL_FETCH_FLAGS | MAIL_FETCH_STREAM_HEADER |
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen MAIL_FETCH_STREAM_BODY | MAIL_FETCH_UIDL_FILE_NAME |
aa41b2e17912d6cad3151babea6a85dd88539d28Timo Sirainen (mail->wanted_fields & ~allowed_pop3_fields) != 0)
aa41b2e17912d6cad3151babea6a85dd88539d28Timo Sirainen /* get vsize decisions */
aa41b2e17912d6cad3151babea6a85dd88539d28Timo Sirainen psize_idx = mail->ibox->cache_fields[MAIL_CACHE_PHYSICAL_FULL_SIZE].idx;
aa41b2e17912d6cad3151babea6a85dd88539d28Timo Sirainen vsize_idx = mail->ibox->cache_fields[MAIL_CACHE_VIRTUAL_FULL_SIZE].idx;
aa41b2e17912d6cad3151babea6a85dd88539d28Timo Sirainen vsize_dec = mail_cache_field_get_decision(mail->ibox->cache,
aa41b2e17912d6cad3151babea6a85dd88539d28Timo Sirainen /* also check if there are any non-[pv]size cached fields */
aa41b2e17912d6cad3151babea6a85dd88539d28Timo Sirainen fields = mail_cache_register_get_list(mail->ibox->cache,
aa41b2e17912d6cad3151babea6a85dd88539d28Timo Sirainen for (i = 0; i < count; i++) {
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen dec = fields[i].decision & ~MAIL_CACHE_DECISION_FORCED;
f318b3dbe2acc177b8ee1c160e4b5b14e7f2cd41Timo Sirainen /* either nothing is cached, or only vsize is cached. */
f318b3dbe2acc177b8ee1c160e4b5b14e7f2cd41Timo Sirainen } else if (vsize_dec != MAIL_CACHE_DECISION_YES) {
f318b3dbe2acc177b8ee1c160e4b5b14e7f2cd41Timo Sirainen /* if virtual size isn't cached permanently,
f318b3dbe2acc177b8ee1c160e4b5b14e7f2cd41Timo Sirainen POP3 isn't being used */
d3280fe317a4598c0868cc440e7a1191c06d0db3Timo Sirainen /* possibly a mixed pop3/imap */
50c617761ee9653bd44646a95178773a3686d62eTimo Sirainenstatic int maildir_quick_size_lookup(struct index_mail *mail, bool vsize,
50c617761ee9653bd44646a95178773a3686d62eTimo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)mail->ibox;
62041dfb7d6ac6e9c633a557075999cdfcff7bd5Timo Sirainen if (!maildir_mail_get_fname(mbox, _mail, &fname))
aa47c9bd1d1fc70cd699c49fd1ca92dbc7615953Timo Sirainen path = maildir_save_file_get_path(_mail->transaction,
c0d069950af1dbc6a4e5c3de3bf2e437796e3ae0Timo Sirainen /* size can be included in filename */
c979eeda1f46483d9c963e265786b701d7683d77Timo Sirainen /* size can be included in uidlist entry */
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen value = maildir_uidlist_lookup_ext(mbox->uidlist, _mail->uid,
5137d2d80255938a0f5fb8f3c1a21b34cf11ada3Timo Sirainen if (*p == '\0') {
96308127e006bb3b1108093bcf4cc1fd9481cb7aTimo Sirainenmaildir_handle_size_caching(struct index_mail *mail, bool quick_check,
8a13b020f90e080570658b18c042e7e352c8b14fTimo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)mail->ibox;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen field = vsize ? MAIL_FETCH_VIRTUAL_SIZE : MAIL_FETCH_PHYSICAL_SIZE;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen if ((mail->data.dont_cache_fetch_fields & field) != 0)
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen if (quick_check && maildir_quick_size_lookup(mail, vsize, &size) > 0) {
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen /* already in filename / uidlist. don't add it anywhere,
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen including to the uidlist if it's already in filename.
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen do some extra checks here to catch potential cache bugs. */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (vsize && mail->data.virtual_size != size) {
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen "Corrupted virtual size for uid=%u: "
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainen } else if (!vsize && mail->data.physical_size != size) {
a423d985ba7261661475811c22b21b80ec765a71Timo Sirainen "Corrupted physical size for uid=%u: "
1460ef7a18c53216ddb4a94bb62fba96076aae8eTimo Sirainen /* 1 = pop3-only, 0 = mixed, -1 = no pop3 */
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen if (pop3_state >= 0 && mail->mail.mail.uid != 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* if size is wanted permanently, store it to uidlist
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen so that in case cache file gets lost we can get it quickly */
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen maildir_uidlist_set_ext(mbox->uidlist, mail->mail.mail.uid,
0177594fa5217b02001f4ec8752154fd2b05c545Timo Sirainenstatic int maildir_mail_get_virtual_size(struct mail *_mail, uoff_t *size_r)
2c70086138fe7ac9abf52cd4223c224fe0bbb488Timo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen if (index_mail_get_cached_virtual_size(mail, size_r)) {
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen i_assert(mail->data.virtual_size != (uoff_t)-1);
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen maildir_handle_size_caching(mail, TRUE, TRUE);
1ae5d61ec366fdb2f3c5b150ca378d6141b0f4bdTimo Sirainen if (maildir_quick_size_lookup(mail, TRUE, &data->virtual_size) < 0)
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen data->dont_cache_fetch_fields |= MAIL_FETCH_VIRTUAL_SIZE;
b644a77b00ce21c67a7becda974a12dfe3a946e4Timo Sirainen /* fallback to reading the file */
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen old_offset = data->stream == NULL ? 0 : data->stream->v_offset;
aa41b2e17912d6cad3151babea6a85dd88539d28Timo Sirainen if (mail_get_stream(_mail, &hdr_size, &body_size, &input) < 0)
d938e9e4ec4c0f326dffd5ebe42c1ad893ce7e52Timo Sirainen maildir_handle_size_caching(mail, FALSE, TRUE);
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainenstatic int maildir_mail_get_physical_size(struct mail *_mail, uoff_t *size_r)
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)mail->ibox;
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen if (index_mail_get_physical_size(_mail, size_r) == 0) {
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen i_assert(mail->data.physical_size != (uoff_t)-1);
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen maildir_handle_size_caching(mail, TRUE, FALSE);
546335814920fb6b5b44c68c7803e654eefeae9dTimo Sirainen if (maildir_quick_size_lookup(mail, FALSE, &data->physical_size) < 0)
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen data->dont_cache_fetch_fields |= MAIL_FETCH_PHYSICAL_SIZE;
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen ret = maildir_file_do(mbox, _mail->uid, do_stat, &st);
42507d758b053bb483de58fba55c73a9eb5d3fbaTimo Sirainen /* saved mail which hasn't been committed yet */
c0c346d0e6a76137ba5006857ed03b1227804170Timo Sirainen path = maildir_save_file_get_path(_mail->transaction,
382f23541ce657be87b079abd6784d376fb4eb43Timo Sirainen mail_storage_set_critical(_mail->box->storage,
817d027593510c3ba70ad542ce0011f5f6916d1eTimo Sirainen maildir_handle_size_caching(mail, FALSE, FALSE);
f81f4bc282cd1944cec187bae89c0701a416ed2aTimo Sirainenmaildir_mail_get_special(struct mail *_mail, enum mail_fetch_field field,
f81f4bc282cd1944cec187bae89c0701a416ed2aTimo Sirainen const char **value_r)
7e2671b295927b461adc8b6c4ed6a1c4761fb323Timo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
7e2671b295927b461adc8b6c4ed6a1c4761fb323Timo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)mail->ibox;
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen if (!maildir_mail_get_fname(mbox, _mail, &fname))
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen path = maildir_save_file_get_path(_mail->transaction,
7baab0b0b60df7ce9093d0881cd322dff1e79491Timo Sirainen *value_r = end == NULL ? fname : t_strdup_until(fname, end);
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen uidl = maildir_uidlist_lookup_ext(mbox->uidlist, _mail->uid,
33b469d1ca66dd2cc496d2d990b8b98e72952a29Timo Sirainen return index_mail_get_special(_mail, field, value_r);
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainenstatic int maildir_mail_get_stream(struct mail *_mail,
eb64c3586d854cddd693f0b811d897399076a441Timo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)mail->ibox;
b3484b5b1f47e4cf112f0e371478a2d7794b31bbTimo Sirainen data->stream = maildir_open_mail(mbox, _mail, &deleted);
19e161dd9e2c3a2ffc96ee8852bec0720cb30d1cTimo Sirainen return index_mail_init_stream(mail, hdr_size, body_size, stream_r);
540555c5b435203e1c26c8e7b924b2643ae07ae3Timo Sirainenstatic void maildir_mail_set_cache_corrupted(struct mail *_mail,
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)mail->ibox;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen /* make sure it gets removed from uidlist.
421d30619384e72a27e2a5d13ff6525aff4d17feTimo Sirainen if it's in file name, we can't really do more than log it. */
ecd69c4e8371853667e01b0c16d436ef7f7393e2Timo Sirainen if (maildir_filename_get_size(fname, MAILDIR_EXTRA_VIRTUAL_SIZE,
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen i_error("Maildir filename has wrong W value: %s/%s",
a757f31393b9d6fc7760a9dec8363404ab3ae576Timo Sirainen } else if (maildir_uidlist_lookup_ext(mbox->uidlist, _mail->uid,