contacts/contacts-cache: cleanups
refactor code a bit; move sorting to Contact remove unneeded hashing in Contact (just use the email address)
This commit is contained in:
@ -1,5 +1,5 @@
|
||||
/*
|
||||
** Copyright (C) 2022 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
|
||||
** Copyright (C) 2022-2025 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
|
||||
@ -32,101 +32,118 @@
|
||||
#include <utils/mu-option.hh>
|
||||
#include "mu-fields.hh"
|
||||
|
||||
struct _InternetAddressList;
|
||||
|
||||
namespace Mu {
|
||||
|
||||
/**
|
||||
* Get the hash value for a lowercase value of s; useful for email-addresses
|
||||
*
|
||||
* @param s a string
|
||||
*
|
||||
* @return a hash value.
|
||||
*/
|
||||
size_t lowercase_hash(const std::string& s);
|
||||
|
||||
struct Contact {
|
||||
enum struct Type {
|
||||
None, Sender, From, ReplyTo, To, Cc, Bcc
|
||||
enum struct Type:char {
|
||||
None='\0', Sender='s', From='f',
|
||||
ReplyTo='r', To='t', Cc='c', Bcc='b'
|
||||
};
|
||||
|
||||
/**
|
||||
* Construct a new Contact
|
||||
*
|
||||
* @param email_ email address
|
||||
* @param name_ name or empty
|
||||
* @param type_ contact field type
|
||||
* @param message_date_ data for the message for this contact
|
||||
* @param email email address
|
||||
* @param name name or empty
|
||||
* @param type contact field type
|
||||
* @param message_date data for the message for this contact
|
||||
*/
|
||||
Contact(const std::string& email_, const std::string& name_ = "",
|
||||
Type type_ = Type::None, ::time_t message_date_ = 0)
|
||||
: email{email_}, name{name_}, type{type_},
|
||||
message_date{message_date_}, personal{}, frequency{1}, tstamp{}
|
||||
Contact(const std::string& email, const std::string& name = {},
|
||||
Type type = {}, int64_t message_date ={})
|
||||
: email{email}, name{name}, type{type},
|
||||
message_date{message_date}, personal{}, frequency{1}, tstamp{}
|
||||
{ cleanup_name(); }
|
||||
|
||||
/**
|
||||
* Construct a new Contact
|
||||
*
|
||||
* @param email_ email address
|
||||
* @param name_ name or empty
|
||||
* @param message_date_ date of message this contact originate from
|
||||
* @param personal_ is this a personal contact?
|
||||
* @param freq_ how often was this contact seen?
|
||||
* @param tstamp_ timestamp for last change
|
||||
* @param email email address
|
||||
* @param name name or empty
|
||||
* @param message_date date of message this contact originate from
|
||||
* @param personal is this a personal contact?
|
||||
* @param freq how often was this contact seen?
|
||||
* @param tstamp timestamp for last change
|
||||
*/
|
||||
Contact(const std::string& email_, const std::string& name_,
|
||||
time_t message_date_, bool personal_, size_t freq_,
|
||||
int64_t tstamp_)
|
||||
: email{email_}, name{name_}, type{Type::None},
|
||||
message_date{message_date_}, personal{personal_}, frequency{freq_},
|
||||
tstamp{tstamp_}
|
||||
{ cleanup_name();}
|
||||
Contact(const std::string& email, const std::string& name,
|
||||
int64_t message_date, bool personal, size_t freq,
|
||||
int64_t tstamp)
|
||||
: email{email}, name{name}, type{},
|
||||
message_date{message_date}, personal{personal}, frequency{freq},
|
||||
tstamp{tstamp}
|
||||
{ cleanup_name(); }
|
||||
|
||||
/**
|
||||
* Get the "display name" for this contact:
|
||||
*
|
||||
* If there's a non-empty name, it's Jane Doe <email@example.com>
|
||||
* otherwise it's just the e-mail address. Names with commas are quoted
|
||||
* If there is a non-empty name, it is of the form
|
||||
* Jane Doe <email@example.com>
|
||||
* Otherwise it is just the e-mail address. Names with commas are quoted
|
||||
* (with the quotes escaped).
|
||||
*
|
||||
* @return the display name
|
||||
*/
|
||||
std::string display_name() const;
|
||||
|
||||
|
||||
/**
|
||||
* Does the contact contain a valid email address as per
|
||||
* https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address
|
||||
* ?
|
||||
*
|
||||
* @return true or false
|
||||
*/
|
||||
bool has_valid_email() const;
|
||||
|
||||
/**
|
||||
* Operator==; based on the hash values (ie. lowercase e-mail address)
|
||||
* Operator==; based on the e-mail address only
|
||||
*
|
||||
* @param rhs some other Contact
|
||||
*
|
||||
* @return true orf false.
|
||||
* @return true or false.
|
||||
*/
|
||||
bool operator== (const Contact& rhs) const noexcept {
|
||||
return hash() == rhs.hash();
|
||||
return email == rhs.email;
|
||||
}
|
||||
/**
|
||||
* Operator!=
|
||||
*
|
||||
* @param rhs some other Contact
|
||||
*
|
||||
* @return true or false.
|
||||
*/
|
||||
bool operator!= (const Contact& rhs) const noexcept {
|
||||
return !(*this == rhs);
|
||||
}
|
||||
|
||||
static constexpr int64_t RecentOffset{15 * 24 * 3600};
|
||||
/**< Contacts seen after now - RecentOffset seconds are considered
|
||||
* "recent" */
|
||||
|
||||
/**
|
||||
* Get a hash-value for this contact, which gets lazily calculated. This
|
||||
* * is for use with container classes. This uses the _lowercase_ email
|
||||
* address.
|
||||
* operator<
|
||||
*
|
||||
* @return the hash
|
||||
* Less "relevant" contacts are smaller than more relevant.
|
||||
*
|
||||
* Used as a somewhat over-engineered way to sort by relevance
|
||||
*
|
||||
* This is currently used for the ordering in mu-cfind and
|
||||
* auto-completion in mu4e, if the various completion methods don't
|
||||
* override it...
|
||||
*
|
||||
* @param rhs some other contact
|
||||
*
|
||||
* @return true of false
|
||||
*/
|
||||
size_t hash() const {
|
||||
static size_t cached_hash;
|
||||
if (cached_hash == 0) {
|
||||
cached_hash = lowercase_hash(email);
|
||||
}
|
||||
return cached_hash;
|
||||
bool operator<(const Contact& rhs) const noexcept {
|
||||
// non-personal is less relevant.
|
||||
if (personal != rhs.personal)
|
||||
return personal < rhs.personal;
|
||||
// older is less relevant for recent messages
|
||||
if (message_date != rhs.message_date &&
|
||||
(message_date > recently() || rhs.message_date > recently()))
|
||||
return message_date < rhs.message_date;
|
||||
// less frequent is less relevant
|
||||
if (frequency != rhs.frequency)
|
||||
return frequency < rhs.frequency;
|
||||
// if all else fails, alphabetically
|
||||
return email < rhs.email;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -153,18 +170,16 @@ struct Contact {
|
||||
#pragma GCC diagnostic pop
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* data members
|
||||
*/
|
||||
|
||||
std::string email; /**< Email address for this contact.Not empty */
|
||||
std::string name; /**< Name for this contact; can be empty. */
|
||||
Type type; /**< Type of contact */
|
||||
int64_t message_date; /**< Date of the contact's message */
|
||||
bool personal; /**< A personal message? */
|
||||
size_t frequency; /**< Frequency of this contact */
|
||||
int64_t tstamp; /**< Timestamp for this contact (internal use) */
|
||||
std::string email{}; /**< Email address for this contact.Not empty */
|
||||
std::string name{}; /**< Name for this contact; can be empty. */
|
||||
Type type{Type::None};/**< Type of contact */
|
||||
int64_t message_date{}; /**< Date of the contact's message */
|
||||
bool personal{}; /**< A personal message? */
|
||||
size_t frequency{}; /**< Frequency of this contact */
|
||||
int64_t tstamp{}; /**< Timestamp for this contact (internal use) */
|
||||
|
||||
private:
|
||||
void cleanup_name() { // replace control characters by spaces.
|
||||
@ -172,6 +187,18 @@ private:
|
||||
if (iscntrl(c))
|
||||
c = ' ';
|
||||
}
|
||||
|
||||
/**
|
||||
* Oldest timestamp considered "recent"
|
||||
*
|
||||
* This is arbitrary of course
|
||||
*
|
||||
* @return timestamp
|
||||
*/
|
||||
static int64_t recently() {
|
||||
static const auto recent{::time({}) - RecentOffset};
|
||||
return recent;
|
||||
}
|
||||
};
|
||||
|
||||
constexpr Option<Contact::Type>
|
||||
@ -212,7 +239,7 @@ std::string to_string(const Contacts& contacts);
|
||||
*/
|
||||
template<> struct std::hash<Mu::Contact> {
|
||||
std::size_t operator()(const Mu::Contact& c) const noexcept {
|
||||
return c.hash();
|
||||
return std::hash<std::string>{}(c.email);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user