#include "lib.h"
#include "str.h"
+#include "ioloop.h"
#include "istream.h"
#include "istream-header-filter.h"
#include "message-header-parser.h"
#include "imapc-storage.h"
static void
-imapc_mail_prefetch_callback(const struct imapc_command_reply *reply,
- void *context)
+imapc_mail_fetch_callback(const struct imapc_command_reply *reply,
+ void *context)
{
- struct imapc_mail *mail = context;
- struct imapc_mailbox *mbox =
- (struct imapc_mailbox *)mail->imail.mail.mail.box;
+ struct imapc_fetch_request *request = context;
+ struct imapc_fetch_request *const *requests;
+ struct imapc_mail *const *mailp;
+ struct imapc_mailbox *mbox = NULL;
+ unsigned int i, count;
- i_assert(mail->fetch_count > 0);
+ array_foreach(&request->mails, mailp) {
+ struct imapc_mail *mail = *mailp;
- if (--mail->fetch_count == 0) {
- struct imapc_mail *const *fetch_mails;
- unsigned int i, count;
+ i_assert(mail->fetch_count > 0);
+ if (--mail->fetch_count == 0)
+ mail->fetching_fields = 0;
+ pool_unref(&mail->imail.mail.pool);
+ mbox = (struct imapc_mailbox *)mail->imail.mail.mail.box;
+ }
+ i_assert(mbox != NULL);
- fetch_mails = array_get(&mbox->fetch_mails, &count);
- for (i = 0; i < count; i++) {
- if (fetch_mails[i] == mail) {
- array_delete(&mbox->fetch_mails, i, 1);
- break;
- }
+ requests = array_get(&mbox->fetch_requests, &count);
+ for (i = 0; i < count; i++) {
+ if (requests[i] == request) {
+ array_delete(&mbox->fetch_requests, i, 1);
+ break;
}
- i_assert(i != count);
- mail->fetching_fields = 0;
}
+ i_assert(i < count);
+
+ array_free(&request->mails);
+ i_free(request);
if (reply->state == IMAPC_COMMAND_STATE_OK)
;
mail_storage_set_internal_error(&mbox->storage->storage);
} else {
mail_storage_set_critical(&mbox->storage->storage,
- "imapc: Mail prefetch failed: %s", reply->text_full);
+ "imapc: Mail FETCH failed: %s", reply->text_full);
}
- pool_unref(&mail->imail.mail.pool);
imapc_client_stop(mbox->storage->client->client);
}
return array_idx(&headers, 0);
}
+static bool
+imapc_mail_try_merge_fetch(struct imapc_mailbox *mbox, string_t *str)
+{
+ const char *s1 = str_c(str);
+ const char *s2 = str_c(mbox->pending_fetch_cmd);
+ const char *p1, *p2;
+
+ i_assert(strncmp(s1, "UID FETCH ", 10) == 0);
+ i_assert(strncmp(s2, "UID FETCH ", 10) == 0);
+
+ /* skip over UID range */
+ p1 = strchr(s1+10, ' ');
+ p2 = strchr(s2+10, ' ');
+
+ if (null_strcmp(p1, p2) != 0)
+ return FALSE;
+ /* append the new UID to the pending FETCH UID range */
+ str_truncate(str, p1-s1);
+ str_insert(mbox->pending_fetch_cmd, p2-s2, ",");
+ str_insert(mbox->pending_fetch_cmd, p2-s2+1, str_c(str) + 10);
+ return TRUE;
+}
+
+static void
+imapc_mail_delayed_send_or_merge(struct imapc_mail *mail, string_t *str)
+{
+ struct imapc_mailbox *mbox =
+ (struct imapc_mailbox *)mail->imail.mail.mail.box;
+
+ if (mbox->pending_fetch_request != NULL &&
+ !imapc_mail_try_merge_fetch(mbox, str)) {
+ /* send the previous FETCH and create a new one */
+ imapc_mail_fetch_flush(mbox);
+ }
+ if (mbox->pending_fetch_request == NULL) {
+ mbox->pending_fetch_request =
+ i_new(struct imapc_fetch_request, 1);
+ i_array_init(&mbox->pending_fetch_request->mails, 4);
+ i_assert(mbox->pending_fetch_cmd->used == 0);
+ str_append_str(mbox->pending_fetch_cmd, str);
+ }
+ array_append(&mbox->pending_fetch_request->mails, &mail, 1);
+
+ if (mbox->to_pending_fetch_send == NULL) {
+ mbox->to_pending_fetch_send =
+ timeout_add_short(0, imapc_mail_fetch_flush, mbox);
+ }
+}
+
static int
imapc_mail_send_fetch(struct mail *_mail, enum mail_fetch_field fields,
const char *const *headers)
{
struct imapc_mail *mail = (struct imapc_mail *)_mail;
struct imapc_mailbox *mbox = (struct imapc_mailbox *)_mail->box;
- struct imapc_command *cmd;
struct mail_index_view *view;
string_t *str;
uint32_t seq;
pool_ref(mail->imail.mail.pool);
mail->fetching_fields |= fields;
- if (mail->fetch_count++ == 0)
- array_append(&mbox->fetch_mails, &mail, 1);
+ mail->fetch_count++;
- cmd = imapc_client_mailbox_cmd(mbox->client_box,
- imapc_mail_prefetch_callback, mail);
- imapc_command_set_flags(cmd, IMAPC_COMMAND_FLAG_RETRIABLE);
- imapc_command_send(cmd, str_c(str));
- mail->imail.data.prefetch_sent = TRUE;
- return 0;
+ imapc_mail_delayed_send_or_merge(mail, str);
+ return 1;
}
static void imapc_mail_cache_get(struct imapc_mail *mail,
fields = imapc_mail_get_wanted_fetch_fields(mail);
if (fields != 0) T_BEGIN {
- (void)imapc_mail_send_fetch(_mail, fields,
- data->wanted_headers == NULL ? NULL :
- data->wanted_headers->name);
+ if (imapc_mail_send_fetch(_mail, fields,
+ data->wanted_headers == NULL ? NULL :
+ data->wanted_headers->name) > 0)
+ mail->imail.data.prefetch_sent = TRUE;
} T_END;
return !mail->imail.data.prefetch_sent;
}
while (imail->fetch_count > 0 &&
(!imapc_mail_have_fields(imail, fields) ||
!imail->header_list_fetched))
- imapc_storage_run(mbox->storage);
+ imapc_mailbox_run(mbox);
return 0;
}
+void imapc_mail_fetch_flush(struct imapc_mailbox *mbox)
+{
+ struct imapc_command *cmd;
+
+ if (mbox->pending_fetch_request == NULL) {
+ i_assert(mbox->to_pending_fetch_send == NULL);
+ return;
+ }
+
+ cmd = imapc_client_mailbox_cmd(mbox->client_box,
+ imapc_mail_fetch_callback,
+ mbox->pending_fetch_request);
+ imapc_command_set_flags(cmd, IMAPC_COMMAND_FLAG_RETRIABLE);
+ imapc_command_send(cmd, str_c(mbox->pending_fetch_cmd));
+
+ array_append(&mbox->fetch_requests, &mbox->pending_fetch_request, 1);
+ mbox->pending_fetch_request = NULL;
+ timeout_remove(&mbox->to_pending_fetch_send);
+ str_truncate(mbox->pending_fetch_cmd, 0);
+}
+
static bool imapc_find_lfile_arg(const struct imapc_untagged_reply *reply,
const struct imap_arg *arg, int *fd_r)
{
imapc_client_run(sctx->client->client);
}
-void imapc_storage_run(struct imapc_storage *storage)
+void imapc_mailbox_run(struct imapc_mailbox *mbox)
{
+ imapc_mail_fetch_flush(mbox);
do {
- imapc_client_run(storage->client->client);
- } while (storage->reopen_count > 0);
+ imapc_client_run(mbox->storage->client->client);
+ } while (mbox->storage->reopen_count > 0);
}
void imapc_simple_callback(const struct imapc_command_reply *reply,
p_array_init(&mbox->untagged_callbacks, pool, 16);
p_array_init(&mbox->resp_text_callbacks, pool, 16);
- p_array_init(&mbox->fetch_mails, pool, 16);
+ p_array_init(&mbox->fetch_requests, pool, 16);
p_array_init(&mbox->delayed_expunged_uids, pool, 16);
+ mbox->pending_fetch_cmd = str_new(pool, 128);
mbox->prev_mail_cache.fd = -1;
imapc_mailbox_register_callbacks(mbox);
return &mbox->box;
imapc_command_sendf(cmd, "SELECT %s", mbox->box.name);
while (ctx.ret == -2)
- imapc_storage_run(mbox->storage);
+ imapc_mailbox_run(mbox);
return ctx.ret;
}
{
struct imapc_mailbox *mbox = (struct imapc_mailbox *)box;
+ imapc_mail_fetch_flush(mbox);
if (mbox->client_box != NULL)
imapc_client_mailbox_close(&mbox->client_box);
if (mbox->delayed_sync_view != NULL)