smaller than the fetched message header. In this case change the
size as well, otherwise reading via istream-mail will fail. */
if (mail->body_fetched || imail->data.physical_size < size) {
+ if (mail->body_fetched)
+ imail->data.inexact_total_sizes = FALSE;
imail->data.physical_size = size;
/* we'll assume that the remote server is working properly and
sending CRLF linefeeds */
} else if (strcasecmp(key, "RFC822.SIZE") == 0) {
if (imap_arg_get_atom(&args[i+1], &value) &&
str_to_uoff(value, &size) == 0 &&
- IMAPC_BOX_HAS_FEATURE(mbox, IMAPC_FEATURE_RFC822_SIZE))
+ IMAPC_BOX_HAS_FEATURE(mbox, IMAPC_FEATURE_RFC822_SIZE)) {
mail->imail.data.physical_size = size;
+ mail->imail.data.virtual_size = size;
+ mail->imail.data.inexact_total_sizes = TRUE;
+ }
match = TRUE;
} else if (strcasecmp(key, "X-GM-MSGID") == 0 ||
strcasecmp(key, "X-GUID") == 0) {
if (IMAPC_BOX_HAS_FEATURE(mbox, IMAPC_FEATURE_RFC822_SIZE) &&
data->stream == NULL) {
- /* trust RFC822.SIZE to be correct */
+ /* Trust RFC822.SIZE to be correct enough to present to the
+ IMAP client. However, it can be wrong in some implementation
+ so try not to trust it too much. */
if (imapc_mail_fetch(_mail, MAIL_FETCH_PHYSICAL_SIZE, NULL) < 0)
return -1;
if (data->physical_size == (uoff_t)-1) {
{
struct imapc_mail *imail = IMAPC_MAIL(_mail);
struct index_mail *mail = &imail->imail;
+ struct imapc_mailbox *mbox = (struct imapc_mailbox *)_mail->box;
index_mail_set_seq(_mail, seq, saving);
+ if (IMAPC_BOX_HAS_FEATURE(mbox, IMAPC_FEATURE_RFC822_SIZE)) {
+ /* RFC822.SIZE may be read from vsize record or cache. It may
+ not be exactly correct. */
+ mail->data.inexact_total_sizes = TRUE;
+ }
/* searching code handles prefetching internally,
elsewhere we want to do it immediately */
{
struct index_mail_data *data = &mail->data;
- if (data->hdr_size_set &&
+ if (data->hdr_size_set && !data->inexact_total_sizes &&
data->physical_size != (uoff_t)-1 &&
data->virtual_size != (uoff_t)-1) {
+ /* We know the total size of this mail and we know the
+ header size, so we can calculate also the body size.
+ However, don't do this if there's a possibility that
+ physical_size or virtual_size don't actually match the
+ mail stream's size (e.g. buggy imapc servers). */
data->body_size.physical_size = data->physical_size -
data->hdr_size.physical_size;
data->body_size.virtual_size = data->virtual_size -
struct mail *_mail = &mail->mail.mail;
struct index_mail_data *data = &mail->data;
struct istream *input;
- bool has_nuls;
+ bool has_nuls, body_size_from_stream = FALSE;
int ret;
if (_mail->box->storage->user->mail_debug &&
}
data->body_size_set = TRUE;
}
+ body_size_from_stream = TRUE;
}
*body_size = data->body_size;
data->body_size.virtual_size;
data->physical_size = data->hdr_size.physical_size +
data->body_size.physical_size;
+ if (body_size_from_stream) {
+ /* the sizes were just calculated */
+ data->inexact_total_sizes = FALSE;
+ }
}
ret = index_mail_stream_check_failure(mail);
bool destroy_callback_set:1;
bool prefetch_sent:1;
bool header_parser_initialized:1;
+ /* virtual_size and physical_size may not match the stream size.
+ Try to avoid trusting them too much. */
+ bool inexact_total_sizes:1;
};
struct index_mail {