diff --git a/lib/mu-msg-part.c b/lib/mu-msg-part.c index 8f431528..79ef0168 100644 --- a/lib/mu-msg-part.c +++ b/lib/mu-msg-part.c @@ -153,11 +153,10 @@ accumulate_text (MuMsg *msg, MuMsgPart *part, GString **gstrp) } /* declaration, so we can use it earlier */ -static gboolean handle_mime_object (MuMsg *msg, - GMimeObject *mobj, GMimeObject *parent, - MuMsgOptions opts, - unsigned *index, MuMsgPartForeachFunc func, - gpointer user_data); +static gboolean +handle_mime_object (MuMsg *msg, GMimeObject *mobj, GMimeObject *parent, + MuMsgOptions opts, unsigned *index, gboolean decrypted, + MuMsgPartForeachFunc func, gpointer user_data); static char* get_text_from_mime_msg (MuMsg *msg, GMimeMessage *mmsg, MuMsgOptions opts) @@ -172,6 +171,7 @@ get_text_from_mime_msg (MuMsg *msg, GMimeMessage *mmsg, MuMsgOptions opts) (GMimeObject *) mmsg, opts, &index, + FALSE, (MuMsgPartForeachFunc)accumulate_text, &gstr); @@ -375,8 +375,7 @@ get_console_pw (const char* user_id, const char *prompt_ctx, static gboolean -handle_encrypted_part (MuMsg *msg, - GMimeMultipartEncrypted *part, GMimeObject *parent, +handle_encrypted_part (MuMsg *msg, GMimeMultipartEncrypted *part, MuMsgOptions opts, unsigned *index, MuMsgPartForeachFunc func, gpointer user_data) { @@ -399,20 +398,20 @@ handle_encrypted_part (MuMsg *msg, } if (dec) { - rv = handle_mime_object (msg, dec, parent, opts, - index, func, user_data); + rv = handle_mime_object (msg, dec, (GMimeObject *) part, + opts, index, TRUE, func, user_data); g_object_unref (dec); } else { - // On failure to decrypt, list the encrypted part as - // an attachment + // On failure to decrypt list the encrypted part as an + // attachment GMimeObject *encrypted; encrypted = g_mime_multipart_get_part (GMIME_MULTIPART (part), 1); g_return_val_if_fail (GMIME_IS_PART(encrypted), FALSE); - rv = handle_mime_object (msg, encrypted, parent, opts, - index, func, user_data); + rv = handle_mime_object (msg, encrypted, (GMimeObject *) part, + opts, index, FALSE, func, user_data); } return rv; @@ -423,7 +422,7 @@ handle_encrypted_part (MuMsg *msg, /* call 'func' with information about this MIME-part */ static gboolean handle_part (MuMsg *msg, GMimePart *part, GMimeObject *parent, - MuMsgOptions opts, unsigned *index, + MuMsgOptions opts, unsigned *index, gboolean decrypted, MuMsgPartForeachFunc func, gpointer user_data) { GMimeContentType *ct; @@ -434,6 +433,12 @@ handle_part (MuMsg *msg, GMimePart *part, GMimeObject *parent, msgpart.size = get_part_size (part); msgpart.part_type = MU_MSG_PART_TYPE_LEAF; msgpart.part_type |= get_disposition ((GMimeObject*)part); + if (decrypted) + msgpart.part_type |= MU_MSG_PART_TYPE_DECRYPTED; + else if ((opts & MU_MSG_OPTION_DECRYPT) && + GMIME_IS_MULTIPART_ENCRYPTED (parent)) + msgpart.part_type |= MU_MSG_PART_TYPE_ENCRYPTED; + ct = g_mime_object_get_content_type ((GMimeObject*)part); if (GMIME_IS_CONTENT_TYPE(ct)) { @@ -466,7 +471,7 @@ handle_part (MuMsg *msg, GMimePart *part, GMimeObject *parent, /* call 'func' with information about this MIME-part */ static gboolean handle_message_part (MuMsg *msg, GMimeMessagePart *mimemsgpart, GMimeObject *parent, - MuMsgOptions opts, unsigned *index, + MuMsgOptions opts, unsigned *index, gboolean decrypted, MuMsgPartForeachFunc func, gpointer user_data) { MuMsgPart msgpart; @@ -494,6 +499,7 @@ handle_message_part (MuMsg *msg, GMimeMessagePart *mimemsgpart, GMimeObject *par (GMimeObject *) mmsg, opts, index, + decrypted, func, user_data); } @@ -503,7 +509,8 @@ handle_message_part (MuMsg *msg, GMimeMessagePart *mimemsgpart, GMimeObject *par static gboolean handle_multipart (MuMsg *msg, GMimeMultipart *mpart, MuMsgOptions opts, - unsigned *index, MuMsgPartForeachFunc func, gpointer user_data) + unsigned *index, gboolean decrypted, + MuMsgPartForeachFunc func, gpointer user_data) { gboolean res; GMimeObject *part; @@ -513,7 +520,8 @@ handle_multipart (MuMsg *msg, GMimeMultipart *mpart, MuMsgOptions opts, for (i = 0; i < mpart->children->len; i++) { part = (GMimeObject *) mpart->children->pdata[i]; res &= handle_mime_object (msg, part, (GMimeObject *) mpart, - opts, index, func, user_data); + opts, index, decrypted, + func, user_data); } return res; @@ -521,18 +529,18 @@ handle_multipart (MuMsg *msg, GMimeMultipart *mpart, MuMsgOptions opts, static gboolean -handle_mime_object (MuMsg *msg, - GMimeObject *mobj, GMimeObject *parent, MuMsgOptions opts, - unsigned *index, MuMsgPartForeachFunc func, gpointer user_data) +handle_mime_object (MuMsg *msg, GMimeObject *mobj, GMimeObject *parent, + MuMsgOptions opts, unsigned *index, gboolean decrypted, + MuMsgPartForeachFunc func, gpointer user_data) { if (GMIME_IS_PART (mobj)) return handle_part (msg, GMIME_PART(mobj), parent, - opts, index, func, user_data); + opts, index, decrypted, func, user_data); else if (GMIME_IS_MESSAGE_PART (mobj)) return handle_message_part (msg, GMIME_MESSAGE_PART(mobj), - parent, opts, index, func, user_data); + parent, opts, index, decrypted, func, user_data); else if ((opts & MU_MSG_OPTION_VERIFY) && GMIME_IS_MULTIPART_SIGNED (mobj)) { gboolean verified, signedpart; @@ -543,18 +551,18 @@ handle_mime_object (MuMsg *msg, // Only process the first part (the second one is the signature) signedpart = handle_mime_object (msg, g_mime_multipart_get_part (GMIME_MULTIPART (mobj), 0), - mobj, opts, index, func, user_data); + mobj, opts, index, decrypted, func, user_data); return verified && signedpart; } else if ((opts & MU_MSG_OPTION_DECRYPT) && GMIME_IS_MULTIPART_ENCRYPTED (mobj)) return handle_encrypted_part (msg, GMIME_MULTIPART_ENCRYPTED (mobj), - parent, opts, index, func, user_data); + opts, index, func, user_data); else if (GMIME_IS_MULTIPART (mobj)) return handle_multipart - (msg, GMIME_MULTIPART (mobj), - opts, index, func, user_data); + (msg, GMIME_MULTIPART (mobj), opts, + index, decrypted, func, user_data); return TRUE; } @@ -576,6 +584,7 @@ mu_msg_part_foreach (MuMsg *msg, MuMsgOptions opts, (GMimeObject *) msg->_file->_mime_msg, opts, &index, + FALSE, func, user_data); } diff --git a/lib/mu-msg-sexp.c b/lib/mu-msg-sexp.c index c9e4a66a..a4615400 100644 --- a/lib/mu-msg-sexp.c +++ b/lib/mu-msg-sexp.c @@ -300,6 +300,21 @@ sig_verdict (MuMsgPart *mpart) } } +static const char* +dec_verdict (MuMsgPart *mpart) +{ + MuMsgPartType ptype; + + ptype = mpart->part_type; + + if (ptype & MU_MSG_PART_TYPE_DECRYPTED) + return ":decryption succeeded"; + else if (ptype & MU_MSG_PART_TYPE_ENCRYPTED) + return ":decryption failed"; + else + return ""; +} + static gchar * get_part_type_string (MuMsgPartType ptype) @@ -348,7 +363,7 @@ each_part (MuMsg *msg, MuMsgPart *part, PartInfo *pinfo) tmp = g_strdup_printf ("%s(:index %d :name \"%s\" :mime-type \"%s/%s\"%s%s " ":type %s " - ":attachment %s :size %i %s)", + ":attachment %s :size %i %s %s)", pinfo->parts ? pinfo->parts: "", part->index, name ? name : "noname", @@ -358,7 +373,8 @@ each_part (MuMsg *msg, MuMsgPart *part, PartInfo *pinfo) parttype, mu_msg_part_maybe_attachment (part) ? "t" : "nil", (int)part->size, - sig_verdict (part)); + sig_verdict (part), + dec_verdict (part)); g_free (pinfo->parts); pinfo->parts = tmp; diff --git a/mu4e/mu4e-vars.el b/mu4e/mu4e-vars.el index 50a6c3e9..ffa9bb3c 100644 --- a/mu4e/mu4e-vars.el +++ b/mu4e/mu4e-vars.el @@ -435,7 +435,7 @@ I.e. a message with the draft flag set." '((t :inherit font-lock-preprocessor-face)) "Face for the mark in the headers list." :group 'mu4e-faces) - + (defface mu4e-header-key-face '((t :inherit message-header-name-face :bold t)) "Face for a header key (such as \"Foo\" in \"Subject:\ Foo\")." @@ -625,6 +625,11 @@ mu4e-compose-mode." :shortname "Sgn" :help "Check for the cryptographic signature" :sortable nil)) + (:decryption . + ( :name "Decryption" + :shortname "Dec" + :help "Check the cryptographic decryption status" + :sortable nil)) (:size . ( :name "Size" :shortname "Size" diff --git a/mu4e/mu4e-view.el b/mu4e/mu4e-view.el index c223aaee..9a518b15 100644 --- a/mu4e/mu4e-view.el +++ b/mu4e/mu4e-view.el @@ -50,7 +50,8 @@ :group 'mu4e) (defcustom mu4e-view-fields - '(:from :to :cc :subject :flags :date :maildir :mailing-list :tags :attachments :signature) + '(:from :to :cc :subject :flags :date :maildir :mailing-list :tags + :attachments :signature :decryption) "Header fields to display in the message view buffer. For the complete list of available headers, see `mu4e-header-info'." :type (list 'symbol) @@ -227,6 +228,8 @@ found." (:attachments (mu4e~view-construct-attachments-header msg)) ;; pgp-signatures (:signature (mu4e~view-construct-signature-header msg)) + ;; pgp-decryption + (:decryption (mu4e~view-construct-decryption-header msg)) (t (mu4e~view-construct-header field (mu4e~view-custom-field msg field)))))) mu4e-view-fields "") @@ -403,6 +406,28 @@ add text-properties to VAL." (val (when val (concat val " (" btn ")")))) (mu4e~view-construct-header :signature val t))) +(defun mu4e~view-construct-decryption-header (msg) + "Construct a Decryption: header, if there are any encrypted parts." + (let* ((parts (mu4e-message-field msg :parts)) + (verdicts + (remove-if 'null + (mapcar (lambda (part) (mu4e-message-part-field part :decryption)) + parts))) + (succeeded (remove-if (lambda (v) (eq v 'failed)) verdicts)) + (failed (remove-if (lambda (v) (eq v 'succeeded)) verdicts)) + (succ (when succeeded + (propertize + (concat (number-to-string (length succeeded)) + " part(s) decrypted") + 'face 'mu4e-ok-face))) + (fail (when failed + (propertize + (concat (number-to-string (length failed)) + " part(s) failed") + 'face 'mu4e-warning-face))) + (val (concat succ fail))) + (mu4e~view-construct-header :decryption val t))) + (defun mu4e~view-open-attach-from-binding () "Open the attachement at point, or click location." (interactive)