2010-08-24 23:57:16 +02:00
|
|
|
/*
|
|
|
|
** Copyright (C) 2008-2010 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
|
|
|
|
**
|
|
|
|
** This program is free software; you can redistribute it and/or modify it
|
|
|
|
** under the terms of the GNU General Public License as published by the
|
|
|
|
** Free Software Foundation; either version 3, or (at your option) any
|
|
|
|
** later version.
|
|
|
|
**
|
|
|
|
** This program is distributed in the hope that it will be useful,
|
|
|
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
** GNU General Public License for more details.
|
|
|
|
**
|
|
|
|
** You should have received a copy of the GNU General Public License
|
|
|
|
** along with this program; if not, write to the Free Software Foundation,
|
|
|
|
** Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
**
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
|
|
|
#endif /*HAVE_CONFIG_H*/
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
#include "mu-util.h"
|
|
|
|
#include "mu-msg-priv.h"
|
|
|
|
#include "mu-msg-part.h"
|
|
|
|
|
|
|
|
struct _PartData {
|
|
|
|
unsigned _idx;
|
|
|
|
MuMsgPartForeachFunc _func;
|
|
|
|
gpointer _user_data;
|
|
|
|
};
|
|
|
|
typedef struct _PartData PartData;
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
part_foreach_cb (GMimeObject *parent, GMimeObject *part, PartData *pdata)
|
|
|
|
{
|
|
|
|
GMimeContentType *ct;
|
|
|
|
MuMsgPart pi;
|
|
|
|
|
|
|
|
memset (&pi, 0, sizeof pi);
|
|
|
|
pi.index = pdata->_idx++;
|
|
|
|
pi.content_id = (char*)g_mime_object_get_content_id (part);
|
|
|
|
|
|
|
|
ct = g_mime_object_get_content_type (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);
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
mu_msg_msg_part_foreach (MuMsg *msg,
|
2010-08-29 21:13:06 +02:00
|
|
|
MuMsgPartForeachFunc func,
|
|
|
|
gpointer user_data)
|
2010-08-24 23:57:16 +02:00
|
|
|
{
|
|
|
|
PartData pdata;
|
|
|
|
|
|
|
|
g_return_if_fail (msg);
|
|
|
|
g_return_if_fail (GMIME_IS_OBJECT(msg->_mime_msg));
|
|
|
|
|
|
|
|
pdata._idx = 0;
|
|
|
|
pdata._func = func;
|
|
|
|
pdata._user_data = user_data;
|
|
|
|
|
|
|
|
g_mime_message_foreach (msg->_mime_msg,
|
|
|
|
(GMimeObjectForeachFunc)part_foreach_cb,
|
|
|
|
&pdata);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
struct _SavePartData {
|
|
|
|
guint idx, wanted_idx;
|
|
|
|
const gchar* targetdir;
|
|
|
|
gboolean overwrite;
|
|
|
|
gboolean stream;
|
2010-08-29 21:13:06 +02:00
|
|
|
guint cookie;
|
2010-08-24 23:57:16 +02:00
|
|
|
gboolean result;
|
|
|
|
};
|
|
|
|
typedef struct _SavePartData SavePartData;
|
|
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
save_part (GMimeObject *part, const char *filename,
|
|
|
|
const char *targetdir, gboolean overwrite)
|
|
|
|
{
|
|
|
|
int fd, rv;
|
|
|
|
GMimeDataWrapper *wrapper;
|
|
|
|
GMimeStream *stream;
|
|
|
|
|
|
|
|
rv = TRUE;
|
|
|
|
fd = mu_util_create_writeable_fd (filename, targetdir,
|
|
|
|
overwrite);
|
|
|
|
if (fd == -1) {
|
|
|
|
g_warning ("error saving file %s%s %s",
|
|
|
|
filename, errno != 0 ? ":" : "",
|
|
|
|
errno != 0 ? strerror(errno) : "");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
stream = g_mime_stream_fs_new (fd);
|
|
|
|
if (!stream) {
|
2010-08-29 21:13:06 +02:00
|
|
|
g_critical ("%s: failed to create stream", __FUNCTION__);
|
2010-08-24 23:57:16 +02:00
|
|
|
close (fd);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
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));
|
|
|
|
if (!wrapper) {
|
|
|
|
g_object_unref (G_OBJECT(stream));
|
2010-08-29 21:13:06 +02:00
|
|
|
g_critical ("%s: failed to create wrapper", __FUNCTION__);
|
2010-08-24 23:57:16 +02:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
rv = g_mime_data_wrapper_write_to_stream (wrapper, stream);
|
|
|
|
g_object_unref (G_OBJECT(stream));
|
|
|
|
|
|
|
|
return rv == -1 ? FALSE : TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
2010-08-29 21:13:06 +02:00
|
|
|
if (!GMIME_IS_PART(part)) /* ie., multiparts are ignored */
|
2010-08-24 23:57:16 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
filename = g_mime_part_get_filename (GMIME_PART(part));
|
|
|
|
if (filename) {
|
|
|
|
spd->result = save_part (part, filename,
|
|
|
|
spd->targetdir,
|
|
|
|
spd->overwrite);
|
2010-08-29 21:13:06 +02:00
|
|
|
} else { /* make up a filename */
|
|
|
|
gchar *my_filename;
|
|
|
|
my_filename = g_strdup_printf ("%x-part-%u",
|
|
|
|
spd->cookie,
|
|
|
|
spd->wanted_idx);
|
|
|
|
spd->result = save_part (part, my_filename,
|
|
|
|
spd->targetdir,
|
|
|
|
spd->overwrite);
|
|
|
|
g_free (my_filename);
|
|
|
|
}
|
2010-08-24 23:57:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
mu_msg_mime_part_save (MuMsg *msg, int wanted_idx,
|
|
|
|
const char *targetdir, gboolean overwrite)
|
|
|
|
{
|
|
|
|
SavePartData spd;
|
2010-08-29 21:13:06 +02:00
|
|
|
const char *msgid;
|
|
|
|
|
|
|
|
g_return_val_if_fail (msg, FALSE);
|
|
|
|
g_return_val_if_fail (wanted_idx >= 0, FALSE);
|
|
|
|
|
2010-08-24 23:57:16 +02:00
|
|
|
spd.idx = 0;
|
|
|
|
spd.wanted_idx = wanted_idx;
|
|
|
|
spd.targetdir = targetdir;
|
|
|
|
spd.overwrite = overwrite;
|
|
|
|
spd.stream = FALSE;
|
|
|
|
spd.result = FALSE;
|
2010-08-29 21:13:06 +02:00
|
|
|
|
|
|
|
/* get something fairly unique for building a filename;
|
|
|
|
* normally based on the message id, but if that is not
|
|
|
|
* available, a random number. basing it on the message id
|
|
|
|
* gives makes it easy to distinguish the parts of different
|
|
|
|
* messages */
|
|
|
|
msgid = mu_msg_get_msgid (msg);
|
|
|
|
spd.cookie = (guint)(msgid ? g_str_hash (msgid) : (guint)random());
|
|
|
|
|
2010-08-24 23:57:16 +02:00
|
|
|
g_mime_message_foreach (msg->_mime_msg,
|
|
|
|
(GMimeObjectForeachFunc)part_foreach_save_cb,
|
|
|
|
&spd);
|
|
|
|
return spd.result;
|
|
|
|
}
|
|
|
|
|