2020-06-10 08:07:14 +02:00
|
|
|
/*
|
|
|
|
** Copyright (C) 2008-2020 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
|
2009-11-25 21:55:06 +01: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 of the License, or
|
|
|
|
** (at your option) any later version.
|
2011-08-29 22:38:55 +02:00
|
|
|
**
|
2009-11-25 21:55:06 +01:00
|
|
|
** 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.
|
2011-08-29 22:38:55 +02:00
|
|
|
**
|
2009-11-25 21:55:06 +01:00
|
|
|
** You should have received a copy of the GNU General Public License
|
|
|
|
** along with this program; if not, write to the Free Software Foundation,
|
2011-08-29 22:38:55 +02:00
|
|
|
** Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
**
|
2009-11-25 21:55:06 +01:00
|
|
|
*/
|
|
|
|
|
2022-02-19 17:57:50 +01:00
|
|
|
#include <functional>
|
2009-11-25 21:55:06 +01:00
|
|
|
#include <string.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
|
2011-01-06 12:15:01 +01:00
|
|
|
#include <gmime/gmime.h>
|
2022-02-19 17:57:50 +01:00
|
|
|
#include <vector>
|
|
|
|
#include <array>
|
2011-01-06 12:15:01 +01:00
|
|
|
|
2022-02-19 17:57:50 +01:00
|
|
|
|
|
|
|
#include "gmime/gmime-message.h"
|
2020-11-28 09:15:49 +01:00
|
|
|
#include "mu-msg-priv.hh" /* include before mu-msg.h */
|
|
|
|
#include "mu-msg.hh"
|
2019-12-16 20:44:35 +01:00
|
|
|
#include "utils/mu-str.h"
|
2009-11-25 21:55:06 +01:00
|
|
|
|
2020-11-28 09:15:49 +01:00
|
|
|
#include "mu-maildir.hh"
|
|
|
|
|
|
|
|
using namespace Mu;
|
2011-05-15 10:06:55 +02:00
|
|
|
|
2011-08-20 10:55:27 +02:00
|
|
|
/* note, we do the gmime initialization here rather than in
|
|
|
|
* mu-runtime, because this way we don't need mu-runtime for simple
|
|
|
|
* cases -- such as our unit tests. Also note that we need gmime init
|
|
|
|
* even for the doc backend, as we use the address parsing functions
|
|
|
|
* also there. */
|
|
|
|
static gboolean _gmime_initialized = FALSE;
|
|
|
|
|
|
|
|
static void
|
2021-10-20 11:18:15 +02:00
|
|
|
gmime_init(void)
|
2011-08-20 10:55:27 +02:00
|
|
|
{
|
2021-10-20 11:18:15 +02:00
|
|
|
g_return_if_fail(!_gmime_initialized);
|
2011-08-29 22:38:55 +02:00
|
|
|
|
2017-07-30 16:47:38 +02:00
|
|
|
g_mime_init();
|
2011-08-20 10:55:27 +02:00
|
|
|
_gmime_initialized = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2021-10-20 11:18:15 +02:00
|
|
|
gmime_uninit(void)
|
2011-08-20 10:55:27 +02:00
|
|
|
{
|
2021-10-20 11:18:15 +02:00
|
|
|
g_return_if_fail(_gmime_initialized);
|
2011-08-29 22:38:55 +02:00
|
|
|
|
2011-08-20 10:55:27 +02:00
|
|
|
g_mime_shutdown();
|
|
|
|
_gmime_initialized = FALSE;
|
|
|
|
}
|
|
|
|
|
2011-05-15 10:06:55 +02:00
|
|
|
static MuMsg*
|
2021-10-20 11:18:15 +02:00
|
|
|
msg_new(void)
|
2011-05-15 10:06:55 +02:00
|
|
|
{
|
2021-10-20 11:18:15 +02:00
|
|
|
MuMsg* self;
|
2011-08-29 22:38:55 +02:00
|
|
|
|
2021-10-20 11:18:15 +02:00
|
|
|
self = g_new0(MuMsg, 1);
|
2011-05-19 18:57:26 +02:00
|
|
|
self->_refcount = 1;
|
2011-09-18 13:42:55 +02:00
|
|
|
|
2011-05-19 18:57:26 +02:00
|
|
|
return self;
|
2011-05-15 10:06:55 +02:00
|
|
|
}
|
|
|
|
|
2011-05-09 01:58:33 +02:00
|
|
|
MuMsg*
|
2021-10-20 11:18:15 +02:00
|
|
|
Mu::mu_msg_new_from_file(const char* path, const char* mdir, GError** err)
|
2009-11-25 21:55:06 +01:00
|
|
|
{
|
2021-10-20 11:18:15 +02:00
|
|
|
MuMsg* self;
|
|
|
|
MuMsgFile* msgfile;
|
|
|
|
gint64 start;
|
2011-08-29 22:38:55 +02:00
|
|
|
|
2021-10-20 11:18:15 +02:00
|
|
|
g_return_val_if_fail(path, NULL);
|
2011-08-29 22:38:55 +02:00
|
|
|
|
2021-10-20 11:18:15 +02:00
|
|
|
start = g_get_monotonic_time();
|
2020-06-26 18:26:45 +02:00
|
|
|
|
2011-08-29 22:38:55 +02:00
|
|
|
if (G_UNLIKELY(!_gmime_initialized)) {
|
2021-10-20 11:18:15 +02:00
|
|
|
gmime_init();
|
|
|
|
atexit(gmime_uninit);
|
2011-08-29 22:38:55 +02:00
|
|
|
}
|
|
|
|
|
2021-10-20 11:18:15 +02:00
|
|
|
msgfile = mu_msg_file_new(path, mdir, err);
|
2011-08-29 22:38:55 +02:00
|
|
|
if (!msgfile)
|
2011-05-19 18:57:26 +02:00
|
|
|
return NULL;
|
2011-08-29 22:38:55 +02:00
|
|
|
|
2021-10-20 11:18:15 +02:00
|
|
|
self = msg_new();
|
2011-06-18 17:48:59 +02:00
|
|
|
self->_file = msgfile;
|
2011-08-29 22:38:55 +02:00
|
|
|
|
2021-10-20 11:18:15 +02:00
|
|
|
g_debug("created message from %s in %" G_GINT64_FORMAT " μs",
|
2022-03-03 23:04:30 +01:00
|
|
|
path,
|
|
|
|
g_get_monotonic_time() - start);
|
2020-06-26 18:26:45 +02:00
|
|
|
|
2011-05-19 18:57:26 +02:00
|
|
|
return self;
|
2009-11-25 21:55:06 +01:00
|
|
|
}
|
|
|
|
|
2011-05-15 10:06:55 +02:00
|
|
|
MuMsg*
|
2021-10-20 11:18:15 +02:00
|
|
|
Mu::mu_msg_new_from_doc(XapianDocument* doc, GError** err)
|
2011-05-15 10:06:55 +02:00
|
|
|
{
|
2021-10-20 11:18:15 +02:00
|
|
|
MuMsg* self;
|
|
|
|
MuMsgDoc* msgdoc;
|
2011-08-29 22:38:55 +02:00
|
|
|
|
2021-10-20 11:18:15 +02:00
|
|
|
g_return_val_if_fail(doc, NULL);
|
2011-08-29 22:38:55 +02:00
|
|
|
|
|
|
|
if (G_UNLIKELY(!_gmime_initialized)) {
|
2021-10-20 11:18:15 +02:00
|
|
|
gmime_init();
|
|
|
|
atexit(gmime_uninit);
|
2011-08-29 22:38:55 +02:00
|
|
|
}
|
|
|
|
|
2021-10-20 11:18:15 +02:00
|
|
|
msgdoc = mu_msg_doc_new(doc, err);
|
2011-05-19 18:57:26 +02:00
|
|
|
if (!msgdoc)
|
|
|
|
return NULL;
|
2011-05-15 10:06:55 +02:00
|
|
|
|
2021-10-20 11:18:15 +02:00
|
|
|
self = msg_new();
|
2011-06-18 17:48:59 +02:00
|
|
|
self->_doc = msgdoc;
|
2011-08-29 22:38:55 +02:00
|
|
|
|
2011-05-19 18:57:26 +02:00
|
|
|
return self;
|
2011-05-15 10:06:55 +02:00
|
|
|
}
|
|
|
|
|
2011-08-29 22:38:55 +02:00
|
|
|
static void
|
2021-10-20 11:18:15 +02:00
|
|
|
mu_msg_destroy(MuMsg* self)
|
2009-11-25 21:55:06 +01:00
|
|
|
{
|
2011-05-19 18:57:26 +02:00
|
|
|
if (!self)
|
|
|
|
return;
|
2010-11-27 13:55:25 +01:00
|
|
|
|
2021-10-20 11:18:15 +02:00
|
|
|
mu_msg_file_destroy(self->_file);
|
|
|
|
mu_msg_doc_destroy(self->_doc);
|
2011-05-15 10:06:55 +02:00
|
|
|
|
2012-08-08 18:13:59 +02:00
|
|
|
{ /* cleanup the strings / lists we stored */
|
2021-10-20 11:18:15 +02:00
|
|
|
mu_str_free_list(self->_free_later_str);
|
2021-01-20 10:18:33 +01:00
|
|
|
for (auto cur = self->_free_later_lst; cur; cur = g_slist_next(cur))
|
|
|
|
g_slist_free_full((GSList*)cur->data, g_free);
|
2021-10-20 11:18:15 +02:00
|
|
|
g_slist_free(self->_free_later_lst);
|
2012-08-08 18:13:59 +02:00
|
|
|
}
|
2011-08-29 22:38:55 +02:00
|
|
|
|
2021-10-20 11:18:15 +02:00
|
|
|
g_free(self);
|
2009-11-25 21:55:06 +01:00
|
|
|
}
|
|
|
|
|
2011-01-09 17:54:14 +01:00
|
|
|
MuMsg*
|
2021-10-20 11:18:15 +02:00
|
|
|
Mu::mu_msg_ref(MuMsg* self)
|
2011-01-09 17:54:14 +01:00
|
|
|
{
|
2021-10-20 11:18:15 +02:00
|
|
|
g_return_val_if_fail(self, NULL);
|
2011-03-15 19:38:26 +01:00
|
|
|
|
2011-05-19 18:57:26 +02:00
|
|
|
++self->_refcount;
|
2011-08-29 22:38:55 +02:00
|
|
|
|
2011-05-19 18:57:26 +02:00
|
|
|
return self;
|
2011-01-09 17:54:14 +01:00
|
|
|
}
|
|
|
|
|
2011-05-09 01:58:33 +02:00
|
|
|
void
|
2021-10-20 11:18:15 +02:00
|
|
|
Mu::mu_msg_unref(MuMsg* self)
|
2009-11-25 21:55:06 +01:00
|
|
|
{
|
2021-10-20 11:18:15 +02:00
|
|
|
g_return_if_fail(self);
|
|
|
|
g_return_if_fail(self->_refcount >= 1);
|
2011-08-29 22:38:55 +02:00
|
|
|
|
|
|
|
if (--self->_refcount == 0)
|
2021-10-20 11:18:15 +02:00
|
|
|
mu_msg_destroy(self);
|
2011-05-14 17:07:51 +02:00
|
|
|
}
|
|
|
|
|
2012-08-08 18:13:59 +02:00
|
|
|
static const gchar*
|
2021-10-20 11:18:15 +02:00
|
|
|
free_later_str(MuMsg* self, gchar* str)
|
2012-08-08 18:13:59 +02:00
|
|
|
{
|
|
|
|
if (str)
|
2021-10-20 11:18:15 +02:00
|
|
|
self->_free_later_str = g_slist_prepend(self->_free_later_str, str);
|
2012-08-08 18:13:59 +02:00
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const GSList*
|
2021-10-20 11:18:15 +02:00
|
|
|
free_later_lst(MuMsg* self, GSList* lst)
|
2012-08-08 18:13:59 +02:00
|
|
|
{
|
|
|
|
if (lst)
|
2021-10-20 11:18:15 +02:00
|
|
|
self->_free_later_lst = g_slist_prepend(self->_free_later_lst, lst);
|
2012-08-08 18:13:59 +02:00
|
|
|
return lst;
|
|
|
|
}
|
|
|
|
|
2011-05-17 22:20:05 +02:00
|
|
|
/* use this instead of mu_msg_get_path so we don't get into infinite
|
|
|
|
* regress...*/
|
|
|
|
static const char*
|
2021-10-20 11:18:15 +02:00
|
|
|
get_path(MuMsg* self)
|
2011-05-17 22:20:05 +02:00
|
|
|
{
|
2021-10-20 11:18:15 +02:00
|
|
|
char* val;
|
|
|
|
gboolean do_free;
|
2011-08-29 22:38:55 +02:00
|
|
|
|
2012-08-08 18:13:59 +02:00
|
|
|
do_free = TRUE;
|
|
|
|
val = NULL;
|
2011-05-19 18:57:26 +02:00
|
|
|
|
|
|
|
if (self->_doc)
|
2022-03-03 23:04:30 +01:00
|
|
|
val = mu_msg_doc_get_str_field(self->_doc, Field::Id::Path);
|
2011-08-29 22:38:55 +02:00
|
|
|
|
2011-05-19 18:57:26 +02:00
|
|
|
/* not in the cache yet? try to get it from the file backend,
|
|
|
|
* in case we are using that */
|
|
|
|
if (!val && self->_file)
|
2022-03-03 23:04:30 +01:00
|
|
|
val = mu_msg_file_get_str_field(self->_file, Field::Id::Path, &do_free);
|
2011-08-29 22:38:55 +02:00
|
|
|
|
2012-08-08 18:13:59 +02:00
|
|
|
/* shouldn't happen */
|
|
|
|
if (!val)
|
2021-10-20 11:18:15 +02:00
|
|
|
g_warning("%s: message without path?!", __func__);
|
2011-05-17 22:20:05 +02:00
|
|
|
|
2021-10-20 11:18:15 +02:00
|
|
|
return free_later_str(self, val);
|
2011-05-17 22:20:05 +02:00
|
|
|
}
|
|
|
|
|
2011-05-14 17:07:51 +02:00
|
|
|
/* for some data, we need to read the message file from disk */
|
2012-07-16 11:55:54 +02:00
|
|
|
gboolean
|
2021-10-20 11:18:15 +02:00
|
|
|
Mu::mu_msg_load_msg_file(MuMsg* self, GError** err)
|
2011-05-14 17:07:51 +02:00
|
|
|
{
|
2021-10-20 11:18:15 +02:00
|
|
|
const char* path;
|
2011-05-14 17:07:51 +02:00
|
|
|
|
2021-10-20 11:18:15 +02:00
|
|
|
g_return_val_if_fail(self, FALSE);
|
2011-08-29 22:38:55 +02:00
|
|
|
|
2012-07-16 11:55:54 +02:00
|
|
|
if (self->_file)
|
|
|
|
return TRUE; /* nothing to do */
|
|
|
|
|
2021-10-20 11:18:15 +02:00
|
|
|
if (!(path = get_path(self))) {
|
|
|
|
mu_util_g_set_error(err, MU_ERROR_INTERNAL, "cannot get path for message");
|
2012-07-16 11:55:54 +02:00
|
|
|
return FALSE;
|
2011-05-19 18:57:26 +02:00
|
|
|
}
|
2011-08-29 22:38:55 +02:00
|
|
|
|
2021-10-20 11:18:15 +02:00
|
|
|
self->_file = mu_msg_file_new(path, NULL, err);
|
2012-07-16 11:55:54 +02:00
|
|
|
|
2021-10-20 11:18:15 +02:00
|
|
|
return (self->_file != NULL);
|
2011-05-14 17:07:51 +02:00
|
|
|
}
|
|
|
|
|
2012-07-16 11:55:54 +02:00
|
|
|
void
|
2021-10-20 11:18:15 +02:00
|
|
|
Mu::mu_msg_unload_msg_file(MuMsg* msg)
|
2012-07-16 11:55:54 +02:00
|
|
|
{
|
2021-10-20 11:18:15 +02:00
|
|
|
g_return_if_fail(msg);
|
2012-07-16 11:55:54 +02:00
|
|
|
|
2021-10-20 11:18:15 +02:00
|
|
|
mu_msg_file_destroy(msg->_file);
|
2012-07-16 11:55:54 +02:00
|
|
|
msg->_file = NULL;
|
|
|
|
}
|
|
|
|
|
2011-06-15 22:51:16 +02:00
|
|
|
static const GSList*
|
2022-03-03 23:04:30 +01:00
|
|
|
get_str_list_field(MuMsg* self, Field::Id field_id)
|
2011-06-15 22:51:16 +02:00
|
|
|
{
|
2021-10-20 11:18:15 +02:00
|
|
|
GSList* val;
|
2011-06-15 22:51:16 +02:00
|
|
|
|
|
|
|
val = NULL;
|
2012-08-08 18:13:59 +02:00
|
|
|
|
2022-03-03 23:04:30 +01:00
|
|
|
if (self->_doc &&
|
2022-03-20 13:12:41 +01:00
|
|
|
any_of(field_from_id(field_id).flags & Field::Flag::Value))
|
2022-03-03 23:04:30 +01:00
|
|
|
val = mu_msg_doc_get_str_list_field(self->_doc, field_id);
|
2022-03-20 13:12:41 +01:00
|
|
|
else if (any_of(field_from_id(field_id).flags & Field::Flag::GMime)) {
|
2011-06-15 22:51:16 +02:00
|
|
|
/* if we don't have a file object yet, we need to
|
|
|
|
* create it from the file on disk */
|
2021-10-20 11:18:15 +02:00
|
|
|
if (!mu_msg_load_msg_file(self, NULL))
|
2011-06-15 22:51:16 +02:00
|
|
|
return NULL;
|
2022-03-03 23:04:30 +01:00
|
|
|
val = mu_msg_file_get_str_list_field(self->_file, field_id);
|
2011-06-15 22:51:16 +02:00
|
|
|
}
|
2011-08-29 22:38:55 +02:00
|
|
|
|
2021-10-20 11:18:15 +02:00
|
|
|
return free_later_lst(self, val);
|
2011-06-15 22:51:16 +02:00
|
|
|
}
|
|
|
|
|
2011-05-14 17:07:51 +02:00
|
|
|
static const char*
|
2022-03-03 23:04:30 +01:00
|
|
|
get_str_field(MuMsg* self, Field::Id field_id)
|
2011-05-14 17:07:51 +02:00
|
|
|
{
|
2021-10-20 11:18:15 +02:00
|
|
|
char* val;
|
2012-08-08 18:13:59 +02:00
|
|
|
gboolean do_free;
|
2011-05-19 18:57:26 +02:00
|
|
|
|
2012-08-11 20:37:33 +02:00
|
|
|
do_free = TRUE;
|
|
|
|
val = NULL;
|
2012-08-08 18:13:59 +02:00
|
|
|
|
2022-03-03 23:04:30 +01:00
|
|
|
if (self->_doc &&
|
2022-03-20 13:12:41 +01:00
|
|
|
any_of(field_from_id(field_id).flags & Field::Flag::Value))
|
2022-03-03 23:04:30 +01:00
|
|
|
val = mu_msg_doc_get_str_field(self->_doc, field_id);
|
2012-08-08 18:13:59 +02:00
|
|
|
|
2022-03-20 13:12:41 +01:00
|
|
|
else if (any_of(field_from_id(field_id).flags & Field::Flag::GMime)) {
|
2011-05-19 18:57:26 +02:00
|
|
|
/* if we don't have a file object yet, we need to
|
|
|
|
* create it from the file on disk */
|
2021-10-20 11:18:15 +02:00
|
|
|
if (!mu_msg_load_msg_file(self, NULL))
|
2011-05-19 18:57:26 +02:00
|
|
|
return NULL;
|
2022-03-03 23:04:30 +01:00
|
|
|
val = mu_msg_file_get_str_field(self->_file, field_id, &do_free);
|
2012-12-28 11:49:31 +01:00
|
|
|
} else
|
2012-08-08 18:13:59 +02:00
|
|
|
val = NULL;
|
2011-08-29 22:38:55 +02:00
|
|
|
|
2021-10-20 11:18:15 +02:00
|
|
|
return do_free ? free_later_str(self, val) : val;
|
2009-11-25 21:55:06 +01:00
|
|
|
}
|
|
|
|
|
2011-05-14 17:07:51 +02:00
|
|
|
static gint64
|
2022-03-03 23:04:30 +01:00
|
|
|
get_num_field(MuMsg* self, Field::Id field_id)
|
2011-05-14 17:07:51 +02:00
|
|
|
{
|
2022-03-03 23:04:30 +01:00
|
|
|
if (self->_doc &&
|
2022-03-20 13:12:41 +01:00
|
|
|
any_of(field_from_id(field_id).flags & Field::Flag::Value))
|
2022-03-03 23:04:30 +01:00
|
|
|
return mu_msg_doc_get_num_field(self->_doc, field_id);
|
2022-02-07 16:36:34 +01:00
|
|
|
|
|
|
|
/* if we don't have a file object yet, we need to
|
|
|
|
* create it from the file on disk */
|
|
|
|
if (!mu_msg_load_msg_file(self, NULL))
|
|
|
|
return -1;
|
2011-05-14 17:07:51 +02:00
|
|
|
|
2022-03-03 23:04:30 +01:00
|
|
|
return mu_msg_file_get_num_field(self->_file, field_id);
|
2011-05-14 17:07:51 +02:00
|
|
|
}
|
|
|
|
|
2011-05-19 21:25:27 +02:00
|
|
|
const char*
|
2021-10-20 11:18:15 +02:00
|
|
|
Mu::mu_msg_get_header(MuMsg* self, const char* header)
|
2011-05-19 21:25:27 +02:00
|
|
|
{
|
2021-10-20 11:18:15 +02:00
|
|
|
GError* err;
|
2020-10-31 08:43:52 +01:00
|
|
|
|
2021-10-20 11:18:15 +02:00
|
|
|
g_return_val_if_fail(self, NULL);
|
|
|
|
g_return_val_if_fail(header, NULL);
|
2011-05-19 21:25:27 +02:00
|
|
|
|
|
|
|
/* if we don't have a file object yet, we need to
|
|
|
|
* create it from the file on disk */
|
2021-10-20 11:18:15 +02:00
|
|
|
err = NULL;
|
|
|
|
if (!mu_msg_load_msg_file(self, &err)) {
|
|
|
|
g_warning("failed to load message file: %s",
|
2022-03-03 23:04:30 +01:00
|
|
|
err ? err->message : "something went wrong");
|
2021-10-20 11:18:15 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return free_later_str(self, mu_msg_file_get_header(self->_file, header));
|
2011-05-19 21:25:27 +02:00
|
|
|
}
|
|
|
|
|
2012-07-10 22:36:21 +02:00
|
|
|
time_t
|
2021-10-20 11:18:15 +02:00
|
|
|
Mu::mu_msg_get_timestamp(MuMsg* self)
|
2012-07-10 22:36:21 +02:00
|
|
|
{
|
2021-10-20 11:18:15 +02:00
|
|
|
const char* path;
|
2012-08-09 08:38:22 +02:00
|
|
|
struct stat statbuf;
|
|
|
|
|
2021-10-20 11:18:15 +02:00
|
|
|
g_return_val_if_fail(self, 0);
|
2012-07-10 22:36:21 +02:00
|
|
|
|
|
|
|
if (self->_file)
|
|
|
|
return self->_file->_timestamp;
|
|
|
|
|
2021-10-20 11:18:15 +02:00
|
|
|
path = mu_msg_get_path(self);
|
|
|
|
if (!path || stat(path, &statbuf) < 0)
|
2012-08-09 08:38:22 +02:00
|
|
|
return 0;
|
2012-07-10 22:36:21 +02:00
|
|
|
|
2012-08-09 08:38:22 +02:00
|
|
|
return statbuf.st_mtime;
|
2012-07-10 22:36:21 +02:00
|
|
|
}
|
|
|
|
|
2011-08-29 22:38:55 +02:00
|
|
|
const char*
|
2021-10-20 11:18:15 +02:00
|
|
|
Mu::mu_msg_get_path(MuMsg* self)
|
2009-11-25 21:55:06 +01:00
|
|
|
{
|
2021-10-20 11:18:15 +02:00
|
|
|
g_return_val_if_fail(self, NULL);
|
2022-03-03 23:04:30 +01:00
|
|
|
return get_str_field(self, Field::Id::Path);
|
2009-11-25 21:55:06 +01:00
|
|
|
}
|
|
|
|
|
2011-08-29 22:38:55 +02:00
|
|
|
const char*
|
2021-10-20 11:18:15 +02:00
|
|
|
Mu::mu_msg_get_subject(MuMsg* self)
|
2009-11-25 21:55:06 +01:00
|
|
|
{
|
2021-10-20 11:18:15 +02:00
|
|
|
g_return_val_if_fail(self, NULL);
|
2022-03-03 23:04:30 +01:00
|
|
|
return get_str_field(self, Field::Id::Subject);
|
2009-11-25 21:55:06 +01:00
|
|
|
}
|
|
|
|
|
2011-08-29 22:38:55 +02:00
|
|
|
const char*
|
2021-10-20 11:18:15 +02:00
|
|
|
Mu::mu_msg_get_msgid(MuMsg* self)
|
2009-11-25 21:55:06 +01:00
|
|
|
{
|
2021-10-20 11:18:15 +02:00
|
|
|
g_return_val_if_fail(self, NULL);
|
2022-03-03 23:04:30 +01:00
|
|
|
return get_str_field(self, Field::Id::MessageId);
|
2009-11-25 21:55:06 +01:00
|
|
|
}
|
|
|
|
|
2012-12-20 22:35:53 +01:00
|
|
|
const char*
|
2021-10-20 11:18:15 +02:00
|
|
|
Mu::mu_msg_get_mailing_list(MuMsg* self)
|
2012-12-20 22:35:53 +01:00
|
|
|
{
|
2021-10-20 11:18:15 +02:00
|
|
|
const char* ml;
|
|
|
|
char* decml;
|
2016-11-15 22:51:38 +01:00
|
|
|
|
2021-10-20 11:18:15 +02:00
|
|
|
g_return_val_if_fail(self, NULL);
|
2016-11-15 22:51:38 +01:00
|
|
|
|
2022-03-03 23:04:30 +01:00
|
|
|
ml = get_str_field(self, Field::Id::MailingList);
|
2015-12-15 06:21:26 +01:00
|
|
|
if (!ml)
|
|
|
|
return NULL;
|
|
|
|
|
2021-10-20 11:18:15 +02:00
|
|
|
decml = g_mime_utils_header_decode_text(NULL, ml);
|
2015-12-15 06:21:26 +01:00
|
|
|
if (!decml)
|
|
|
|
return NULL;
|
|
|
|
|
2021-10-20 11:18:15 +02:00
|
|
|
return free_later_str(self, decml);
|
2012-12-20 22:35:53 +01:00
|
|
|
}
|
|
|
|
|
2011-08-29 22:38:55 +02:00
|
|
|
const char*
|
2021-10-20 11:18:15 +02:00
|
|
|
Mu::mu_msg_get_maildir(MuMsg* self)
|
2010-02-08 20:17:11 +01:00
|
|
|
{
|
2021-10-20 11:18:15 +02:00
|
|
|
g_return_val_if_fail(self, NULL);
|
2022-03-03 23:04:30 +01:00
|
|
|
return get_str_field(self, Field::Id::Maildir);
|
2010-02-08 20:17:11 +01:00
|
|
|
}
|
|
|
|
|
2011-08-29 22:38:55 +02:00
|
|
|
const char*
|
2021-10-20 11:18:15 +02:00
|
|
|
Mu::mu_msg_get_from(MuMsg* self)
|
2009-11-25 21:55:06 +01:00
|
|
|
{
|
2021-10-20 11:18:15 +02:00
|
|
|
g_return_val_if_fail(self, NULL);
|
2022-03-03 23:04:30 +01:00
|
|
|
return get_str_field(self, Field::Id::From);
|
2009-11-25 21:55:06 +01:00
|
|
|
}
|
|
|
|
|
2011-08-29 22:38:55 +02:00
|
|
|
const char*
|
2021-10-20 11:18:15 +02:00
|
|
|
Mu::mu_msg_get_to(MuMsg* self)
|
2009-11-25 21:55:06 +01:00
|
|
|
{
|
2021-10-20 11:18:15 +02:00
|
|
|
g_return_val_if_fail(self, NULL);
|
2022-03-03 23:04:30 +01:00
|
|
|
return get_str_field(self, Field::Id::To);
|
2009-11-25 21:55:06 +01:00
|
|
|
}
|
|
|
|
|
2011-08-29 22:38:55 +02:00
|
|
|
const char*
|
2021-10-20 11:18:15 +02:00
|
|
|
Mu::mu_msg_get_cc(MuMsg* self)
|
2009-11-25 21:55:06 +01:00
|
|
|
{
|
2021-10-20 11:18:15 +02:00
|
|
|
g_return_val_if_fail(self, NULL);
|
2022-03-03 23:04:30 +01:00
|
|
|
return get_str_field(self, Field::Id::Cc);
|
2009-12-11 18:44:57 +01:00
|
|
|
}
|
2009-11-25 21:55:06 +01:00
|
|
|
|
2011-08-29 22:38:55 +02:00
|
|
|
const char*
|
2021-10-20 11:18:15 +02:00
|
|
|
Mu::mu_msg_get_bcc(MuMsg* self)
|
2011-05-01 17:31:00 +02:00
|
|
|
{
|
2021-10-20 11:18:15 +02:00
|
|
|
g_return_val_if_fail(self, NULL);
|
2022-03-03 23:04:30 +01:00
|
|
|
return get_str_field(self, Field::Id::Bcc);
|
2011-05-01 17:31:00 +02:00
|
|
|
}
|
|
|
|
|
2009-11-25 21:55:06 +01:00
|
|
|
time_t
|
2021-10-20 11:18:15 +02:00
|
|
|
Mu::mu_msg_get_date(MuMsg* self)
|
2009-11-25 21:55:06 +01:00
|
|
|
{
|
2021-10-20 11:18:15 +02:00
|
|
|
g_return_val_if_fail(self, (time_t)-1);
|
2022-03-03 23:04:30 +01:00
|
|
|
return (time_t)get_num_field(self, Field::Id::Date);
|
2009-11-25 21:55:06 +01:00
|
|
|
}
|
|
|
|
|
2022-03-20 13:12:41 +01:00
|
|
|
Flags
|
2021-10-20 11:18:15 +02:00
|
|
|
Mu::mu_msg_get_flags(MuMsg* self)
|
2009-11-25 21:55:06 +01:00
|
|
|
{
|
2022-03-20 13:12:41 +01:00
|
|
|
g_return_val_if_fail(self, Flags::None);
|
|
|
|
return static_cast<Flags>(get_num_field(self, Field::Id::Flags));
|
2009-11-25 21:55:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
size_t
|
2021-10-20 11:18:15 +02:00
|
|
|
Mu::mu_msg_get_size(MuMsg* self)
|
2009-11-25 21:55:06 +01:00
|
|
|
{
|
2021-10-20 11:18:15 +02:00
|
|
|
g_return_val_if_fail(self, (size_t)-1);
|
2022-03-03 23:04:30 +01:00
|
|
|
return (size_t)get_num_field(self, Field::Id::Size);
|
2009-11-25 21:55:06 +01:00
|
|
|
}
|
|
|
|
|
2022-03-20 13:12:41 +01:00
|
|
|
Mu::Priority
|
2021-10-20 11:18:15 +02:00
|
|
|
Mu::mu_msg_get_prio(MuMsg* self)
|
2009-11-25 21:55:06 +01:00
|
|
|
{
|
2022-03-20 13:12:41 +01:00
|
|
|
g_return_val_if_fail(self, Priority{});
|
2022-02-13 13:32:10 +01:00
|
|
|
|
2022-03-20 13:12:41 +01:00
|
|
|
return priority_from_char(
|
2022-03-03 23:04:30 +01:00
|
|
|
static_cast<char>(get_num_field(self, Field::Id::Priority)));
|
2009-11-25 21:55:06 +01:00
|
|
|
}
|
|
|
|
|
2012-08-09 08:38:22 +02:00
|
|
|
struct _BodyData {
|
2021-10-20 11:18:15 +02:00
|
|
|
GString* gstr;
|
2012-08-09 08:38:22 +02:00
|
|
|
gboolean want_html;
|
|
|
|
};
|
|
|
|
typedef struct _BodyData BodyData;
|
|
|
|
|
|
|
|
static void
|
2021-10-20 11:18:15 +02:00
|
|
|
accumulate_body(MuMsg* msg, MuMsgPart* mpart, BodyData* bdata)
|
2012-08-09 08:38:22 +02:00
|
|
|
{
|
2021-10-20 11:18:15 +02:00
|
|
|
char* txt;
|
|
|
|
GMimePart* mimepart;
|
|
|
|
gboolean has_err, is_plain, is_html;
|
2012-08-09 08:38:22 +02:00
|
|
|
|
2013-04-17 23:12:37 +02:00
|
|
|
if (!GMIME_IS_PART(mpart->data))
|
|
|
|
return;
|
2021-10-20 11:18:15 +02:00
|
|
|
if (mpart->part_type & MU_MSG_PART_TYPE_ATTACHMENT)
|
2019-02-18 07:30:55 +01:00
|
|
|
return;
|
2013-04-17 23:12:37 +02:00
|
|
|
|
2019-02-18 07:30:55 +01:00
|
|
|
mimepart = (GMimePart*)mpart->data;
|
2021-10-20 11:18:15 +02:00
|
|
|
is_html = mpart->part_type & MU_MSG_PART_TYPE_TEXT_HTML;
|
|
|
|
is_plain = mpart->part_type & MU_MSG_PART_TYPE_TEXT_PLAIN;
|
2012-08-09 08:38:22 +02:00
|
|
|
|
2021-10-20 11:18:15 +02:00
|
|
|
txt = NULL;
|
|
|
|
has_err = TRUE;
|
2019-05-06 16:57:19 +02:00
|
|
|
if ((bdata->want_html && is_html) || (!bdata->want_html && is_plain))
|
2021-10-20 11:18:15 +02:00
|
|
|
txt = mu_msg_mime_part_to_string(mimepart, &has_err);
|
2016-11-15 22:51:38 +01:00
|
|
|
|
2019-02-18 07:30:55 +01:00
|
|
|
if (!has_err && txt)
|
2021-10-20 11:18:15 +02:00
|
|
|
bdata->gstr = g_string_append(bdata->gstr, txt);
|
2012-08-09 08:38:22 +02:00
|
|
|
|
2021-10-20 11:18:15 +02:00
|
|
|
g_free(txt);
|
2012-08-09 08:38:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static char*
|
2021-10-20 11:18:15 +02:00
|
|
|
get_body(MuMsg* self, MuMsgOptions opts, gboolean want_html)
|
2012-08-09 08:38:22 +02:00
|
|
|
{
|
|
|
|
BodyData bdata;
|
|
|
|
|
|
|
|
bdata.want_html = want_html;
|
2021-10-20 11:18:15 +02:00
|
|
|
bdata.gstr = g_string_sized_new(4096);
|
2012-08-09 08:38:22 +02:00
|
|
|
|
2020-05-05 20:25:36 +02:00
|
|
|
/* wipe out some irrelevant options */
|
|
|
|
opts &= ~MU_MSG_OPTION_VERIFY;
|
|
|
|
opts &= ~MU_MSG_OPTION_EXTRACT_IMAGES;
|
|
|
|
|
2021-10-20 11:18:15 +02:00
|
|
|
mu_msg_part_foreach(self, opts, (MuMsgPartForeachFunc)accumulate_body, &bdata);
|
2012-08-09 08:38:22 +02:00
|
|
|
|
2012-09-12 11:11:02 +02:00
|
|
|
if (bdata.gstr->len == 0) {
|
2021-10-20 11:18:15 +02:00
|
|
|
g_string_free(bdata.gstr, TRUE);
|
2012-09-12 11:11:02 +02:00
|
|
|
return NULL;
|
|
|
|
} else
|
2021-10-20 11:18:15 +02:00
|
|
|
return g_string_free(bdata.gstr, FALSE);
|
2012-08-09 08:38:22 +02:00
|
|
|
}
|
|
|
|
|
2017-06-24 12:20:16 +02:00
|
|
|
typedef struct {
|
2021-10-20 11:18:15 +02:00
|
|
|
GMimeContentType* ctype;
|
|
|
|
gboolean want_html;
|
2017-06-24 12:20:16 +02:00
|
|
|
} ContentTypeData;
|
2016-12-18 17:16:02 +01:00
|
|
|
|
|
|
|
static void
|
2021-10-20 11:18:15 +02:00
|
|
|
find_content_type(MuMsg* msg, MuMsgPart* mpart, ContentTypeData* cdata)
|
2016-12-18 17:16:02 +01:00
|
|
|
{
|
2021-10-20 11:18:15 +02:00
|
|
|
GMimePart* wanted;
|
2017-06-24 12:20:16 +02:00
|
|
|
|
2016-12-18 17:16:02 +01:00
|
|
|
if (!GMIME_IS_PART(mpart->data))
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* text-like attachments are included when in text-mode */
|
|
|
|
|
2021-10-20 11:18:15 +02:00
|
|
|
if (!cdata->want_html && (mpart->part_type & MU_MSG_PART_TYPE_TEXT_PLAIN))
|
2020-11-28 09:15:49 +01:00
|
|
|
wanted = (GMimePart*)mpart->data;
|
2021-10-20 11:18:15 +02:00
|
|
|
else if (!(mpart->part_type & MU_MSG_PART_TYPE_ATTACHMENT) && cdata->want_html &&
|
2022-03-03 23:04:30 +01:00
|
|
|
(mpart->part_type & MU_MSG_PART_TYPE_TEXT_HTML))
|
2020-11-28 09:15:49 +01:00
|
|
|
wanted = (GMimePart*)mpart->data;
|
2017-06-24 12:20:16 +02:00
|
|
|
else
|
|
|
|
wanted = NULL;
|
|
|
|
|
2016-12-18 17:16:02 +01:00
|
|
|
if (wanted)
|
2021-10-20 11:18:15 +02:00
|
|
|
cdata->ctype = g_mime_object_get_content_type(GMIME_OBJECT(wanted));
|
2016-12-18 17:16:02 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static const GSList*
|
2021-10-20 11:18:15 +02:00
|
|
|
get_content_type_parameters(MuMsg* self, MuMsgOptions opts, gboolean want_html)
|
2016-12-18 17:16:02 +01:00
|
|
|
{
|
|
|
|
ContentTypeData cdata;
|
2017-06-24 12:20:16 +02:00
|
|
|
|
2016-12-18 17:16:02 +01:00
|
|
|
cdata.want_html = want_html;
|
2021-10-20 11:18:15 +02:00
|
|
|
cdata.ctype = NULL;
|
2016-12-18 17:16:02 +01:00
|
|
|
|
2020-05-05 20:25:36 +02:00
|
|
|
/* wipe out some irrelevant options */
|
|
|
|
opts &= ~MU_MSG_OPTION_VERIFY;
|
|
|
|
opts &= ~MU_MSG_OPTION_EXTRACT_IMAGES;
|
|
|
|
|
2021-10-20 11:18:15 +02:00
|
|
|
mu_msg_part_foreach(self, opts, (MuMsgPartForeachFunc)find_content_type, &cdata);
|
2016-12-18 17:16:02 +01:00
|
|
|
|
|
|
|
if (cdata.ctype) {
|
2021-10-20 11:18:15 +02:00
|
|
|
GSList* gslist;
|
|
|
|
GMimeParamList* paramlist;
|
|
|
|
const GMimeParam* param;
|
|
|
|
int i, len;
|
2017-06-24 12:20:16 +02:00
|
|
|
|
2021-10-20 11:18:15 +02:00
|
|
|
gslist = NULL;
|
|
|
|
paramlist = g_mime_content_type_get_parameters(cdata.ctype);
|
|
|
|
len = g_mime_param_list_length(paramlist);
|
2016-12-18 17:16:02 +01:00
|
|
|
|
2017-07-30 16:47:38 +02:00
|
|
|
for (i = 0; i < len; ++i) {
|
2021-10-20 11:18:15 +02:00
|
|
|
param = g_mime_param_list_get_parameter_at(paramlist, i);
|
|
|
|
gslist = g_slist_prepend(gslist, g_strdup(param->name));
|
|
|
|
gslist = g_slist_prepend(gslist, g_strdup(param->value));
|
2016-12-18 17:16:02 +01:00
|
|
|
}
|
|
|
|
|
2021-10-20 11:18:15 +02:00
|
|
|
return free_later_lst(self, g_slist_reverse(gslist));
|
2016-12-18 17:16:02 +01:00
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
const GSList*
|
2021-10-20 11:18:15 +02:00
|
|
|
Mu::mu_msg_get_body_text_content_type_parameters(MuMsg* self, MuMsgOptions opts)
|
2016-12-18 17:16:02 +01:00
|
|
|
{
|
2021-10-20 11:18:15 +02:00
|
|
|
g_return_val_if_fail(self, NULL);
|
2016-12-18 17:16:02 +01:00
|
|
|
return get_content_type_parameters(self, opts, FALSE);
|
|
|
|
}
|
|
|
|
|
2009-11-25 21:55:06 +01:00
|
|
|
const char*
|
2021-10-20 11:18:15 +02:00
|
|
|
Mu::mu_msg_get_body_html(MuMsg* self, MuMsgOptions opts)
|
2009-11-25 21:55:06 +01:00
|
|
|
{
|
2021-10-20 11:18:15 +02:00
|
|
|
g_return_val_if_fail(self, NULL);
|
|
|
|
return free_later_str(self, get_body(self, opts, TRUE));
|
2009-11-25 21:55:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
const char*
|
2021-10-20 11:18:15 +02:00
|
|
|
Mu::mu_msg_get_body_text(MuMsg* self, MuMsgOptions opts)
|
2009-11-25 21:55:06 +01:00
|
|
|
{
|
2021-10-20 11:18:15 +02:00
|
|
|
g_return_val_if_fail(self, NULL);
|
|
|
|
return free_later_str(self, get_body(self, opts, FALSE));
|
2009-11-25 21:55:06 +01:00
|
|
|
}
|
|
|
|
|
2011-06-15 22:51:16 +02:00
|
|
|
const GSList*
|
2021-10-20 11:18:15 +02:00
|
|
|
Mu::mu_msg_get_references(MuMsg* self)
|
2011-04-30 12:50:56 +02:00
|
|
|
{
|
2021-10-20 11:18:15 +02:00
|
|
|
g_return_val_if_fail(self, NULL);
|
2022-03-03 23:04:30 +01:00
|
|
|
return get_str_list_field(self, Field::Id::References);
|
2011-04-30 12:50:56 +02:00
|
|
|
}
|
|
|
|
|
2011-06-15 23:26:30 +02:00
|
|
|
const GSList*
|
2021-10-20 11:18:15 +02:00
|
|
|
Mu::mu_msg_get_tags(MuMsg* self)
|
2011-06-15 23:26:30 +02:00
|
|
|
{
|
2021-10-20 11:18:15 +02:00
|
|
|
g_return_val_if_fail(self, NULL);
|
2022-03-03 23:04:30 +01:00
|
|
|
return get_str_list_field(self, Field::Id::Tags);
|
2011-06-15 23:26:30 +02:00
|
|
|
}
|
|
|
|
|
2009-11-25 21:55:06 +01:00
|
|
|
const char*
|
2022-03-03 23:04:30 +01:00
|
|
|
Mu::mu_msg_get_field_string(MuMsg* self, Field::Id field_id)
|
2009-11-25 21:55:06 +01:00
|
|
|
{
|
2021-10-20 11:18:15 +02:00
|
|
|
g_return_val_if_fail(self, NULL);
|
2022-03-03 23:04:30 +01:00
|
|
|
return get_str_field(self, field_id);
|
2009-11-25 21:55:06 +01:00
|
|
|
}
|
|
|
|
|
2011-06-15 22:51:16 +02:00
|
|
|
const GSList*
|
2022-03-03 23:04:30 +01:00
|
|
|
Mu::mu_msg_get_field_string_list(MuMsg* self, Field::Id field_id)
|
2011-06-15 22:51:16 +02:00
|
|
|
{
|
2021-10-20 11:18:15 +02:00
|
|
|
g_return_val_if_fail(self, NULL);
|
2022-03-03 23:04:30 +01:00
|
|
|
return get_str_list_field(self, field_id);
|
2011-06-15 22:51:16 +02:00
|
|
|
}
|
|
|
|
|
2009-11-25 21:55:06 +01:00
|
|
|
gint64
|
2022-03-03 23:04:30 +01:00
|
|
|
Mu::mu_msg_get_field_numeric(MuMsg* self, Field::Id field_id)
|
2009-11-25 21:55:06 +01:00
|
|
|
{
|
2021-10-20 11:18:15 +02:00
|
|
|
g_return_val_if_fail(self, -1);
|
2022-03-03 23:04:30 +01:00
|
|
|
return get_num_field(self, field_id);
|
2009-11-25 21:55:06 +01:00
|
|
|
}
|
2011-05-14 17:14:24 +02:00
|
|
|
|
2011-08-29 22:38:55 +02:00
|
|
|
|
2022-03-20 13:12:41 +01:00
|
|
|
static Mu::Contacts
|
2022-02-19 17:57:50 +01:00
|
|
|
get_all_contacts(MuMsg *self)
|
2011-05-14 17:14:24 +02:00
|
|
|
{
|
2022-03-20 13:12:41 +01:00
|
|
|
Contacts contacts;
|
2011-08-29 22:38:55 +02:00
|
|
|
|
2022-03-20 13:12:41 +01:00
|
|
|
field_for_each([&](const auto& field){
|
2022-03-19 17:38:30 +01:00
|
|
|
if (!field.is_contact())
|
|
|
|
return;
|
|
|
|
auto type_contacts{mu_msg_get_contacts(self, field.id)};
|
2022-03-03 23:04:30 +01:00
|
|
|
|
2022-02-19 17:57:50 +01:00
|
|
|
contacts.reserve(contacts.size() + type_contacts.size());
|
2022-03-19 17:38:30 +01:00
|
|
|
contacts.insert(contacts.end(), type_contacts.begin(),
|
|
|
|
type_contacts.end());
|
|
|
|
});
|
2011-05-14 17:14:24 +02:00
|
|
|
|
2022-02-19 17:57:50 +01:00
|
|
|
return contacts;
|
|
|
|
}
|
2022-03-03 23:04:30 +01:00
|
|
|
|
2022-03-20 13:12:41 +01:00
|
|
|
Mu::Contacts
|
|
|
|
Mu::mu_msg_get_contacts(MuMsg *self, std::optional<Field::Id> field_id)
|
2022-02-19 17:57:50 +01:00
|
|
|
{
|
|
|
|
typedef const char*(*AddressFunc)(MuMsg*);
|
|
|
|
using AddressInfo = std::pair<GMimeAddressType, AddressFunc>;
|
|
|
|
|
2022-03-20 13:12:41 +01:00
|
|
|
g_return_val_if_fail(self, Contacts{});
|
|
|
|
g_return_val_if_fail(!field_id || field_from_id(*field_id).is_contact(),
|
|
|
|
Contacts{});
|
2022-03-19 17:38:30 +01:00
|
|
|
if (!field_id)
|
2022-02-19 17:57:50 +01:00
|
|
|
return get_all_contacts(self);
|
2022-03-03 23:04:30 +01:00
|
|
|
|
2022-02-19 17:57:50 +01:00
|
|
|
const auto info = std::invoke([&]()->AddressInfo {
|
2022-03-19 17:38:30 +01:00
|
|
|
switch (*field_id) {
|
2022-03-20 13:12:41 +01:00
|
|
|
case Field::Id::From:
|
2022-02-19 17:57:50 +01:00
|
|
|
return { GMIME_ADDRESS_TYPE_FROM, mu_msg_get_from };
|
2022-03-20 13:12:41 +01:00
|
|
|
case Field::Id::To:
|
2022-02-19 17:57:50 +01:00
|
|
|
return { GMIME_ADDRESS_TYPE_TO, mu_msg_get_to };
|
2022-03-20 13:12:41 +01:00
|
|
|
case Field::Id::Cc:
|
2022-02-19 17:57:50 +01:00
|
|
|
return { GMIME_ADDRESS_TYPE_CC, mu_msg_get_cc };
|
2022-03-20 13:12:41 +01:00
|
|
|
case Field::Id::Bcc:
|
2022-02-19 17:57:50 +01:00
|
|
|
return { GMIME_ADDRESS_TYPE_BCC, mu_msg_get_bcc };
|
|
|
|
default:
|
|
|
|
throw std::logic_error("bug");
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
const auto mdate{mu_msg_get_date(self)};
|
|
|
|
if (self->_file) {
|
|
|
|
if (auto&& lst{g_mime_message_get_addresses(
|
|
|
|
self->_file->_mime_msg, info.first)}; lst)
|
2022-03-20 13:12:41 +01:00
|
|
|
return make_contacts(lst, *field_id, mdate);
|
2022-02-19 17:57:50 +01:00
|
|
|
} else if (info.second) {
|
2022-03-03 23:04:30 +01:00
|
|
|
if (auto&& lst_str{info.second(self)}; lst_str)
|
2022-03-20 13:12:41 +01:00
|
|
|
return make_contacts(lst_str, *field_id, mdate);
|
2011-05-19 18:57:26 +02:00
|
|
|
}
|
2022-03-03 23:04:30 +01:00
|
|
|
|
2022-02-19 17:57:50 +01:00
|
|
|
return {};
|
2011-05-14 17:14:24 +02:00
|
|
|
}
|
|
|
|
|
2011-07-14 21:20:40 +02:00
|
|
|
|
2011-08-03 22:03:58 +02:00
|
|
|
gboolean
|
2021-10-20 11:18:15 +02:00
|
|
|
Mu::mu_msg_is_readable(MuMsg* self)
|
2011-08-03 22:03:58 +02:00
|
|
|
{
|
2021-10-20 11:18:15 +02:00
|
|
|
g_return_val_if_fail(self, FALSE);
|
2011-08-29 22:38:55 +02:00
|
|
|
|
2021-10-20 11:18:15 +02:00
|
|
|
return access(mu_msg_get_path(self), R_OK) == 0 ? TRUE : FALSE;
|
2011-08-03 22:03:58 +02:00
|
|
|
}
|
|
|
|
|
2011-09-18 13:42:55 +02:00
|
|
|
|
2011-08-01 21:42:23 +02:00
|
|
|
/*
|
|
|
|
* move a msg to another maildir, trying to maintain 'integrity',
|
|
|
|
* ie. msg in 'new/' will go to new/, one in cur/ goes to cur/. be
|
|
|
|
* super-paranoid here...
|
|
|
|
*/
|
2022-02-16 22:03:48 +01:00
|
|
|
bool
|
|
|
|
Mu::mu_msg_move_to_maildir(MuMsg* self,
|
|
|
|
const std::string& root_maildir_path,
|
2022-03-03 23:04:30 +01:00
|
|
|
const std::string& target_maildir,
|
2022-03-20 13:12:41 +01:00
|
|
|
Flags flags,
|
2022-03-03 23:04:30 +01:00
|
|
|
bool ignore_dups,
|
|
|
|
bool new_name,
|
|
|
|
GError** err)
|
2022-02-16 22:03:48 +01:00
|
|
|
{
|
|
|
|
g_return_val_if_fail(self, false);
|
|
|
|
|
|
|
|
|
|
|
|
const auto srcpath{mu_msg_get_path(self)};
|
|
|
|
const auto dstpath{mu_maildir_determine_target(srcpath,
|
|
|
|
root_maildir_path,
|
|
|
|
target_maildir,
|
|
|
|
flags,
|
|
|
|
new_name)};
|
|
|
|
if (!dstpath)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!mu_maildir_move_message(srcpath, *dstpath, ignore_dups))
|
|
|
|
return false;
|
2012-08-08 18:13:59 +02:00
|
|
|
|
|
|
|
/* clear the old backends */
|
2021-10-20 11:18:15 +02:00
|
|
|
mu_msg_doc_destroy(self->_doc);
|
2012-08-09 08:38:22 +02:00
|
|
|
self->_doc = NULL;
|
2021-10-20 11:18:15 +02:00
|
|
|
mu_msg_file_destroy(self->_file);
|
2011-09-12 19:42:53 +02:00
|
|
|
|
2012-08-08 18:13:59 +02:00
|
|
|
/* and create a new one */
|
2022-02-16 22:03:48 +01:00
|
|
|
self->_file = mu_msg_file_new(dstpath->c_str(), target_maildir.c_str(), err);
|
2019-12-16 20:44:35 +01:00
|
|
|
|
2022-02-16 22:03:48 +01:00
|
|
|
return !!self->_file;
|
2019-12-16 20:44:35 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
2021-10-20 11:18:15 +02:00
|
|
|
cleanup_contact(char* contact)
|
2019-12-16 20:44:35 +01:00
|
|
|
{
|
|
|
|
char *c, *c2;
|
|
|
|
|
|
|
|
/* replace "'<> with space */
|
|
|
|
for (c2 = contact; *c2; ++c2)
|
|
|
|
if (*c2 == '"' || *c2 == '\'' || *c2 == '<' || *c2 == '>')
|
|
|
|
*c2 = ' ';
|
|
|
|
|
|
|
|
/* remove everything between '()' if it's after the 5th pos;
|
|
|
|
* good to cleanup corporate contact address spam... */
|
2021-10-20 11:18:15 +02:00
|
|
|
c = g_strstr_len(contact, -1, "(");
|
2019-12-16 20:44:35 +01:00
|
|
|
if (c && c - contact > 5)
|
|
|
|
*c = '\0';
|
|
|
|
|
2021-10-20 11:18:15 +02:00
|
|
|
g_strstrip(contact);
|
2019-12-16 20:44:35 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* this is still somewhat simplistic... */
|
|
|
|
const char*
|
2021-10-20 11:18:15 +02:00
|
|
|
Mu::mu_str_display_contact_s(const char* str)
|
2019-12-16 20:44:35 +01:00
|
|
|
{
|
|
|
|
static gchar contact[255];
|
2021-10-20 11:18:15 +02:00
|
|
|
gchar * c, *c2;
|
2019-12-16 20:44:35 +01:00
|
|
|
|
|
|
|
str = str ? str : "";
|
2021-10-20 11:18:15 +02:00
|
|
|
g_strlcpy(contact, str, sizeof(contact));
|
2019-12-16 20:44:35 +01:00
|
|
|
|
|
|
|
/* we check for '<', so we can strip out the address stuff in
|
|
|
|
* e.g. 'Hello World <hello@world.xx>, but only if there is
|
|
|
|
* something alphanumeric before the <
|
|
|
|
*/
|
2021-10-20 11:18:15 +02:00
|
|
|
c = g_strstr_len(contact, -1, "<");
|
2019-12-16 20:44:35 +01:00
|
|
|
if (c != NULL) {
|
2021-10-20 11:18:15 +02:00
|
|
|
for (c2 = contact; c2 < c && !(isalnum(*c2)); ++c2)
|
|
|
|
;
|
2019-12-16 20:44:35 +01:00
|
|
|
if (c2 != c) /* apparently, there was something,
|
2022-03-03 23:04:30 +01:00
|
|
|
* so we can remove the <... part*/
|
2019-12-16 20:44:35 +01:00
|
|
|
*c = '\0';
|
|
|
|
}
|
|
|
|
|
2021-10-20 11:18:15 +02:00
|
|
|
cleanup_contact(contact);
|
2019-12-16 20:44:35 +01:00
|
|
|
|
|
|
|
return contact;
|
|
|
|
}
|
|
|
|
|
|
|
|
char*
|
2021-10-20 11:18:15 +02:00
|
|
|
Mu::mu_str_display_contact(const char* str)
|
2019-12-16 20:44:35 +01:00
|
|
|
{
|
2021-10-20 11:18:15 +02:00
|
|
|
g_return_val_if_fail(str, NULL);
|
2019-12-16 20:44:35 +01:00
|
|
|
|
2021-10-20 11:18:15 +02:00
|
|
|
return g_strdup(mu_str_display_contact_s(str));
|
2019-12-16 20:44:35 +01:00
|
|
|
}
|