typedef void command_func_t(struct client *client);
+#define MSGS_BITMASK_SIZE(client) \
+ (((client)->messages_count + (CHAR_BIT-1)) / CHAR_BIT)
+
struct client {
int fd_in, fd_out;
struct io *io;
unsigned int uid_validity;
unsigned int messages_count;
- unsigned int deleted_count;
- unsigned int expunged_count;
+ unsigned int deleted_count, expunged_count, seen_change_count;
uoff_t *message_sizes;
uoff_t total_size;
uoff_t deleted_size;
uoff_t byte_counter_offset;
unsigned char *deleted_bitmask;
+ unsigned char *seen_bitmask;
unsigned int disconnected:1;
unsigned int deleted:1;
#include "capability.h"
#include "commands.h"
-#define MSGS_BITMASK_SIZE(client) \
- ((client->messages_count + (CHAR_BIT-1)) / CHAR_BIT)
-
static const char *get_msgnum(struct client *client, const char *args,
unsigned int *msgnum)
{
return search_args;
}
-static bool expunge_mails(struct client *client)
+static bool update_mails(struct client *client)
{
struct mail_search_args *search_args;
struct mail_search_context *ctx;
struct mail *mail;
- uint32_t idx;
-
- if (client->deleted_bitmask == NULL)
- return TRUE;
+ uint32_t idx, bit;
if (mailbox_is_readonly(client->mailbox)) {
/* silently ignore */
mail = mail_alloc(client->trans, 0, NULL);
while (mailbox_search_next(ctx, mail) > 0) {
idx = mail->seq - 1;
- if ((client->deleted_bitmask[idx / CHAR_BIT] &
- 1 << (idx % CHAR_BIT)) != 0) {
+ bit = 1 << (idx % CHAR_BIT);
+ if (client->deleted_bitmask != NULL &&
+ (client->deleted_bitmask[idx / CHAR_BIT] & bit) != 0) {
mail_expunge(mail);
client->expunged_count++;
+ } else if (client->seen_bitmask != NULL &&
+ (client->seen_bitmask[idx / CHAR_BIT] & bit) != 0) {
+ mail_update_flags(mail, MODIFY_ADD, MAIL_SEEN);
}
}
mail_free(&mail);
static int cmd_quit(struct client *client, const char *args ATTR_UNUSED)
{
- if (client->deleted) {
- if (!expunge_mails(client)) {
+ if (client->deleted || client->seen_bitmask != NULL) {
+ if (!update_mails(client)) {
client_send_storage_error(client);
client_disconnect(client,
"Storage error during logout.");
return ret;
}
- if (body_lines == (uoff_t)-1 && !no_flag_updates) {
+ if (body_lines == (uoff_t)-1 && client->seen_bitmask != NULL) {
if ((mail_get_flags(ctx->mail) & MAIL_SEEN) == 0) {
/* mark the message seen with RETR command */
- (void)mail_update_flags(ctx->mail,
- MODIFY_ADD, MAIL_SEEN);
+ client->seen_bitmask[msgnum / CHAR_BIT] |= 1 << (msgnum % CHAR_BIT);
+ client->seen_change_count++;
}
}
client->deleted_count = 0;
client->deleted_size = 0;
}
+ if (client->seen_change_count > 0) {
+ memset(client->seen_bitmask, 0, MSGS_BITMASK_SIZE(client));
+ client->seen_change_count = 0;
+ }
if (enable_last_command) {
/* remove all \Seen flags (as specified by RFC 1460) */
mail_update_flags(mail, MODIFY_REMOVE, MAIL_SEEN);
mail_free(&mail);
(void)mailbox_search_deinit(&search_ctx);
- } else {
- /* forget all our seen flag updates.
- FIXME: is this needed? it loses data added to cache file */
- mailbox_transaction_rollback(&client->trans);
+
+ mailbox_transaction_commit(&client->trans);
client->trans = mailbox_transaction_begin(client->mailbox, 0);
}