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.
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;
/* 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;
}
{
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;
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);
#include "hostpid.h"
#include "mail-cache.h"
#include "mail-storage-private.h"
+#include "message-part-data.h"
#include <time.h>
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);
+}