diff --git a/lib/mu-msg-crypto.c b/lib/mu-msg-crypto.c index b77fc90c..6e690756 100644 --- a/lib/mu-msg-crypto.c +++ b/lib/mu-msg-crypto.c @@ -115,7 +115,7 @@ get_gpg (GError **err) } return g_strdup (envpath); } - + if (!(path = g_find_program_in_path ("gpg")) && !(path = g_find_program_in_path ("gpg2"))) { mu_util_g_set_error (err, MU_ERROR, "gpg/gpg2 not found"); @@ -134,7 +134,7 @@ get_gpg_crypto_context (MuMsgOptions opts, GError **err) cctx = NULL; if (!(gpg = get_gpg (err))) return NULL; - + cctx = g_mime_gpg_context_new ( (GMimePasswordRequestFunc)password_requester, gpg); g_free (gpg); @@ -165,7 +165,7 @@ get_crypto_context (MuMsgOptions opts, MuMsgPartPasswordFunc password_func, cctx = get_gpg_crypto_context (opts, err); if (!cctx) return NULL; - + /* use gobject to pass data to the callback func */ cbdata = g_new0 (CallbackData, 1); cbdata->pw_func = password_func ? password_func : dummy_password_func; @@ -355,21 +355,32 @@ mu_msg_part_sig_status_report_destroy (MuMsgPartSigStatusReport *report) } -MuMsgPartSigStatusReport* +static inline void +tag_with_sig_status(GObject *part, + MuMsgPartSigStatusReport *report) +{ + g_object_set_data_full + (part, SIG_STATUS_REPORT, report, + (GDestroyNotify)mu_msg_part_sig_status_report_destroy); +} + + +void mu_msg_crypto_verify_part (GMimeMultipartSigned *sig, MuMsgOptions opts, GError **err) { + /* the signature status */ MuMsgPartSigStatusReport *report; GMimeCryptoContext *ctx; GMimeSignatureList *sigs; - g_return_val_if_fail (GMIME_IS_MULTIPART_SIGNED(sig), NULL); + g_return_if_fail (GMIME_IS_MULTIPART_SIGNED(sig)); ctx = get_crypto_context (opts, NULL, NULL, err); if (!ctx) { mu_util_g_set_error (err, MU_ERROR_CRYPTO, "failed to get crypto context"); - return NULL; + return; } sigs = g_mime_multipart_signed_verify (sig, ctx, err); @@ -378,13 +389,42 @@ mu_msg_crypto_verify_part (GMimeMultipartSigned *sig, MuMsgOptions opts, if (err && !*err) mu_util_g_set_error (err, MU_ERROR_CRYPTO, "verification failed"); - return NULL; + return; } report = get_status_report (sigs); g_mime_signature_list_clear (sigs); - return report; + /* tag this part with the signature status check */ + tag_with_sig_status(G_OBJECT(sig), report); +} + + +static inline void +check_decrypt_result(GMimeMultipartEncrypted *part, GMimeDecryptResult *res, + GError **err) +{ + GMimeSignatureList *sigs; + MuMsgPartSigStatusReport *report; + + if (res) { + /* Check if the decrypted part had any embed signatures */ + sigs = res->signatures; + if (sigs) { + report = get_status_report (sigs); + g_mime_signature_list_clear (sigs); + + /* tag this part with the signature status check */ + tag_with_sig_status(G_OBJECT(part), report); + } + else { + if (err && !*err) + mu_util_g_set_error (err, MU_ERROR_CRYPTO, + "verification failed"); + } + g_object_unref (res); + } + } @@ -417,10 +457,7 @@ mu_msg_crypto_decrypt_part (GMimeMultipartEncrypted *enc, MuMsgOptions opts, dec = g_mime_multipart_encrypted_decrypt (enc, ctx, &res, err); g_object_unref (ctx); - /* we don't use the 3rd param 'res' * (GMimeDecryptResult), - * but we must unref it. */ - if (res) - g_object_unref (res); + check_decrypt_result(enc, res, err); if (!dec) { if (err && !*err) diff --git a/lib/mu-msg-file.c b/lib/mu-msg-file.c index 1e6bd6f3..debc22df 100644 --- a/lib/mu-msg-file.c +++ b/lib/mu-msg-file.c @@ -287,6 +287,8 @@ msg_cflags_cb (GMimeObject *parent, GMimeObject *part, MuFlags *flags) if (GMIME_IS_MULTIPART_SIGNED(part)) *flags |= MU_FLAG_SIGNED; + /* FIXME: An encrypted part might be signed at the same time. + * In that case the signed flag is lost. */ if (GMIME_IS_MULTIPART_ENCRYPTED(part)) *flags |= MU_FLAG_ENCRYPTED; diff --git a/lib/mu-msg-part.c b/lib/mu-msg-part.c index 1de0fde2..2493484f 100644 --- a/lib/mu-msg-part.c +++ b/lib/mu-msg-part.c @@ -316,30 +316,18 @@ get_disposition (GMimeObject *mobj) return MU_MSG_PART_TYPE_NONE; } -#define SIG_STATUS_REPORT "sig-status-report" - /* call 'func' with information about this MIME-part */ -static gboolean +static inline void check_signature (MuMsg *msg, GMimeMultipartSigned *part, MuMsgOptions opts) { - /* the signature status */ - MuMsgPartSigStatusReport *sigrep; GError *err; - err = NULL; - sigrep = mu_msg_crypto_verify_part (part, opts, &err); + err = NULL; + mu_msg_crypto_verify_part (part, opts, &err); if (err) { g_warning ("error verifying signature: %s", err->message); g_clear_error (&err); } - - /* tag this part with the signature status check */ - g_object_set_data_full - (G_OBJECT(part), SIG_STATUS_REPORT, - sigrep, - (GDestroyNotify)mu_msg_part_sig_status_report_destroy); - - return TRUE; } @@ -454,14 +442,20 @@ handle_part (MuMsg *msg, GMimePart *part, GMimeObject *parent, msgpart.part_type |= MU_MSG_PART_TYPE_TEXT_HTML; } - /* put the verification info in the pgp-signature part */ + /* put the verification info in the pgp-signature and every + * descendent of a pgp-encrypted part */ msgpart.sig_status_report = NULL; - if (g_ascii_strcasecmp (msgpart.subtype, "pgp-signature") == 0) + if (g_ascii_strcasecmp (msgpart.subtype, "pgp-signature") == 0 || + decrypted) { msgpart.sig_status_report = (MuMsgPartSigStatusReport*) g_object_get_data (G_OBJECT(parent), SIG_STATUS_REPORT); + if (msgpart.sig_status_report) + msgpart.part_type |= MU_MSG_PART_TYPE_SIGNED; + } + msgpart.data = (gpointer)part; msgpart.index = (*index)++; @@ -501,7 +495,7 @@ handle_message_part (MuMsg *msg, GMimeMessagePart *mimemsgpart, if (mmsg) return handle_mime_object (msg, mmsg->mime_part, - (GMimeObject *) mmsg, + parent, opts, index, decrypted, @@ -513,8 +507,8 @@ handle_message_part (MuMsg *msg, GMimeMessagePart *mimemsgpart, } static gboolean -handle_multipart (MuMsg *msg, GMimeMultipart *mpart, MuMsgOptions opts, - unsigned *index, gboolean decrypted, +handle_multipart (MuMsg *msg, GMimeMultipart *mpart, GMimeObject *parent, + MuMsgOptions opts, unsigned *index, gboolean decrypted, MuMsgPartForeachFunc func, gpointer user_data) { gboolean res; @@ -524,7 +518,7 @@ handle_multipart (MuMsg *msg, GMimeMultipart *mpart, MuMsgOptions opts, res = TRUE; for (i = 0; i < mpart->children->len; i++) { part = (GMimeObject *) mpart->children->pdata[i]; - res &= handle_mime_object (msg, part, (GMimeObject *) mpart, + res &= handle_mime_object (msg, part, parent, opts, index, decrypted, func, user_data); } @@ -548,15 +542,11 @@ handle_mime_object (MuMsg *msg, GMimeObject *mobj, GMimeObject *parent, parent, opts, index, decrypted, func, user_data); else if ((opts & MU_MSG_OPTION_VERIFY) && GMIME_IS_MULTIPART_SIGNED (mobj)) { - gboolean verified, multipart; - - verified = check_signature + check_signature (msg, GMIME_MULTIPART_SIGNED (mobj), opts); - multipart = handle_multipart - (msg, GMIME_MULTIPART (mobj), opts, + return handle_multipart + (msg, GMIME_MULTIPART (mobj), mobj, opts, index, decrypted, func, user_data); - - return verified && multipart; } else if ((opts & MU_MSG_OPTION_DECRYPT) && GMIME_IS_MULTIPART_ENCRYPTED (mobj)) return handle_encrypted_part @@ -564,7 +554,7 @@ handle_mime_object (MuMsg *msg, GMimeObject *mobj, GMimeObject *parent, opts, index, func, user_data); else if (GMIME_IS_MULTIPART (mobj)) return handle_multipart - (msg, GMIME_MULTIPART (mobj), opts, + (msg, GMIME_MULTIPART (mobj), parent, opts, index, decrypted, func, user_data); return TRUE; } diff --git a/lib/mu-msg-part.h b/lib/mu-msg-part.h index 1650821f..5dd82a16 100644 --- a/lib/mu-msg-part.h +++ b/lib/mu-msg-part.h @@ -25,6 +25,8 @@ #include #include /* for ssize_t */ +#define SIG_STATUS_REPORT "sig-status-report" + G_BEGIN_DECLS enum _MuMsgPartType { diff --git a/lib/mu-msg-priv.h b/lib/mu-msg-priv.h index 56687218..8f617191 100644 --- a/lib/mu-msg-priv.h +++ b/lib/mu-msg-priv.h @@ -115,10 +115,9 @@ typedef char* (*MuMsgPartPasswordFunc) (const char *user_id, const char *promp * * @return a status report object, free with mu_msg_part_sig_status_report_destroy */ -MuMsgPartSigStatusReport* mu_msg_crypto_verify_part (GMimeMultipartSigned *sig, - MuMsgOptions opts, - GError **err) - G_GNUC_MALLOC G_GNUC_WARN_UNUSED_RESULT; +void mu_msg_crypto_verify_part (GMimeMultipartSigned *sig, + MuMsgOptions opts, + GError **err); /** * decrypt the given encrypted mime multipart diff --git a/mu/tests/test-mu-query.c b/mu/tests/test-mu-query.c index 3cb6f86b..5778a863 100644 --- a/mu/tests/test-mu-query.c +++ b/mu/tests/test-mu-query.c @@ -90,7 +90,7 @@ assert_no_dups (MuMsgIter *iter) /* note: this also *moves the iter* */ static guint -run_and_count_matches (const char *xpath, const char *query) +run_and_count_matches_with_query_flags (const char *xpath, const char *query, MuQueryFlags flags) { MuQuery *mquery; MuMsgIter *iter; @@ -131,7 +131,7 @@ run_and_count_matches (const char *xpath, const char *query) iter = mu_query_run (mquery, query, MU_MSG_FIELD_ID_NONE, -1, - MU_QUERY_FLAG_NONE, NULL); + flags, NULL); mu_query_destroy (mquery); g_assert (iter); @@ -155,6 +155,12 @@ run_and_count_matches (const char *xpath, const char *query) return count1; } +static guint +run_and_count_matches (const char *xpath, const char *query) +{ + return run_and_count_matches_with_query_flags (xpath, query, MU_QUERY_FLAG_NONE); +} + typedef struct { const char *query; size_t count; /* expected number of matches */ @@ -629,6 +635,32 @@ test_mu_query_tags_02 (void) } } +/* Tests for https://github.com/djcb/mu/issues/380 + + On certain platforms, something goes wrong during compilation and + the --related option doesn't work. +*/ +static void +test_mu_query_threads_compilation_error (void) +{ + gchar *xpath; + + xpath = fill_database (MU_TESTMAILDIR); + g_assert (xpath != NULL); + + g_assert_cmpuint (run_and_count_matches_with_query_flags + (xpath, "msgid:uwsireh25.fsf@one.dot.net", + MU_QUERY_FLAG_NONE), + ==, 1); + + g_assert_cmpuint (run_and_count_matches_with_query_flags + (xpath, "msgid:uwsireh25.fsf@one.dot.net", + MU_QUERY_FLAG_INCLUDE_RELATED), + ==, 3); + + g_free (xpath); +} + static void test_mu_query_preprocess (void) @@ -711,6 +743,9 @@ main (int argc, char *argv[]) g_test_add_func ("/mu-query/test-mu-query-tags_02", test_mu_query_tags_02); + g_test_add_func ("/mu-query/test-mu-query-threads-compilation-error", + test_mu_query_threads_compilation_error); + if (!g_test_verbose()) g_log_set_handler (NULL, G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL| diff --git a/mu4e/mu4e-main.el b/mu4e/mu4e-main.el index c149263a..623ee1a6 100644 --- a/mu4e/mu4e-main.el +++ b/mu4e/mu4e-main.el @@ -47,6 +47,10 @@ ;; (define-key map "U" 'mu4e-update-mail-and-index) + (define-key map (kbd "C-S-u") 'mu4e-update-mail-and-index) + ;; for terminal users + (define-key map (kbd "C-c C-u") 'mu4e-update-mail-and-index) + (define-key map "S" 'mu4e-interrupt-update-mail) (define-key map (kbd "C-S-u") 'mu4e-update-mail-and-index) diff --git a/mu4e/mu4e-vars.el b/mu4e/mu4e-vars.el index ff74e2d2..66dbc3fa 100644 --- a/mu4e/mu4e-vars.el +++ b/mu4e/mu4e-vars.el @@ -61,7 +61,7 @@ Common values are \"offlineimap\", \"fetchmail\" and \"mbsync\", but you use arbitrary shell-commands. If you set it to \"true\" (the default), the command won't don't anything, which is useful if you get your mail without the need to explicitly run any -scripts, for example when running yout own mail-server." +scripts, for example when running your own mail-server." :type 'string :group 'mu4e :safe 'stringp)