dovecot-2.0: pop3: Added support for showing messages in "pop3 o...
dovecot at dovecot.org
dovecot at dovecot.org
Wed May 4 12:44:27 EEST 2011
details: http://hg.dovecot.org/dovecot-2.0/rev/c9b7e829c6a9
changeset: 12768:c9b7e829c6a9
user: Timo Sirainen <tss at iki.fi>
date: Wed May 04 11:43:59 2011 +0200
description:
pop3: Added support for showing messages in "pop3 order".
diffstat:
src/pop3/pop3-client.c | 64 ++++++++++++++++++++----
src/pop3/pop3-client.h | 18 +++++-
src/pop3/pop3-commands.c | 124 ++++++++++++++++++++++++++++++----------------
3 files changed, 148 insertions(+), 58 deletions(-)
diffs (truncated from 502 to 300 lines):
diff -r fac2d4fe86b1 -r c9b7e829c6a9 src/pop3/pop3-client.c
--- a/src/pop3/pop3-client.c Wed May 04 11:43:16 2011 +0200
+++ b/src/pop3/pop3-client.c Wed May 04 11:43:59 2011 +0200
@@ -39,6 +39,11 @@
struct client *pop3_clients;
unsigned int pop3_client_count;
+static enum mail_sort_type pop3_sort_program[] = {
+ MAIL_SORT_POP3_ORDER,
+ MAIL_SORT_END
+};
+
static void client_input(struct client *client);
static int client_output(struct client *client);
@@ -103,6 +108,28 @@
return mail_get_virtual_size(mail, size_r);
}
+static void
+msgnum_to_seq_map_add(ARRAY_TYPE(uint32_t) *msgnum_to_seq_map,
+ struct client *client, struct mail *mail,
+ unsigned int msgnum)
+{
+ uint32_t seq;
+
+ if (mail->seq == msgnum+1)
+ return;
+
+ if (!array_is_created(msgnum_to_seq_map))
+ i_array_init(msgnum_to_seq_map, client->messages_count);
+ else {
+ /* add any messages between this and the previous one that had
+ a POP3 order defined */
+ seq = array_count(msgnum_to_seq_map) + 1;
+ for (; seq <= msgnum; seq++)
+ array_append(msgnum_to_seq_map, &seq, 1);
+ }
+ array_append(msgnum_to_seq_map, &mail->seq, 1);
+}
+
static int read_mailbox(struct client *client, uint32_t *failed_uid_r)
{
struct mailbox_status status;
@@ -112,6 +139,8 @@
struct mail *mail;
uoff_t size;
ARRAY_DEFINE(message_sizes, uoff_t);
+ ARRAY_TYPE(uint32_t) msgnum_to_seq_map = ARRAY_INIT;
+ unsigned int msgnum;
int ret = 1;
*failed_uid_r = 0;
@@ -124,13 +153,14 @@
search_args = mail_search_build_init();
mail_search_build_add_all(search_args);
- ctx = mailbox_search_init(t, search_args, NULL);
+ ctx = mailbox_search_init(t, search_args, pop3_sort_program);
mail_search_args_unref(&search_args);
- client->last_seen = 0;
+ client->last_seen_pop3_msn = 0;
client->total_size = 0;
i_array_init(&message_sizes, client->messages_count);
+ msgnum = 0;
mail = mail_alloc(t, MAIL_FETCH_VIRTUAL_SIZE, NULL);
while (mailbox_search_next(ctx, mail)) {
if (pop3_mail_get_size(client, mail, &size) < 0) {
@@ -138,29 +168,40 @@
*failed_uid_r = mail->uid;
break;
}
+ msgnum_to_seq_map_add(&msgnum_to_seq_map, client, mail, msgnum);
if ((mail_get_flags(mail) & MAIL_SEEN) != 0)
- client->last_seen = mail->seq;
+ client->last_seen_pop3_msn = msgnum + 1;
client->total_size += size;
array_append(&message_sizes, &size, 1);
+ msgnum++;
}
mail_free(&mail);
if (mailbox_search_deinit(&ctx) < 0)
ret = -1;
- if (ret > 0) {
- client->trans = t;
- client->message_sizes =
- buffer_free_without_data(&message_sizes.arr.buffer);
- } else {
+ if (ret <= 0) {
/* commit the transaction instead of rollbacking to make sure
we don't lose data (virtual sizes) added to cache file */
(void)mailbox_transaction_commit(&t);
array_free(&message_sizes);
+ if (array_is_created(&msgnum_to_seq_map))
+ array_free(&msgnum_to_seq_map);
+ return ret;
}
- return ret;
+
+ client->trans = t;
+ client->message_sizes =
+ buffer_free_without_data(&message_sizes.arr.buffer);
+ if (array_is_created(&msgnum_to_seq_map)) {
+ client->msgnum_to_seq_map_count =
+ array_count(&msgnum_to_seq_map);
+ client->msgnum_to_seq_map =
+ buffer_free_without_data(&msgnum_to_seq_map.arr.buffer);
+ }
+ return 1;
}
static int init_mailbox(struct client *client, const char **error_r)
@@ -349,8 +390,8 @@
}
/* 1..new-1 were probably left to mailbox by previous POP3 session */
- old_msg_count = client->lowest_retr > 0 ?
- client->lowest_retr - 1 : client->messages_count;
+ old_msg_count = client->lowest_retr_pop3_msn > 0 ?
+ client->lowest_retr_pop3_msn - 1 : client->messages_count;
for (i = 0, old_hash = 0; i < old_msg_count; i++)
old_hash ^= client->message_uidl_hashes[i];
@@ -464,6 +505,7 @@
i_free(client->message_uidl_hashes);
i_free(client->deleted_bitmask);
i_free(client->seen_bitmask);
+ i_free(client->msgnum_to_seq_map);
if (client->io != NULL)
io_remove(&client->io);
diff -r fac2d4fe86b1 -r c9b7e829c6a9 src/pop3/pop3-client.h
--- a/src/pop3/pop3-client.h Wed May 04 11:43:16 2011 +0200
+++ b/src/pop3/pop3-client.h Wed May 04 11:43:59 2011 +0200
@@ -9,6 +9,12 @@
#define MSGS_BITMASK_SIZE(client) \
(((client)->messages_count + (CHAR_BIT-1)) / CHAR_BIT)
+/*
+ pop3_msn = 1..n in the POP3 protocol
+ msgnum = 0..n-1 = pop3_msn-1
+ seq = 1..n = mail's sequence number in lib-storage. when pop3 sort ordering
+ is used, msgnum_to_seq_map[] can be used for translation.
+*/
struct client {
struct client *prev, *next;
@@ -34,17 +40,23 @@
unsigned int uid_validity;
unsigned int messages_count;
unsigned int deleted_count, expunged_count, seen_change_count;
- uint32_t *message_uidl_hashes;
- uoff_t *message_sizes;
uoff_t total_size;
uoff_t deleted_size;
- uint32_t last_seen, lowest_retr;
+ uint32_t last_seen_pop3_msn, lowest_retr_pop3_msn;
+
+ /* [msgnum] contains mail seq. anything after it has seq = msgnum+1 */
+ uint32_t *msgnum_to_seq_map;
+ uint32_t msgnum_to_seq_map_count;
uoff_t top_bytes;
uoff_t retr_bytes;
unsigned int top_count;
unsigned int retr_count;
+ /* [msgnum] */
+ uint32_t *message_uidl_hashes;
+ uoff_t *message_sizes;
+ /* [msgnum/8] & msgnum%8 */
unsigned char *deleted_bitmask;
unsigned char *seen_bitmask;
diff -r fac2d4fe86b1 -r c9b7e829c6a9 src/pop3/pop3-commands.c
--- a/src/pop3/pop3-commands.c Wed May 04 11:43:16 2011 +0200
+++ b/src/pop3/pop3-commands.c Wed May 04 11:43:59 2011 +0200
@@ -14,6 +14,17 @@
#include "pop3-capability.h"
#include "pop3-commands.h"
+static enum mail_sort_type pop3_sort_program[] = {
+ MAIL_SORT_POP3_ORDER,
+ MAIL_SORT_END
+};
+
+static uint32_t msgnum_to_seq(struct client *client, uint32_t msgnum)
+{
+ return msgnum < client->msgnum_to_seq_map_count ?
+ client->msgnum_to_seq_map[msgnum] : msgnum+1;
+}
+
static const char *get_msgnum(struct client *client, const char *args,
unsigned int *msgnum)
{
@@ -132,8 +143,8 @@
(1 << (ctx->msgnum % CHAR_BIT)))
continue;
}
- ret = client_send_line(client, "%u %"PRIuUOFF_T,
- ctx->msgnum+1,
+
+ ret = client_send_line(client, "%u %"PRIuUOFF_T, ctx->msgnum+1,
client->message_sizes[ctx->msgnum]);
if (ret < 0)
break;
@@ -172,7 +183,7 @@
static int cmd_last(struct client *client, const char *args ATTR_UNUSED)
{
- client_send_line(client, "+OK %u", client->last_seen);
+ client_send_line(client, "+OK %u", client->last_seen_pop3_msn);
return 1;
}
@@ -197,12 +208,28 @@
return search_args;
}
+static int client_verify_ordering(struct client *client,
+ struct mail *mail, uint32_t msgnum)
+{
+ uint32_t seq;
+
+ seq = msgnum_to_seq(client, msgnum);
+ if (seq != mail->seq) {
+ i_error("Message ordering changed unexpectedly "
+ "(msg #%u: storage seq %u -> %u)",
+ msgnum+1, seq, mail->seq);
+ return -1;
+ }
+ return 0;
+}
+
bool client_update_mails(struct client *client)
{
struct mail_search_args *search_args;
struct mail_search_context *ctx;
struct mail *mail;
- uint32_t idx, bit;
+ uint32_t msgnum, bit;
+ bool ret = TRUE;
if (mailbox_is_readonly(client->mailbox)) {
/* silently ignore */
@@ -210,26 +237,35 @@
}
search_args = pop3_search_build(client, 0);
- ctx = mailbox_search_init(client->trans, search_args, NULL);
+ ctx = mailbox_search_init(client->trans, search_args,
+ pop3_sort_program);
mail_search_args_unref(&search_args);
+ msgnum = 0;
mail = mail_alloc(client->trans, 0, NULL);
while (mailbox_search_next(ctx, mail)) {
- idx = mail->seq - 1;
- bit = 1 << (idx % CHAR_BIT);
+ if (client_verify_ordering(client, mail, msgnum) < 0) {
+ ret = FALSE;
+ break;
+ }
+
+ bit = 1 << (msgnum % CHAR_BIT);
if (client->deleted_bitmask != NULL &&
- (client->deleted_bitmask[idx / CHAR_BIT] & bit) != 0) {
+ (client->deleted_bitmask[msgnum / CHAR_BIT] & bit) != 0) {
mail_expunge(mail);
client->expunged_count++;
} else if (client->seen_bitmask != NULL &&
- (client->seen_bitmask[idx / CHAR_BIT] & bit) != 0) {
+ (client->seen_bitmask[msgnum / CHAR_BIT] & bit) != 0) {
mail_update_flags(mail, MODIFY_ADD, MAIL_SEEN);
}
+ msgnum++;
}
mail_free(&mail);
client->seen_change_count = 0;
- return mailbox_search_deinit(&ctx) == 0;
+ if (mailbox_search_deinit(&ctx) < 0)
+ ret = FALSE;
+ return ret;
}
static int cmd_quit(struct client *client, const char *args ATTR_UNUSED)
@@ -260,7 +296,6 @@
}
struct fetch_context {
- struct mail_search_context *search_ctx;
struct mail *mail;
struct istream *stream;
More information about the dovecot-cvs
mailing list