return 0;
}
+static void imapc_mail_cache_get(struct imapc_mail *mail,
+ struct imapc_mail_cache *cache)
+{
+ if (mail->body_fetched)
+ return;
+
+ if (cache->fd != -1) {
+ mail->fd = cache->fd;
+ mail->imail.data.stream =
+ i_stream_create_fd(mail->fd, 0, FALSE);
+ cache->fd = -1;
+ } else if (cache->buf != NULL) {
+ mail->body = cache->buf;
+ mail->imail.data.stream =
+ i_stream_create_from_data(mail->body->data,
+ mail->body->used);
+ cache->buf = NULL;
+ } else {
+ return;
+ }
+ mail->body_fetched = TRUE;
+ imapc_mail_init_stream(mail, TRUE);
+}
+
bool imapc_mail_prefetch(struct mail *_mail)
{
struct imapc_mail *mail = (struct imapc_mail *)_mail;
+ struct imapc_mailbox *mbox = (struct imapc_mailbox *)_mail->box;
struct index_mail_data *data = &mail->imail.data;
enum mail_fetch_field fields = 0;
+ if (mbox->prev_mail_cache.uid == _mail->uid)
+ imapc_mail_cache_get(mail, &mbox->prev_mail_cache);
+
if ((mail->imail.wanted_fields & MAIL_FETCH_RECEIVED_DATE) != 0 &&
data->received_date == (time_t)-1)
fields |= MAIL_FETCH_RECEIVED_DATE;
return;
/* maybe the existing stream has no body. replace it. */
i_stream_unref(&imail->data.stream);
+ if (mail->fd != -1) {
+ if (close(mail->fd) < 0)
+ i_error("close(imapc mail) failed: %m");
+ mail->fd = -1;
+ }
}
if (arg->type == IMAP_ARG_LITERAL_SIZE) {
i_error("dup() failed: %m");
return;
}
- imail->data.stream = i_stream_create_fd(fd, 0, TRUE);
+ mail->fd = fd;
+ imail->data.stream = i_stream_create_fd(fd, 0, FALSE);
} else {
if (!imap_arg_get_nstring(arg, &value))
return;
imail->data.stream = i_stream_create_from_data(mail->body->data,
mail->body->used);
}
+ mail->body_fetched = body;
imapc_mail_init_stream(mail, body);
}
pool = pool_alloconly_create("mail", 2048);
mail = p_new(pool, struct imapc_mail, 1);
mail->imail.mail.pool = pool;
+ mail->fd = -1;
index_mail_init(&mail->imail, t, wanted_fields, wanted_headers);
return &mail->imail.mail.mail;
static void imapc_mail_free(struct mail *_mail)
{
struct imapc_mail *mail = (struct imapc_mail *)_mail;
-
+ struct imapc_mailbox *mbox = (struct imapc_mailbox *)_mail->box;
+ struct imapc_mail_cache *cache = &mbox->prev_mail_cache;
+
+ if (mail->body_fetched) {
+ imapc_mail_cache_free(cache);
+ cache->uid = _mail->uid;
+ if (cache->fd != -1) {
+ cache->fd = mail->fd;
+ mail->fd = -1;
+ } else {
+ cache->buf = mail->body;
+ mail->body = NULL;
+ }
+ }
+ if (mail->fd != -1) {
+ if (close(mail->fd) < 0)
+ i_error("close(imapc mail) failed: %m");
+ }
if (mail->body != NULL)
buffer_free(&mail->body);
+
index_mail_free(_mail);
}
enum mail_fetch_field fetching_fields;
unsigned int fetch_count;
+ int fd;
buffer_t *body;
+ bool body_fetched;
};
extern struct mail_vfuncs imapc_mail_vfuncs;
str_to_uint32(reply->resp_text_value, &uid_validity) < 0)
return;
- mbox->sync_uid_validity = uid_validity;
+ if (mbox->sync_uid_validity != uid_validity) {
+ mbox->sync_uid_validity = uid_validity;
+ imapc_mail_cache_free(&mbox->prev_mail_cache);
+ }
}
static void
p_array_init(&mbox->fetch_mails, pool, 16);
p_array_init(&mbox->permanent_keywords, pool, 32);
p_array_init(&mbox->delayed_expunged_uids, pool, 16);
+ mbox->prev_mail_cache.fd = -1;
imapc_mailbox_register_callbacks(mbox);
return &mbox->box;
}
return 0;
}
+void imapc_mail_cache_free(struct imapc_mail_cache *cache)
+{
+ if (cache->fd != -1) {
+ if (close(cache->fd) < 0)
+ i_error("close(imapc cached mail) failed: %m");
+ cache->fd = -1;
+ }
+ if (cache->buf != NULL)
+ buffer_free(&cache->buf);
+ cache->uid = 0;
+}
+
static void imapc_mailbox_close(struct mailbox *box)
{
struct imapc_mailbox *mbox = (struct imapc_mailbox *)box;
ARRAY_DEFINE(untagged_callbacks, struct imapc_storage_event_callback);
};
+struct imapc_mail_cache {
+ uint32_t uid;
+
+ /* either fd != -1 or buf != NULL */
+ int fd;
+ buffer_t *buf;
+};
+
struct imapc_mailbox {
struct mailbox box;
struct imapc_storage *storage;
uint32_t exists_count;
uint32_t min_append_uid;
+ /* keep the previous fetched message body cached,
+ mainly for partial IMAP fetches */
+ struct imapc_mail_cache prev_mail_cache;
+
uint32_t prev_skipped_rseq, prev_skipped_uid;
unsigned int selecting:1;
void imapc_transaction_save_rollback(struct mail_save_context *ctx);
void imapc_storage_run(struct imapc_storage *storage);
+void imapc_mail_cache_free(struct imapc_mail_cache *cache);
void imapc_copy_error_from_reply(struct imapc_storage *storage,
enum mail_error default_error,