]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
pop3: Added pop3_deleted_flag setting.
authorTimo Sirainen <tss@iki.fi>
Tue, 14 May 2013 13:32:30 +0000 (16:32 +0300)
committerTimo Sirainen <tss@iki.fi>
Tue, 14 May 2013 13:32:30 +0000 (16:32 +0300)
doc/example-config/conf.d/20-pop3.conf
src/pop3/pop3-client.c
src/pop3/pop3-client.h
src/pop3/pop3-commands.c
src/pop3/pop3-settings.c
src/pop3/pop3-settings.h

index be64c2c23c87d4d8bd7f8160477ca05ac71a318e..ded9fa9c4da1f4cb133bafb939de29cb201d9113 100644 (file)
@@ -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
index e99f7bd0e1485246ef91c2a1499ded77b62e332d..6de571c2019a5797f03d1f0168508b64940e59c8 100644 (file)
@@ -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) {
index 5c3bfe57263e68d92ce07018041553918c00da1a..f8e6c35286e7b6563fc5995763bbb41a29528034 100644 (file)
@@ -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;
index a617f94afa290c4da1e5fa61dc68467393feb923..29e1d4474de411da1a3ff4cc5c4281f74ab6eca8 100644 (file)
@@ -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);
index 2f3fbfffbba899ac5857ba81c5efdbeab6a5bfee..d9dc69af5b54bae349a871edc8bc784ec4729401 100644 (file)
@@ -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[] = {
index e9bd2ba03d2a937fe1026f6bce8019b1dc99fdc2..90cbf7766247b7e4011410ab4acb332021e2cbe5 100644 (file)
@@ -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;
 };