* MuMsgPart refactoring / cleanups

This commit is contained in:
djcb
2012-08-01 10:45:03 +03:00
parent c403f0a9c0
commit 6a7562422f
5 changed files with 492 additions and 477 deletions

View File

@ -1,5 +1,4 @@
/* -*-mode: c; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-*/
/*
** Copyright (C) 2008-2012 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
**
@ -36,63 +35,71 @@
#endif /*BUILD_CRYPTO*/
struct _FindPartData {
guint idx, wanted_idx;
GMimeObject *part;
struct _DoData {
GMimeObject *mime_obj;
unsigned index;
};
typedef struct _FindPartData FindPartData;
/* is this either a leaf part or an embedded message? */
static gboolean
is_part_or_message_part (GMimeObject *part)
{
return GMIME_IS_PART(part) || GMIME_IS_MESSAGE_PART (part);
}
typedef struct _DoData DoData;
static void
find_part_cb (GMimeObject *parent, GMimeObject *part, FindPartData *fpdata)
do_it_with_index (MuMsg *msg, MuMsgPart *part, DoData *ddata)
{
/* ignore other parts */
if (!is_part_or_message_part (part))
if (ddata->mime_obj)
return;
/* g_printerr ("%u Type-name: %s\n", */
/* fpdata->idx, G_OBJECT_TYPE_NAME((GObject*)part)); */
if (fpdata->part || fpdata->wanted_idx != fpdata->idx++)
return; /* not yet found */
fpdata->part = part;
if (part->index == ddata->index)
ddata->mime_obj = (GMimeObject*)part->data;
}
static GMimeObject*
find_part (MuMsg* msg, guint partidx)
get_mime_object_at_index (MuMsg *msg, MuMsgOptions opts, unsigned index)
{
FindPartData fpdata;
DoData ddata;
fpdata.wanted_idx = partidx;
fpdata.idx = 0;
fpdata.part = NULL;
ddata.mime_obj = NULL;
ddata.index = index;
mu_mime_message_foreach (msg->_file->_mime_msg,
mu_msg_get_auto_decrypt(msg),
(GMimeObjectForeachFunc)find_part_cb,
&fpdata);
return fpdata.part;
mu_msg_part_foreach (msg, opts,
(MuMsgPartForeachFunc)do_it_with_index,
&ddata);
return ddata.mime_obj;
}
struct _PartData {
MuMsg *_msg;
unsigned _idx;
MuMsgPartForeachFunc _func;
gpointer _user_data;
GMimePart *_body_part;
MuMsgOptions _opts;
};
typedef struct _PartData PartData;
typedef gboolean (*MuMsgPartMatchFunc) (MuMsgPart *, gpointer);
struct _MatchData {
MuMsgPartMatchFunc match_func;
gpointer user_data;
int index;
};
typedef struct _MatchData MatchData;
static void
check_match (MuMsg *msg, MuMsgPart *part, MatchData *mdata)
{
if (mdata->index != -1)
return;
if (mdata->match_func (part, mdata->user_data))
mdata->index = part->index;
}
int
get_matching_part_index (MuMsg *msg, MuMsgOptions opts,
MuMsgPartMatchFunc func, gpointer user_data)
{
MatchData mdata;
mdata.match_func = func;
mdata.user_data = user_data;
mdata.index = -1;
mu_msg_part_foreach (msg, opts,
(MuMsgPartForeachFunc)check_match,
&mdata);
return mdata.index;
}
struct _TxtData {
@ -101,12 +108,10 @@ struct _TxtData {
};
typedef struct _TxtData TxtData;
static gchar *mime_message_to_string (GMimeMessage *mimemsg,
gboolean decrypt);
static gchar *mime_message_to_string (GMimeMessage *mimemsg, gboolean decrypt);
static void
each_mime_part_get_text (GMimeObject *parent, GMimeObject *part,
TxtData *tdata)
each_mime_part_get_text (GMimeObject *parent, GMimeObject *part, TxtData *tdata)
{
char *txt;
txt = NULL;
@ -186,16 +191,15 @@ mu_msg_part_get_text (MuMsg *msg, MuMsgPart *self, gboolean *err)
if (GMIME_IS_PART(mobj)) {
/* ignore all but plain text */
if ((strcasecmp (self->type, "text") == 0) &&
(strcasecmp (self->subtype, "plain") == 0))
if ((strcasecmp (self->type, "text") != 0) ||
(strcasecmp (self->subtype, "plain") != 0))
return NULL;
return mu_msg_mime_part_to_string ((GMimePart*)mobj, err);
}
if (GMIME_IS_MESSAGE(mobj))
return mime_message_to_string ((GMimeMessage*)mobj,
mu_msg_get_auto_decrypt(msg));
g_return_val_if_reached (NULL);
return mime_message_to_string ((GMimeMessage*)mobj,TRUE);
return NULL;
}
@ -209,7 +213,7 @@ get_part_size (GMimePart *part)
GMimeStream *stream;
wrapper = g_mime_part_get_content_object (part);
if (!wrapper)
if (!GMIME_IS_DATA_WRAPPER(wrapper))
return -1;
stream = g_mime_data_wrapper_get_stream (wrapper);
@ -218,212 +222,324 @@ get_part_size (GMimePart *part)
else
return g_mime_stream_length (stream);
/* NOTE: it seems we shouldn't unref stream/wrapper */
/* NOTE: stream/wrapper are owned by gmime, no unreffing */
}
#ifdef BUILD_CRYPTO
static void
check_signature_maybe (GMimeObject *parent, GMimeObject *mobj, MuMsgPart *pi,
MuMsgOptions opts)
/* #ifdef BUILD_CRYPTO */
/* static void */
/* check_signature_maybe (GMimeObject *parent, GMimeObject *mobj, MuMsgPart *pi, */
/* MuMsgOptions opts) */
/* { */
/* GMimeContentType *ctype; */
/* GError *err; */
/* gboolean pkcs7; */
/* if (!GMIME_IS_MULTIPART_SIGNED (parent)) */
/* return; */
/* ctype = g_mime_object_get_content_type (mobj); */
/* if (g_mime_content_type_is_type */
/* (ctype, "application", "pgp-signature")) */
/* pkcs7 = FALSE; */
/* else if (g_mime_content_type_is_type */
/* (ctype, "application", "x-pkcs7-signature")) */
/* pkcs7 = TRUE; */
/* else return; /\* don't know how to handle other kinds *\/ */
/* if (pkcs7) */
/* opts |= MU_MSG_OPTION_USE_PKCS7; /\* gpg is the default *\/ */
/* err = NULL; */
/* pi->sig_infos = mu_msg_mime_sig_infos */
/* (GMIME_MULTIPART_SIGNED (parent), opts, &err); */
/* if (err) { */
/* g_warning ("error verifying signature: %s", err->message); */
/* g_clear_error (&err); */
/* } */
/* } */
/* #endif /\*BUILD_CRYPTO*\/ */
/* static gboolean */
/* init_msg_part_from_mime_part (MuMsgOptions opts, GMimeObject *parent, */
/* GMimePart *part, MuMsgPart *pi) */
/* { */
/* const gchar *fname, *descr; */
/* GMimeContentType *ct; */
/* ct = g_mime_object_get_content_type ((GMimeObject*)part); */
/* if (GMIME_IS_CONTENT_TYPE(ct)) { */
/* pi->type = (char*)g_mime_content_type_get_media_type (ct); */
/* pi->subtype = (char*)g_mime_content_type_get_media_subtype (ct); */
/* } */
/* pi->disposition = (char*)g_mime_object_get_disposition */
/* ((GMimeObject*)part); */
/* fname = g_mime_part_get_filename (part); */
/* pi->file_name = fname ? mu_str_utf8ify (fname) : NULL; */
/* descr = g_mime_part_get_content_description (part); */
/* pi->description = descr ? mu_str_utf8ify (descr) : NULL; */
/* pi->size = get_part_size (part); */
/* pi->part_type = MU_MSG_PART_TYPE_LEAF; */
/* if (!pi->disposition || */
/* g_ascii_strcasecmp (pi->disposition, */
/* GMIME_DISPOSITION_INLINE) == 0) */
/* pi->part_type |= MU_MSG_PART_TYPE_INLINE; */
/* if (GMIME_IS_MULTIPART_SIGNED (parent)) */
/* pi->part_type |= MU_MSG_PART_TYPE_SIGNED; */
/* /\* 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, */
/* pi, opts); */
/* #endif /\*BUILD_CRYPTO*\/ */
/* return TRUE; */
/* } */
static char*
mime_part_get_filename (GMimeObject *mobj, unsigned index,
gboolean construct_if_needed)
{
GMimeContentType *ctype;
GError *err;
gboolean pkcs7;
gchar *fname, *cur;
if (!GMIME_IS_MULTIPART_SIGNED (parent))
return;
ctype = g_mime_object_get_content_type (mobj);
if (g_mime_content_type_is_type
(ctype, "application", "pgp-signature"))
pkcs7 = FALSE;
else if (g_mime_content_type_is_type
(ctype, "application", "x-pkcs7-signature"))
pkcs7 = TRUE;
else return; /* don't know how to handle other kinds */
if (pkcs7)
opts |= MU_MSG_OPTION_USE_PKCS7; /* gpg is the default */
err = NULL;
pi->sig_infos = mu_msg_mime_sig_infos
(GMIME_MULTIPART_SIGNED (parent), opts, &err);
if (err) {
g_warning ("error verifying signature: %s", err->message);
g_clear_error (&err);
if (GMIME_IS_PART (mobj)) {
/* the easy case: the part has a filename */
fname = (gchar*)g_mime_part_get_filename (GMIME_PART(mobj));
if (fname) /* don't include directory components */
fname = g_path_get_basename (fname);
}
if (!fname && !construct_if_needed)
return NULL;
if (GMIME_IS_MESSAGE_PART(mobj)) {
GMimeMessage *msg;
const char *subj;
msg = g_mime_message_part_get_message
(GMIME_MESSAGE_PART(mobj));
subj = g_mime_message_get_subject (msg);
fname = g_strdup_printf ("%s.eml", subj ? subj : "message");
}
if (!fname)
fname = g_strdup_printf ("%u.part", index);
/* remove slashes, spaces, colons... */
for (cur = fname; *cur; ++cur)
if (*cur == '/' || *cur == ' ' || *cur == ':')
*cur = '-';
return fname;
}
char*
mu_msg_part_get_filename (MuMsgPart *mpart, gboolean construct_if_needed)
{
g_return_val_if_fail (mpart, NULL);
g_return_val_if_fail (GMIME_IS_OBJECT(mpart->data), NULL);
#endif /*BUILD_CRYPTO*/
return mime_part_get_filename ((GMimeObject*)mpart->data,
mpart->index, construct_if_needed);
}
static MuMsgPartType
get_disposition (GMimeObject *mobj)
{
const char *disp;
disp = g_mime_object_get_disposition (mobj);
if (!disp)
return MU_MSG_PART_TYPE_NONE;
if (strcasecmp (disp, GMIME_DISPOSITION_ATTACHMENT) == 0)
return MU_MSG_PART_TYPE_ATTACHMENT;
if (strcasecmp (disp, GMIME_DISPOSITION_INLINE) == 0)
return MU_MSG_PART_TYPE_INLINE;
return MU_MSG_PART_TYPE_NONE;
}
static gboolean
init_msg_part_from_mime_part (MuMsgOptions opts, GMimeObject *parent,
GMimePart *part, MuMsgPart *pi)
handle_children (MuMsg *msg,
GMimeObject *mobj, MuMsgOptions opts,
unsigned index, MuMsgPartForeachFunc func,
gpointer user_data);
/* call 'func' with information about this MIME-part */
static gboolean
handle_signed_part (MuMsg *msg,
GMimeMultipartSigned *part, GMimeObject *parent,
MuMsgOptions opts, unsigned index,
MuMsgPartForeachFunc func, gpointer user_data)
{
return TRUE;
}
/* call 'func' with information about this MIME-part */
static gboolean
handle_encrypted_part (MuMsg *msg,
GMimeMultipartEncrypted *part, GMimeObject *parent,
MuMsgOptions opts, unsigned index,
MuMsgPartForeachFunc func, gpointer user_data)
{
return TRUE;
}
/* call 'func' with information about this MIME-part */
static gboolean
handle_part (MuMsg *msg, GMimePart *part, GMimeObject *parent,
MuMsgOptions opts, unsigned index,
MuMsgPartForeachFunc func, gpointer user_data)
{
const gchar *fname, *descr;
GMimeContentType *ct;
MuMsgPart msgpart;
memset (&msgpart, 0, sizeof(MuMsgPart));
ct = g_mime_object_get_content_type ((GMimeObject*)part);
if (GMIME_IS_CONTENT_TYPE(ct)) {
pi->type = (char*)g_mime_content_type_get_media_type (ct);
pi->subtype = (char*)g_mime_content_type_get_media_subtype (ct);
msgpart.type = g_mime_content_type_get_media_type (ct);
msgpart.subtype = g_mime_content_type_get_media_subtype (ct);
}
pi->disposition = (char*)g_mime_object_get_disposition
((GMimeObject*)part);
msgpart.size = get_part_size (part);
fname = g_mime_part_get_filename (part);
pi->file_name = fname ? mu_str_utf8ify (fname) : NULL;
msgpart.part_type = MU_MSG_PART_TYPE_LEAF;
msgpart.part_type |= get_disposition ((GMimeObject*)part);
descr = g_mime_part_get_content_description (part);
pi->description = descr ? mu_str_utf8ify (descr) : NULL;
pi->size = get_part_size (part);
pi->part_type = MU_MSG_PART_TYPE_LEAF;
/* a top-level non-attachment text part is probably a body */
if ((!parent || GMIME_IS_MESSAGE(parent)) &&
((msgpart.part_type & MU_MSG_PART_TYPE_ATTACHMENT) == 0) &&
g_strcmp0 (msgpart.type, "text") == 0)
msgpart.part_type |= MU_MSG_PART_TYPE_BODY;
if (!pi->disposition ||
g_ascii_strcasecmp (pi->disposition,
GMIME_DISPOSITION_INLINE) == 0)
pi->part_type |= MU_MSG_PART_TYPE_INLINE;
msgpart.data = (gpointer)part;
msgpart.index = index;
if (GMIME_IS_MULTIPART_SIGNED (parent))
pi->part_type |= MU_MSG_PART_TYPE_SIGNED;
if (GMIME_IS_MULTIPART_ENCRYPTED (parent))
pi->part_type |= MU_MSG_PART_TYPE_ENCRYPTED;
/* 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,
pi, opts);
#endif /*BUILD_CRYPTO*/
func (msg, &msgpart, user_data);
return TRUE;
}
static gchar*
get_filename_for_mime_message_part (GMimeMessage *mmsg)
/* call 'func' with information about this MIME-part */
static gboolean
handle_message_part (MuMsg *msg, GMimeMessagePart *mmsg, GMimeObject *parent,
MuMsgOptions opts, unsigned index,
MuMsgPartForeachFunc func, gpointer user_data)
{
gchar *name, *cur;
MuMsgPart msgpart;
memset (&msgpart, 0, sizeof(MuMsgPart));
name = (char*)g_mime_message_get_subject (mmsg);
if (!name)
name = "message";
msgpart.type = "message";
msgpart.subtype = "rfc822";
msgpart.index = index;
name = g_strconcat (name, ".eml", NULL);
/* msgpart.size = 0; /\* maybe calculate this? *\/ */
/* remove slashes... */
for (cur = name ; *cur; ++cur) {
if (*cur == '/' || *cur == ' ' || *cur == ':')
*cur = '-';
msgpart.part_type = MU_MSG_PART_TYPE_MESSAGE;
msgpart.part_type |= get_disposition ((GMimeObject*)mmsg);
msgpart.data = (gpointer)mmsg;
func (msg, &msgpart, user_data);
if (opts & MU_MSG_OPTION_RECURSE_RFC822) {
GMimeMessage *mime_msg;
mime_msg = g_mime_message_part_get_message (mmsg);
return handle_children
(msg,
(GMimeObject*)mime_msg,
opts, index, func, user_data);
}
return name;
return TRUE;
}
static gboolean
init_msg_part_from_mime_message_part (GMimeMessage *mmsg, MuMsgPart *pi)
handle_mime_object (MuMsg *msg,
GMimeObject *mobj, GMimeObject *parent, MuMsgOptions opts,
unsigned index, MuMsgPartForeachFunc func, gpointer user_data)
{
pi->disposition = GMIME_DISPOSITION_ATTACHMENT;
/* pseudo-file name... */
pi->file_name = get_filename_for_mime_message_part (mmsg);
pi->description = g_strdup ("message");
pi->type = "message";
pi->subtype = "rfc822";
pi->size = 0;
pi->part_type = MU_MSG_PART_TYPE_MESSAGE;
if (GMIME_IS_PART (mobj))
return handle_part
(msg, GMIME_PART(mobj), parent,
opts, index, 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);
else if (GMIME_IS_MULTIPART_SIGNED (mobj))
return handle_signed_part
(msg, GMIME_MULTIPART_SIGNED (mobj),
parent, opts, index, func, user_data);
else if (GMIME_IS_MULTIPART_ENCRYPTED (mobj))
return handle_encrypted_part
(msg, GMIME_MULTIPART_ENCRYPTED (mobj),
parent, opts, index, func, user_data);
return TRUE;
}
static void
msg_part_free (MuMsgPart *pi)
static gboolean
handle_children (MuMsg *msg,
GMimeObject *mobj, MuMsgOptions opts,
unsigned index, MuMsgPartForeachFunc func,
gpointer user_data)
{
if (!pi)
return;
g_free (pi->file_name);
g_free (pi->description);
#ifdef BUILD_CRYPTO
mu_msg_part_free_sig_infos (pi->sig_infos);
#endif /*BUILD_CRYPTO*/
}
static void
part_foreach_cb (GMimeObject *parent, GMimeObject *mobj, PartData *pdata)
{
MuMsgPart pi;
gboolean rv;
GMimePartIter *iter;
/* ignore other non-leaf / message parts */
if (!is_part_or_message_part (mobj))
return;
/* the children */
iter = g_mime_part_iter_new (mobj);
memset (&pi, 0, sizeof(pi));
pi.index = pdata->_idx++;
pi.content_id = (char*)g_mime_object_get_content_id (mobj);
if (!iter)
return FALSE;
for (rv = TRUE; rv && g_mime_part_iter_is_valid (iter);
g_mime_part_iter_next (iter), index++)
rv = handle_mime_object (
msg, g_mime_part_iter_get_current (iter),
g_mime_part_iter_get_parent (iter),
opts, index, func, user_data);
if (GMIME_IS_PART(mobj)) {
pi.data = (gpointer)mobj;
rv = init_msg_part_from_mime_part
(pdata->_opts, parent, (GMimePart*)mobj, &pi);
g_mime_part_iter_free (iter);
/* check if this is the body part */
if (rv && (void*)pdata->_body_part == (void*)mobj)
pi.part_type |= MU_MSG_PART_TYPE_BODY;
} else if (GMIME_IS_MESSAGE_PART(mobj)) {
GMimeMessage *mmsg;
mmsg = g_mime_message_part_get_message ((GMimeMessagePart*)mobj);
if (!mmsg)
return;
/* use the message, not the message part */
pi.data = (gpointer)mmsg;
rv = init_msg_part_from_mime_message_part (mmsg, &pi);
} else
rv = FALSE; /* ignore */
if (rv)
pdata->_func(pdata->_msg, &pi, pdata->_user_data);
msg_part_free (&pi);
return rv;
}
void
mu_msg_part_foreach (MuMsg *msg, MuMsgPartForeachFunc func, gpointer user_data,
MuMsgOptions opts)
gboolean
mu_msg_part_foreach (MuMsg *msg, MuMsgOptions opts,
MuMsgPartForeachFunc func, gpointer user_data)
{
PartData pdata;
GMimeMessage *mime_msg;
GMimeObject *toplevel;
unsigned idx;
g_return_if_fail (msg);
g_return_val_if_fail (msg, FALSE);
if (!mu_msg_load_msg_file (msg, NULL))
return;
return FALSE;
mime_msg = msg->_file->_mime_msg;
idx = 0;
toplevel = g_mime_message_get_mime_part
(GMIME_MESSAGE(msg->_file->_mime_msg));
if (!toplevel || !handle_mime_object
(msg, toplevel, NULL, opts, idx++, func, user_data))
return FALSE;
pdata._msg = msg;
pdata._idx = 0;
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;
mu_mime_message_foreach (msg->_file->_mime_msg,
mu_msg_get_auto_decrypt(msg),
(GMimeObjectForeachFunc)part_foreach_cb,
&pdata);
return handle_children (msg, toplevel, opts, idx, func,
user_data);
}
@ -490,13 +606,16 @@ write_object_to_fd (GMimeObject *obj, int fd, GError **err)
}
gboolean
mu_msg_part_mime_save_object (GMimeObject *obj, const char *fullpath,
gboolean overwrite, gboolean use_existing, GError **err)
static gboolean
save_object (GMimeObject *obj, MuMsgOptions opts, const char *fullpath,
GError **err)
{
int fd;
gboolean rv;
gboolean use_existing, overwrite;
use_existing = opts & MU_MSG_OPTION_USE_EXISTING;
overwrite = opts & MU_MSG_OPTION_OVERWRITE;
/* don't try to overwrite when we already have it; useful when
* you're sure it's not a different file with the same name */
@ -529,41 +648,25 @@ mu_msg_part_mime_save_object (GMimeObject *obj, const char *fullpath,
gchar*
mu_msg_part_filepath (MuMsg *msg, const char* targetdir, guint partidx,
GError **err)
mu_msg_part_get_path (MuMsg *msg, MuMsgOptions opts,
const char* targetdir, unsigned index, GError **err)
{
char *fname, *filepath;
GMimeObject* mobj;
g_return_val_if_fail (msg, NULL);
if (!mu_msg_load_msg_file (msg, NULL))
return NULL;
if (!(mobj = find_part (msg, partidx))) {
mu_util_g_set_error (err,MU_ERROR_GMIME,
"cannot find part %u", partidx);
return NULL;
}
if (GMIME_IS_PART (mobj)) {
/* the easy case: the part has a filename */
fname = (gchar*)g_mime_part_get_filename (GMIME_PART(mobj));
if (fname) /* security: don't includ directory
* components */
fname = g_path_get_basename (fname);
else
fname = g_strdup_printf ("%x-part-%u",
g_str_hash (mu_msg_get_path (msg)),
partidx);
} else if (GMIME_IS_MESSAGE_PART(mobj))
fname = get_filename_for_mime_message_part
(g_mime_message_part_get_message
((GMimeMessagePart*)mobj));
else {
mobj = get_mime_object_at_index (msg, opts, index);
if (!mobj){
mu_util_g_set_error (err, MU_ERROR_GMIME,
"part %u cannot be saved", partidx);
"cannot find part %u", index);
return NULL;
}
fname = mime_part_get_filename (mobj, index, TRUE);
filepath = g_build_path (G_DIR_SEPARATOR_S, targetdir ? targetdir : "",
fname, NULL);
g_free (fname);
@ -574,7 +677,8 @@ mu_msg_part_filepath (MuMsg *msg, const char* targetdir, guint partidx,
gchar*
mu_msg_part_filepath_cache (MuMsg *msg, guint partid)
mu_msg_part_get_cache_path (MuMsg *msg, MuMsgOptions opts, guint partid,
GError **err)
{
char *dirname, *filepath;
const char* path;
@ -585,8 +689,6 @@ mu_msg_part_filepath_cache (MuMsg *msg, guint partid)
return NULL;
path = mu_msg_get_path (msg);
if (!path)
return NULL;
/* g_compute_checksum_for_string may be better, but requires
* rel. new glib (2.16) */
@ -596,61 +698,56 @@ mu_msg_part_filepath_cache (MuMsg *msg, guint partid)
partid);
if (!mu_util_create_dir_maybe (dirname, 0700, FALSE)) {
mu_util_g_set_error (err, MU_ERROR_FILE, "failed to create dir %s",
dirname);
g_free (dirname);
return NULL;
}
filepath = mu_msg_part_filepath (msg, dirname, partid, NULL);
filepath = mu_msg_part_get_path (msg, opts, dirname, partid, err);
g_free (dirname);
if (!filepath)
g_warning ("%s: could not get filename", __FUNCTION__);
return filepath;
}
gboolean
mu_msg_part_save (MuMsg *msg, const char *fullpath, guint partidx,
gboolean overwrite, gboolean use_cached, GError **err)
mu_msg_part_save (MuMsg *msg, MuMsgOptions opts,
const char *fullpath, guint partidx, GError **err)
{
GMimeObject *part;
g_return_val_if_fail (msg, FALSE);
g_return_val_if_fail (fullpath, FALSE);
g_return_val_if_fail (!overwrite||!use_cached, FALSE);
g_return_val_if_fail (!((opts & MU_MSG_OPTION_OVERWRITE) &&
(opts & MU_MSG_OPTION_USE_EXISTING)), FALSE);
if (!mu_msg_load_msg_file (msg, err))
return FALSE;
part = find_part (msg, partidx);
if (!is_part_or_message_part (part)) {
part = get_mime_object_at_index (msg, opts, partidx);
if (!GMIME_IS_PART(part) || GMIME_IS_MESSAGE_PART(part)) {
g_set_error (err, MU_ERROR_DOMAIN, MU_ERROR_GMIME,
"unexpected type %s for part %u",
G_OBJECT_TYPE_NAME((GObject*)part),
partidx);
return FALSE;
} else
return mu_msg_part_mime_save_object (part, fullpath, overwrite,
use_cached, err);
}
return save_object (part, opts, fullpath, err);
}
gchar*
mu_msg_part_save_temp (MuMsg *msg, guint partidx, GError **err)
mu_msg_part_save_temp (MuMsg *msg, MuMsgOptions opts, guint partidx, GError **err)
{
gchar *filepath;
gboolean rv;
filepath = mu_msg_part_filepath_cache (msg, partidx);
if (!filepath) {
g_set_error (err, MU_ERROR_DOMAIN, MU_ERROR_FILE,
"Could not get temp filepath");
filepath = mu_msg_part_get_cache_path (msg, opts, partidx, err);
if (!filepath)
return NULL;
}
rv = mu_msg_part_save (msg, filepath, partidx, FALSE, TRUE, err);
if (!rv) {
if (!mu_msg_part_save (msg, opts, filepath, partidx, err)) {
g_free (filepath);
return NULL;
}
@ -658,59 +755,18 @@ mu_msg_part_save_temp (MuMsg *msg, guint partidx, GError **err)
return filepath;
}
typedef gboolean (*MatchFunc) (GMimeObject *part, gpointer data);
struct _MatchData {
MatchFunc _matcher;
gpointer _user_data;
gint _idx, _found_idx;
};
typedef struct _MatchData MatchData;
static void
part_match_foreach_cb (GMimeObject *parent, GMimeObject *part,
MatchData *mdata)
{
if (mdata->_found_idx < 0)
if (mdata->_matcher (part, mdata->_user_data))
mdata->_found_idx = mdata->_idx;
++mdata->_idx;
}
static int
msg_part_find_idx (GMimeMessage *mimemsg, gboolean auto_decrypt,
MatchFunc func, gpointer user_data)
{
MatchData mdata;
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;
mu_mime_message_foreach (mimemsg, auto_decrypt,
(GMimeObjectForeachFunc)part_match_foreach_cb,
&mdata);
return mdata._found_idx;
}
static gboolean
match_content_id (GMimeObject *part, const char *cid)
match_cid (MuMsgPart *mpart, const char *cid)
{
return g_strcmp0 (g_mime_object_get_content_id (part),
cid) == 0 ? TRUE : FALSE;
const char *this_cid;
this_cid = g_mime_object_get_content_id ((GMimeObject*)mpart->data);
return g_strcmp0 (this_cid, cid) ? TRUE : FALSE;
}
int
mu_msg_part_find_cid (MuMsg *msg, const char* sought_cid)
mu_msg_find_index_for_cid (MuMsg *msg, MuMsgOptions opts, const char *sought_cid)
{
const char* cid;
@ -723,53 +779,43 @@ mu_msg_part_find_cid (MuMsg *msg, const char* sought_cid)
cid = g_str_has_prefix (sought_cid, "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);
return get_matching_part_index (msg, opts,
(MuMsgPartMatchFunc)match_cid,
(gpointer)(char*)cid);
}
struct _MatchData2 {
GSList *_lst;
struct _RxMatchData {
GSList *_lst;
const GRegex *_rx;
guint _idx;
};
typedef struct _MatchData2 MatchData2;
typedef struct _RxMatchData RxMatchData;
static void
match_filename_rx (GMimeObject *parent, GMimeObject *part, MatchData2 *mdata)
match_filename_rx (MuMsg *msg, MuMsgPart *mpart, RxMatchData *mdata)
{
const char *fname;
char *fname;
/* ignore other parts -- we need this guard so the counting of
* parts is the same as in other functions for dealing with
* msg parts (this is needed since we expose the numbers to
* the user) */
if (!is_part_or_message_part (part))
fname = mu_msg_part_get_filename (mpart, FALSE);
if (!fname)
return;
fname = g_mime_part_get_filename (GMIME_PART(part));
if (!fname) {
++mdata->_idx;
return;
}
if (g_regex_match (mdata->_rx, fname, 0, NULL))
mdata->_lst = g_slist_prepend (mdata->_lst,
GUINT_TO_POINTER(mdata->_idx++));
GUINT_TO_POINTER(mpart->index));
g_free (fname);
}
GSList*
mu_msg_part_find_files (MuMsg *msg, const GRegex *pattern)
mu_msg_find_files (MuMsg *msg, MuMsgOptions opts, const GRegex *pattern)
{
MatchData2 mdata;
RxMatchData mdata;
g_return_val_if_fail (msg, NULL);
g_return_val_if_fail (pattern, NULL);
if (!mu_msg_load_msg_file (msg, NULL))
return NULL;
@ -777,17 +823,15 @@ mu_msg_part_find_files (MuMsg *msg, const GRegex *pattern)
mdata._rx = pattern;
mdata._idx = 0;
mu_mime_message_foreach (msg->_file->_mime_msg,
mu_msg_get_auto_decrypt(msg),
(GMimeObjectForeachFunc)match_filename_rx,
&mdata);
mu_msg_part_foreach (msg, opts,
(MuMsgPartForeachFunc)match_filename_rx,
&mdata);
return mdata._lst;
}
gboolean
mu_msg_part_looks_like_attachment (MuMsgPart *part,
gboolean include_inline)
mu_msg_part_looks_like_attachment (MuMsgPart *part, gboolean include_inline)
{
g_return_val_if_fail (part, FALSE);