Skip to content

Commit

Permalink
lib-storage: Set keyword based on attachment presence when saving
Browse files Browse the repository at this point in the history
If attachment is detected, use $HasAttachment, if not
use $HasNoAttachment
  • Loading branch information
cmouse authored and sirainen committed Jan 30, 2018
1 parent a2940d7 commit 9674255
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 1 deletion.
6 changes: 6 additions & 0 deletions src/lib-storage/mail-storage-private.h
Expand Up @@ -778,6 +778,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.
Expand Down
16 changes: 15 additions & 1 deletion src/lib-storage/mail-storage.c
Expand Up @@ -2163,7 +2163,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;
Expand All @@ -2180,6 +2181,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;
}

Expand Down Expand Up @@ -2387,6 +2394,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;
Expand Down Expand Up @@ -2416,6 +2425,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);
Expand Down
3 changes: 3 additions & 0 deletions src/lib-storage/mail-storage.h
Expand Up @@ -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,
Expand Down
71 changes: 71 additions & 0 deletions src/lib-storage/mail.c
Expand Up @@ -10,6 +10,7 @@
#include "hostpid.h"
#include "mail-cache.h"
#include "mail-storage-private.h"
#include "message-part-data.h"

#include <time.h>

Expand Down Expand Up @@ -474,3 +475,73 @@ 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_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);
}

0 comments on commit 9674255

Please sign in to comment.