* WIP: rough implementation of attachment extraction
This commit is contained in:
@ -19,11 +19,31 @@
|
|||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "mu-msg-gmime.h"
|
#include "mu-msg-gmime.h"
|
||||||
#include "mu-msg-str.h"
|
#include "mu-msg-str.h"
|
||||||
#include "mu-cmd.h"
|
#include "mu-cmd.h"
|
||||||
|
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
save_part (const char* path, unsigned idx)
|
||||||
|
{
|
||||||
|
MuMsgGMime* msg;
|
||||||
|
|
||||||
|
msg = mu_msg_gmime_new (path, NULL);
|
||||||
|
if (!msg)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
mu_msg_gmime_mime_part_save (msg, idx, NULL, TRUE); /* FIXME */
|
||||||
|
|
||||||
|
mu_msg_gmime_destroy (msg);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
each_part (MuMsgPartInfo* part, gpointer user_data)
|
each_part (MuMsgPartInfo* part, gpointer user_data)
|
||||||
{
|
{
|
||||||
@ -62,14 +82,32 @@ mu_cmd_extract (MuConfigOptions *opts)
|
|||||||
|
|
||||||
/* note: params[0] will be 'view' */
|
/* note: params[0] will be 'view' */
|
||||||
if (!opts->params[0] || !opts->params[1]) {
|
if (!opts->params[0] || !opts->params[1]) {
|
||||||
g_printerr ("Missing files to view\n");
|
g_printerr ("missing file to extract\n");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
mu_msg_gmime_init();
|
mu_msg_gmime_init();
|
||||||
|
|
||||||
rv = show_parts (opts->params[1]);
|
rv = FALSE;
|
||||||
|
if (!opts->params[2]) /* no explicit part, show, don't save */
|
||||||
|
rv = show_parts (opts->params[1]);
|
||||||
|
else {
|
||||||
|
int i;
|
||||||
|
for (i = 2; opts->params[i]; ++i) {
|
||||||
|
unsigned idx = atoi (opts->params[i]);
|
||||||
|
if (idx == 0) {
|
||||||
|
g_printerr ("not a valid index: %s", opts->params[i]);
|
||||||
|
rv = FALSE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!save_part (opts->params[1], idx)) {
|
||||||
|
g_printerr ("failed to save part %d of %s", idx,
|
||||||
|
opts->params[1]);
|
||||||
|
rv = FALSE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mu_msg_gmime_uninit();
|
mu_msg_gmime_uninit();
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
|
|||||||
@ -771,18 +771,6 @@ mu_msg_gmime_get_summary (MuMsgGMime *msg, size_t max_lines)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
gboolean
|
|
||||||
mu_msg_gmime_mime_part_save (MuMsgGMime *msg, unsigned idx,
|
|
||||||
const char *targetdir)
|
|
||||||
{
|
|
||||||
return TRUE; /* FIXME */
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const char*
|
const char*
|
||||||
mu_msg_gmime_get_field_string (MuMsgGMime *msg, const MuMsgField* field)
|
mu_msg_gmime_get_field_string (MuMsgGMime *msg, const MuMsgField* field)
|
||||||
{
|
{
|
||||||
@ -984,7 +972,6 @@ mu_msg_gmime_uninit (void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct _PartData {
|
struct _PartData {
|
||||||
unsigned _idx;
|
unsigned _idx;
|
||||||
MuMsgPartInfoForeachFunc _func;
|
MuMsgPartInfoForeachFunc _func;
|
||||||
@ -997,28 +984,22 @@ static void
|
|||||||
part_foreach_cb (GMimeObject *parent, GMimeObject *part, PartData *pdata)
|
part_foreach_cb (GMimeObject *parent, GMimeObject *part, PartData *pdata)
|
||||||
{
|
{
|
||||||
GMimeContentType *ct;
|
GMimeContentType *ct;
|
||||||
GMimeContentDisposition *cd;
|
|
||||||
MuMsgPartInfo pi;
|
MuMsgPartInfo pi;
|
||||||
|
|
||||||
ct = g_mime_object_get_content_type (part);
|
|
||||||
|
|
||||||
/* ignore non-MIME */
|
|
||||||
if (!GMIME_IS_CONTENT_TYPE(ct)) {
|
|
||||||
g_debug ("not a content type!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
||||||
pi.type = (char*)g_mime_content_type_get_media_type (ct);
|
|
||||||
pi.subtype = (char*)g_mime_content_type_get_media_subtype (ct);
|
ct = g_mime_object_get_content_type (part);
|
||||||
pi.disposition = (char*)g_mime_object_get_disposition (part);
|
if (GMIME_IS_CONTENT_TYPE(ct)) {
|
||||||
|
pi.type = (char*)g_mime_content_type_get_media_type (ct);
|
||||||
cd = g_mime_object_get_content_disposition (part);
|
pi.subtype = (char*)g_mime_content_type_get_media_subtype (ct);
|
||||||
if (GMIME_IS_CONTENT_DISPOSITION(cd))
|
}
|
||||||
pi.file_name = (char*)g_mime_content_disposition_get_parameter
|
|
||||||
(cd , "filename");
|
if (GMIME_IS_PART(part)) {
|
||||||
|
pi.disposition = (char*)g_mime_object_get_disposition (part);
|
||||||
|
pi.file_name = (char*)g_mime_part_get_filename (GMIME_PART(part));
|
||||||
|
}
|
||||||
|
|
||||||
pdata->_func(&pi, pdata->_user_data);
|
pdata->_func(&pi, pdata->_user_data);
|
||||||
}
|
}
|
||||||
@ -1046,3 +1027,75 @@ mu_msg_gmime_msg_part_infos_foreach (MuMsgGMime *msg,
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
struct _SavePartData {
|
||||||
|
guint idx, wanted_idx;
|
||||||
|
const gchar* targetdir;
|
||||||
|
gboolean overwrite;
|
||||||
|
gboolean stream;
|
||||||
|
gboolean result;
|
||||||
|
};
|
||||||
|
typedef struct _SavePartData SavePartData;
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
part_foreach_save_cb (GMimeObject *parent, GMimeObject *part,
|
||||||
|
SavePartData *spd)
|
||||||
|
{
|
||||||
|
const gchar* filename;
|
||||||
|
|
||||||
|
/* did we find the right part yet? */
|
||||||
|
if (spd->result || spd->wanted_idx != spd->idx++)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!GMIME_IS_PART(part))
|
||||||
|
return;
|
||||||
|
|
||||||
|
filename = g_mime_part_get_filename (GMIME_PART(part));
|
||||||
|
if (filename) {
|
||||||
|
int fd, rv;
|
||||||
|
GMimeDataWrapper *wrapper;
|
||||||
|
GMimeStream *stream;
|
||||||
|
|
||||||
|
fd = mu_util_create_writeable_file (filename, spd->targetdir,
|
||||||
|
spd->overwrite);
|
||||||
|
if (fd == -1) {
|
||||||
|
g_warning ("error saving file %s", filename);
|
||||||
|
spd->result = FALSE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
stream = g_mime_stream_fs_new (fd);
|
||||||
|
g_mime_stream_fs_set_owner (GMIME_STREAM_FS(stream),
|
||||||
|
TRUE); /* GMimeStream will close fd */
|
||||||
|
|
||||||
|
wrapper = g_mime_part_get_content_object (GMIME_PART(part));
|
||||||
|
rv = g_mime_data_wrapper_write_to_stream (wrapper, stream);
|
||||||
|
|
||||||
|
g_object_unref (G_OBJECT(stream));
|
||||||
|
//g_object_unref (G_OBJECT(wrapper));
|
||||||
|
|
||||||
|
spd->result = (rv != -1);
|
||||||
|
} else
|
||||||
|
spd->result = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
mu_msg_gmime_mime_part_save (MuMsgGMime *msg, int wanted_idx,
|
||||||
|
const char *targetdir, gboolean overwrite)
|
||||||
|
{
|
||||||
|
SavePartData spd;
|
||||||
|
spd.idx = 0;
|
||||||
|
spd.wanted_idx = wanted_idx;
|
||||||
|
spd.targetdir = targetdir;
|
||||||
|
spd.overwrite = overwrite;
|
||||||
|
spd.stream = FALSE;
|
||||||
|
spd.result = FALSE;
|
||||||
|
|
||||||
|
g_mime_message_foreach (msg->_mime_msg,
|
||||||
|
(GMimeObjectForeachFunc)part_foreach_save_cb,
|
||||||
|
&spd);
|
||||||
|
|
||||||
|
return spd.result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@ -142,13 +142,15 @@ void mu_msg_gmime_mime_part_foreach (MuMsgGMime* msg,
|
|||||||
* save a specific attachment to some targetdir
|
* save a specific attachment to some targetdir
|
||||||
*
|
*
|
||||||
* @param msg a valid MuMsgGMime instance
|
* @param msg a valid MuMsgGMime instance
|
||||||
* @param index index of the attachment you want to save
|
* @param wanted_idx index of the attachment you want to save
|
||||||
* @param targetdir filesystem directory to save the attachment
|
* @param targetdir filesystem directory to save the attachment
|
||||||
|
* @param overwrite existing files?
|
||||||
*
|
*
|
||||||
* @return TRUE if saving succeeded, FALSE otherwise
|
* @return TRUE if saving succeeded, FALSE otherwise
|
||||||
*/
|
*/
|
||||||
gboolean mu_msg_gmime_mime_part_save (MuMsgGMime *msg, unsigned num,
|
gboolean
|
||||||
const char *targetdir);
|
mu_msg_gmime_mime_part_save (MuMsgGMime *msg, int wanted_idx,
|
||||||
|
const char *targetdir, gboolean overwrite);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get the sender (From:) of this message
|
* get the sender (From:) of this message
|
||||||
|
|||||||
@ -23,6 +23,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@ -154,10 +155,40 @@ mu_util_str_from_strv (const gchar **params)
|
|||||||
str = g_string_sized_new (64); /* just a guess */
|
str = g_string_sized_new (64); /* just a guess */
|
||||||
|
|
||||||
for (i = 0; params[i]; ++i) {
|
for (i = 0; params[i]; ++i) {
|
||||||
|
|
||||||
if (i>0)
|
if (i>0)
|
||||||
g_string_append_c (str, ' ');
|
g_string_append_c (str, ' ');
|
||||||
|
|
||||||
g_string_append (str, params[i]);
|
g_string_append (str, params[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return g_string_free (str, FALSE);
|
return g_string_free (str, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
mu_util_create_writeable_file (const char* filename, const char* dir, gboolean overwrite)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
char *fullpath;
|
||||||
|
|
||||||
|
errno = 0; /* clear! */
|
||||||
|
g_return_val_if_fail (filename, -1);
|
||||||
|
|
||||||
|
fullpath = g_strdup_printf ("%s%s%s",
|
||||||
|
dir ? dir : "",
|
||||||
|
dir ? G_DIR_SEPARATOR_S : "",
|
||||||
|
filename);
|
||||||
|
|
||||||
|
if (overwrite)
|
||||||
|
fd = open (fullpath, O_WRONLY|O_CREAT|O_TRUNC, 0644);
|
||||||
|
else
|
||||||
|
fd = open (fullpath, O_WRONLY|O_CREAT, 0644);
|
||||||
|
|
||||||
|
if (fd < 0)
|
||||||
|
g_debug ("%s: cannot open %s for writing: %s",
|
||||||
|
__FUNCTION__, fullpath, strerror(errno));
|
||||||
|
|
||||||
|
g_free (fullpath);
|
||||||
|
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|||||||
@ -70,6 +70,22 @@ gboolean mu_util_check_dir (const gchar* path, gboolean readable,
|
|||||||
gboolean writeable) G_GNUC_WARN_UNUSED_RESULT;
|
gboolean writeable) G_GNUC_WARN_UNUSED_RESULT;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* create a writeable file and return its file descriptor (which
|
||||||
|
* you'll need to close(2) when done with it.)
|
||||||
|
*
|
||||||
|
* @param filename the filename
|
||||||
|
* @param dir the target directory, or NULL for the current
|
||||||
|
* @param overwrite should we allow for overwriting existing files?
|
||||||
|
*
|
||||||
|
* @return a file descriptor, or -1 in case of error. If it's a fily
|
||||||
|
* system error, 'errno' may have more info.
|
||||||
|
*/
|
||||||
|
int mu_util_create_writeable_file (const char* filename, const char* dir,
|
||||||
|
gboolean overwrite);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* convert a string array in to a string, with the elements separated
|
* convert a string array in to a string, with the elements separated
|
||||||
* by ' '
|
* by ' '
|
||||||
|
|||||||
Reference in New Issue
Block a user