* crypto: implement automagic decryption when so requested

(mainly by adding some smartness to various part_foreach functions, adding
  mu_msg_(get|set)_auto_decrypt to mark a message for auto-decryption)
This commit is contained in:
djcb 2012-07-27 18:04:17 +03:00
parent c88aea5285
commit 8432156765
6 changed files with 234 additions and 65 deletions

View File

@ -42,6 +42,10 @@
#include "mu-maildir.h"
#include "mu-msg-priv.h"
#ifdef BUILD_CRYPTO
#include "mu-msg-crypto.h"
#endif /*BUILD_CRYPTO*/
static gboolean init_file_metadata (MuMsgFile *self, const char* path,
const char *mdir, GError **err);
@ -285,9 +289,10 @@ get_content_flags (MuMsgFile *self)
flags = MU_FLAG_NONE;
if (GMIME_IS_MESSAGE(self->_mime_msg))
g_mime_message_foreach (self->_mime_msg,
(GMimeObjectForeachFunc)msg_cflags_cb,
&flags);
mu_mime_message_foreach (self->_mime_msg,
FALSE, /* never decrypt for this */
(GMimeObjectForeachFunc)msg_cflags_cb,
&flags);
return flags;
}
@ -555,7 +560,8 @@ cleanup:
GMimePart*
mu_msg_mime_get_body_part (GMimeMessage *msg, gboolean want_html)
mu_msg_mime_get_body_part (GMimeMessage *msg, gboolean decrypt,
gboolean want_html)
{
GetBodyData data;
@ -564,9 +570,10 @@ mu_msg_mime_get_body_part (GMimeMessage *msg, gboolean want_html)
memset (&data, 0, sizeof(GetBodyData));
data._want_html = want_html;
g_mime_message_foreach (msg,
(GMimeObjectForeachFunc)get_body_cb,
&data);
mu_mime_message_foreach (msg,
decrypt,
(GMimeObjectForeachFunc)get_body_cb,
&data);
if (want_html)
return (GMimePart*)data._html_part;
else
@ -583,7 +590,9 @@ get_body (MuMsgFile *self, gboolean want_html)
g_return_val_if_fail (self, NULL);
g_return_val_if_fail (GMIME_IS_MESSAGE(self->_mime_msg), NULL);
part = mu_msg_mime_get_body_part (self->_mime_msg, want_html);
part = mu_msg_mime_get_body_part (self->_mime_msg,
self->_auto_decrypt,
want_html);
if (GMIME_IS_PART(part)) {
gboolean err;
gchar *str;
@ -656,7 +665,7 @@ get_concatenated_text (MuMsgFile *self)
g_return_val_if_fail (GMIME_IS_MESSAGE(self->_mime_msg), NULL);
txt = NULL;
g_mime_message_foreach (self->_mime_msg,
mu_mime_message_foreach (self->_mime_msg, self->_auto_decrypt,
(GMimeObjectForeachFunc)append_text,
&txt);
return txt;
@ -851,7 +860,6 @@ mu_msg_file_get_num_field (MuMsgFile *self, const MuMsgFieldId mfid)
}
const char*
mu_msg_file_get_header (MuMsgFile *self, const char *header)
{
@ -868,3 +876,70 @@ mu_msg_file_get_header (MuMsgFile *self, const char *header)
return hdr ? free_string_later (self, mu_str_utf8ify(hdr)) : NULL;
}
struct _ForeachData {
GMimeObjectForeachFunc user_func;
gpointer user_data;
gboolean decrypt;
};
typedef struct _ForeachData ForeachData;
static void
foreach_cb (GMimeObject *parent, GMimeObject *part, ForeachData *fdata)
{
fdata->user_func (parent, part, fdata->user_data);
#ifdef BUILD_CRYPTO
/* maybe iterate over decrypted parts */
if (fdata->decrypt &&
GMIME_IS_MULTIPART_ENCRYPTED (part)) {
GError *err;
GMimeObject *dec;
err = NULL;
dec = mu_msg_crypto_decrypt_part
(GMIME_MULTIPART_ENCRYPTED(part),
MU_MSG_OPTION_NONE, &err);
if (!dec||err) {
g_printerr ("crypto error: %s\n",
err ? err->message : "something went wrong");
g_clear_error(&err);
g_clear_object(&dec);
return;
}
if (GMIME_IS_MULTIPART (dec))
g_mime_multipart_foreach (
(GMIME_MULTIPART(dec)),
(GMimeObjectForeachFunc)foreach_cb,
fdata);
else
foreach_cb (parent, dec, fdata);
g_object_unref (dec);
}
#endif /*BUILD_CRYPTO*/
}
void
mu_mime_message_foreach (GMimeMessage *msg, gboolean decrypt,
GMimeObjectForeachFunc func, gpointer user_data)
{
ForeachData fdata;
g_return_if_fail (GMIME_IS_MESSAGE (msg));
g_return_if_fail (func);
fdata.user_func = func;
fdata.user_data = user_data;
fdata.decrypt = decrypt;
g_mime_message_foreach
(msg,
(GMimeObjectForeachFunc)foreach_cb,
&fdata);
}

View File

@ -76,9 +76,10 @@ find_part (MuMsg* msg, guint partidx)
fpdata.idx = 0;
fpdata.part = NULL;
g_mime_message_foreach (msg->_file->_mime_msg,
(GMimeObjectForeachFunc)find_part_cb,
&fpdata);
mu_mime_message_foreach (msg->_file->_mime_msg,
mu_msg_get_auto_decrypt(msg),
(GMimeObjectForeachFunc)find_part_cb,
&fpdata);
return fpdata.part;
}
@ -94,19 +95,28 @@ typedef struct _PartData PartData;
static gchar *mime_message_to_string (GMimeMessage *mimemsg);
struct _TxtData {
GString *gstr;
gboolean decrypt;
};
typedef struct _TxtData TxtData;
static gchar *mime_message_to_string (GMimeMessage *mimemsg,
gboolean decrypt);
static void
each_mime_part_get_text (GMimeObject *parent, GMimeObject *part,
GString **gstr)
TxtData *tdata)
{
char *txt;
txt = NULL;
if (GMIME_IS_MESSAGE(part)) {
txt = mime_message_to_string (GMIME_MESSAGE(part));
txt = mime_message_to_string (GMIME_MESSAGE(part),
tdata->decrypt);
if (txt)
*gstr = g_string_append (*gstr, txt);
tdata->gstr =
g_string_append (tdata->gstr, txt);
}
if (GMIME_IS_PART (part)) {
@ -120,47 +130,57 @@ each_mime_part_get_text (GMimeObject *parent, GMimeObject *part,
}
if (txt) {
*gstr = g_string_append_c (*gstr, '\n');
*gstr = g_string_append (*gstr, txt);
tdata->gstr = g_string_append_c (tdata->gstr, '\n');
tdata->gstr = g_string_append (tdata->gstr, txt);
g_free (txt);
}
}
static gchar *
mime_message_to_string (GMimeMessage *mimemsg)
static gchar*
mime_message_to_string (GMimeMessage *mimemsg, gboolean decrypt)
{
GString *data;
TxtData tdata;
InternetAddressList *addresses;
gchar *adrs;
const char *str;
data = g_string_sized_new (2048); /* just a guess */
g_string_append (data, g_mime_message_get_sender(mimemsg));
g_string_append_c (data, '\n');
g_string_append (data, g_mime_message_get_subject(mimemsg));
g_string_append_c (data, '\n');
tdata.gstr = g_string_sized_new (2048); /* just a guess */
/* put sender, recipients and subject in the string, so they
* can be indexed as well */
str = g_mime_message_get_sender(mimemsg);
if (str) {
g_string_append (tdata.gstr, str);
g_string_append_c (tdata.gstr, '\n');
}
str = g_mime_message_get_subject(mimemsg);
if (str) {
g_string_append (tdata.gstr, str);
g_string_append_c (tdata.gstr, '\n');
}
addresses = g_mime_message_get_all_recipients (mimemsg);
adrs = internet_address_list_to_string (addresses, FALSE);
g_object_unref(G_OBJECT(addresses));
g_string_append (data, adrs);
if (adrs)
g_string_append (tdata.gstr, adrs);
g_free (adrs);
/* recurse through all text parts */
g_mime_message_foreach
(mimemsg,
tdata.decrypt = decrypt;
mu_mime_message_foreach
(mimemsg, decrypt,
(GMimeObjectForeachFunc)each_mime_part_get_text,
&data);
&tdata);
return g_string_free (data, FALSE);
return g_string_free (tdata.gstr, FALSE);
}
char*
mu_msg_part_get_text (MuMsgPart *self, gboolean *err)
mu_msg_part_get_text (MuMsg *msg, MuMsgPart *self, gboolean *err)
{
GMimeObject *mobj;
g_return_val_if_fail (msg, NULL);
g_return_val_if_fail (self && self->data, NULL);
mobj = (GMimeObject*)self->data;
@ -173,8 +193,8 @@ mu_msg_part_get_text (MuMsgPart *self, gboolean *err)
}
if (GMIME_IS_MESSAGE(mobj))
return mime_message_to_string ((GMimeMessage*)mobj);
return mime_message_to_string ((GMimeMessage*)mobj,
mu_msg_get_auto_decrypt(msg));
g_return_val_if_reached (NULL);
return NULL;
}
@ -234,6 +254,9 @@ check_signature_maybe (GMimeObject *parent, GMimeObject *mobj, MuMsgPart *pi,
g_clear_error (&err);
}
}
#endif /*BUILD_CRYPTO*/
static gboolean
@ -273,7 +296,7 @@ init_msg_part_from_mime_part (MuMsgOptions opts, GMimeObject *parent,
/* if we have crypto support, check the signature if there is one */
#ifdef BUILD_CRYPTO
if (opts & MU_MSG_OPTION_CHECK_SIGNATURES)
check_signature_maybe (parent, (GMimeObject*)part,
check_signature_maybe (parent, (GMimeObject*)part,
pi, opts);
#endif /*BUILD_CRYPTO*/
@ -332,14 +355,13 @@ msg_part_free (MuMsgPart *pi)
#endif /*BUILD_CRYPTO*/
}
static void
part_foreach_cb (GMimeObject *parent, GMimeObject *mobj, PartData *pdata)
{
MuMsgPart pi;
gboolean rv;
/* ignore non-leaf / message parts */
/* ignore other non-leaf / message parts */
if (!is_part_or_message_part (mobj))
return;
@ -348,13 +370,12 @@ part_foreach_cb (GMimeObject *parent, GMimeObject *mobj, PartData *pdata)
pi.content_id = (char*)g_mime_object_get_content_id (mobj);
if (GMIME_IS_PART(mobj)) {
pi.data = (gpointer)mobj;
rv = init_msg_part_from_mime_part
(pdata->_opts, parent, (GMimePart*)mobj, &pi);
/* check if this is the body part */
if ((void*)pdata->_body_part == (void*)mobj)
if (rv && (void*)pdata->_body_part == (void*)mobj)
pi.part_type |= MU_MSG_PART_TYPE_BODY;
} else if (GMIME_IS_MESSAGE_PART(mobj)) {
@ -393,14 +414,16 @@ mu_msg_part_foreach (MuMsg *msg, MuMsgPartForeachFunc func, gpointer user_data,
pdata._msg = msg;
pdata._idx = 0;
pdata._body_part = mu_msg_mime_get_body_part (mime_msg, FALSE);
pdata._body_part = mu_msg_mime_get_body_part
(mime_msg, mu_msg_get_auto_decrypt(msg), FALSE);
pdata._func = func;
pdata._user_data = user_data;
pdata._opts = opts;
g_mime_message_foreach (msg->_file->_mime_msg,
(GMimeObjectForeachFunc)part_foreach_cb,
&pdata);
mu_mime_message_foreach (msg->_file->_mime_msg,
mu_msg_get_auto_decrypt(msg),
(GMimeObjectForeachFunc)part_foreach_cb,
&pdata);
}
@ -658,21 +681,22 @@ part_match_foreach_cb (GMimeObject *parent, GMimeObject *part,
}
static int
msg_part_find_idx (GMimeMessage *msg, MatchFunc func, gpointer user_data)
msg_part_find_idx (GMimeMessage *mimemsg, gboolean auto_decrypt,
MatchFunc func, gpointer user_data)
{
MatchData mdata;
g_return_val_if_fail (msg, -1);
g_return_val_if_fail (GMIME_IS_MESSAGE(msg), -1);
g_return_val_if_fail (mimemsg, -1);
g_return_val_if_fail (GMIME_IS_MESSAGE(mimemsg), -1);
mdata._idx = 0;
mdata._found_idx = -1;
mdata._matcher = func;
mdata._user_data = user_data;
g_mime_message_foreach (msg,
(GMimeObjectForeachFunc)part_match_foreach_cb,
&mdata);
mu_mime_message_foreach (mimemsg, auto_decrypt,
(GMimeObjectForeachFunc)part_match_foreach_cb,
&mdata);
return mdata._found_idx;
}
@ -700,6 +724,7 @@ mu_msg_part_find_cid (MuMsg *msg, const char* sought_cid)
sought_cid + 4 : sought_cid;
return msg_part_find_idx (msg->_file->_mime_msg,
mu_msg_get_auto_decrypt(msg),
(MatchFunc)match_content_id,
(gpointer)(char*)cid);
}
@ -752,9 +777,10 @@ mu_msg_part_find_files (MuMsg *msg, const GRegex *pattern)
mdata._rx = pattern;
mdata._idx = 0;
g_mime_message_foreach (msg->_file->_mime_msg,
(GMimeObjectForeachFunc)match_filename_rx,
&mdata);
mu_mime_message_foreach (msg->_file->_mime_msg,
mu_msg_get_auto_decrypt(msg),
(GMimeObjectForeachFunc)match_filename_rx,
&mdata);
return mdata._lst;
}

View File

@ -123,7 +123,7 @@ typedef struct _MuMsgPart MuMsgPart;
*
* @return utf8 string for this MIME part, to be freed by caller
*/
char* mu_msg_part_get_text (MuMsgPart *part, gboolean *err);
char* mu_msg_part_get_text (MuMsg *msg, MuMsgPart *part, gboolean *err);
/**
@ -211,6 +211,8 @@ gchar* mu_msg_part_filepath_cache (MuMsg *msg, guint partid)
*/
int mu_msg_part_find_cid (MuMsg *msg, const char* content_id);
/**
* retrieve a list of indices for mime-parts with filenames matching a regex
*

View File

@ -44,6 +44,9 @@ struct _MuMsgFile {
char _path [PATH_MAX + 1];
char _maildir [PATH_MAX + 1];
/* whether to attemp to automagically decrypt encrypted parts */
gboolean _auto_decrypt;
/* list where we push allocated strings so we can
* free them when the struct gets destroyed
*/
@ -97,15 +100,25 @@ gboolean mu_msg_part_mime_save_object (GMimeObject *obj, const char *fullpath,
* get the MIME part that's probably the body of the message (heuristic)
*
* @param self a MuMsg
* @param decrypt whether decryption should be attempted, if needed
* @param want_html whether it should be a html type of body
*
* @return the MIME part, or NULL in case of error.
*/
GMimePart* mu_msg_mime_get_body_part (GMimeMessage *msg, gboolean want_html);
GMimePart* mu_msg_mime_get_body_part (GMimeMessage *msg, gboolean decrypt,
gboolean want_html);
/**
* Like g_mime_message_foreach, but will recurse into encrypted parts
*
* @param msg
* @param decrypt whether to try to automatically decrypt
* @param func
* @param user_data
*/
void mu_mime_message_foreach (GMimeMessage *msg, gboolean decrypt,
GMimeObjectForeachFunc func, gpointer user_data);
#ifdef BUILD_CRYPTO
/**
@ -136,6 +149,18 @@ char* mu_msg_mime_decrypt (GMimeMultipartEncrypted *encpart,
MuMsgOptions opts, GError **err);
/**
* decrypt the given encrypted mime multipart
*
* @param enc encrypted part
* @param opts options
* @param err receives error data
*
* @return the decrypted part, or NULL in case of error
*/
GMimeObject* mu_msg_crypto_decrypt_part (GMimeMultipartEncrypted *enc, MuMsgOptions opts,
GError **err);
#endif /*BUILD_CRYPTO*/
G_END_DECLS

View File

@ -84,7 +84,8 @@ msg_new (void)
}
MuMsg*
mu_msg_new_from_file (const char *path, const char *mdir, GError **err)
mu_msg_new_from_file (const char *path, const char *mdir,
GError **err)
{
MuMsg *self;
MuMsgFile *msgfile;
@ -169,6 +170,26 @@ mu_msg_unref (MuMsg *self)
}
void
mu_msg_set_auto_decrypt (MuMsg *msg, gboolean autodecrypt)
{
g_return_if_fail (msg);
mu_msg_load_msg_file (msg, NULL);
msg->_file->_auto_decrypt = autodecrypt;
}
gboolean
mu_msg_get_auto_decrypt (MuMsg *msg)
{
g_return_val_if_fail (msg, FALSE);
if (!msg->_file)
return FALSE;
return msg->_file->_auto_decrypt;
}
/* use this instead of mu_msg_get_path so we don't get into infinite
* regress...*/
static const char*
@ -377,8 +398,6 @@ mu_msg_get_timestamp (MuMsg *self)
}
const char*
mu_msg_get_path (MuMsg *self)
{

View File

@ -38,18 +38,16 @@ enum _MuMsgOptions {
/* 1 << 0 is still free! */
/* for -> sexp conversion */
MU_MSG_OPTION_HEADERS_ONLY = 1 << 1,
MU_MSG_OPTION_EXTRACT_IMAGES = 1 << 2,
/* 1 << 3 is still free! */
/* below options are for checking signatures; only effective
* if mu was built with crypto support */
MU_MSG_OPTION_CHECK_SIGNATURES = 1 << 4,
MU_MSG_OPTION_AUTO_RETRIEVE_KEY = 1 << 5,
MU_MSG_OPTION_USE_AGENT = 1 << 6,
MU_MSG_OPTION_USE_PKCS7 = 1 << 7 /* gpg is the default */
};
typedef enum _MuMsgOptions MuMsgOptions;
@ -138,6 +136,28 @@ MuMsg *mu_msg_ref (MuMsg *msg);
void mu_msg_unref (MuMsg *msg);
/**
* should we set this message to 'autodecrypt'? if so, try to
* automatically decrypt encrypted message parts.
*
* @param msg a message
* @param autodecrypt TRUE or FALSE
*
* @return
*/
void mu_msg_set_auto_decrypt (MuMsg *msg, gboolean autodecrypt);
/**
* get the autodecrypt status for this message. See @func mu_msg_set_auto_decrypt
*
* @param msg a message
*
* @return the auto-decrypt status
*/
gboolean mu_msg_get_auto_decrypt (MuMsg *msg);
/**
* cache the values from the backend (file or db), so we don't the
@ -566,6 +586,8 @@ typedef gboolean (*MuMsgContactForeachFunc) (MuMsgContact* contact,
void mu_msg_contact_foreach (MuMsg *msg, MuMsgContactForeachFunc func,
gpointer user_data);
G_END_DECLS
#endif /*__MU_MSG_H__*/