From: Timo Sirainen Date: Tue, 14 May 2013 13:32:30 +0000 (+0300) Subject: pop3: Added pop3_deleted_flag setting. X-Git-Tag: 2.2.2~30 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f64b66ffacc4e42002d87b940ef74f08b1e5b12f;p=thirdparty%2Fdovecot%2Fcore.git pop3: Added pop3_deleted_flag setting. --- diff --git a/doc/example-config/conf.d/20-pop3.conf b/doc/example-config/conf.d/20-pop3.conf index be64c2c23c..ded9fa9c4d 100644 --- a/doc/example-config/conf.d/20-pop3.conf +++ b/doc/example-config/conf.d/20-pop3.conf @@ -59,6 +59,13 @@ protocol pop3 { # rename: Append a temporary -2, -3, etc. counter after the UIDL. #pop3_uidl_duplicates = allow + # This option changes POP3 behavior so that it's not possible to actually + # delete mails via POP3, only hide them from future POP3 sessions. The mails + # will still be counted towards user's quota until actually deleted via IMAP. + # Use e.g. "$POP3Deleted" as the value (it will be visible as IMAP keyword). + # Make sure you can legally archive mails before enabling this setting. + #pop3_deleted_flag = + # POP3 logout format string: # %i - total number of bytes read from client # %o - total number of bytes sent to client diff --git a/src/pop3/pop3-client.c b/src/pop3/pop3-client.c index e99f7bd0e1..6de571c201 100644 --- a/src/pop3/pop3-client.c +++ b/src/pop3/pop3-client.c @@ -141,6 +141,7 @@ static int read_mailbox(struct client *client, uint32_t *failed_uid_r) struct mailbox_status status; struct mailbox_transaction_context *t; struct mail_search_args *search_args; + struct mail_search_arg *sarg; struct mail_search_context *ctx; struct mail *mail; uoff_t size; @@ -158,7 +159,17 @@ static int read_mailbox(struct client *client, uint32_t *failed_uid_r) t = mailbox_transaction_begin(client->mailbox, 0); search_args = mail_search_build_init(); - mail_search_build_add_all(search_args); + if (client->deleted_kw != NULL) { + sarg = mail_search_build_add(search_args, SEARCH_KEYWORDS); + sarg->match_not = TRUE; + sarg->value.str = p_strdup(search_args->pool, + client->set->pop3_deleted_flag); + i_array_init(&client->all_seqs, 32); + } else { + mail_search_build_add_all(search_args); + } + mail_search_args_init(search_args, client->mailbox, TRUE, NULL); + ctx = mailbox_search_init(t, search_args, pop3_sort_program, client->set->pop3_fast_size_lookups ? 0 : MAIL_FETCH_VIRTUAL_SIZE, NULL); @@ -175,6 +186,8 @@ static int read_mailbox(struct client *client, uint32_t *failed_uid_r) *failed_uid_r = mail->uid; break; } + if (array_is_created(&client->all_seqs)) + seq_range_array_add(&client->all_seqs, mail->seq); msgnum_to_seq_map_add(&msgnum_to_seq_map, client, mail, msgnum); if ((mail_get_flags(mail) & MAIL_SEEN) != 0) @@ -197,7 +210,13 @@ static int read_mailbox(struct client *client, uint32_t *failed_uid_r) array_free(&msgnum_to_seq_map); return ret; } - i_assert(msgnum == client->messages_count); + i_assert(msgnum <= client->messages_count); + client->messages_count = msgnum; + + if (!array_is_created(&client->all_seqs)) { + i_array_init(&client->all_seqs, 1); + seq_range_array_add_range(&client->all_seqs, 1, msgnum); + } client->trans = t; client->message_sizes = @@ -211,6 +230,26 @@ static int read_mailbox(struct client *client, uint32_t *failed_uid_r) return 1; } +static int init_pop3_deleted_flag(struct client *client, const char **error_r) +{ + const char *deleted_keywords[2]; + + if (client->set->pop3_deleted_flag[0] == '\0') + return 0; + + deleted_keywords[0] = client->set->pop3_deleted_flag; + deleted_keywords[1] = NULL; + if (mailbox_keywords_create(client->mailbox, deleted_keywords, + &client->deleted_kw) < 0) { + *error_r = t_strdup_printf( + "pop3_deleted_flags: Invalid keyword '%s': %s", + client->set->pop3_deleted_flag, + mailbox_get_last_error(client->mailbox, NULL)); + return -1; + } + return 0; +} + static int init_mailbox(struct client *client, const char **error_r) { uint32_t failed_uid = 0, last_failed_uid = 0; @@ -392,7 +431,8 @@ int client_create(int fd_in, int fd_out, const char *session_id, } client->mail_set = mail_storage_get_settings(storage); - if (init_mailbox(client, &errmsg) < 0) { + if (init_pop3_deleted_flag(client, &errmsg) < 0 || + init_mailbox(client, &errmsg) < 0) { i_error("Couldn't init INBOX: %s", errmsg); client_destroy(client, "Mailbox init failed"); return -1; @@ -553,6 +593,9 @@ static void client_default_destroy(struct client *client, const char *reason) message sizes. */ (void)mailbox_transaction_commit(&client->trans); } + array_free(&client->all_seqs); + if (client->deleted_kw != NULL) + mailbox_keywords_unref(&client->deleted_kw); if (client->mailbox != NULL) mailbox_free(&client->mailbox); if (client->anvil_sent) { diff --git a/src/pop3/pop3-client.h b/src/pop3/pop3-client.h index 5c3bfe5726..f8e6c35286 100644 --- a/src/pop3/pop3-client.h +++ b/src/pop3/pop3-client.h @@ -1,6 +1,8 @@ #ifndef POP3_CLIENT_H #define POP3_CLIENT_H +#include "seq-range-array.h" + struct client; struct mail_storage; @@ -48,6 +50,7 @@ struct client { struct mail_namespace *inbox_ns; struct mailbox *mailbox; struct mailbox_transaction_context *trans; + struct mail_keywords *deleted_kw; struct timeout *to_session_dotlock_refresh; struct dotlock *session_dotlock; @@ -63,6 +66,9 @@ struct client { uoff_t deleted_size; uint32_t last_seen_pop3_msn, lowest_retr_pop3_msn; + /* All sequences currently visible in the mailbox. */ + ARRAY_TYPE(seq_range) all_seqs; + /* [msgnum] contains mail seq. anything after it has seq = msgnum+1 */ uint32_t *msgnum_to_seq_map; uint32_t msgnum_to_seq_map_count; diff --git a/src/pop3/pop3-commands.c b/src/pop3/pop3-commands.c index a617f94afa..29e1d4474d 100644 --- a/src/pop3/pop3-commands.c +++ b/src/pop3/pop3-commands.c @@ -196,11 +196,12 @@ static struct mail_search_args * pop3_search_build(struct client *client, uint32_t seq) { struct mail_search_args *search_args; + struct mail_search_arg *sarg; search_args = mail_search_build_init(); if (seq == 0) { - mail_search_build_add_seqset(search_args, - 1, client->messages_count); + sarg = mail_search_build_add(search_args, SEARCH_SEQSET); + sarg->value.seqset = client->all_seqs; } else { mail_search_build_add_seqset(search_args, seq, seq); } @@ -222,6 +223,15 @@ static int client_verify_ordering(struct client *client, return 0; } +static void client_expunge(struct client *client, struct mail *mail) +{ + if (client->deleted_kw != NULL) + mail_update_keywords(mail, MODIFY_ADD, client->deleted_kw); + else + mail_expunge(mail); + client->expunged_count++; +} + bool client_update_mails(struct client *client) { struct mail_search_args *search_args; @@ -250,8 +260,7 @@ bool client_update_mails(struct client *client) bit = 1 << (msgnum % CHAR_BIT); if (client->deleted_bitmask != NULL && (client->deleted_bitmask[msgnum / CHAR_BIT] & bit) != 0) { - mail_expunge(mail); - client->expunged_count++; + client_expunge(client, mail); } else if (client->seen_bitmask != NULL && (client->seen_bitmask[msgnum / CHAR_BIT] & bit) != 0) { mail_update_flags(mail, MODIFY_ADD, MAIL_SEEN); diff --git a/src/pop3/pop3-settings.c b/src/pop3/pop3-settings.c index 2f3fbfffbb..d9dc69af5b 100644 --- a/src/pop3/pop3-settings.c +++ b/src/pop3/pop3-settings.c @@ -71,6 +71,7 @@ static const struct setting_define pop3_setting_defines[] = { DEF(SET_STR, pop3_client_workarounds), DEF(SET_STR, pop3_logout_format), DEF(SET_ENUM, pop3_uidl_duplicates), + DEF(SET_STR, pop3_deleted_flag), SETTING_DEFINE_LIST_END }; @@ -86,7 +87,8 @@ static const struct pop3_settings pop3_default_settings = { .pop3_fast_size_lookups = FALSE, .pop3_client_workarounds = "", .pop3_logout_format = "top=%t/%p, retr=%r/%b, del=%d/%m, size=%s", - .pop3_uidl_duplicates = "allow:rename" + .pop3_uidl_duplicates = "allow:rename", + .pop3_deleted_flag = "" }; static const struct setting_parser_info *pop3_setting_dependencies[] = { diff --git a/src/pop3/pop3-settings.h b/src/pop3/pop3-settings.h index e9bd2ba03d..90cbf77662 100644 --- a/src/pop3/pop3-settings.h +++ b/src/pop3/pop3-settings.h @@ -23,6 +23,7 @@ struct pop3_settings { const char *pop3_client_workarounds; const char *pop3_logout_format; const char *pop3_uidl_duplicates; + const char *pop3_deleted_flag; enum pop3_client_workarounds parsed_workarounds; };