2011-05-21 13:12:01 +02:00
|
|
|
/* -*-mode: c; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-*/
|
2010-08-24 23:57:16 +02:00
|
|
|
/*
|
2013-03-30 10:32:07 +01:00
|
|
|
** Copyright (C) 2008-2013 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
|
2010-08-24 23:57:16 +02:00
|
|
|
**
|
|
|
|
** 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.
|
|
|
|
**
|
|
|
|
*/
|
|
|
|
|
2011-01-09 13:55:25 +01:00
|
|
|
#if HAVE_CONFIG_H
|
2010-08-24 23:57:16 +02:00
|
|
|
#include "config.h"
|
|
|
|
#endif /*HAVE_CONFIG_H*/
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
#include "mu-util.h"
|
2012-01-11 23:22:20 +01:00
|
|
|
#include "mu-str.h"
|
2010-08-24 23:57:16 +02:00
|
|
|
#include "mu-msg-priv.h"
|
|
|
|
#include "mu-msg-part.h"
|
|
|
|
|
2012-08-11 10:54:08 +02:00
|
|
|
static gboolean handle_children (MuMsg *msg,
|
|
|
|
GMimeMessage *mime_msg, MuMsgOptions opts,
|
|
|
|
unsigned index, MuMsgPartForeachFunc func,
|
2012-08-07 10:43:54 +02:00
|
|
|
gpointer user_data);
|
2012-08-01 09:45:03 +02:00
|
|
|
struct _DoData {
|
|
|
|
GMimeObject *mime_obj;
|
|
|
|
unsigned index;
|
2011-01-10 23:45:03 +01:00
|
|
|
};
|
2012-08-01 09:45:03 +02:00
|
|
|
typedef struct _DoData DoData;
|
2011-01-10 23:45:03 +01:00
|
|
|
|
2012-08-01 09:45:03 +02:00
|
|
|
static void
|
|
|
|
do_it_with_index (MuMsg *msg, MuMsgPart *part, DoData *ddata)
|
|
|
|
{
|
|
|
|
if (ddata->mime_obj)
|
|
|
|
return;
|
2011-01-10 23:45:03 +01:00
|
|
|
|
2012-08-01 09:45:03 +02:00
|
|
|
if (part->index == ddata->index)
|
|
|
|
ddata->mime_obj = (GMimeObject*)part->data;
|
|
|
|
}
|
|
|
|
|
|
|
|
static GMimeObject*
|
|
|
|
get_mime_object_at_index (MuMsg *msg, MuMsgOptions opts, unsigned index)
|
2012-02-13 21:35:22 +01:00
|
|
|
{
|
2012-08-01 09:45:03 +02:00
|
|
|
DoData ddata;
|
|
|
|
|
|
|
|
ddata.mime_obj = NULL;
|
|
|
|
ddata.index = index;
|
|
|
|
|
|
|
|
mu_msg_part_foreach (msg, opts,
|
|
|
|
(MuMsgPartForeachFunc)do_it_with_index,
|
|
|
|
&ddata);
|
|
|
|
|
|
|
|
return ddata.mime_obj;
|
2012-02-13 21:35:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-01 09:45:03 +02:00
|
|
|
typedef gboolean (*MuMsgPartMatchFunc) (MuMsgPart *, gpointer);
|
|
|
|
struct _MatchData {
|
|
|
|
MuMsgPartMatchFunc match_func;
|
|
|
|
gpointer user_data;
|
|
|
|
int index;
|
|
|
|
};
|
|
|
|
typedef struct _MatchData MatchData;
|
|
|
|
|
2011-01-10 23:45:03 +01:00
|
|
|
static void
|
2012-08-01 09:45:03 +02:00
|
|
|
check_match (MuMsg *msg, MuMsgPart *part, MatchData *mdata)
|
2011-01-10 23:45:03 +01:00
|
|
|
{
|
2012-08-01 09:45:03 +02:00
|
|
|
if (mdata->index != -1)
|
2012-02-13 21:35:22 +01:00
|
|
|
return;
|
|
|
|
|
2012-08-01 09:45:03 +02:00
|
|
|
if (mdata->match_func (part, mdata->user_data))
|
|
|
|
mdata->index = part->index;
|
2011-01-10 23:45:03 +01:00
|
|
|
}
|
|
|
|
|
2012-09-13 20:12:12 +02:00
|
|
|
static int
|
2012-08-01 09:45:03 +02:00
|
|
|
get_matching_part_index (MuMsg *msg, MuMsgOptions opts,
|
|
|
|
MuMsgPartMatchFunc func, gpointer user_data)
|
2011-01-10 23:45:03 +01:00
|
|
|
{
|
2012-08-01 09:45:03 +02:00
|
|
|
MatchData mdata;
|
2011-01-10 23:45:03 +01:00
|
|
|
|
2012-08-01 09:45:03 +02:00
|
|
|
mdata.match_func = func;
|
|
|
|
mdata.user_data = user_data;
|
|
|
|
mdata.index = -1;
|
2011-09-12 19:38:40 +02:00
|
|
|
|
2012-08-01 09:45:03 +02:00
|
|
|
mu_msg_part_foreach (msg, opts,
|
|
|
|
(MuMsgPartForeachFunc)check_match,
|
|
|
|
&mdata);
|
|
|
|
return mdata.index;
|
2011-01-10 23:45:03 +01:00
|
|
|
}
|
|
|
|
|
2012-07-24 21:12:22 +02:00
|
|
|
|
|
|
|
static void
|
2012-08-07 11:02:44 +02:00
|
|
|
accumulate_text_message (MuMsg *msg, MuMsgPart *part, GString **gstrp)
|
2012-07-24 21:12:22 +02:00
|
|
|
{
|
2012-08-07 11:02:44 +02:00
|
|
|
const gchar *str;
|
|
|
|
char *adrs;
|
|
|
|
GMimeMessage *mimemsg;
|
|
|
|
InternetAddressList *addresses;
|
|
|
|
|
|
|
|
/* put sender, recipients and subject in the string, so they
|
|
|
|
* can be indexed as well */
|
|
|
|
mimemsg = GMIME_MESSAGE (part->data);
|
|
|
|
str = g_mime_message_get_sender (mimemsg);
|
|
|
|
g_string_append_printf
|
|
|
|
(*gstrp, "%s%s", str ? str : "", str ? "\n" : "");
|
|
|
|
str = g_mime_message_get_subject (mimemsg);
|
|
|
|
g_string_append_printf
|
|
|
|
(*gstrp, "%s%s", str ? str : "", str ? "\n" : "");
|
2012-08-01 16:02:11 +02:00
|
|
|
addresses = g_mime_message_get_all_recipients (mimemsg);
|
|
|
|
adrs = internet_address_list_to_string (addresses, FALSE);
|
|
|
|
g_object_unref (addresses);
|
|
|
|
g_string_append_printf
|
|
|
|
(*gstrp, "%s%s", adrs ? adrs : "", adrs ? "\n" : "");
|
|
|
|
g_free (adrs);
|
2012-08-07 11:02:44 +02:00
|
|
|
}
|
2012-08-01 16:02:11 +02:00
|
|
|
|
2012-08-07 11:02:44 +02:00
|
|
|
static void
|
|
|
|
accumulate_text_part (MuMsg *msg, MuMsgPart *part, GString **gstrp)
|
|
|
|
{
|
|
|
|
GMimeContentType *ctype;
|
|
|
|
gboolean err;
|
|
|
|
char *txt;
|
|
|
|
ctype = g_mime_object_get_content_type ((GMimeObject*)part->data);
|
|
|
|
if (!g_mime_content_type_is_type (ctype, "text", "plain"))
|
|
|
|
return; /* not plain text */
|
|
|
|
txt = mu_msg_mime_part_to_string
|
|
|
|
((GMimePart*)part->data, &err);
|
|
|
|
if (txt)
|
|
|
|
g_string_append (*gstrp, txt);
|
|
|
|
g_free (txt);
|
2012-07-24 21:12:22 +02:00
|
|
|
}
|
|
|
|
|
2012-08-07 11:02:44 +02:00
|
|
|
static void
|
|
|
|
accumulate_text (MuMsg *msg, MuMsgPart *part, GString **gstrp)
|
|
|
|
{
|
|
|
|
if (GMIME_IS_MESSAGE(part->data))
|
|
|
|
accumulate_text_message (msg, part, gstrp);
|
|
|
|
else if (GMIME_IS_PART (part->data))
|
|
|
|
accumulate_text_part (msg, part, gstrp);
|
|
|
|
}
|
2012-07-24 21:12:22 +02:00
|
|
|
|
2012-09-14 09:06:14 +02:00
|
|
|
static char*
|
|
|
|
get_text_from_mime_msg (MuMsg *msg, GMimeMessage *mmsg, MuMsgOptions opts,
|
|
|
|
unsigned index)
|
|
|
|
{
|
|
|
|
GString *gstr;
|
|
|
|
|
|
|
|
gstr = g_string_sized_new (4096);
|
|
|
|
handle_children (msg, mmsg, opts, index,
|
|
|
|
(MuMsgPartForeachFunc)accumulate_text,
|
|
|
|
&gstr);
|
|
|
|
|
|
|
|
return g_string_free (gstr, FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-11-23 23:11:45 +01:00
|
|
|
char*
|
2012-08-22 23:00:28 +02:00
|
|
|
mu_msg_part_get_text (MuMsg *msg, MuMsgPart *self, MuMsgOptions opts)
|
2011-11-23 23:11:45 +01:00
|
|
|
{
|
2012-08-11 10:54:08 +02:00
|
|
|
GMimeObject *mobj;
|
|
|
|
GMimeMessage *mime_msg;
|
2012-08-22 23:00:28 +02:00
|
|
|
gboolean err;
|
2011-12-01 20:23:13 +01:00
|
|
|
|
2012-07-27 17:04:17 +02:00
|
|
|
g_return_val_if_fail (msg, NULL);
|
2013-04-17 23:12:37 +02:00
|
|
|
g_return_val_if_fail (self && GMIME_IS_OBJECT(self->data),
|
|
|
|
NULL);
|
2012-08-07 10:43:54 +02:00
|
|
|
|
2011-12-01 20:23:13 +01:00
|
|
|
mobj = (GMimeObject*)self->data;
|
|
|
|
|
2012-08-22 23:00:28 +02:00
|
|
|
err = FALSE;
|
2012-08-11 10:54:08 +02:00
|
|
|
if (GMIME_IS_PART (mobj)) {
|
|
|
|
if (self->part_type & MU_MSG_PART_TYPE_TEXT_PLAIN)
|
2012-09-13 20:12:12 +02:00
|
|
|
return mu_msg_mime_part_to_string ((GMimePart*)mobj,
|
|
|
|
&err);
|
2012-08-11 10:54:08 +02:00
|
|
|
else
|
|
|
|
return NULL; /* non-text MimePart */
|
|
|
|
}
|
|
|
|
|
|
|
|
mime_msg = NULL;
|
2012-09-14 09:06:14 +02:00
|
|
|
|
2012-08-11 10:54:08 +02:00
|
|
|
if (GMIME_IS_MESSAGE_PART (mobj))
|
|
|
|
mime_msg = g_mime_message_part_get_message
|
|
|
|
((GMimeMessagePart*)mobj);
|
|
|
|
else if (GMIME_IS_MESSAGE (mobj))
|
|
|
|
mime_msg = (GMimeMessage*)mobj;
|
2012-09-14 09:06:14 +02:00
|
|
|
|
2012-09-17 11:43:53 +02:00
|
|
|
/* apparently, g_mime_message_part_get_message may still
|
|
|
|
* return NULL */
|
|
|
|
if (mime_msg)
|
|
|
|
return get_text_from_mime_msg (msg, mime_msg,
|
|
|
|
opts, self->index);
|
|
|
|
return NULL;
|
2011-11-23 23:11:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-04-11 17:25:49 +02:00
|
|
|
/* note: this will return -1 in case of error or if the size is
|
|
|
|
* unknown */
|
2011-11-18 11:20:42 +01:00
|
|
|
static ssize_t
|
|
|
|
get_part_size (GMimePart *part)
|
|
|
|
{
|
|
|
|
GMimeDataWrapper *wrapper;
|
|
|
|
GMimeStream *stream;
|
|
|
|
|
|
|
|
wrapper = g_mime_part_get_content_object (part);
|
2012-08-01 09:45:03 +02:00
|
|
|
if (!GMIME_IS_DATA_WRAPPER(wrapper))
|
2011-11-18 11:20:42 +01:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
stream = g_mime_data_wrapper_get_stream (wrapper);
|
|
|
|
if (!stream)
|
2012-04-11 17:25:49 +02:00
|
|
|
return -1; /* no stream -> size is 0 */
|
|
|
|
else
|
|
|
|
return g_mime_stream_length (stream);
|
2011-11-18 11:20:42 +01:00
|
|
|
|
2012-08-01 09:45:03 +02:00
|
|
|
/* NOTE: stream/wrapper are owned by gmime, no unreffing */
|
2011-11-18 11:20:42 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-07 11:02:44 +02:00
|
|
|
static void
|
|
|
|
cleanup_filename (char *fname)
|
|
|
|
{
|
|
|
|
gchar *cur;
|
|
|
|
|
|
|
|
/* remove slashes, spaces, colons... */
|
|
|
|
for (cur = fname; *cur; ++cur)
|
|
|
|
if (*cur == '/' || *cur == ' ' || *cur == ':')
|
|
|
|
*cur = '-';
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-01 09:45:03 +02:00
|
|
|
static char*
|
|
|
|
mime_part_get_filename (GMimeObject *mobj, unsigned index,
|
|
|
|
gboolean construct_if_needed)
|
2012-07-24 21:12:22 +02:00
|
|
|
{
|
2012-08-07 11:02:44 +02:00
|
|
|
gchar *fname;
|
2012-07-24 21:12:22 +02:00
|
|
|
|
2012-08-01 22:22:50 +02:00
|
|
|
fname = NULL;
|
|
|
|
|
2012-08-01 09:45:03 +02:00
|
|
|
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;
|
2012-07-24 21:12:22 +02:00
|
|
|
|
2012-08-01 09:45:03 +02:00
|
|
|
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");
|
2012-07-24 21:12:22 +02:00
|
|
|
}
|
2012-07-27 17:04:17 +02:00
|
|
|
|
2012-08-01 09:45:03 +02:00
|
|
|
if (!fname)
|
|
|
|
fname = g_strdup_printf ("%u.part", index);
|
2012-07-27 17:04:17 +02:00
|
|
|
|
2012-08-01 09:45:03 +02:00
|
|
|
/* remove slashes, spaces, colons... */
|
2012-08-07 11:02:44 +02:00
|
|
|
cleanup_filename (fname);
|
2012-08-01 09:45:03 +02:00
|
|
|
return fname;
|
|
|
|
}
|
2012-07-27 17:04:17 +02:00
|
|
|
|
2012-01-15 13:10:04 +01:00
|
|
|
|
2012-08-01 09:45:03 +02:00
|
|
|
char*
|
|
|
|
mu_msg_part_get_filename (MuMsgPart *mpart, gboolean construct_if_needed)
|
2012-01-15 13:10:04 +01:00
|
|
|
{
|
2012-08-01 09:45:03 +02:00
|
|
|
g_return_val_if_fail (mpart, NULL);
|
|
|
|
g_return_val_if_fail (GMIME_IS_OBJECT(mpart->data), NULL);
|
2012-02-13 21:35:22 +01:00
|
|
|
|
2012-08-01 09:45:03 +02:00
|
|
|
return mime_part_get_filename ((GMimeObject*)mpart->data,
|
|
|
|
mpart->index, construct_if_needed);
|
|
|
|
}
|
2012-01-15 13:10:04 +01:00
|
|
|
|
|
|
|
|
2012-08-01 09:45:03 +02:00
|
|
|
static MuMsgPartType
|
|
|
|
get_disposition (GMimeObject *mobj)
|
|
|
|
{
|
|
|
|
const char *disp;
|
2012-01-15 13:10:04 +01:00
|
|
|
|
2012-08-01 09:45:03 +02:00
|
|
|
disp = g_mime_object_get_disposition (mobj);
|
|
|
|
if (!disp)
|
|
|
|
return MU_MSG_PART_TYPE_NONE;
|
2012-07-24 21:12:22 +02:00
|
|
|
|
2012-08-01 09:45:03 +02:00
|
|
|
if (strcasecmp (disp, GMIME_DISPOSITION_ATTACHMENT) == 0)
|
|
|
|
return MU_MSG_PART_TYPE_ATTACHMENT;
|
2012-02-13 21:35:22 +01:00
|
|
|
|
2012-08-01 09:45:03 +02:00
|
|
|
if (strcasecmp (disp, GMIME_DISPOSITION_INLINE) == 0)
|
|
|
|
return MU_MSG_PART_TYPE_INLINE;
|
2012-07-24 21:12:22 +02:00
|
|
|
|
2012-08-01 09:45:03 +02:00
|
|
|
return MU_MSG_PART_TYPE_NONE;
|
|
|
|
}
|
2012-02-13 21:35:22 +01:00
|
|
|
|
2012-09-14 11:17:40 +02:00
|
|
|
/* declaration, so we can use it in handle_encrypted_part */
|
|
|
|
static gboolean handle_mime_object (MuMsg *msg,
|
|
|
|
GMimeObject *mobj, GMimeObject *parent,
|
|
|
|
MuMsgOptions opts,
|
|
|
|
unsigned index, MuMsgPartForeachFunc func,
|
|
|
|
gpointer user_data);
|
|
|
|
|
2012-08-30 19:26:35 +02:00
|
|
|
#define SIG_STATUS_REPORT "sig-status-report"
|
2012-08-30 11:53:52 +02:00
|
|
|
|
2012-08-01 09:45:03 +02:00
|
|
|
/* call 'func' with information about this MIME-part */
|
|
|
|
static gboolean
|
2012-08-30 11:53:52 +02:00
|
|
|
check_signature (MuMsg *msg, GMimeMultipartSigned *part, MuMsgOptions opts)
|
2012-08-01 09:45:03 +02:00
|
|
|
{
|
2012-08-30 11:53:52 +02:00
|
|
|
/* the signature status */
|
2012-08-30 19:26:35 +02:00
|
|
|
MuMsgPartSigStatusReport *sigrep;
|
2012-08-30 11:53:52 +02:00
|
|
|
GError *err;
|
|
|
|
|
|
|
|
err = NULL;
|
2012-08-30 19:26:35 +02:00
|
|
|
sigrep = mu_msg_crypto_verify_part (part, opts, &err);
|
2012-08-30 11:53:52 +02:00
|
|
|
if (err) {
|
|
|
|
g_warning ("error verifying signature: %s", err->message);
|
|
|
|
g_clear_error (&err);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* tag this part with the signature status check */
|
2012-08-30 19:26:35 +02:00
|
|
|
g_object_set_data_full
|
|
|
|
(G_OBJECT(part), SIG_STATUS_REPORT,
|
|
|
|
sigrep,
|
|
|
|
(GDestroyNotify)mu_msg_part_sig_status_report_destroy);
|
2012-09-14 11:17:40 +02:00
|
|
|
|
2012-02-13 21:35:22 +01:00
|
|
|
return TRUE;
|
2012-01-15 13:10:04 +01:00
|
|
|
}
|
|
|
|
|
2012-09-13 21:57:04 +02:00
|
|
|
|
2012-09-14 11:17:40 +02:00
|
|
|
/* Note: this is function will be called by GMime when it needs a
|
|
|
|
* password. However, GMime <= 2.6.10 does not handle
|
|
|
|
* getting passwords correctly, so this might fail. see:
|
|
|
|
* password_requester in mu-msg-crypto.c */
|
2012-09-13 21:57:04 +02:00
|
|
|
static gchar*
|
|
|
|
get_console_pw (const char* user_id, const char *prompt_ctx,
|
|
|
|
gboolean reprompt, gpointer user_data)
|
|
|
|
{
|
|
|
|
char *prompt, *pass;
|
|
|
|
|
2012-09-14 11:17:40 +02:00
|
|
|
if (!g_mime_check_version(2,6,11))
|
|
|
|
g_printerr (
|
|
|
|
"*** the gmime library you are using has version "
|
|
|
|
"%u.%u.%u (<= 2.6.10)\n"
|
|
|
|
"*** this version has a bug in its password "
|
|
|
|
"retrieval routine, and probably won't work.\n",
|
|
|
|
gmime_major_version, gmime_minor_version,
|
|
|
|
gmime_micro_version);
|
|
|
|
|
2012-09-13 21:57:04 +02:00
|
|
|
if (reprompt)
|
|
|
|
g_print ("Authentication failed. Please try again\n");
|
|
|
|
|
|
|
|
prompt = g_strdup_printf ("Password for %s: ", user_id);
|
|
|
|
|
|
|
|
pass = mu_util_read_password (prompt);
|
|
|
|
g_free (prompt);
|
|
|
|
|
|
|
|
return pass;
|
|
|
|
}
|
|
|
|
|
2012-09-14 11:17:40 +02:00
|
|
|
|
2012-08-01 09:45:03 +02:00
|
|
|
static gboolean
|
|
|
|
handle_encrypted_part (MuMsg *msg,
|
|
|
|
GMimeMultipartEncrypted *part, GMimeObject *parent,
|
|
|
|
MuMsgOptions opts, unsigned index,
|
|
|
|
MuMsgPartForeachFunc func, gpointer user_data)
|
2012-02-13 21:35:22 +01:00
|
|
|
{
|
2012-09-12 11:12:24 +02:00
|
|
|
GError *err;
|
|
|
|
GMimeObject *dec;
|
2012-09-13 21:57:04 +02:00
|
|
|
MuMsgPartPasswordFunc pw_func;
|
|
|
|
|
|
|
|
if (opts & MU_MSG_OPTION_CONSOLE_PASSWORD)
|
|
|
|
pw_func = (MuMsgPartPasswordFunc)get_console_pw;
|
|
|
|
else
|
|
|
|
pw_func = NULL;
|
|
|
|
|
2012-09-12 11:12:24 +02:00
|
|
|
|
|
|
|
err = NULL;
|
2012-09-13 21:57:04 +02:00
|
|
|
dec = mu_msg_crypto_decrypt_part (part, opts, pw_func, NULL, &err);
|
2012-09-12 11:12:24 +02:00
|
|
|
if (err) {
|
|
|
|
g_warning ("error decrypting part: %s", err->message);
|
|
|
|
g_clear_error (&err);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dec) {
|
|
|
|
gboolean rv;
|
|
|
|
rv = handle_mime_object (msg, dec, parent, opts,
|
|
|
|
index + 1, func, user_data);
|
|
|
|
g_object_unref (dec);
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2012-08-01 09:45:03 +02:00
|
|
|
return TRUE;
|
|
|
|
}
|
2013-07-21 13:44:44 +02:00
|
|
|
|
2012-02-13 21:35:22 +01:00
|
|
|
|
2012-08-08 18:13:59 +02:00
|
|
|
|
2012-08-01 09:45:03 +02:00
|
|
|
/* 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)
|
|
|
|
{
|
|
|
|
GMimeContentType *ct;
|
|
|
|
MuMsgPart msgpart;
|
2012-02-13 21:35:22 +01:00
|
|
|
|
2012-08-01 09:45:03 +02:00
|
|
|
memset (&msgpart, 0, sizeof(MuMsgPart));
|
2012-02-13 21:35:22 +01:00
|
|
|
|
2012-08-09 08:38:22 +02:00
|
|
|
msgpart.size = get_part_size (part);
|
|
|
|
msgpart.part_type = MU_MSG_PART_TYPE_LEAF;
|
|
|
|
msgpart.part_type |= get_disposition ((GMimeObject*)part);
|
|
|
|
|
2012-08-01 09:45:03 +02:00
|
|
|
ct = g_mime_object_get_content_type ((GMimeObject*)part);
|
|
|
|
if (GMIME_IS_CONTENT_TYPE(ct)) {
|
|
|
|
msgpart.type = g_mime_content_type_get_media_type (ct);
|
|
|
|
msgpart.subtype = g_mime_content_type_get_media_subtype (ct);
|
2012-08-09 08:38:22 +02:00
|
|
|
/* store as in the part_type as well, for quick
|
|
|
|
* checking */
|
|
|
|
if (g_mime_content_type_is_type (ct, "text", "plain"))
|
|
|
|
msgpart.part_type |= MU_MSG_PART_TYPE_TEXT_PLAIN;
|
|
|
|
else if (g_mime_content_type_is_type (ct, "text", "html"))
|
|
|
|
msgpart.part_type |= MU_MSG_PART_TYPE_TEXT_HTML;
|
2012-02-13 21:35:22 +01:00
|
|
|
}
|
|
|
|
|
2012-09-01 19:03:48 +02:00
|
|
|
/* put the verification info in the pgp-signature part */
|
2012-08-30 19:26:35 +02:00
|
|
|
msgpart.sig_status_report = NULL;
|
2012-09-01 19:03:48 +02:00
|
|
|
if (g_ascii_strcasecmp (msgpart.subtype, "pgp-signature") == 0)
|
2012-08-30 19:26:35 +02:00
|
|
|
msgpart.sig_status_report =
|
|
|
|
(MuMsgPartSigStatusReport*)
|
|
|
|
g_object_get_data (G_OBJECT(parent), SIG_STATUS_REPORT);
|
|
|
|
|
2012-08-08 18:13:59 +02:00
|
|
|
msgpart.data = (gpointer)part;
|
|
|
|
msgpart.index = index;
|
2012-02-13 21:35:22 +01:00
|
|
|
|
2012-08-01 09:45:03 +02:00
|
|
|
func (msg, &msgpart, user_data);
|
2012-02-13 21:35:22 +01:00
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-01 09:45:03 +02:00
|
|
|
/* call 'func' with information about this MIME-part */
|
|
|
|
static gboolean
|
2012-09-17 11:43:53 +02:00
|
|
|
handle_message_part (MuMsg *msg, GMimeMessagePart *mimemsgpart, GMimeObject *parent,
|
2012-08-11 10:54:08 +02:00
|
|
|
MuMsgOptions opts, unsigned index,
|
|
|
|
MuMsgPartForeachFunc func, gpointer user_data)
|
2012-02-13 21:35:22 +01:00
|
|
|
{
|
2012-08-01 09:45:03 +02:00
|
|
|
MuMsgPart msgpart;
|
2012-09-17 11:43:53 +02:00
|
|
|
|
2012-08-01 09:45:03 +02:00
|
|
|
memset (&msgpart, 0, sizeof(MuMsgPart));
|
2012-02-13 21:35:22 +01:00
|
|
|
|
2012-08-01 09:45:03 +02:00
|
|
|
msgpart.type = "message";
|
|
|
|
msgpart.subtype = "rfc822";
|
|
|
|
msgpart.index = index;
|
2012-07-17 18:16:42 +02:00
|
|
|
|
2012-08-01 09:45:03 +02:00
|
|
|
/* msgpart.size = 0; /\* maybe calculate this? *\/ */
|
2012-02-13 21:35:22 +01:00
|
|
|
|
2012-08-01 09:45:03 +02:00
|
|
|
msgpart.part_type = MU_MSG_PART_TYPE_MESSAGE;
|
2012-09-17 11:43:53 +02:00
|
|
|
msgpart.part_type |= get_disposition ((GMimeObject*)mimemsgpart);
|
2011-11-23 23:11:45 +01:00
|
|
|
|
2012-09-17 11:43:53 +02:00
|
|
|
msgpart.data = (gpointer)mimemsgpart;
|
2012-08-01 09:45:03 +02:00
|
|
|
func (msg, &msgpart, user_data);
|
2012-07-24 21:12:22 +02:00
|
|
|
|
2012-09-17 11:43:53 +02:00
|
|
|
if (opts & MU_MSG_OPTION_RECURSE_RFC822) {
|
|
|
|
GMimeMessage *mmsg; /* this may return NULL for some messages */
|
|
|
|
mmsg = g_mime_message_part_get_message (mimemsgpart);
|
|
|
|
if (mmsg)
|
|
|
|
return handle_children
|
|
|
|
(msg, mmsg,
|
|
|
|
opts, index, func, user_data);
|
|
|
|
}
|
2012-08-11 10:54:08 +02:00
|
|
|
|
2012-08-01 09:45:03 +02:00
|
|
|
return TRUE;
|
|
|
|
}
|
2012-07-24 22:38:37 +02:00
|
|
|
|
|
|
|
|
2012-08-01 09:45:03 +02:00
|
|
|
static gboolean
|
|
|
|
handle_mime_object (MuMsg *msg,
|
|
|
|
GMimeObject *mobj, GMimeObject *parent, MuMsgOptions opts,
|
|
|
|
unsigned index, MuMsgPartForeachFunc func, gpointer user_data)
|
|
|
|
{
|
|
|
|
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);
|
2012-08-30 19:26:35 +02:00
|
|
|
else if ((opts & MU_MSG_OPTION_VERIFY) &&
|
|
|
|
GMIME_IS_MULTIPART_SIGNED (mobj))
|
2012-08-30 11:53:52 +02:00
|
|
|
return check_signature
|
|
|
|
(msg, GMIME_MULTIPART_SIGNED (mobj), opts);
|
2012-09-12 11:12:24 +02:00
|
|
|
else if ((opts & MU_MSG_OPTION_DECRYPT) &&
|
|
|
|
GMIME_IS_MULTIPART_ENCRYPTED (mobj))
|
2012-08-01 09:45:03 +02:00
|
|
|
return handle_encrypted_part
|
|
|
|
(msg, GMIME_MULTIPART_ENCRYPTED (mobj),
|
|
|
|
parent, opts, index, func, user_data);
|
|
|
|
return TRUE;
|
|
|
|
}
|
2012-07-24 22:38:37 +02:00
|
|
|
|
2012-08-11 10:54:08 +02:00
|
|
|
struct _ForeachData {
|
|
|
|
MuMsgPartForeachFunc func;
|
|
|
|
gpointer user_data;
|
|
|
|
MuMsg *msg;
|
|
|
|
unsigned index;
|
|
|
|
MuMsgOptions opts;
|
|
|
|
|
|
|
|
};
|
|
|
|
typedef struct _ForeachData ForeachData;
|
|
|
|
|
|
|
|
static void
|
|
|
|
each_child (GMimeObject *parent, GMimeObject *part,
|
|
|
|
ForeachData *fdata)
|
|
|
|
{
|
|
|
|
handle_mime_object (fdata->msg,
|
|
|
|
part,
|
|
|
|
parent,
|
|
|
|
fdata->opts,
|
|
|
|
fdata->index++,
|
|
|
|
fdata->func,
|
|
|
|
fdata->user_data);
|
|
|
|
}
|
|
|
|
|
2012-02-13 21:35:22 +01:00
|
|
|
|
2012-08-01 09:45:03 +02:00
|
|
|
static gboolean
|
|
|
|
handle_children (MuMsg *msg,
|
2012-08-11 10:54:08 +02:00
|
|
|
GMimeMessage *mime_msg, MuMsgOptions opts,
|
2012-08-01 09:45:03 +02:00
|
|
|
unsigned index, MuMsgPartForeachFunc func,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
2012-08-11 10:54:08 +02:00
|
|
|
ForeachData fdata;
|
2012-08-01 09:45:03 +02:00
|
|
|
|
2012-08-11 10:54:08 +02:00
|
|
|
fdata.func = func;
|
|
|
|
fdata.user_data = user_data;
|
|
|
|
fdata.opts = opts;
|
|
|
|
fdata.msg = msg;
|
|
|
|
fdata.index = 0;
|
2010-08-24 23:57:16 +02:00
|
|
|
|
2012-08-11 10:54:08 +02:00
|
|
|
g_mime_message_foreach (mime_msg, (GMimeObjectForeachFunc)each_child,
|
|
|
|
&fdata);
|
2011-11-23 23:11:45 +01:00
|
|
|
|
2012-08-11 10:54:08 +02:00
|
|
|
return TRUE;
|
2012-08-01 09:45:03 +02:00
|
|
|
}
|
|
|
|
|
2012-08-11 10:54:08 +02:00
|
|
|
|
2012-08-01 09:45:03 +02:00
|
|
|
gboolean
|
|
|
|
mu_msg_part_foreach (MuMsg *msg, MuMsgOptions opts,
|
|
|
|
MuMsgPartForeachFunc func, gpointer user_data)
|
2010-08-24 23:57:16 +02:00
|
|
|
{
|
2012-08-01 09:45:03 +02:00
|
|
|
g_return_val_if_fail (msg, FALSE);
|
2011-09-12 19:38:40 +02:00
|
|
|
|
2012-07-16 11:55:54 +02:00
|
|
|
if (!mu_msg_load_msg_file (msg, NULL))
|
2012-08-01 09:45:03 +02:00
|
|
|
return FALSE;
|
2011-11-23 23:11:45 +01:00
|
|
|
|
2012-09-17 11:43:53 +02:00
|
|
|
return handle_children (msg, msg->_file->_mime_msg,
|
|
|
|
opts, 0, func, user_data);
|
2010-08-24 23:57:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-07-22 18:39:17 +02:00
|
|
|
gboolean
|
2012-02-13 21:35:22 +01:00
|
|
|
write_part_to_fd (GMimePart *part, int fd, GError **err)
|
2010-08-24 23:57:16 +02:00
|
|
|
{
|
2011-05-21 13:12:01 +02:00
|
|
|
GMimeStream *stream;
|
|
|
|
GMimeDataWrapper *wrapper;
|
|
|
|
gboolean rv;
|
2011-09-12 19:38:40 +02:00
|
|
|
|
2011-05-21 13:12:01 +02:00
|
|
|
stream = g_mime_stream_fs_new (fd);
|
|
|
|
if (!GMIME_IS_STREAM(stream)) {
|
2012-04-01 12:08:02 +02:00
|
|
|
g_set_error (err, MU_ERROR_DOMAIN, MU_ERROR_GMIME,
|
2011-09-12 19:38:40 +02:00
|
|
|
"failed to create stream");
|
2011-05-21 13:12:01 +02:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
g_mime_stream_fs_set_owner (GMIME_STREAM_FS(stream), FALSE);
|
2011-09-12 19:38:40 +02:00
|
|
|
|
2012-02-13 21:35:22 +01:00
|
|
|
wrapper = g_mime_part_get_content_object (part);
|
2011-05-21 13:12:01 +02:00
|
|
|
if (!GMIME_IS_DATA_WRAPPER(wrapper)) {
|
2012-04-01 12:08:02 +02:00
|
|
|
g_set_error (err, MU_ERROR_DOMAIN, MU_ERROR_GMIME,
|
2011-09-12 19:38:40 +02:00
|
|
|
"failed to create wrapper");
|
2011-05-21 13:12:01 +02:00
|
|
|
g_object_unref (stream);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
g_object_ref (part); /* FIXME: otherwise, the unrefs below
|
|
|
|
* give errors...*/
|
2011-09-12 19:38:40 +02:00
|
|
|
|
2012-04-04 16:56:01 +02:00
|
|
|
if (g_mime_data_wrapper_write_to_stream (wrapper, stream) == -1) {
|
|
|
|
rv = FALSE;
|
2012-04-01 12:08:02 +02:00
|
|
|
g_set_error (err, MU_ERROR_DOMAIN, MU_ERROR_GMIME,
|
2011-09-12 19:38:40 +02:00
|
|
|
"failed to write to stream");
|
2012-04-04 16:56:01 +02:00
|
|
|
} else
|
|
|
|
rv = TRUE;
|
2011-09-12 19:38:40 +02:00
|
|
|
|
2013-04-16 23:07:05 +02:00
|
|
|
/* g_object_unref (wrapper); we don't own it */
|
2011-05-21 13:12:01 +02:00
|
|
|
g_object_unref (stream);
|
2011-09-12 19:38:40 +02:00
|
|
|
|
2011-05-21 13:12:01 +02:00
|
|
|
return rv;
|
2011-01-09 13:55:25 +01:00
|
|
|
}
|
|
|
|
|
2010-08-24 23:57:16 +02:00
|
|
|
|
2012-02-13 21:35:22 +01:00
|
|
|
|
|
|
|
static gboolean
|
|
|
|
write_object_to_fd (GMimeObject *obj, int fd, GError **err)
|
|
|
|
{
|
|
|
|
gchar *str;
|
|
|
|
str = g_mime_object_to_string (obj);
|
|
|
|
|
|
|
|
if (!str) {
|
2012-04-01 12:08:02 +02:00
|
|
|
g_set_error (err, MU_ERROR_DOMAIN, MU_ERROR_GMIME,
|
2012-02-13 21:35:22 +01:00
|
|
|
"could not get string from object");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (write (fd, str, strlen(str)) == -1) {
|
2012-04-01 12:08:02 +02:00
|
|
|
g_set_error (err, MU_ERROR_DOMAIN, MU_ERROR_GMIME,
|
2012-02-13 21:35:22 +01:00
|
|
|
"failed to write object: %s",
|
|
|
|
strerror(errno));
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-01 09:45:03 +02:00
|
|
|
static gboolean
|
|
|
|
save_object (GMimeObject *obj, MuMsgOptions opts, const char *fullpath,
|
|
|
|
GError **err)
|
2011-01-09 13:55:25 +01:00
|
|
|
{
|
2011-05-21 13:12:01 +02:00
|
|
|
int fd;
|
|
|
|
gboolean rv;
|
2012-08-01 09:45:03 +02:00
|
|
|
gboolean use_existing, overwrite;
|
|
|
|
|
|
|
|
use_existing = opts & MU_MSG_OPTION_USE_EXISTING;
|
|
|
|
overwrite = opts & MU_MSG_OPTION_OVERWRITE;
|
2011-09-12 19:38:40 +02:00
|
|
|
|
2011-05-21 13:12:01 +02:00
|
|
|
/* 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)
|
2011-01-10 23:45:03 +01:00
|
|
|
return TRUE;
|
2011-09-12 19:38:40 +02:00
|
|
|
|
2011-05-21 13:12:01 +02:00
|
|
|
/* ok, try to create the file */
|
|
|
|
fd = mu_util_create_writeable_fd (fullpath, 0600, overwrite);
|
|
|
|
if (fd == -1) {
|
2012-04-01 12:08:02 +02:00
|
|
|
g_set_error (err, MU_ERROR_DOMAIN, MU_ERROR_FILE,
|
2011-05-21 13:12:01 +02:00
|
|
|
"could not open '%s' for writing: %s",
|
|
|
|
fullpath, errno ? strerror(errno) : "error");
|
|
|
|
return FALSE;
|
2011-09-12 19:38:40 +02:00
|
|
|
}
|
2011-05-21 13:12:01 +02:00
|
|
|
|
2012-02-13 21:35:22 +01:00
|
|
|
if (GMIME_IS_PART (obj))
|
|
|
|
rv = write_part_to_fd ((GMimePart*)obj, fd, err);
|
|
|
|
else
|
|
|
|
rv = write_object_to_fd (obj, fd, err);
|
|
|
|
|
2011-09-12 19:38:40 +02:00
|
|
|
if (close (fd) != 0 && !err) { /* don't write on top of old err */
|
2012-04-01 12:08:02 +02:00
|
|
|
g_set_error (err, MU_ERROR_DOMAIN, MU_ERROR_FILE,
|
2011-05-21 13:12:01 +02:00
|
|
|
"could not close '%s': %s",
|
|
|
|
fullpath, errno ? strerror(errno) : "error");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2011-09-12 19:38:40 +02:00
|
|
|
return rv;
|
2011-01-10 23:45:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
gchar*
|
2012-08-01 09:45:03 +02:00
|
|
|
mu_msg_part_get_path (MuMsg *msg, MuMsgOptions opts,
|
|
|
|
const char* targetdir, unsigned index, GError **err)
|
2011-01-10 23:45:03 +01:00
|
|
|
{
|
2011-05-21 13:12:01 +02:00
|
|
|
char *fname, *filepath;
|
2012-02-13 21:35:22 +01:00
|
|
|
GMimeObject* mobj;
|
2011-05-21 13:12:01 +02:00
|
|
|
|
2012-08-01 09:45:03 +02:00
|
|
|
g_return_val_if_fail (msg, NULL);
|
2011-09-19 23:21:37 +02:00
|
|
|
|
2012-08-01 09:45:03 +02:00
|
|
|
if (!mu_msg_load_msg_file (msg, NULL))
|
2011-05-21 13:12:01 +02:00
|
|
|
return NULL;
|
2011-09-12 19:38:40 +02:00
|
|
|
|
2012-08-01 09:45:03 +02:00
|
|
|
mobj = get_mime_object_at_index (msg, opts, index);
|
|
|
|
if (!mobj){
|
2012-07-20 10:54:37 +02:00
|
|
|
mu_util_g_set_error (err, MU_ERROR_GMIME,
|
2012-08-01 09:45:03 +02:00
|
|
|
"cannot find part %u", index);
|
2012-02-13 21:35:22 +01:00
|
|
|
return NULL;
|
|
|
|
}
|
2011-05-21 13:12:01 +02:00
|
|
|
|
2012-08-01 09:45:03 +02:00
|
|
|
fname = mime_part_get_filename (mobj, index, TRUE);
|
2011-05-21 13:12:01 +02:00
|
|
|
filepath = g_build_path (G_DIR_SEPARATOR_S, targetdir ? targetdir : "",
|
|
|
|
fname, NULL);
|
|
|
|
g_free (fname);
|
|
|
|
|
|
|
|
return filepath;
|
2010-08-24 23:57:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-01-10 23:45:03 +01:00
|
|
|
|
|
|
|
gchar*
|
2012-08-01 09:45:03 +02:00
|
|
|
mu_msg_part_get_cache_path (MuMsg *msg, MuMsgOptions opts, guint partid,
|
|
|
|
GError **err)
|
2010-08-24 23:57:16 +02:00
|
|
|
{
|
2011-05-21 13:12:01 +02:00
|
|
|
char *dirname, *filepath;
|
|
|
|
const char* path;
|
2011-09-12 19:38:40 +02:00
|
|
|
|
2011-05-21 13:12:01 +02:00
|
|
|
g_return_val_if_fail (msg, NULL);
|
2011-09-12 19:38:40 +02:00
|
|
|
|
2012-07-16 11:55:54 +02:00
|
|
|
if (!mu_msg_load_msg_file (msg, NULL))
|
2011-09-19 23:21:37 +02:00
|
|
|
return NULL;
|
|
|
|
|
2011-05-21 13:12:01 +02:00
|
|
|
path = mu_msg_get_path (msg);
|
2011-01-10 23:45:03 +01:00
|
|
|
|
2011-05-21 13:12:01 +02:00
|
|
|
/* g_compute_checksum_for_string may be better, but requires
|
|
|
|
* rel. new glib (2.16) */
|
2011-01-10 23:45:03 +01:00
|
|
|
dirname = g_strdup_printf ("%s%c%x%c%u",
|
2011-05-21 13:12:01 +02:00
|
|
|
mu_util_cache_dir(), G_DIR_SEPARATOR,
|
|
|
|
g_str_hash (path), G_DIR_SEPARATOR,
|
|
|
|
partid);
|
2011-09-12 19:38:40 +02:00
|
|
|
|
2011-08-09 06:54:23 +02:00
|
|
|
if (!mu_util_create_dir_maybe (dirname, 0700, FALSE)) {
|
2012-08-09 08:38:22 +02:00
|
|
|
mu_util_g_set_error (err, MU_ERROR_FILE,
|
|
|
|
"failed to create dir %s", dirname);
|
2011-01-10 23:45:03 +01:00
|
|
|
g_free (dirname);
|
2011-05-21 13:12:01 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2012-08-01 09:45:03 +02:00
|
|
|
filepath = mu_msg_part_get_path (msg, opts, dirname, partid, err);
|
2011-05-21 13:12:01 +02:00
|
|
|
g_free (dirname);
|
2011-09-12 19:38:40 +02:00
|
|
|
|
2011-05-21 13:12:01 +02:00
|
|
|
return filepath;
|
2010-08-24 23:57:16 +02:00
|
|
|
}
|
|
|
|
|
2011-01-10 23:45:03 +01:00
|
|
|
|
2010-08-24 23:57:16 +02:00
|
|
|
gboolean
|
2012-08-01 09:45:03 +02:00
|
|
|
mu_msg_part_save (MuMsg *msg, MuMsgOptions opts,
|
|
|
|
const char *fullpath, guint partidx, GError **err)
|
2010-08-24 23:57:16 +02:00
|
|
|
{
|
2011-05-21 13:12:01 +02:00
|
|
|
GMimeObject *part;
|
2011-09-12 19:38:40 +02:00
|
|
|
|
2011-05-21 13:12:01 +02:00
|
|
|
g_return_val_if_fail (msg, FALSE);
|
|
|
|
g_return_val_if_fail (fullpath, FALSE);
|
2012-08-01 09:45:03 +02:00
|
|
|
g_return_val_if_fail (!((opts & MU_MSG_OPTION_OVERWRITE) &&
|
|
|
|
(opts & MU_MSG_OPTION_USE_EXISTING)), FALSE);
|
2011-09-12 19:38:40 +02:00
|
|
|
|
2012-07-17 18:16:42 +02:00
|
|
|
if (!mu_msg_load_msg_file (msg, err))
|
2011-09-19 23:21:37 +02:00
|
|
|
return FALSE;
|
|
|
|
|
2012-08-01 09:45:03 +02:00
|
|
|
part = get_mime_object_at_index (msg, opts, partidx);
|
2012-09-21 11:35:53 +02:00
|
|
|
|
|
|
|
/* special case: convert a message-part into a message */
|
|
|
|
if (GMIME_IS_MESSAGE_PART (part))
|
|
|
|
part = (GMimeObject*)g_mime_message_part_get_message
|
|
|
|
(GMIME_MESSAGE_PART (part));
|
|
|
|
|
|
|
|
if (!GMIME_IS_PART(part) && !GMIME_IS_MESSAGE(part)) {
|
2012-04-01 12:08:02 +02:00
|
|
|
g_set_error (err, MU_ERROR_DOMAIN, MU_ERROR_GMIME,
|
2012-02-13 21:35:22 +01:00
|
|
|
"unexpected type %s for part %u",
|
|
|
|
G_OBJECT_TYPE_NAME((GObject*)part),
|
|
|
|
partidx);
|
2011-05-21 13:12:01 +02:00
|
|
|
return FALSE;
|
2012-08-01 09:45:03 +02:00
|
|
|
}
|
2011-01-10 23:45:03 +01:00
|
|
|
|
2012-09-21 11:35:53 +02:00
|
|
|
|
2012-08-01 09:45:03 +02:00
|
|
|
return save_object (part, opts, fullpath, err);
|
2011-01-10 23:45:03 +01:00
|
|
|
}
|
|
|
|
|
2012-01-15 13:10:04 +01:00
|
|
|
|
|
|
|
gchar*
|
2012-08-01 09:45:03 +02:00
|
|
|
mu_msg_part_save_temp (MuMsg *msg, MuMsgOptions opts, guint partidx, GError **err)
|
2012-01-15 13:10:04 +01:00
|
|
|
{
|
|
|
|
gchar *filepath;
|
|
|
|
|
2012-08-01 09:45:03 +02:00
|
|
|
filepath = mu_msg_part_get_cache_path (msg, opts, partidx, err);
|
|
|
|
if (!filepath)
|
2012-01-15 13:10:04 +01:00
|
|
|
return NULL;
|
|
|
|
|
2012-08-01 09:45:03 +02:00
|
|
|
if (!mu_msg_part_save (msg, opts, filepath, partidx, err)) {
|
2012-01-15 13:10:04 +01:00
|
|
|
g_free (filepath);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return filepath;
|
|
|
|
}
|
|
|
|
|
2012-08-01 09:45:03 +02:00
|
|
|
static gboolean
|
|
|
|
match_cid (MuMsgPart *mpart, const char *cid)
|
2011-01-10 23:45:03 +01:00
|
|
|
{
|
2012-08-01 09:45:03 +02:00
|
|
|
const char *this_cid;
|
2010-08-24 23:57:16 +02:00
|
|
|
|
2012-08-01 09:45:03 +02:00
|
|
|
this_cid = g_mime_object_get_content_id ((GMimeObject*)mpart->data);
|
2011-01-10 23:45:03 +01:00
|
|
|
|
2012-08-01 09:45:03 +02:00
|
|
|
return g_strcmp0 (this_cid, cid) ? TRUE : FALSE;
|
2011-01-10 23:45:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2012-08-01 09:45:03 +02:00
|
|
|
mu_msg_find_index_for_cid (MuMsg *msg, MuMsgOptions opts, const char *sought_cid)
|
2011-01-10 23:45:03 +01:00
|
|
|
{
|
2011-05-21 13:12:01 +02:00
|
|
|
const char* cid;
|
2011-09-12 19:38:40 +02:00
|
|
|
|
2011-05-22 12:42:19 +02:00
|
|
|
g_return_val_if_fail (msg, -1);
|
2011-05-21 13:12:01 +02:00
|
|
|
g_return_val_if_fail (sought_cid, -1);
|
2011-09-12 19:38:40 +02:00
|
|
|
|
2012-07-16 11:55:54 +02:00
|
|
|
if (!mu_msg_load_msg_file (msg, NULL))
|
2011-09-19 23:21:37 +02:00
|
|
|
return -1;
|
|
|
|
|
2011-05-21 13:12:01 +02:00
|
|
|
cid = g_str_has_prefix (sought_cid, "cid:") ?
|
2011-09-12 19:38:40 +02:00
|
|
|
sought_cid + 4 : sought_cid;
|
|
|
|
|
2012-08-01 09:45:03 +02:00
|
|
|
return get_matching_part_index (msg, opts,
|
|
|
|
(MuMsgPartMatchFunc)match_cid,
|
|
|
|
(gpointer)(char*)cid);
|
2011-01-10 23:45:03 +01:00
|
|
|
}
|
|
|
|
|
2012-08-01 09:45:03 +02:00
|
|
|
struct _RxMatchData {
|
|
|
|
GSList *_lst;
|
2011-05-22 12:42:19 +02:00
|
|
|
const GRegex *_rx;
|
|
|
|
guint _idx;
|
|
|
|
};
|
2012-08-01 09:45:03 +02:00
|
|
|
typedef struct _RxMatchData RxMatchData;
|
2011-01-10 23:45:03 +01:00
|
|
|
|
2011-05-22 12:42:19 +02:00
|
|
|
|
|
|
|
static void
|
2012-08-01 09:45:03 +02:00
|
|
|
match_filename_rx (MuMsg *msg, MuMsgPart *mpart, RxMatchData *mdata)
|
2011-05-21 13:12:01 +02:00
|
|
|
{
|
2012-08-01 09:45:03 +02:00
|
|
|
char *fname;
|
2011-09-12 19:38:40 +02:00
|
|
|
|
2012-08-01 09:45:03 +02:00
|
|
|
fname = mu_msg_part_get_filename (mpart, FALSE);
|
|
|
|
if (!fname)
|
2012-02-13 21:35:22 +01:00
|
|
|
return;
|
2011-09-12 19:38:40 +02:00
|
|
|
|
2011-05-22 12:42:19 +02:00
|
|
|
if (g_regex_match (mdata->_rx, fname, 0, NULL))
|
|
|
|
mdata->_lst = g_slist_prepend (mdata->_lst,
|
2012-08-01 09:45:03 +02:00
|
|
|
GUINT_TO_POINTER(mpart->index));
|
|
|
|
g_free (fname);
|
2011-05-21 13:12:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-05-22 12:42:19 +02:00
|
|
|
GSList*
|
2012-08-01 09:45:03 +02:00
|
|
|
mu_msg_find_files (MuMsg *msg, MuMsgOptions opts, const GRegex *pattern)
|
2011-05-21 13:12:01 +02:00
|
|
|
{
|
2012-08-01 09:45:03 +02:00
|
|
|
RxMatchData mdata;
|
2011-09-12 19:38:40 +02:00
|
|
|
|
2011-05-22 12:42:19 +02:00
|
|
|
g_return_val_if_fail (msg, NULL);
|
|
|
|
g_return_val_if_fail (pattern, NULL);
|
|
|
|
|
2012-07-16 11:55:54 +02:00
|
|
|
if (!mu_msg_load_msg_file (msg, NULL))
|
2011-09-19 23:21:37 +02:00
|
|
|
return NULL;
|
|
|
|
|
2011-05-22 12:42:19 +02:00
|
|
|
mdata._lst = NULL;
|
|
|
|
mdata._rx = pattern;
|
|
|
|
mdata._idx = 0;
|
2011-09-12 19:38:40 +02:00
|
|
|
|
2012-08-01 09:45:03 +02:00
|
|
|
mu_msg_part_foreach (msg, opts,
|
|
|
|
(MuMsgPartForeachFunc)match_filename_rx,
|
|
|
|
&mdata);
|
2011-05-22 12:42:19 +02:00
|
|
|
return mdata._lst;
|
2011-05-21 13:12:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-01-11 22:17:03 +01:00
|
|
|
gboolean
|
2012-08-09 10:45:04 +02:00
|
|
|
mu_msg_part_maybe_attachment (MuMsgPart *part)
|
2011-01-11 22:17:03 +01:00
|
|
|
{
|
2011-05-21 13:12:01 +02:00
|
|
|
g_return_val_if_fail (part, FALSE);
|
2011-01-11 22:17:03 +01:00
|
|
|
|
2012-08-09 10:45:04 +02:00
|
|
|
/* attachments must be leaf parts */
|
2012-09-25 14:20:26 +02:00
|
|
|
if (!(part->part_type & MU_MSG_PART_TYPE_LEAF))
|
2011-05-21 13:12:01 +02:00
|
|
|
return FALSE;
|
2011-01-11 22:17:03 +01:00
|
|
|
|
2012-09-27 16:31:49 +02:00
|
|
|
/* parts other than text/plain, text/html are considered
|
|
|
|
* attachments as well */
|
|
|
|
if (!(part->part_type & MU_MSG_PART_TYPE_TEXT_PLAIN) &&
|
|
|
|
!(part->part_type & MU_MSG_PART_TYPE_TEXT_HTML))
|
|
|
|
return TRUE;
|
2012-08-09 10:45:04 +02:00
|
|
|
|
2012-09-25 14:20:26 +02:00
|
|
|
return part->part_type & MU_MSG_PART_TYPE_ATTACHMENT ? TRUE : FALSE;
|
2011-01-11 22:17:03 +01:00
|
|
|
}
|