mirror of https://github.com/djcb/mu.git
message: implement conversion to sexp
Like mu-msg-sexp, but for Mu::Message
This commit is contained in:
parent
e9fdf7f01d
commit
97c1725461
|
@ -22,6 +22,7 @@ lib_mu_message=static_library(
|
|||
'mu-message.hh',
|
||||
'mu-message-part.cc',
|
||||
'mu-message-part.hh',
|
||||
'mu-message-sexp.cc',
|
||||
'mu-contact.hh',
|
||||
'mu-contact.cc',
|
||||
'mu-document.cc',
|
||||
|
|
|
@ -0,0 +1,177 @@
|
|||
/*
|
||||
** Copyright (C) 2011-2022 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.
|
||||
**
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "mu-message.hh"
|
||||
#include "mu-query-results.hh"
|
||||
#include "utils/mu-str.h"
|
||||
#include "mu-msg.hh"
|
||||
#include "mu-msg-part.hh"
|
||||
#include "mu-maildir.hh"
|
||||
#include "utils/mu-utils.hh"
|
||||
|
||||
using namespace Mu;
|
||||
|
||||
static void
|
||||
add_prop_nonempty(Sexp::List& list, std::string&& elm,
|
||||
std::vector<std::string>&& items)
|
||||
{
|
||||
if (items.empty())
|
||||
return;
|
||||
|
||||
Sexp::List elms;
|
||||
for(auto&& item: items)
|
||||
elms.add(Sexp::make_string(std::move(item)));
|
||||
|
||||
list.add_prop(std::move(elm), Sexp::make_list(std::move(elms)));
|
||||
}
|
||||
|
||||
static void
|
||||
add_prop_nonempty(Sexp::List& list, std::string&& name, std::string&& value)
|
||||
{
|
||||
if (!value.empty())
|
||||
list.add_prop(std::move(name),
|
||||
Sexp::make_string(std::move(value)));
|
||||
}
|
||||
|
||||
static Mu::Sexp
|
||||
make_contact_sexp(const Contact& contact)
|
||||
{
|
||||
return Sexp::make_list(
|
||||
/* name */
|
||||
Sexp::make_string(contact.name, true/*?nil*/),
|
||||
/* dot */
|
||||
Sexp::make_symbol("."),
|
||||
/* email */
|
||||
Sexp::make_string(contact.email));
|
||||
}
|
||||
|
||||
static void
|
||||
add_list_post(Sexp::List& list, const Message& message)
|
||||
{
|
||||
if (!message.has_mime_message())
|
||||
return;
|
||||
|
||||
/* some mailing lists do not set the reply-to; see pull #1278. So for
|
||||
* those cases, check the List-Post address and use that instead */
|
||||
|
||||
GMatchInfo* minfo;
|
||||
GRegex* rx;
|
||||
const auto list_post{message.header("List-Post")};
|
||||
if (!list_post)
|
||||
return;
|
||||
|
||||
rx = g_regex_new("<?mailto:([a-z0-9!@#$%&'*+-/=?^_`{|}~]+)>?",
|
||||
G_REGEX_CASELESS, (GRegexMatchFlags)0, {});
|
||||
g_return_if_fail(rx);
|
||||
|
||||
if (g_regex_match(rx, list_post->c_str(), (GRegexMatchFlags)0, &minfo)) {
|
||||
auto address = (char*)g_match_info_fetch(minfo, 1);
|
||||
list.add_prop(":list-post", make_contact_sexp(Contact{address}));
|
||||
g_free(address);
|
||||
}
|
||||
|
||||
g_match_info_free(minfo);
|
||||
g_regex_unref(rx);
|
||||
}
|
||||
|
||||
static void
|
||||
add_contacts(Sexp::List& list, const Message& message)
|
||||
{
|
||||
auto add_contact_type = [&](const Contacts& contacts, std::string&& prop) {
|
||||
Sexp::List clist;
|
||||
seq_for_each(contacts, [&](auto&& c) { clist.add(make_contact_sexp(c)); });
|
||||
if (!clist.empty())
|
||||
list.add_prop(std::move(prop),
|
||||
Sexp::make_list(std::move(clist)));
|
||||
};
|
||||
|
||||
add_contact_type(message.from(),":from");
|
||||
add_contact_type(message.to(), ":to");
|
||||
add_contact_type(message.cc(), ":cc");
|
||||
add_contact_type(message.bcc(), ":bcc");
|
||||
|
||||
// FIXME: reply-to.
|
||||
}
|
||||
|
||||
static void
|
||||
add_flags(Sexp::List& list, const Message& message)
|
||||
{
|
||||
Sexp::List flaglist;
|
||||
const auto flags{message.flags()};
|
||||
for (auto&& info: AllMessageFlagInfos)
|
||||
if (any_of(flags & info.flag))
|
||||
flaglist.add(Sexp::make_symbol_sv(info.name));
|
||||
|
||||
if (!flaglist.empty())
|
||||
list.add_prop(":flags", Sexp::make_list(std::move(flaglist)));
|
||||
}
|
||||
|
||||
static void
|
||||
add_date_and_size(Sexp::List& items, const Message& message)
|
||||
{
|
||||
auto t{message.date()};
|
||||
if (t != 0) {
|
||||
Sexp::List dlist;
|
||||
dlist.add(Sexp::make_number((unsigned)(t >> 16)));
|
||||
dlist.add(Sexp::make_number((unsigned)(t & 0xffff)));
|
||||
dlist.add(Sexp::make_number(0));
|
||||
items.add_prop(":date", Sexp::make_list(std::move(dlist)));
|
||||
}
|
||||
|
||||
auto size{message.size()};
|
||||
if (size != 0)
|
||||
items.add_prop(":size", Sexp::make_number(size));
|
||||
}
|
||||
|
||||
Mu::Sexp::List
|
||||
Message::to_sexp_list() const
|
||||
{
|
||||
Sexp::List items;
|
||||
|
||||
// if (docid != 0)
|
||||
// items.add_prop(":docid", Sexp::make_number(docid));
|
||||
|
||||
add_prop_nonempty(items, ":subject", subject());
|
||||
add_prop_nonempty(items, ":message-id", message_id());
|
||||
add_prop_nonempty(items, ":mailing-list", mailing_list());
|
||||
add_prop_nonempty(items, ":path", path());
|
||||
add_prop_nonempty(items, ":maildir",maildir());
|
||||
|
||||
items.add_prop(":priority",
|
||||
Sexp::make_symbol_sv(priority_name(priority())));
|
||||
|
||||
add_contacts(items, *this);
|
||||
add_list_post(items, *this);
|
||||
|
||||
add_prop_nonempty(items, ":references", references());
|
||||
add_prop_nonempty(items, ":tags", tags());
|
||||
|
||||
add_date_and_size(items, *this);
|
||||
add_flags(items, *this);
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
Mu::Sexp
|
||||
Message::to_sexp() const
|
||||
{
|
||||
return Sexp::make_list(to_sexp_list());
|
||||
}
|
|
@ -149,6 +149,14 @@ Message::unload_mime_message() const
|
|||
{
|
||||
priv_->mime_msg = Nothing;
|
||||
}
|
||||
|
||||
bool
|
||||
Message::has_mime_message() const
|
||||
{
|
||||
return !!priv_->mime_msg;
|
||||
}
|
||||
|
||||
|
||||
static Priority
|
||||
get_priority(const MimeMessage& mime_msg)
|
||||
{
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
|
||||
#include "utils/mu-option.hh"
|
||||
#include "utils/mu-result.hh"
|
||||
#include "utils/mu-sexp.hh"
|
||||
|
||||
namespace Mu {
|
||||
|
||||
|
@ -147,7 +148,6 @@ public:
|
|||
*/
|
||||
Contacts bcc() const { return document().contacts_value(Field::Id::Bcc); }
|
||||
|
||||
|
||||
/**
|
||||
* Get the maildir this message lives in; ie, if the path is
|
||||
* ~/Maildir/foo/bar/cur/msg, the maildir would be foo/bar
|
||||
|
@ -235,11 +235,24 @@ public:
|
|||
|
||||
|
||||
/*
|
||||
* Below require a file-backed message, which is a relatively slow
|
||||
* if there isn't one already ()
|
||||
*
|
||||
* Convert to Sexp
|
||||
*/
|
||||
|
||||
/**
|
||||
* convert the message to a Lisp symbolic expression (for further
|
||||
* processing in e.g. emacs)
|
||||
*
|
||||
*
|
||||
* @return a Mu::Sexp or a Mu::Sexp::List representing the message.
|
||||
*/
|
||||
Mu::Sexp::List to_sexp_list() const;
|
||||
Mu::Sexp to_sexp() const;
|
||||
|
||||
/*
|
||||
* Below require a file-backed message, which is a relatively slow
|
||||
* if there isn't one already; see load_mime_message()
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Get the text body
|
||||
|
@ -298,6 +311,15 @@ public:
|
|||
*/
|
||||
void unload_mime_message() const;
|
||||
|
||||
/**
|
||||
* Has a (file-base) GMime message been loaded?
|
||||
*
|
||||
*
|
||||
* @return true or false
|
||||
*/
|
||||
bool has_mime_message() const;
|
||||
|
||||
|
||||
struct Private;
|
||||
private:
|
||||
Message(const std::string& path, Option<const std::string&> mdir);
|
||||
|
|
Loading…
Reference in New Issue