message: contact: remove ::Type, use Field

Don't need a special Type {} in Contact, when we have more-or-less the same info
in Field.
This commit is contained in:
Dirk-Jan C. Binnema
2022-03-19 18:38:30 +02:00
parent a23c99ff7e
commit d4285975b3
5 changed files with 76 additions and 111 deletions

View File

@ -18,11 +18,13 @@
*/ */
#include "mu-message-contact.hh" #include "mu-message-contact.hh"
#include "mu-message.hh"
#include <gmime/gmime.h> #include <gmime/gmime.h>
#include <glib.h> #include <glib.h>
using namespace Mu; using namespace Mu;
using namespace Mu::Message;
std::string std::string
MessageContact::display_name() const MessageContact::display_name() const
@ -35,8 +37,7 @@ MessageContact::display_name() const
Mu::MessageContacts Mu::MessageContacts
Mu::make_message_contacts(InternetAddressList* addr_lst, Mu::make_message_contacts(InternetAddressList* addr_lst,
MessageContact::Type type, Field::Id field_id, ::time_t message_date)
::time_t message_date)
{ {
MessageContacts contacts; MessageContacts contacts;
size_t num{}; size_t num{};
@ -59,7 +60,7 @@ Mu::make_message_contacts(InternetAddressList* addr_lst,
continue; continue;
contacts.push_back(MessageContact{email, name ? name : "", contacts.push_back(MessageContact{email, name ? name : "",
type, message_date}); field_id, message_date});
++num; ++num;
} }
@ -69,7 +70,7 @@ Mu::make_message_contacts(InternetAddressList* addr_lst,
Mu::MessageContacts Mu::MessageContacts
Mu::make_message_contacts(const std::string& addrs, Mu::make_message_contacts(const std::string& addrs,
MessageContact::Type type, Field::Id field_id,
::time_t message_date) ::time_t message_date)
{ {
auto addr_list = internet_address_list_parse(NULL, addrs.c_str()); auto addr_list = internet_address_list_parse(NULL, addrs.c_str());
@ -78,7 +79,7 @@ Mu::make_message_contacts(const std::string& addrs,
return {}; return {};
} }
auto contacts{make_message_contacts(addr_list, type, message_date)}; auto contacts{make_message_contacts(addr_list, field_id, message_date)};
g_object_unref(addr_list); g_object_unref(addr_list);
return contacts; return contacts;
@ -109,13 +110,13 @@ test_ctor_foo()
MessageContact c{ MessageContact c{
"foo@example.com", "foo@example.com",
"Foo Bar", "Foo Bar",
MessageContact::Type::Bcc, Field::Id::Bcc,
1645214647 1645214647
}; };
assert_equal(c.email, "foo@example.com"); assert_equal(c.email, "foo@example.com");
assert_equal(c.name, "Foo Bar"); assert_equal(c.name, "Foo Bar");
g_assert_true(c.type == MessageContact::Type::Bcc); g_assert_true(c.field_id == Field::Id::Bcc);
g_assert_cmpuint(c.message_date,==,1645214647); g_assert_cmpuint(c.message_date,==,1645214647);
assert_equal(c.display_name(), "Foo Bar <foo@example.com>"); assert_equal(c.display_name(), "Foo Bar <foo@example.com>");
@ -178,12 +179,12 @@ test_make_contacts()
internet_address_list_parse(NULL, str)}; internet_address_list_parse(NULL, str)};
g_assert_true(lst); g_assert_true(lst);
const auto addrs{make_message_contacts(lst, MessageContact::Type::Cc, 54321 )}; const auto addrs{make_message_contacts(lst, Field::Id::Cc, 54321 )};
g_object_unref(lst); g_object_unref(lst);
g_assert_cmpuint(addrs.size(),==,3); g_assert_cmpuint(addrs.size(),==,3);
const auto addrs2{make_message_contacts(str, MessageContact::Type::To, 12345 )}; const auto addrs2{make_message_contacts(str, Field::Id::To, 12345 )};
g_assert_cmpuint(addrs2.size(),==,3); g_assert_cmpuint(addrs2.size(),==,3);
assert_equal(addrs2[0].name, "Abc"); assert_equal(addrs2[0].name, "Abc");
@ -201,7 +202,7 @@ test_make_contacts_2()
"De\nf <baa@example.com>, " "De\nf <baa@example.com>, "
"\tGhi <zzz@example.com>"; "\tGhi <zzz@example.com>";
const auto addrs2{make_message_contacts(str, MessageContact::Type::Bcc, 12345 )}; const auto addrs2{make_message_contacts(str, Field::Id::Bcc, 12345 )};
g_assert_cmpuint(addrs2.size(),==,3); g_assert_cmpuint(addrs2.size(),==,3);
assert_equal(addrs2[0].name, "Äbc"); assert_equal(addrs2[0].name, "Äbc");
@ -221,7 +222,7 @@ test_make_contacts_err()
InternetAddressList *lst{ internet_address_list_parse(NULL, "")}; InternetAddressList *lst{ internet_address_list_parse(NULL, "")};
g_assert_false(lst); g_assert_false(lst);
const auto addrs{make_message_contacts("", MessageContact::Type::To, 77777)}; const auto addrs{make_message_contacts("", Field::Id::To, 77777)};
g_assert_true(addrs.empty()); g_assert_true(addrs.empty());
} }

View File

@ -44,31 +44,19 @@ namespace Mu {
*/ */
size_t lowercase_hash(const std::string& s); size_t lowercase_hash(const std::string& s);
struct MessageContact { struct MessageContact {
/**
* Contact types
*/
enum struct Type {
To, /**< To recipient */
From, /**< Sender */
Cc, /**< Cc recipient */
Bcc, /**< Bcc recipient */
ReplyTo, /**< Reply-To wannabe recipient */
Unknown, /**< Unknown type */
};
/** /**
* Construct a new MessageContact * Construct a new MessageContact
* *
* @param email_ email address * @param email_ email address
* @param name_ name or empty * @param name_ name or empty
* @param type_ contact type * @param field_id_ contact field id, or {}
* @param message_date_ data for the message for this contact * @param message_date_ data for the message for this contact
*/ */
MessageContact(const std::string& email_, const std::string& name_ = "", MessageContact(const std::string& email_, const std::string& name_ = "",
Type type_ = Type::Unknown, time_t message_date_ = 0) std::optional<MessageField::Id> field_id_ = {},
: email{email_}, name{name_}, type{type_}, time_t message_date_ = 0)
: email{email_}, name{name_}, field_id{field_id_},
message_date{message_date_}, personal{}, frequency{1}, tstamp{} message_date{message_date_}, personal{}, frequency{1}, tstamp{}
{ cleanup_name(); } { cleanup_name(); }
@ -85,7 +73,7 @@ struct MessageContact {
MessageContact(const std::string& email_, const std::string& name_, MessageContact(const std::string& email_, const std::string& name_,
time_t message_date_, bool personal_, size_t freq_, time_t message_date_, bool personal_, size_t freq_,
int64_t tstamp_) int64_t tstamp_)
: email{email_}, name{name_}, type{Type::Unknown}, : email{email_}, name{name_}, field_id{},
message_date{message_date_}, personal{personal_}, frequency{freq_}, message_date{message_date_}, personal{personal_}, frequency{freq_},
tstamp{tstamp_} tstamp{tstamp_}
{ cleanup_name();} { cleanup_name();}
@ -126,39 +114,18 @@ struct MessageContact {
return cached_hash; return cached_hash;
} }
/**
* Get the MessageField for this contact-type, if any.
*
* @return the message-field or nullopt.
*/
constexpr std::optional<MessageField> const field() {
switch(type){
case Type::From:
return message_field(MessageField::Id::From);
case Type::To:
return message_field(MessageField::Id::To);
case Type::Cc:
return message_field(MessageField::Id::Cc);
case Type::Bcc:
return message_field(MessageField::Id::Bcc);
default:
return std::nullopt;
}
}
/* /*
* data members * data members
*/ */
std::string email; /**< Email address for this contact.Not empty */ std::string email; /**< Email address for this contact.Not empty */
std::string name; /**< Name for this contact; can be empty. */ std::string name; /**< Name for this contact; can be empty. */
Type type{Type::Unknown}; /**< Type of contact */ std::optional<MessageField::Id> field_id; /**< Field Id of contact or nullopt */
::time_t message_date; /**< date of the message from which the ::time_t message_date; /**< date of the message from which the
* contact originates */ * contact originates */
bool personal; /**< A personal message? */ bool personal; /**< A personal message? */
size_t frequency; /**< Frequency of this contact */ size_t frequency; /**< Frequency of this contact */
int64_t tstamp; /**< Timestamp for this contact */ int64_t tstamp; /**< Timestamp for this contact */
private: private:
void cleanup_name() { // replace control characters by spaces. void cleanup_name() { // replace control characters by spaces.
@ -174,7 +141,7 @@ using MessageContacts = std::vector<MessageContact>;
* Create a sequence of MessageContact objects from an InternetAddressList * Create a sequence of MessageContact objects from an InternetAddressList
* *
* @param addr_lst an address list * @param addr_lst an address list
* @param type the type of addresses * @param field_id the field_id for message field for these addresses
* @param message_date the date of the message from which the InternetAddressList * @param message_date the date of the message from which the InternetAddressList
* originates. * originates.
* *
@ -182,20 +149,20 @@ using MessageContacts = std::vector<MessageContact>;
*/ */
MessageContacts MessageContacts
make_message_contacts(/*const*/ struct _InternetAddressList* addr_lst, make_message_contacts(/*const*/ struct _InternetAddressList* addr_lst,
MessageContact::Type type, ::time_t message_date); MessageField::Id field_id, ::time_t message_date);
/** /**
* Create a sequence of MessageContact objects from an InternetAddressList * Create a sequence of MessageContact objects from an InternetAddressList
* *
* @param addrs a string with one more valid addresses (as per internet_address_list_parse()) * @param addrs a string with one more valid addresses (as per internet_address_list_parse())
* @param type the type of addresses * @param field_id the field_id for message field for these addresses
* @param message_date the date of the message from which the addresses originate * @param message_date the date of the message from which the addresses originate
* *
* @return a sequence of MessageContact objects. * @return a sequence of MessageContact objects.
*/ */
MessageContacts MessageContacts
make_message_contacts(const std::string& addrs, make_message_contacts(const std::string& addrs,
MessageContact::Type type, ::time_t message_date); MessageField::Id field_id, ::time_t message_date);
} // namespace Mu } // namespace Mu
/** /**
@ -207,7 +174,4 @@ template<> struct std::hash<Mu::MessageContact> {
} }
}; };
#endif /* MU_MESSAGE_CONTACT_HH__ */ #endif /* MU_MESSAGE_CONTACT_HH__ */

View File

@ -19,7 +19,7 @@
#include <string.h> #include <string.h>
#include <ctype.h> #include <ctype.h>
#include "mu-message-flags.hh" #include "mu-message.hh"
#include "mu-query-results.hh" #include "mu-query-results.hh"
#include "utils/mu-str.h" #include "utils/mu-str.h"
#include "mu-msg.hh" #include "mu-msg.hh"
@ -27,6 +27,7 @@
#include "mu-maildir.hh" #include "mu-maildir.hh"
using namespace Mu; using namespace Mu;
using namespace Mu::Message;
static void static void
add_prop_nonempty(Sexp::List& list, const char* elm, const GSList* str_lst) add_prop_nonempty(Sexp::List& list, const char* elm, const GSList* str_lst)
@ -76,9 +77,9 @@ add_list_post(Sexp::List& list, MuMsg* msg)
return; return;
rx = g_regex_new("<?mailto:([a-z0-9!@#$%&'*+-/=?^_`{|}~]+)>?", rx = g_regex_new("<?mailto:([a-z0-9!@#$%&'*+-/=?^_`{|}~]+)>?",
G_REGEX_CASELESS, G_REGEX_CASELESS,
(GRegexMatchFlags)0, (GRegexMatchFlags)0,
NULL); NULL);
g_return_if_fail(rx); g_return_if_fail(rx);
if (g_regex_match(rx, list_post, (GRegexMatchFlags)0, &minfo)) { if (g_regex_match(rx, list_post, (GRegexMatchFlags)0, &minfo)) {
@ -94,22 +95,22 @@ add_list_post(Sexp::List& list, MuMsg* msg)
static void static void
add_contacts(Sexp::List& list, MuMsg* msg) add_contacts(Sexp::List& list, MuMsg* msg)
{ {
using ContactPair = std::pair<MessageContact::Type, std::string_view>; using ContactPair = std::pair<Field::Id, std::string_view>;
constexpr std::array<ContactPair, 5> contact_types = {{ constexpr std::array<ContactPair, 5> contact_types = {{
{ MessageContact::Type::From, ":from" }, { Field::Id::From, ":from" },
{ MessageContact::Type::To, ":to" }, { Field::Id::To, ":to" },
{ MessageContact::Type::Cc, ":cc" }, { Field::Id::Cc, ":cc" },
{ MessageContact::Type::ReplyTo, ":reply-to" }, // { Field::Id::ReplyTo, ":reply-to" },
{ MessageContact::Type::Bcc, ":bcc" }, { Field::Id::Bcc, ":bcc" },
}}; }};
for (auto&& contact_type : contact_types) { for (auto&& contact_type : contact_types) {
const auto contacts{mu_msg_get_contacts(msg, contact_type.first)}; const auto contacts{mu_msg_get_contacts(msg, contact_type.first)};
if (contacts.empty()) if (contacts.empty())
continue; continue;
Sexp::List c_list; Sexp::List c_list;
for (auto&& contact: contacts) for (auto&& contact: contacts)
c_list.add(make_contact_sexp(contact)); c_list.add(make_contact_sexp(contact));
@ -151,7 +152,7 @@ get_temp_file(MuMsg* msg, MuMsgOptions opts, unsigned index)
errexit: errexit:
g_warning("failed to save mime part: %s", g_warning("failed to save mime part: %s",
err->message ? err->message : "something went wrong"); err->message ? err->message : "something went wrong");
g_clear_error(&err); g_clear_error(&err);
g_free(path); g_free(path);
@ -216,11 +217,11 @@ make_part_types(MuMsgPartType ptype)
MuMsgPartType ptype; MuMsgPartType ptype;
const char* name; const char* name;
} ptypes[] = {{MU_MSG_PART_TYPE_LEAF, "leaf"}, } ptypes[] = {{MU_MSG_PART_TYPE_LEAF, "leaf"},
{MU_MSG_PART_TYPE_MESSAGE, "message"}, {MU_MSG_PART_TYPE_MESSAGE, "message"},
{MU_MSG_PART_TYPE_INLINE, "inline"}, {MU_MSG_PART_TYPE_INLINE, "inline"},
{MU_MSG_PART_TYPE_ATTACHMENT, "attachment"}, {MU_MSG_PART_TYPE_ATTACHMENT, "attachment"},
{MU_MSG_PART_TYPE_SIGNED, "signed"}, {MU_MSG_PART_TYPE_SIGNED, "signed"},
{MU_MSG_PART_TYPE_ENCRYPTED, "encrypted"}}; {MU_MSG_PART_TYPE_ENCRYPTED, "encrypted"}};
Sexp::List list; Sexp::List list;
for (auto u = 0U; u != G_N_ELEMENTS(ptypes); ++u) for (auto u = 0U; u != G_N_ELEMENTS(ptypes); ++u)
@ -234,8 +235,8 @@ static void
each_part(MuMsg* msg, MuMsgPart* part, PartInfo* pinfo) each_part(MuMsg* msg, MuMsgPart* part, PartInfo* pinfo)
{ {
auto mimetype = format("%s/%s", auto mimetype = format("%s/%s",
part->type ? part->type : "application", part->type ? part->type : "application",
part->subtype ? part->subtype : "octet-stream"); part->subtype ? part->subtype : "octet-stream");
auto maybe_attach = Sexp::make_symbol(mu_msg_part_maybe_attachment(part) ? "t" : "nil"); auto maybe_attach = Sexp::make_symbol(mu_msg_part_maybe_attachment(part) ? "t" : "nil");
Sexp::List partlist; Sexp::List partlist;
@ -285,7 +286,7 @@ add_message_file_parts(Sexp::List& items, MuMsg* msg, MuMsgOptions opts)
GError* err{NULL}; GError* err{NULL};
if (!mu_msg_load_msg_file(msg, &err)) { if (!mu_msg_load_msg_file(msg, &err)) {
g_warning("failed to load message file: %s", g_warning("failed to load message file: %s",
err ? err->message : "some error occurred"); err ? err->message : "some error occurred");
g_clear_error(&err); g_clear_error(&err);
return; return;
} }
@ -301,8 +302,8 @@ add_message_file_parts(Sexp::List& items, MuMsg* msg, MuMsgOptions opts)
add_prop_nonempty(items, ":user-agent", str); add_prop_nonempty(items, ":user-agent", str);
add_prop_nonempty(items, add_prop_nonempty(items,
":body-txt-params", ":body-txt-params",
mu_msg_get_body_text_content_type_parameters(msg, opts)); mu_msg_get_body_text_content_type_parameters(msg, opts));
add_prop_nonempty(items, ":body-txt", mu_msg_get_body_text(msg, opts)); add_prop_nonempty(items, ":body-txt", mu_msg_get_body_text(msg, opts));
add_prop_nonempty(items, ":body-html", mu_msg_get_body_html(msg, opts)); add_prop_nonempty(items, ":body-html", mu_msg_get_body_html(msg, opts));
} }
@ -358,7 +359,7 @@ Mu::msg_to_sexp_list(MuMsg* msg, unsigned docid, MuMsgOptions opts)
add_prop_nonempty(items, ":maildir", mu_msg_get_maildir(msg)); add_prop_nonempty(items, ":maildir", mu_msg_get_maildir(msg));
items.add_prop(":priority", items.add_prop(":priority",
Sexp::make_symbol_sv(message_priority_name(mu_msg_get_prio(msg)))); Sexp::make_symbol_sv(message_priority_name(mu_msg_get_prio(msg))));
/* in the no-headers-only case (see below) we get a more complete list of contacts, so no /* in the no-headers-only case (see below) we get a more complete list of contacts, so no
* need to get them here if that's the case */ * need to get them here if that's the case */

View File

@ -624,40 +624,40 @@ get_all_contacts(MuMsg *self)
{ {
MessageContacts contacts; MessageContacts contacts;
for (auto&& mtype : { MessageContact::Type::From, MessageContact::Type::To, message_field_for_each([&](const auto& field){
MessageContact::Type::Cc, MessageContact::Type::ReplyTo, if (!field.is_contact())
MessageContact::Type::Bcc}) { return;
auto type_contacts{mu_msg_get_contacts(self, mtype)}; auto type_contacts{mu_msg_get_contacts(self, field.id)};
contacts.reserve(contacts.size() + type_contacts.size()); contacts.reserve(contacts.size() + type_contacts.size());
contacts.insert(contacts.end(), type_contacts.begin(), type_contacts.end()); contacts.insert(contacts.end(), type_contacts.begin(),
} type_contacts.end());
});
return contacts; return contacts;
} }
Mu::MessageContacts Mu::MessageContacts
Mu::mu_msg_get_contacts(MuMsg *self, MessageContact::Type mtype) Mu::mu_msg_get_contacts(MuMsg *self, std::optional<MessageField::Id> field_id)
{ {
typedef const char*(*AddressFunc)(MuMsg*); typedef const char*(*AddressFunc)(MuMsg*);
using AddressInfo = std::pair<GMimeAddressType, AddressFunc>; using AddressInfo = std::pair<GMimeAddressType, AddressFunc>;
g_return_val_if_fail(self, MessageContacts{}); g_return_val_if_fail(self, MessageContacts{});
g_return_val_if_fail(!field_id || message_field(*field_id).is_contact(),
if (mtype == MessageContact::Type::Unknown) MessageContacts{});
if (!field_id)
return get_all_contacts(self); return get_all_contacts(self);
const auto info = std::invoke([&]()->AddressInfo { const auto info = std::invoke([&]()->AddressInfo {
switch (mtype) { switch (*field_id) {
case MessageContact::Type::From: case MessageField::Id::From:
return { GMIME_ADDRESS_TYPE_FROM, mu_msg_get_from }; return { GMIME_ADDRESS_TYPE_FROM, mu_msg_get_from };
case MessageContact::Type::To: case MessageField::Id::To:
return { GMIME_ADDRESS_TYPE_TO, mu_msg_get_to }; return { GMIME_ADDRESS_TYPE_TO, mu_msg_get_to };
case MessageContact::Type::Cc: case MessageField::Id::Cc:
return { GMIME_ADDRESS_TYPE_CC, mu_msg_get_cc }; return { GMIME_ADDRESS_TYPE_CC, mu_msg_get_cc };
case MessageContact::Type::ReplyTo: case MessageField::Id::Bcc:
return { GMIME_ADDRESS_TYPE_REPLY_TO, {} };
case MessageContact::Type::Bcc:
return { GMIME_ADDRESS_TYPE_BCC, mu_msg_get_bcc }; return { GMIME_ADDRESS_TYPE_BCC, mu_msg_get_bcc };
default: default:
throw std::logic_error("bug"); throw std::logic_error("bug");
@ -668,10 +668,10 @@ Mu::mu_msg_get_contacts(MuMsg *self, MessageContact::Type mtype)
if (self->_file) { if (self->_file) {
if (auto&& lst{g_mime_message_get_addresses( if (auto&& lst{g_mime_message_get_addresses(
self->_file->_mime_msg, info.first)}; lst) self->_file->_mime_msg, info.first)}; lst)
return make_message_contacts(lst, mtype, mdate); return make_message_contacts(lst, *field_id, mdate);
} else if (info.second) { } else if (info.second) {
if (auto&& lst_str{info.second(self)}; lst_str) if (auto&& lst_str{info.second(self)}; lst_str)
return make_message_contacts(lst_str, mtype, mdate); return make_message_contacts(lst_str, *field_id, mdate);
} }
return {}; return {};

View File

@ -441,13 +441,12 @@ bool mu_msg_move_to_maildir(MuMsg* msg,
* Get a sequence with contacts of the given type for this message. * Get a sequence with contacts of the given type for this message.
* *
* @param msg a valid MuMsg* instance * @param msg a valid MuMsg* instance
* @param mtype the contact type; with Type::Unknown, get _all_ types. * @param field_id the contact field or none; if none get _all_ contact types.
* *
* @return a sequence * @return a sequence
*/ */
Mu::MessageContacts mu_msg_get_contacts (MuMsg *self, Mu::MessageContacts mu_msg_get_contacts (MuMsg *self,
MessageContact::Type mtype=MessageContact::Type::Unknown); std::optional<MessageField::Id> field_id={});
/** /**
* create a 'display contact' from an email header To/Cc/Bcc/From-type address * create a 'display contact' from an email header To/Cc/Bcc/From-type address
* ie., turn * ie., turn