* implement saving mime-part by file-name, improve error handling

This commit is contained in:
Dirk-Jan C. Binnema
2011-05-21 14:12:01 +03:00
parent 3d84650f42
commit 6355e78bc1
3 changed files with 292 additions and 203 deletions

View File

@ -33,17 +33,21 @@ static gboolean
save_part (MuMsg *msg, const char *targetdir, guint partidx, gboolean overwrite, save_part (MuMsg *msg, const char *targetdir, guint partidx, gboolean overwrite,
gboolean play) gboolean play)
{ {
GError *err;
gchar *filepath; gchar *filepath;
filepath = mu_msg_part_filepath (msg, targetdir, partidx); filepath = mu_msg_part_filepath (msg, targetdir, partidx);
if (!filepath) { if (!filepath) {
g_warning ("%s: failed to get filepath", __FUNCTION__); g_warning ("failed to get filepath");
return FALSE; return FALSE;
} }
if (!mu_msg_part_save (msg, filepath, partidx, overwrite, FALSE)) { err = NULL;
g_warning ("%s: failed to save MIME-part %d at %s", if (!mu_msg_part_save (msg, filepath, partidx, overwrite, FALSE, &err)) {
__FUNCTION__, partidx, filepath); g_warning ("failed to save MIME-part: %s",
err&&err->message ? err->message : "error");
if (err)
g_error_free (err);
g_free (filepath); g_free (filepath);
return FALSE; return FALSE;
} }
@ -51,6 +55,7 @@ save_part (MuMsg *msg, const char *targetdir, guint partidx, gboolean overwrite,
if (play) if (play)
mu_util_play (filepath, TRUE, FALSE); mu_util_play (filepath, TRUE, FALSE);
g_free (filepath);
return TRUE; return TRUE;
} }
@ -89,6 +94,26 @@ save_numbered_parts (MuMsg *msg, MuConfig *opts)
return rv; return rv;
} }
static gboolean
save_part_with_filename (MuMsg *msg, const char *filename, MuConfig *opts)
{
int idx;
idx = mu_msg_part_find_file (msg, filename);
if (idx == -1) {
g_warning ("file '%s' not found in this message", filename);
return FALSE;
}
if (!save_part (msg, opts->targetdir, idx, opts->overwrite,
opts->play))
return FALSE;
return TRUE;
}
struct _SaveData { struct _SaveData {
gboolean attachments_only; gboolean attachments_only;
gboolean result; gboolean result;
@ -126,6 +151,7 @@ save_part_if (MuMsg *msg, MuMsgPart *part, SaveData *sd)
{ {
gchar *filepath; gchar *filepath;
gboolean rv; gboolean rv;
GError *err;
if (ignore_part (msg, part, sd)) if (ignore_part (msg, part, sd))
return; return;
@ -136,10 +162,16 @@ save_part_if (MuMsg *msg, MuMsgPart *part, SaveData *sd)
filepath = mu_msg_part_filepath (msg, sd->targetdir, part->index); filepath = mu_msg_part_filepath (msg, sd->targetdir, part->index);
if (!filepath) if (!filepath)
goto leave; goto leave;
err = NULL;
if (!mu_msg_part_save (msg, filepath, part->index, if (!mu_msg_part_save (msg, filepath, part->index,
sd->overwrite, FALSE)) sd->overwrite, FALSE, &err)) {
g_warning ("failed to save MIME-part: %s",
err&&err->message ? err->message : "error");
if (err)
g_error_free (err);
goto leave; goto leave;
}
if (sd->play && !mu_util_play (filepath, TRUE, FALSE)) if (sd->play && !mu_util_play (filepath, TRUE, FALSE))
goto leave; goto leave;
@ -183,7 +215,7 @@ save_certain_parts (MuMsg *msg, gboolean attachments_only,
static gboolean static gboolean
save_parts (const char *path, MuConfig *opts) save_parts (const char *path, const char *filename, MuConfig *opts)
{ {
MuMsg* msg; MuMsg* msg;
gboolean rv; gboolean rv;
@ -202,7 +234,9 @@ save_parts (const char *path, MuConfig *opts)
/* should we save some explicit parts? */ /* should we save some explicit parts? */
if (opts->parts) if (opts->parts)
rv = save_numbered_parts (msg, opts); rv = save_numbered_parts (msg, opts);
else if (filename)
rv = save_part_with_filename (msg, filename, opts);
else if (opts->save_attachments) /* all attachments */ else if (opts->save_attachments) /* all attachments */
rv = save_certain_parts (msg, TRUE, rv = save_certain_parts (msg, TRUE,
opts->targetdir, opts->overwrite, opts->targetdir, opts->overwrite,
@ -257,8 +291,14 @@ show_parts (const char* path, MuConfig *opts)
static gboolean static gboolean
check_params (MuConfig *opts) check_params (MuConfig *opts)
{ {
if (!opts->params[1] || opts->params[2]) { if (!opts->params[1] || (opts->params[2] && opts->params[3])) {
g_warning ("usage: mu extract [options] <file>"); g_warning ("usage: mu extract [options] <file> [<filename>]");
return FALSE;
}
if (opts->params[2] && (opts->save_attachments || opts->save_all)) {
g_warning ("--save-attachments --save-all is allowed don't accept "
"a filename");
return FALSE; return FALSE;
} }
@ -289,7 +329,8 @@ mu_cmd_extract (MuConfig *opts)
if (!check_params (opts)) if (!check_params (opts))
return MU_EXITCODE_ERROR; return MU_EXITCODE_ERROR;
if (!opts->parts && if (!opts->params[2] &&
!opts->parts &&
!opts->save_attachments && !opts->save_attachments &&
!opts->save_all) /* show, don't save */ !opts->save_all) /* show, don't save */
rv = show_parts (opts->params[1], opts); rv = show_parts (opts->params[1], opts);
@ -299,7 +340,9 @@ mu_cmd_extract (MuConfig *opts)
g_warning ("target '%s' is not a writable directory", g_warning ("target '%s' is not a writable directory",
opts->targetdir); opts->targetdir);
else else
rv = save_parts (opts->params[1], opts); /* save */ rv = save_parts (opts->params[1],
opts->params[2],
opts); /* save */
} }
return rv ? MU_EXITCODE_OK : MU_EXITCODE_ERROR; return rv ? MU_EXITCODE_OK : MU_EXITCODE_ERROR;

View File

@ -1,3 +1,5 @@
/* -*-mode: c; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-*/
/* /*
** Copyright (C) 2008-2011 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl> ** Copyright (C) 2008-2011 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
** **
@ -29,8 +31,8 @@
#include "mu-msg-part.h" #include "mu-msg-part.h"
struct _FindPartData { struct _FindPartData {
guint idx, wanted_idx; guint idx, wanted_idx;
GMimeObject *part; GMimeObject *part;
}; };
typedef struct _FindPartData FindPartData; typedef struct _FindPartData FindPartData;
@ -38,32 +40,32 @@ typedef struct _FindPartData FindPartData;
static void static void
find_part_cb (GMimeObject *parent, GMimeObject *part, FindPartData *fpdata) find_part_cb (GMimeObject *parent, GMimeObject *part, FindPartData *fpdata)
{ {
if (fpdata->part || fpdata->wanted_idx != fpdata->idx++) if (fpdata->part || fpdata->wanted_idx != fpdata->idx++)
return; /* not yet found */ return; /* not yet found */
fpdata->part = part; fpdata->part = part;
} }
static GMimeObject* static GMimeObject*
find_part (MuMsg* msg, guint partidx) find_part (MuMsg* msg, guint partidx)
{ {
FindPartData fpdata; FindPartData fpdata;
fpdata.wanted_idx = partidx; fpdata.wanted_idx = partidx;
fpdata.idx = 0; fpdata.idx = 0;
fpdata.part = NULL; fpdata.part = NULL;
g_mime_message_foreach (msg->_file->_mime_msg, g_mime_message_foreach (msg->_file->_mime_msg,
(GMimeObjectForeachFunc)find_part_cb, (GMimeObjectForeachFunc)find_part_cb,
&fpdata); &fpdata);
return fpdata.part; return fpdata.part;
} }
struct _PartData { struct _PartData {
MuMsg *_msg; MuMsg *_msg;
unsigned _idx; unsigned _idx;
MuMsgPartForeachFunc _func; MuMsgPartForeachFunc _func;
gpointer _user_data; gpointer _user_data;
}; };
typedef struct _PartData PartData; typedef struct _PartData PartData;
@ -71,134 +73,141 @@ typedef struct _PartData PartData;
static void static void
part_foreach_cb (GMimeObject *parent, GMimeObject *part, PartData *pdata) part_foreach_cb (GMimeObject *parent, GMimeObject *part, PartData *pdata)
{ {
GMimeContentType *ct; GMimeContentType *ct;
MuMsgPart pi; MuMsgPart pi;
memset (&pi, 0, sizeof pi); memset (&pi, 0, sizeof pi);
pi.index = pdata->_idx++; pi.index = pdata->_idx++;
pi.content_id = (char*)g_mime_object_get_content_id (part); pi.content_id = (char*)g_mime_object_get_content_id (part);
ct = g_mime_object_get_content_type (part); ct = g_mime_object_get_content_type (part);
if (GMIME_IS_CONTENT_TYPE(ct)) { if (GMIME_IS_CONTENT_TYPE(ct)) {
pi.type = (char*)g_mime_content_type_get_media_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.subtype = (char*)g_mime_content_type_get_media_subtype (ct);
} }
if (GMIME_IS_PART(part)) { if (GMIME_IS_PART(part)) {
pi.disposition = (char*)g_mime_object_get_disposition (part); pi.disposition = (char*)g_mime_object_get_disposition (part);
pi.file_name = (char*)g_mime_part_get_filename (GMIME_PART(part)); pi.file_name = (char*)g_mime_part_get_filename (GMIME_PART(part));
} }
pdata->_func(pdata->_msg, &pi, pdata->_user_data); pdata->_func(pdata->_msg, &pi, pdata->_user_data);
} }
void void
mu_msg_part_foreach (MuMsg *msg, MuMsgPartForeachFunc func, mu_msg_part_foreach (MuMsg *msg, MuMsgPartForeachFunc func,
gpointer user_data) gpointer user_data)
{ {
PartData pdata; PartData pdata;
g_return_if_fail (msg); g_return_if_fail (msg);
g_return_if_fail (GMIME_IS_OBJECT(msg->_file->_mime_msg)); g_return_if_fail (GMIME_IS_OBJECT(msg->_file->_mime_msg));
pdata._msg = msg; pdata._msg = msg;
pdata._idx = 0; pdata._idx = 0;
pdata._func = func; pdata._func = func;
pdata._user_data = user_data; pdata._user_data = user_data;
g_mime_message_foreach (msg->_file->_mime_msg, g_mime_message_foreach (msg->_file->_mime_msg,
(GMimeObjectForeachFunc)part_foreach_cb, (GMimeObjectForeachFunc)part_foreach_cb,
&pdata); &pdata);
} }
static gboolean static gboolean
write_to_stream (GMimeObject *part, int fd) write_to_stream (GMimeObject *part, int fd)
{ {
GMimeStream *stream; GMimeStream *stream;
GMimeDataWrapper *wrapper; GMimeDataWrapper *wrapper;
gboolean rv; gboolean rv;
stream = g_mime_stream_fs_new (fd); stream = g_mime_stream_fs_new (fd);
if (!GMIME_IS_STREAM(stream)) { if (!GMIME_IS_STREAM(stream)) {
g_critical ("%s: failed to create stream",__FUNCTION__); g_critical ("%s: failed to create stream",__FUNCTION__);
return FALSE; return FALSE;
} }
g_mime_stream_fs_set_owner (GMIME_STREAM_FS(stream), FALSE); g_mime_stream_fs_set_owner (GMIME_STREAM_FS(stream), FALSE);
wrapper = g_mime_part_get_content_object (GMIME_PART(part)); wrapper = g_mime_part_get_content_object (GMIME_PART(part));
if (!GMIME_IS_DATA_WRAPPER(wrapper)) { if (!GMIME_IS_DATA_WRAPPER(wrapper)) {
g_critical ("%s: failed to create wrapper", __FUNCTION__); g_critical ("%s: failed to create wrapper", __FUNCTION__);
g_object_unref (stream);
return FALSE;
}
g_object_ref (part); /* FIXME: otherwise, the unrefs below
* give errors...*/
rv = g_mime_data_wrapper_write_to_stream (wrapper, stream);
if (!rv)
g_critical ("%s: failed to write to stream", __FUNCTION__);
g_object_unref (wrapper);
g_object_unref (stream); g_object_unref (stream);
return FALSE;
}
g_object_ref (part); /* FIXME: otherwise, the unrefs below
* give errors...*/
return rv; rv = g_mime_data_wrapper_write_to_stream (wrapper, stream);
if (!rv)
g_critical ("%s: failed to write to stream", __FUNCTION__);
g_object_unref (wrapper);
g_object_unref (stream);
return rv;
} }
gboolean gboolean
save_part (GMimeObject *part, const char *fullpath, save_part (GMimeObject *part, const char *fullpath,
gboolean overwrite, gboolean use_existing) gboolean overwrite, gboolean use_existing, GError **err)
{ {
int fd; int fd;
gboolean rv; gboolean rv;
/* 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 */
if (use_existing && access (fullpath, F_OK) == 0)
return TRUE;
/* ok, try to create the file */
fd = mu_util_create_writeable_fd (fullpath, 0600, overwrite);
if (fd == -1)
return FALSE;
rv = write_to_stream (part, fd);
if (close (fd) != 0)
g_warning ("%s: failed to close %s: %s", __FUNCTION__,
fullpath, strerror(errno));
/* 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 */
if (use_existing && access (fullpath, F_OK) == 0)
return TRUE; return TRUE;
/* ok, try to create the file */
fd = mu_util_create_writeable_fd (fullpath, 0600, overwrite);
if (fd == -1) {
g_set_error (err, 0, MU_ERROR_FILE,
"could not open '%s' for writing: %s",
fullpath, errno ? strerror(errno) : "error");
return FALSE;
}
rv = write_to_stream (part, fd);
if (close (fd) != 0) {
g_set_error (err, 0, MU_ERROR_FILE,
"could not close '%s': %s",
fullpath, errno ? strerror(errno) : "error");
return FALSE;
}
return TRUE;
} }
gchar* gchar*
mu_msg_part_filepath (MuMsg *msg, const char* targetdir, guint partidx) mu_msg_part_filepath (MuMsg *msg, const char* targetdir, guint partidx)
{ {
char *fname, *filepath; char *fname, *filepath;
GMimeObject* part; GMimeObject* part;
part = find_part (msg, partidx); part = find_part (msg, partidx);
if (!part) { if (!part) {
g_warning ("%s: cannot find part %u", __FUNCTION__, partidx); g_warning ("%s: cannot find part %u", __FUNCTION__, partidx);
return NULL; return NULL;
} }
/* the easy case: the part has a filename */ /* the easy case: the part has a filename */
fname = (gchar*)g_mime_part_get_filename (GMIME_PART(part)); fname = (gchar*)g_mime_part_get_filename (GMIME_PART(part));
if (fname) /* security: don't include any directory components... */ if (fname) /* security: don't include any directory components... */
fname = g_path_get_basename (fname); fname = g_path_get_basename (fname);
else else
fname = g_strdup_printf ("%x-part-%u", fname = g_strdup_printf ("%x-part-%u",
g_str_hash (mu_msg_get_path (msg)), g_str_hash (mu_msg_get_path (msg)),
partidx); partidx);
filepath = g_build_path (G_DIR_SEPARATOR_S, targetdir ? targetdir : "", filepath = g_build_path (G_DIR_SEPARATOR_S, targetdir ? targetdir : "",
fname, NULL); fname, NULL);
g_free (fname); g_free (fname);
return filepath; return filepath;
} }
@ -206,143 +215,168 @@ mu_msg_part_filepath (MuMsg *msg, const char* targetdir, guint partidx)
gchar* gchar*
mu_msg_part_filepath_cache (MuMsg *msg, guint partid) mu_msg_part_filepath_cache (MuMsg *msg, guint partid)
{ {
char *dirname, *filepath; char *dirname, *filepath;
const char* path; const char* path;
g_return_val_if_fail (msg, NULL); g_return_val_if_fail (msg, NULL);
path = mu_msg_get_path (msg); path = mu_msg_get_path (msg);
if (!path) if (!path)
return NULL; return NULL;
/* g_compute_checksum_for_string may be better, but requires /* g_compute_checksum_for_string may be better, but requires
* rel. new glib (2.16) */ * rel. new glib (2.16) */
dirname = g_strdup_printf ("%s%c%x%c%u", dirname = g_strdup_printf ("%s%c%x%c%u",
mu_util_cache_dir(), G_DIR_SEPARATOR, mu_util_cache_dir(), G_DIR_SEPARATOR,
g_str_hash (path), G_DIR_SEPARATOR, g_str_hash (path), G_DIR_SEPARATOR,
partid); partid);
if (!mu_util_create_dir_maybe (dirname, 0700)) { if (!mu_util_create_dir_maybe (dirname, 0700)) {
g_free (dirname);
return NULL;
}
filepath = mu_msg_part_filepath (msg, dirname, partid);
g_free (dirname); g_free (dirname);
if (!filepath) return NULL;
g_warning ("%s: could not get filename", __FUNCTION__); }
filepath = mu_msg_part_filepath (msg, dirname, partid);
g_free (dirname);
if (!filepath)
g_warning ("%s: could not get filename", __FUNCTION__);
return filepath; return filepath;
} }
gboolean gboolean
mu_msg_part_save (MuMsg *msg, const char *fullpath, guint partidx, mu_msg_part_save (MuMsg *msg, const char *fullpath, guint partidx,
gboolean overwrite, gboolean use_cached) gboolean overwrite, gboolean use_cached, GError **err)
{ {
GMimeObject *part; GMimeObject *part;
g_return_val_if_fail (msg, FALSE); g_return_val_if_fail (msg, FALSE);
g_return_val_if_fail (fullpath, FALSE); g_return_val_if_fail (fullpath, FALSE);
g_return_val_if_fail (!overwrite||!use_cached, FALSE); g_return_val_if_fail (!overwrite||!use_cached, FALSE);
part = find_part (msg, partidx); part = find_part (msg, partidx);
if (!GMIME_IS_PART(part)) { if (!GMIME_IS_PART(part)) {
g_warning ("%s: cannot find part %u", __FUNCTION__, partidx); g_set_error (err, 0, MU_ERROR_GMIME,
return FALSE; "cannot find part %u", partidx);
} return FALSE;
}
if (!save_part (part, fullpath, overwrite, use_cached)) { if (!save_part (part, fullpath, overwrite, use_cached, err))
g_warning ("%s: failed to save '%s'", __FUNCTION__, fullpath); return FALSE;
return FALSE;
}
return TRUE; return TRUE;
} }
typedef gboolean (*MatchFunc) (GMimeObject *part, gpointer data); typedef gboolean (*MatchFunc) (GMimeObject *part, gpointer data);
struct _MatchData { struct _MatchData {
MatchFunc _matcher; MatchFunc _matcher;
gpointer _user_data; gpointer _user_data;
gint _idx, _found_idx; gint _idx, _found_idx;
}; };
typedef struct _MatchData MatchData; typedef struct _MatchData MatchData;
static void static void
part_match_foreach_cb (GMimeObject *parent, GMimeObject *part, MatchData *mdata) part_match_foreach_cb (GMimeObject *parent, GMimeObject *part, MatchData *mdata)
{ {
if (mdata->_found_idx < 0) if (mdata->_found_idx < 0)
if (mdata->_matcher (part, mdata->_user_data)) if (mdata->_matcher (part, mdata->_user_data))
mdata->_found_idx = mdata->_idx; mdata->_found_idx = mdata->_idx;
++mdata->_idx; ++mdata->_idx;
} }
static int static int
msg_part_find_idx (GMimeMessage *msg, MatchFunc func, gpointer user_data) msg_part_find_idx (GMimeMessage *msg, MatchFunc func, gpointer user_data)
{ {
MatchData mdata; MatchData mdata;
g_return_val_if_fail (msg, -1); g_return_val_if_fail (msg, -1);
g_return_val_if_fail (GMIME_IS_MESSAGE(msg), -1); g_return_val_if_fail (GMIME_IS_MESSAGE(msg), -1);
mdata._idx = 0; mdata._idx = 0;
mdata._found_idx = -1; mdata._found_idx = -1;
mdata._matcher = func; mdata._matcher = func;
mdata._user_data = user_data; mdata._user_data = user_data;
g_mime_message_foreach (msg, g_mime_message_foreach (msg,
(GMimeObjectForeachFunc)part_match_foreach_cb, (GMimeObjectForeachFunc)part_match_foreach_cb,
&mdata); &mdata);
return mdata._found_idx; return mdata._found_idx;
} }
static gboolean static gboolean
match_content_id (GMimeObject *part, const char *cid) match_content_id (GMimeObject *part, const char *cid)
{ {
return g_strcmp0 (g_mime_object_get_content_id (part), return g_strcmp0 (g_mime_object_get_content_id (part),
cid) == 0 ? TRUE : FALSE; cid) == 0 ? TRUE : FALSE;
} }
int int
mu_msg_part_find_cid (MuMsg *msg, const char* sought_cid) mu_msg_part_find_cid (MuMsg *msg, const char* sought_cid)
{ {
const char* cid; const char* cid;
g_return_val_if_fail (msg, -1L); g_return_val_if_fail (msg, -1L);
g_return_val_if_fail (sought_cid, -1); g_return_val_if_fail (sought_cid, -1);
cid = g_str_has_prefix (sought_cid, "cid:") ? cid = g_str_has_prefix (sought_cid, "cid:") ?
sought_cid + 4 : sought_cid; sought_cid + 4 : sought_cid;
return msg_part_find_idx (msg->_file->_mime_msg, return msg_part_find_idx (msg->_file->_mime_msg,
(MatchFunc)match_content_id, (MatchFunc)match_content_id,
(gpointer)cid); (gpointer)cid);
} }
static gboolean
match_filename (GMimeObject *part, const char *sought_filename)
{
const char *fname;
if (!GMIME_IS_PART(part))
return FALSE;
fname = g_mime_part_get_filename (GMIME_PART(part));
if (!fname)
return FALSE;
return g_strcmp0 (fname, sought_filename) == 0 ? TRUE : FALSE;
}
int
mu_msg_part_find_file (MuMsg *msg, const char* sought_filename)
{
g_return_val_if_fail (msg, -1);
g_return_val_if_fail (sought_filename, -1);
return msg_part_find_idx (msg->_file->_mime_msg,
(MatchFunc)match_filename,
(gpointer)sought_filename);
}
gboolean 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); g_return_val_if_fail (part, FALSE);
if (!part->disposition)
return FALSE;
if (g_ascii_strcasecmp (part->disposition,
GMIME_DISPOSITION_ATTACHMENT) == 0)
return TRUE;
if (include_inline &&
g_ascii_strcasecmp (part->disposition,
GMIME_DISPOSITION_INLINE) == 0)
return TRUE;
if (!part->disposition)
return FALSE; return FALSE;
if (g_ascii_strcasecmp (part->disposition,
GMIME_DISPOSITION_ATTACHMENT) == 0)
return TRUE;
if (include_inline &&
g_ascii_strcasecmp (part->disposition,
GMIME_DISPOSITION_INLINE) == 0)
return TRUE;
return FALSE;
} }

View File

@ -1,3 +1,5 @@
/* -*-mode: c; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-*/
/* /*
** Copyright (C) 2008-2010 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl> ** Copyright (C) 2008-2010 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
** **
@ -101,14 +103,15 @@ gboolean mu_msg_part_looks_like_attachment (MuMsgPart *part,
* @param partidx index of the attachment you want to save * @param partidx index of the attachment you want to save
* @param overwrite overwrite existing files? * @param overwrite overwrite existing files?
* @param don't raise error when the file already exists * @param don't raise error when the file already exists
* @param err receives error information (when function returns NULL)
* *
* @return full path to the message part saved or NULL in case or error; free with g_free * @return full path to the message part saved or NULL in case or error; free with g_free
*/ */
gboolean mu_msg_part_save (MuMsg *msg, const char *filepath, guint partidx, gboolean mu_msg_part_save (MuMsg *msg, const char *filepath, guint partidx,
gboolean overwrite, gboolean use_cached); gboolean overwrite, gboolean use_cached, GError **err);
/** /**
* get a filename for the saving the message part; try the filename * get a filename for the saving the message part; try the filename
* specified for the message part if any, otherwise determine a unique * specified for the message part if any, otherwise determine a unique
* name based on the partidx and the message path * name based on the partidx and the message path
@ -123,7 +126,7 @@ gchar* mu_msg_part_filepath (MuMsg *msg, const char* targetdir,
guint partidx) G_GNUC_WARN_UNUSED_RESULT; guint partidx) G_GNUC_WARN_UNUSED_RESULT;
/** /**
* get a full path name for saving the message part in the cache * get a full path name for saving the message part in the cache
* directory for this message; if needed, create the directory (but * directory for this message; if needed, create the directory (but
* not the file) * not the file)
@ -137,8 +140,8 @@ gchar* mu_msg_part_filepath_cache (MuMsg *msg, guint partid)
G_GNUC_WARN_UNUSED_RESULT; G_GNUC_WARN_UNUSED_RESULT;
/** /**
* get the part inede for the message part with a certain content-id * get the part index for the message part with a certain content-id
* *
* @param msg a message * @param msg a message
* @param content_id a content-id to search * @param content_id a content-id to search
@ -147,10 +150,19 @@ gchar* mu_msg_part_filepath_cache (MuMsg *msg, guint partid)
*/ */
int mu_msg_part_find_cid (MuMsg *msg, const char* content_id); int mu_msg_part_find_cid (MuMsg *msg, const char* content_id);
/**
* get the (first) part index for the message part with a certain
* filename
*
* @param msg a message
* @param sought_filename filename to look for
*
* @return the part index number of the found part, or -1 if it was not found
*/
int mu_msg_part_find_file (MuMsg *msg, const char* sought_filename);
typedef void (*MuMsgPartForeachFunc) (MuMsg *, MuMsgPart *, gpointer); typedef void (*MuMsgPartForeachFunc) (MuMsg*, MuMsgPart*, gpointer);
/** /**
* call a function for each of the mime part in a message * call a function for each of the mime part in a message
* *