Mercurial > dovecot > core-2.2
changeset 22782:db50f01b8373
lib-storage: Set keyword based on attachment presence when saving
If attachment is detected, use $HasAttachment, if not
use $HasNoAttachment
author | Aki Tuomi <aki.tuomi@dovecot.fi> |
---|---|
date | Sat, 11 Nov 2017 10:07:42 +0200 |
parents | 4b60d9bdc1a7 |
children | 751eb2d43bc7 |
files | src/lib-storage/mail-storage-private.h src/lib-storage/mail-storage.c src/lib-storage/mail-storage.h src/lib-storage/mail.c |
diffstat | 4 files changed, 95 insertions(+), 1 deletions(-) [+] |
line wrap: on
line diff
--- a/src/lib-storage/mail-storage-private.h Mon Nov 20 10:09:23 2017 +0200 +++ b/src/lib-storage/mail-storage-private.h Sat Nov 11 10:07:42 2017 +0200 @@ -778,6 +778,12 @@ 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.
--- a/src/lib-storage/mail-storage.c Mon Nov 20 10:09:23 2017 +0200 +++ b/src/lib-storage/mail-storage.c Sat Nov 11 10:07:42 2017 +0200 @@ -2163,7 +2163,8 @@ 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; @@ -2180,6 +2181,12 @@ /* 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; } @@ -2387,6 +2394,8 @@ { 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; @@ -2416,6 +2425,11 @@ 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);
--- a/src/lib-storage/mail-storage.h Mon Nov 20 10:09:23 2017 +0200 +++ b/src/lib-storage/mail-storage.h Sat Nov 11 10:07:42 2017 +0200 @@ -15,6 +15,9 @@ /* 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,
--- a/src/lib-storage/mail.c Mon Nov 20 10:09:23 2017 +0200 +++ b/src/lib-storage/mail.c Sat Nov 11 10:07:42 2017 +0200 @@ -10,6 +10,7 @@ #include "hostpid.h" #include "mail-cache.h" #include "mail-storage-private.h" +#include "message-part-data.h" #include <time.h> @@ -474,3 +475,73 @@ 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_storage_set_critical(mail->box->storage, + "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); +}