Merge branch 'master' of github.com:djcb/mu
This commit is contained in:
@ -115,7 +115,7 @@ get_gpg (GError **err)
|
|||||||
}
|
}
|
||||||
return g_strdup (envpath);
|
return g_strdup (envpath);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(path = g_find_program_in_path ("gpg")) &&
|
if (!(path = g_find_program_in_path ("gpg")) &&
|
||||||
!(path = g_find_program_in_path ("gpg2"))) {
|
!(path = g_find_program_in_path ("gpg2"))) {
|
||||||
mu_util_g_set_error (err, MU_ERROR, "gpg/gpg2 not found");
|
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;
|
cctx = NULL;
|
||||||
if (!(gpg = get_gpg (err)))
|
if (!(gpg = get_gpg (err)))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
cctx = g_mime_gpg_context_new (
|
cctx = g_mime_gpg_context_new (
|
||||||
(GMimePasswordRequestFunc)password_requester, gpg);
|
(GMimePasswordRequestFunc)password_requester, gpg);
|
||||||
g_free (gpg);
|
g_free (gpg);
|
||||||
@ -165,7 +165,7 @@ get_crypto_context (MuMsgOptions opts, MuMsgPartPasswordFunc password_func,
|
|||||||
cctx = get_gpg_crypto_context (opts, err);
|
cctx = get_gpg_crypto_context (opts, err);
|
||||||
if (!cctx)
|
if (!cctx)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* use gobject to pass data to the callback func */
|
/* use gobject to pass data to the callback func */
|
||||||
cbdata = g_new0 (CallbackData, 1);
|
cbdata = g_new0 (CallbackData, 1);
|
||||||
cbdata->pw_func = password_func ? password_func : dummy_password_func;
|
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,
|
mu_msg_crypto_verify_part (GMimeMultipartSigned *sig, MuMsgOptions opts,
|
||||||
GError **err)
|
GError **err)
|
||||||
{
|
{
|
||||||
|
/* the signature status */
|
||||||
MuMsgPartSigStatusReport *report;
|
MuMsgPartSigStatusReport *report;
|
||||||
GMimeCryptoContext *ctx;
|
GMimeCryptoContext *ctx;
|
||||||
GMimeSignatureList *sigs;
|
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);
|
ctx = get_crypto_context (opts, NULL, NULL, err);
|
||||||
if (!ctx) {
|
if (!ctx) {
|
||||||
mu_util_g_set_error (err, MU_ERROR_CRYPTO,
|
mu_util_g_set_error (err, MU_ERROR_CRYPTO,
|
||||||
"failed to get crypto context");
|
"failed to get crypto context");
|
||||||
return NULL;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sigs = g_mime_multipart_signed_verify (sig, ctx, err);
|
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)
|
if (err && !*err)
|
||||||
mu_util_g_set_error (err, MU_ERROR_CRYPTO,
|
mu_util_g_set_error (err, MU_ERROR_CRYPTO,
|
||||||
"verification failed");
|
"verification failed");
|
||||||
return NULL;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
report = get_status_report (sigs);
|
report = get_status_report (sigs);
|
||||||
g_mime_signature_list_clear (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);
|
dec = g_mime_multipart_encrypted_decrypt (enc, ctx, &res, err);
|
||||||
g_object_unref (ctx);
|
g_object_unref (ctx);
|
||||||
|
|
||||||
/* we don't use the 3rd param 'res' * (GMimeDecryptResult),
|
check_decrypt_result(enc, res, err);
|
||||||
* but we must unref it. */
|
|
||||||
if (res)
|
|
||||||
g_object_unref (res);
|
|
||||||
|
|
||||||
if (!dec) {
|
if (!dec) {
|
||||||
if (err && !*err)
|
if (err && !*err)
|
||||||
|
|||||||
@ -287,6 +287,8 @@ msg_cflags_cb (GMimeObject *parent, GMimeObject *part, MuFlags *flags)
|
|||||||
if (GMIME_IS_MULTIPART_SIGNED(part))
|
if (GMIME_IS_MULTIPART_SIGNED(part))
|
||||||
*flags |= MU_FLAG_SIGNED;
|
*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))
|
if (GMIME_IS_MULTIPART_ENCRYPTED(part))
|
||||||
*flags |= MU_FLAG_ENCRYPTED;
|
*flags |= MU_FLAG_ENCRYPTED;
|
||||||
|
|
||||||
|
|||||||
@ -316,30 +316,18 @@ get_disposition (GMimeObject *mobj)
|
|||||||
return MU_MSG_PART_TYPE_NONE;
|
return MU_MSG_PART_TYPE_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define SIG_STATUS_REPORT "sig-status-report"
|
|
||||||
|
|
||||||
/* call 'func' with information about this MIME-part */
|
/* call 'func' with information about this MIME-part */
|
||||||
static gboolean
|
static inline void
|
||||||
check_signature (MuMsg *msg, GMimeMultipartSigned *part, MuMsgOptions opts)
|
check_signature (MuMsg *msg, GMimeMultipartSigned *part, MuMsgOptions opts)
|
||||||
{
|
{
|
||||||
/* the signature status */
|
|
||||||
MuMsgPartSigStatusReport *sigrep;
|
|
||||||
GError *err;
|
GError *err;
|
||||||
|
|
||||||
err = NULL;
|
err = NULL;
|
||||||
sigrep = mu_msg_crypto_verify_part (part, opts, &err);
|
mu_msg_crypto_verify_part (part, opts, &err);
|
||||||
if (err) {
|
if (err) {
|
||||||
g_warning ("error verifying signature: %s", err->message);
|
g_warning ("error verifying signature: %s", err->message);
|
||||||
g_clear_error (&err);
|
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;
|
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;
|
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 =
|
msgpart.sig_status_report =
|
||||||
(MuMsgPartSigStatusReport*)
|
(MuMsgPartSigStatusReport*)
|
||||||
g_object_get_data (G_OBJECT(parent),
|
g_object_get_data (G_OBJECT(parent),
|
||||||
SIG_STATUS_REPORT);
|
SIG_STATUS_REPORT);
|
||||||
|
|
||||||
|
if (msgpart.sig_status_report)
|
||||||
|
msgpart.part_type |= MU_MSG_PART_TYPE_SIGNED;
|
||||||
|
}
|
||||||
|
|
||||||
msgpart.data = (gpointer)part;
|
msgpart.data = (gpointer)part;
|
||||||
msgpart.index = (*index)++;
|
msgpart.index = (*index)++;
|
||||||
|
|
||||||
@ -501,7 +495,7 @@ handle_message_part (MuMsg *msg, GMimeMessagePart *mimemsgpart,
|
|||||||
if (mmsg)
|
if (mmsg)
|
||||||
return handle_mime_object (msg,
|
return handle_mime_object (msg,
|
||||||
mmsg->mime_part,
|
mmsg->mime_part,
|
||||||
(GMimeObject *) mmsg,
|
parent,
|
||||||
opts,
|
opts,
|
||||||
index,
|
index,
|
||||||
decrypted,
|
decrypted,
|
||||||
@ -513,8 +507,8 @@ handle_message_part (MuMsg *msg, GMimeMessagePart *mimemsgpart,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
handle_multipart (MuMsg *msg, GMimeMultipart *mpart, MuMsgOptions opts,
|
handle_multipart (MuMsg *msg, GMimeMultipart *mpart, GMimeObject *parent,
|
||||||
unsigned *index, gboolean decrypted,
|
MuMsgOptions opts, unsigned *index, gboolean decrypted,
|
||||||
MuMsgPartForeachFunc func, gpointer user_data)
|
MuMsgPartForeachFunc func, gpointer user_data)
|
||||||
{
|
{
|
||||||
gboolean res;
|
gboolean res;
|
||||||
@ -524,7 +518,7 @@ handle_multipart (MuMsg *msg, GMimeMultipart *mpart, MuMsgOptions opts,
|
|||||||
res = TRUE;
|
res = TRUE;
|
||||||
for (i = 0; i < mpart->children->len; i++) {
|
for (i = 0; i < mpart->children->len; i++) {
|
||||||
part = (GMimeObject *) mpart->children->pdata[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,
|
opts, index, decrypted,
|
||||||
func, user_data);
|
func, user_data);
|
||||||
}
|
}
|
||||||
@ -548,15 +542,11 @@ handle_mime_object (MuMsg *msg, GMimeObject *mobj, GMimeObject *parent,
|
|||||||
parent, opts, index, decrypted, func, user_data);
|
parent, opts, index, decrypted, func, user_data);
|
||||||
else if ((opts & MU_MSG_OPTION_VERIFY) &&
|
else if ((opts & MU_MSG_OPTION_VERIFY) &&
|
||||||
GMIME_IS_MULTIPART_SIGNED (mobj)) {
|
GMIME_IS_MULTIPART_SIGNED (mobj)) {
|
||||||
gboolean verified, multipart;
|
check_signature
|
||||||
|
|
||||||
verified = check_signature
|
|
||||||
(msg, GMIME_MULTIPART_SIGNED (mobj), opts);
|
(msg, GMIME_MULTIPART_SIGNED (mobj), opts);
|
||||||
multipart = handle_multipart
|
return handle_multipart
|
||||||
(msg, GMIME_MULTIPART (mobj), opts,
|
(msg, GMIME_MULTIPART (mobj), mobj, opts,
|
||||||
index, decrypted, func, user_data);
|
index, decrypted, func, user_data);
|
||||||
|
|
||||||
return verified && multipart;
|
|
||||||
} else if ((opts & MU_MSG_OPTION_DECRYPT) &&
|
} else if ((opts & MU_MSG_OPTION_DECRYPT) &&
|
||||||
GMIME_IS_MULTIPART_ENCRYPTED (mobj))
|
GMIME_IS_MULTIPART_ENCRYPTED (mobj))
|
||||||
return handle_encrypted_part
|
return handle_encrypted_part
|
||||||
@ -564,7 +554,7 @@ handle_mime_object (MuMsg *msg, GMimeObject *mobj, GMimeObject *parent,
|
|||||||
opts, index, func, user_data);
|
opts, index, func, user_data);
|
||||||
else if (GMIME_IS_MULTIPART (mobj))
|
else if (GMIME_IS_MULTIPART (mobj))
|
||||||
return handle_multipart
|
return handle_multipart
|
||||||
(msg, GMIME_MULTIPART (mobj), opts,
|
(msg, GMIME_MULTIPART (mobj), parent, opts,
|
||||||
index, decrypted, func, user_data);
|
index, decrypted, func, user_data);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,6 +25,8 @@
|
|||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
#include <unistd.h> /* for ssize_t */
|
#include <unistd.h> /* for ssize_t */
|
||||||
|
|
||||||
|
#define SIG_STATUS_REPORT "sig-status-report"
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
enum _MuMsgPartType {
|
enum _MuMsgPartType {
|
||||||
|
|||||||
@ -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
|
* @return a status report object, free with mu_msg_part_sig_status_report_destroy
|
||||||
*/
|
*/
|
||||||
MuMsgPartSigStatusReport* mu_msg_crypto_verify_part (GMimeMultipartSigned *sig,
|
void mu_msg_crypto_verify_part (GMimeMultipartSigned *sig,
|
||||||
MuMsgOptions opts,
|
MuMsgOptions opts,
|
||||||
GError **err)
|
GError **err);
|
||||||
G_GNUC_MALLOC G_GNUC_WARN_UNUSED_RESULT;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* decrypt the given encrypted mime multipart
|
* decrypt the given encrypted mime multipart
|
||||||
|
|||||||
@ -90,7 +90,7 @@ assert_no_dups (MuMsgIter *iter)
|
|||||||
|
|
||||||
/* note: this also *moves the iter* */
|
/* note: this also *moves the iter* */
|
||||||
static guint
|
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;
|
MuQuery *mquery;
|
||||||
MuMsgIter *iter;
|
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,
|
iter = mu_query_run (mquery, query, MU_MSG_FIELD_ID_NONE, -1,
|
||||||
MU_QUERY_FLAG_NONE, NULL);
|
flags, NULL);
|
||||||
mu_query_destroy (mquery);
|
mu_query_destroy (mquery);
|
||||||
g_assert (iter);
|
g_assert (iter);
|
||||||
|
|
||||||
@ -155,6 +155,12 @@ run_and_count_matches (const char *xpath, const char *query)
|
|||||||
return count1;
|
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 {
|
typedef struct {
|
||||||
const char *query;
|
const char *query;
|
||||||
size_t count; /* expected number of matches */
|
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
|
static void
|
||||||
test_mu_query_preprocess (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",
|
g_test_add_func ("/mu-query/test-mu-query-tags_02",
|
||||||
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())
|
if (!g_test_verbose())
|
||||||
g_log_set_handler (NULL,
|
g_log_set_handler (NULL,
|
||||||
G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL|
|
G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL|
|
||||||
|
|||||||
@ -47,6 +47,10 @@
|
|||||||
|
|
||||||
;;
|
;;
|
||||||
(define-key map "U" 'mu4e-update-mail-and-index)
|
(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 "S" 'mu4e-interrupt-update-mail)
|
||||||
(define-key map (kbd "C-S-u") 'mu4e-update-mail-and-index)
|
(define-key map (kbd "C-S-u") 'mu4e-update-mail-and-index)
|
||||||
|
|
||||||
|
|||||||
@ -61,7 +61,7 @@ Common values are \"offlineimap\", \"fetchmail\" and \"mbsync\",
|
|||||||
but you use arbitrary shell-commands. If you set it to
|
but you use arbitrary shell-commands. If you set it to
|
||||||
\"true\" (the default), the command won't don't anything, which is
|
\"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
|
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
|
:type 'string
|
||||||
:group 'mu4e
|
:group 'mu4e
|
||||||
:safe 'stringp)
|
:safe 'stringp)
|
||||||
|
|||||||
Reference in New Issue
Block a user