]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-storage: Set keyword based on attachment presence when saving
authorAki Tuomi <aki.tuomi@dovecot.fi>
Sat, 11 Nov 2017 08:07:42 +0000 (10:07 +0200)
committerTimo Sirainen <timo.sirainen@dovecot.fi>
Wed, 17 Jan 2018 13:48:00 +0000 (15:48 +0200)
If attachment is detected, use $HasAttachment, if not
use $HasNoAttachment

src/lib-storage/mail-storage-private.h
src/lib-storage/mail-storage.c
src/lib-storage/mail-storage.h
src/lib-storage/mail.c

index 6a7e37c2fe1f70b3d49085c22e9913b611a5cfd1..552163f0d5841ea2d92d579d2f2a2b1cf8fc1bb3 100644 (file)
@@ -774,6 +774,12 @@ bool mail_prefetch(struct mail *mail);
 void mail_set_aborted(struct mail *mail);
 void mail_set_expunged(struct mail *mail);
 void mail_set_seq_saving(struct mail *mail, uint32_t seq);
+/* Returns true IF and only IF the mail has EITHER one of the
+   attachment keywords set. If it has both, or none, it will return FALSE. */
+bool mail_has_attachment_keywords(struct mail *mail);
+/* Sets attachment keywords. */
+void mail_set_attachment_keywords(struct mail *mail);
+
 void mailbox_set_deleted(struct mailbox *box);
 int mailbox_mark_index_deleted(struct mailbox *box, bool del);
 /* Easy wrapper for getting mailbox's MAILBOX_LIST_PATH_TYPE_MAILBOX.
index 393c86b5815d19a4fccd9e443d3ef21be3fda12d..17bade8525996544bd2d54777957e7beb100f946 100644 (file)
@@ -2232,7 +2232,8 @@ struct mail_save_context *
 mailbox_save_alloc(struct mailbox_transaction_context *t)
 {
        struct mail_save_context *ctx;
-
+       const struct mail_storage_settings *mail_set =
+               mailbox_get_settings(t->box);
        T_BEGIN {
                ctx = t->box->v.save_alloc(t);
        } T_END;
@@ -2249,6 +2250,12 @@ mailbox_save_alloc(struct mailbox_transaction_context *t)
                /* make sure the mail isn't used before mail_set_seq_saving() */
                mailbox_save_dest_mail_close(ctx);
        }
+
+       /* make sure parts get parsed early on */
+       if (mail_set->parsed_mail_attachment_detection_add_flags_on_save)
+               mail_add_temp_wanted_fields(ctx->dest_mail,
+                                           MAIL_FETCH_MESSAGE_PARTS, NULL);
+
        return ctx;
 }
 
@@ -2442,6 +2449,8 @@ int mailbox_save_finish(struct mail_save_context **_ctx)
 {
        struct mail_save_context *ctx = *_ctx;
        struct mailbox_transaction_context *t = ctx->transaction;
+       const struct mail_storage_settings *mail_set =
+               mailbox_get_settings(t->box);
        /* we need to keep a copy of this because save_finish implementations
           will likely zero the data structure during cleanup */
        struct mail_keywords *keywords = ctx->data.keywords;
@@ -2471,6 +2480,11 @@ int mailbox_save_finish(struct mail_save_context **_ctx)
                        mailbox_save_add_pvt_flags(t, pvt_flags);
                t->save_count++;
        }
+
+       if (mail_set->parsed_mail_attachment_detection_add_flags_on_save &&
+           !mail_has_attachment_keywords(ctx->dest_mail))
+               mail_set_attachment_keywords(ctx->dest_mail);
+
        if (keywords != NULL)
                mailbox_keywords_unref(&keywords);
        mailbox_save_context_reset(ctx, TRUE);
index 08d1ea376de75ad73773eb3a2e5972e0a967aeeb..46d4a6ecac96a96bd9ff0266c28a94d8a62784c0 100644 (file)
@@ -15,6 +15,9 @@ struct message_size;
 /* If some operation is taking long, call notify_ok every n seconds. */
 #define MAIL_STORAGE_STAYALIVE_SECS 15
 
+#define MAIL_KEYWORD_HAS_ATTACHMENT "$HasAttachment"
+#define MAIL_KEYWORD_HAS_NO_ATTACHMENT "$HasNoAttachment"
+
 enum mail_storage_flags {
        /* Remember message headers' MD5 sum */
        MAIL_STORAGE_FLAG_KEEP_HEADER_MD5       = 0x01,
index 56970aaff0336bf6f055be4cd62f8fc809c32cb2..ac9ca5a0700cb4e1e0595b080bacc5f1bc5fb77d 100644 (file)
@@ -10,6 +10,7 @@
 #include "hostpid.h"
 #include "mail-cache.h"
 #include "mail-storage-private.h"
+#include "message-part-data.h"
 
 #include <time.h>
 
@@ -449,3 +450,72 @@ void mail_generate_guid_128_hash(const char *guid, guid_128_t guid_128_r)
                              GUID_128_SIZE);
        }
 }
+
+static bool
+mail_message_has_attachment(struct message_part *part,
+                           const struct message_part_attachment_settings *set)
+{
+       for (; part != NULL; part = part->next) {
+               if (message_part_is_attachment(part, set) ||
+                   mail_message_has_attachment(part->children, set))
+                       return TRUE;
+       }
+
+       return FALSE;
+}
+
+bool mail_has_attachment_keywords(struct mail *mail)
+{
+       const char *const *kw = mail_get_keywords(mail);
+       return (str_array_icase_find(kw, MAIL_KEYWORD_HAS_ATTACHMENT) !=
+               str_array_icase_find(kw, MAIL_KEYWORD_HAS_NO_ATTACHMENT));
+}
+
+void mail_set_attachment_keywords(struct mail *mail)
+{
+       const struct mail_storage_settings *mail_set =
+               mail_storage_get_settings(mailbox_get_storage(mail->box));
+
+       const char *const keyword_has_attachment[] = {
+               MAIL_KEYWORD_HAS_ATTACHMENT,
+               NULL,
+       };
+       const char *const keyword_has_no_attachment[] = {
+               MAIL_KEYWORD_HAS_NO_ATTACHMENT,
+               NULL
+       };
+       struct message_part_attachment_settings set = {
+               .content_type_filter =
+                       mail_set->parsed_mail_attachment_content_type_filter,
+               .exclude_inlined =
+                       mail_set->parsed_mail_attachment_exclude_inlined,
+       };
+       struct mail_keywords *kw_has = NULL, *kw_has_not = NULL;
+
+       /* walk all parts and see if there is an attachment */
+       struct message_part *parts;
+       if (mail_get_parts(mail, &parts) < 0) {
+               mail_set_critical(mail, "Failed to add attachment keywords: "
+                                 "mail_get_parts() failed: %s",
+                                 mail_storage_get_last_internal_error(mail->box->storage, NULL));
+               return;
+       } else if (mailbox_keywords_create(mail->box, keyword_has_attachment, &kw_has) < 0 ||
+                  mailbox_keywords_create(mail->box, keyword_has_no_attachment, &kw_has_not) < 0) {
+               if (mail_set->mail_debug) {
+                       i_debug("Failed to add attachment keywords: mailbox_keyword_create(%s) failed: %s",
+                               mailbox_get_vname(mail->box),
+                               mail_storage_get_last_error(mail->box->storage, NULL));
+               }
+       } else {
+               bool has_attachment = mail_message_has_attachment(parts, &set);
+
+               /* make sure only one of the keywords gets set */
+               mail_update_keywords(mail, MODIFY_REMOVE, has_attachment ? kw_has_not : kw_has);
+               mail_update_keywords(mail, MODIFY_ADD, has_attachment ? kw_has : kw_has_not);
+       }
+
+       if (kw_has != NULL)
+               mailbox_keywords_unref(&kw_has);
+       if (kw_has_not != NULL)
+               mailbox_keywords_unref(&kw_has_not);
+}