mirror of https://github.com/djcb/mu.git
*: update code for Mu::MessageFlags
Migrate the code to use the new niceness
This commit is contained in:
parent
473134a7b1
commit
f6f17d5d6b
|
@ -17,6 +17,7 @@
|
||||||
**
|
**
|
||||||
*/
|
*/
|
||||||
#include "mu-guile-message.hh"
|
#include "mu-guile-message.hh"
|
||||||
|
#include "mu-message-flags.hh"
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
|
|
||||||
#include <glib-object.h>
|
#include <glib-object.h>
|
||||||
|
@ -40,9 +41,7 @@ using namespace Mu;
|
||||||
|
|
||||||
/* some symbols */
|
/* some symbols */
|
||||||
static SCM SYMB_PRIO_LOW, SYMB_PRIO_NORMAL, SYMB_PRIO_HIGH;
|
static SCM SYMB_PRIO_LOW, SYMB_PRIO_NORMAL, SYMB_PRIO_HIGH;
|
||||||
static SCM SYMB_FLAG_NEW, SYMB_FLAG_PASSED, SYMB_FLAG_REPLIED, SYMB_FLAG_SEEN, SYMB_FLAG_TRASHED,
|
static std::array<SCM, AllMessageFlagInfos.size()> SYMB_FLAGS;
|
||||||
SYMB_FLAG_DRAFT, SYMB_FLAG_FLAGGED, SYMB_FLAG_SIGNED, SYMB_FLAG_ENCRYPTED, SYMB_FLAG_HAS_ATTACH,
|
|
||||||
SYMB_FLAG_UNREAD, SYMB_FLAG_LIST;
|
|
||||||
static SCM SYMB_CONTACT_TO, SYMB_CONTACT_CC, SYMB_CONTACT_BCC, SYMB_CONTACT_FROM;
|
static SCM SYMB_CONTACT_TO, SYMB_CONTACT_CC, SYMB_CONTACT_BCC, SYMB_CONTACT_FROM;
|
||||||
|
|
||||||
struct _MuMsgWrapper {
|
struct _MuMsgWrapper {
|
||||||
|
@ -72,11 +71,10 @@ mu_guile_msg_to_scm(MuMsg* msg)
|
||||||
SCM_RETURN_NEWSMOB(MSG_TAG, msgwrap);
|
SCM_RETURN_NEWSMOB(MSG_TAG, msgwrap);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct _FlagData {
|
typedef struct {
|
||||||
MuFlags flags;
|
MessageFlags flags;
|
||||||
SCM lst;
|
SCM lst;
|
||||||
};
|
} FlagData;
|
||||||
typedef struct _FlagData FlagData;
|
|
||||||
|
|
||||||
#define MU_GUILE_INITIALIZED_OR_ERROR \
|
#define MU_GUILE_INITIALIZED_OR_ERROR \
|
||||||
do { \
|
do { \
|
||||||
|
@ -89,45 +87,20 @@ typedef struct _FlagData FlagData;
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
static void
|
|
||||||
check_flag(MuFlags flag, FlagData* fdata)
|
|
||||||
{
|
|
||||||
SCM flag_scm;
|
|
||||||
|
|
||||||
if (!(fdata->flags & flag))
|
|
||||||
return;
|
|
||||||
|
|
||||||
switch (flag) {
|
|
||||||
case MU_FLAG_NONE: flag_scm = SCM_UNDEFINED; break;
|
|
||||||
case MU_FLAG_NEW: flag_scm = SYMB_FLAG_NEW; break;
|
|
||||||
case MU_FLAG_PASSED: flag_scm = SYMB_FLAG_PASSED; break;
|
|
||||||
case MU_FLAG_REPLIED: flag_scm = SYMB_FLAG_REPLIED; break;
|
|
||||||
case MU_FLAG_SEEN: flag_scm = SYMB_FLAG_SEEN; break;
|
|
||||||
case MU_FLAG_TRASHED: flag_scm = SYMB_FLAG_TRASHED; break;
|
|
||||||
case MU_FLAG_SIGNED: flag_scm = SYMB_FLAG_SIGNED; break;
|
|
||||||
case MU_FLAG_DRAFT: flag_scm = SYMB_FLAG_DRAFT; break;
|
|
||||||
case MU_FLAG_FLAGGED: flag_scm = SYMB_FLAG_FLAGGED; break;
|
|
||||||
case MU_FLAG_ENCRYPTED: flag_scm = SYMB_FLAG_ENCRYPTED; break;
|
|
||||||
case MU_FLAG_HAS_ATTACH: flag_scm = SYMB_FLAG_HAS_ATTACH; break;
|
|
||||||
case MU_FLAG_UNREAD: flag_scm = SYMB_FLAG_UNREAD; break;
|
|
||||||
case MU_FLAG_LIST: flag_scm = SYMB_FLAG_LIST; break;
|
|
||||||
default: flag_scm = SCM_UNDEFINED;
|
|
||||||
}
|
|
||||||
|
|
||||||
fdata->lst = scm_append_x(scm_list_2(fdata->lst, scm_list_1(flag_scm)));
|
|
||||||
}
|
|
||||||
|
|
||||||
static SCM
|
static SCM
|
||||||
get_flags_scm(MuMsg* msg)
|
get_flags_scm(MuMsg* msg)
|
||||||
{
|
{
|
||||||
FlagData fdata;
|
SCM lst{SCM_EOL};
|
||||||
|
const auto flags{mu_msg_get_flags(msg)};
|
||||||
|
|
||||||
fdata.flags = mu_msg_get_flags(msg);
|
for (auto i = 0; i != AllMessageFlagInfos.size(); ++i) {
|
||||||
fdata.lst = SCM_EOL;
|
const auto& info{AllMessageFlagInfos.at(i)};
|
||||||
|
if (any_of(info.flag & flags))
|
||||||
|
scm_append_x(scm_list_2(lst, scm_list_1(SYMB_FLAGS.at(i))));
|
||||||
|
}
|
||||||
|
|
||||||
mu_flags_foreach((MuFlagsForeachFunc)check_flag, &fdata);
|
return lst;
|
||||||
|
|
||||||
return fdata.lst;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static SCM
|
static SCM
|
||||||
|
@ -488,19 +461,11 @@ define_symbols(void)
|
||||||
SYMB_PRIO_NORMAL = register_symbol("mu:prio:normal");
|
SYMB_PRIO_NORMAL = register_symbol("mu:prio:normal");
|
||||||
SYMB_PRIO_HIGH = register_symbol("mu:prio:high");
|
SYMB_PRIO_HIGH = register_symbol("mu:prio:high");
|
||||||
|
|
||||||
SYMB_FLAG_NEW = register_symbol("mu:flag:new");
|
for (auto i = 0U; i != AllMessageFlagInfos.size(); ++i) {
|
||||||
SYMB_FLAG_PASSED = register_symbol("mu:flag:passed");
|
const auto& info{AllMessageFlagInfos.at(i)};
|
||||||
SYMB_FLAG_REPLIED = register_symbol("mu:flag:replied");
|
const auto name = "mu:flag:" + std::string{info.name};
|
||||||
SYMB_FLAG_SEEN = register_symbol("mu:flag:seen");
|
SYMB_FLAGS[i] = register_symbol(name.c_str());
|
||||||
SYMB_FLAG_TRASHED = register_symbol("mu:flag:trashed");
|
}
|
||||||
SYMB_FLAG_DRAFT = register_symbol("mu:flag:draft");
|
|
||||||
SYMB_FLAG_FLAGGED = register_symbol("mu:flag:flagged");
|
|
||||||
SYMB_FLAG_SIGNED = register_symbol("mu:flag:signed");
|
|
||||||
SYMB_FLAG_ENCRYPTED = register_symbol("mu:flag:encrypted");
|
|
||||||
SYMB_FLAG_HAS_ATTACH = register_symbol("mu:flag:has-attach");
|
|
||||||
SYMB_FLAG_UNREAD = register_symbol("mu:flag:unread");
|
|
||||||
|
|
||||||
SYMB_FLAG_LIST = register_symbol("mu:flag:list");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct {
|
static struct {
|
||||||
|
|
|
@ -344,15 +344,15 @@ looks_like_attachment(GMimeObject* part)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
msg_cflags_cb(GMimeObject* parent, GMimeObject* part, MuFlags* flags)
|
msg_cflags_cb(GMimeObject* parent, GMimeObject* part, MessageFlags* flags)
|
||||||
{
|
{
|
||||||
if (GMIME_IS_MULTIPART_SIGNED(part))
|
if (GMIME_IS_MULTIPART_SIGNED(part))
|
||||||
*flags |= MU_FLAG_SIGNED;
|
*flags |= MessageFlags::Signed;
|
||||||
|
|
||||||
/* FIXME: An encrypted part might be signed at the same time.
|
/* FIXME: An encrypted part might be signed at the same time.
|
||||||
* In that case the signed flag is lost. */
|
* In that case the signed flag is lost. */
|
||||||
if (GMIME_IS_MULTIPART_ENCRYPTED(part))
|
if (GMIME_IS_MULTIPART_ENCRYPTED(part))
|
||||||
*flags |= MU_FLAG_ENCRYPTED;
|
*flags |= MessageFlags::Encrypted;
|
||||||
|
|
||||||
/* smime */
|
/* smime */
|
||||||
if (GMIME_IS_APPLICATION_PKCS7_MIME(part)) {
|
if (GMIME_IS_APPLICATION_PKCS7_MIME(part)) {
|
||||||
|
@ -361,10 +361,10 @@ msg_cflags_cb(GMimeObject* parent, GMimeObject* part, MuFlags* flags)
|
||||||
if (pkcs7) {
|
if (pkcs7) {
|
||||||
switch(pkcs7->smime_type) {
|
switch(pkcs7->smime_type) {
|
||||||
case GMIME_SECURE_MIME_TYPE_ENVELOPED_DATA:
|
case GMIME_SECURE_MIME_TYPE_ENVELOPED_DATA:
|
||||||
*flags |= MU_FLAG_ENCRYPTED;
|
*flags |= MessageFlags::Encrypted;
|
||||||
break;
|
break;
|
||||||
case GMIME_SECURE_MIME_TYPE_SIGNED_DATA:
|
case GMIME_SECURE_MIME_TYPE_SIGNED_DATA:
|
||||||
*flags |= MU_FLAG_SIGNED;
|
*flags |= MessageFlags::Signed;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -372,27 +372,20 @@ msg_cflags_cb(GMimeObject* parent, GMimeObject* part, MuFlags* flags)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*flags & MU_FLAG_HAS_ATTACH)
|
if (any_of(*flags & MessageFlags::HasAttachment))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!GMIME_IS_PART(part))
|
if (!GMIME_IS_PART(part))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (*flags & MU_FLAG_HAS_ATTACH)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (looks_like_attachment(part))
|
if (looks_like_attachment(part))
|
||||||
*flags |= MU_FLAG_HAS_ATTACH;
|
*flags |= MessageFlags::HasAttachment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static MessageFlags
|
||||||
static MuFlags
|
|
||||||
get_content_flags(MuMsgFile* self)
|
get_content_flags(MuMsgFile* self)
|
||||||
{
|
{
|
||||||
MuFlags flags;
|
MessageFlags flags{MessageFlags::None};
|
||||||
char* ml;
|
|
||||||
|
|
||||||
flags = MU_FLAG_NONE;
|
|
||||||
|
|
||||||
if (GMIME_IS_MESSAGE(self->_mime_msg)) {
|
if (GMIME_IS_MESSAGE(self->_mime_msg)) {
|
||||||
/* toplevel */
|
/* toplevel */
|
||||||
|
@ -404,29 +397,29 @@ get_content_flags(MuMsgFile* self)
|
||||||
&flags);
|
&flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
ml = get_mailing_list(self);
|
char *ml{get_mailing_list(self)};
|
||||||
if (ml) {
|
if (ml) {
|
||||||
flags |= MU_FLAG_LIST;
|
flags |= MessageFlags::MailingList;
|
||||||
g_free(ml);
|
g_free(ml);
|
||||||
}
|
}
|
||||||
|
|
||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
static MuFlags
|
static MessageFlags
|
||||||
get_flags(MuMsgFile* self)
|
get_flags(MuMsgFile* self)
|
||||||
{
|
{
|
||||||
MuFlags flags;
|
g_return_val_if_fail(self, MessageFlags::None);
|
||||||
|
|
||||||
g_return_val_if_fail(self, MU_FLAG_INVALID);
|
auto flags{mu_maildir_flags_from_path(self->_path)
|
||||||
|
.value_or(MessageFlags::None)};
|
||||||
flags = mu_maildir_get_flags_from_path(self->_path);
|
|
||||||
flags |= get_content_flags(self);
|
flags |= get_content_flags(self);
|
||||||
|
|
||||||
/* pseudo-flag --> unread means either NEW or NOT SEEN, just
|
/* pseudo-flag --> unread means either NEW or NOT SEEN, just
|
||||||
* for searching convenience */
|
* for searching convenience */
|
||||||
if ((flags & MU_FLAG_NEW) || !(flags & MU_FLAG_SEEN))
|
if (any_of(flags & MessageFlags::New) ||
|
||||||
flags |= MU_FLAG_UNREAD;
|
none_of(flags & MessageFlags::Seen))
|
||||||
|
flags |= MessageFlags::Unread;
|
||||||
|
|
||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#include "mu-message-flags.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"
|
||||||
|
@ -138,27 +139,19 @@ add_contacts(Sexp::List& list, MuMsg* msg)
|
||||||
add_list_post(list, msg);
|
add_list_post(list, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
Sexp::List flaglist;
|
|
||||||
MuFlags msgflags;
|
|
||||||
} FlagData;
|
|
||||||
|
|
||||||
static void
|
|
||||||
each_flag(MuFlags flag, FlagData* fdata)
|
|
||||||
{
|
|
||||||
if (flag & fdata->msgflags)
|
|
||||||
fdata->flaglist.add(Sexp::make_symbol(mu_flag_name(flag)));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
add_flags(Sexp::List& list, MuMsg* msg)
|
add_flags(Sexp::List& list, MuMsg* msg)
|
||||||
{
|
{
|
||||||
FlagData fdata{};
|
Sexp::List flaglist;
|
||||||
fdata.msgflags = mu_msg_get_flags(msg);
|
const auto flags{mu_msg_get_flags(msg)};
|
||||||
|
for (auto&& info: AllMessageFlagInfos)
|
||||||
|
if (any_of(flags & info.flag))
|
||||||
|
flaglist.add(Sexp::make_symbol_sv(info.name));
|
||||||
|
|
||||||
mu_flags_foreach((MuFlagsForeachFunc)each_flag, &fdata);
|
if (!flaglist.empty())
|
||||||
if (!fdata.flaglist.empty())
|
list.add_prop(":flags", Sexp::make_list(std::move(flaglist)));
|
||||||
list.add_prop(":flags", Sexp::make_list(std::move(fdata.flaglist)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static char*
|
static char*
|
||||||
|
|
|
@ -20,9 +20,12 @@
|
||||||
#ifndef MU_MSG_HH__
|
#ifndef MU_MSG_HH__
|
||||||
#define MU_MSG_HH__
|
#define MU_MSG_HH__
|
||||||
|
|
||||||
#include <mu-flags.hh>
|
#include <utils/mu-result.hh>
|
||||||
#include <mu-msg-fields.h>
|
|
||||||
|
#include <mu-message-flags.hh>
|
||||||
#include <mu-message-priority.hh>
|
#include <mu-message-priority.hh>
|
||||||
|
|
||||||
|
#include <mu-msg-fields.h>
|
||||||
#include <utils/mu-util.h>
|
#include <utils/mu-util.h>
|
||||||
#include <utils/mu-utils.hh>
|
#include <utils/mu-utils.hh>
|
||||||
#include <utils/mu-option.hh>
|
#include <utils/mu-option.hh>
|
||||||
|
@ -294,10 +297,10 @@ time_t mu_msg_get_date(MuMsg* msg);
|
||||||
*
|
*
|
||||||
* @param msg valid MuMsg* instance
|
* @param msg valid MuMsg* instance
|
||||||
*
|
*
|
||||||
* @return the file/content flags as logically OR'd #MuMsgFlags or 0
|
* @return the file/content flags as logically OR'd #Mu::MessageFlags.
|
||||||
* if there are none. Non-standard flags are ignored.
|
* Non-standard flags are ignored.
|
||||||
*/
|
*/
|
||||||
MuFlags mu_msg_get_flags(MuMsg* msg);
|
MessageFlags mu_msg_get_flags(MuMsg* msg);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get the file size in bytes of this message
|
* get the file size in bytes of this message
|
||||||
|
@ -417,39 +420,25 @@ gboolean mu_msg_is_readable(MuMsg* self);
|
||||||
*
|
*
|
||||||
* @param msg a message with an existing file system path in an actual
|
* @param msg a message with an existing file system path in an actual
|
||||||
* maildir
|
* maildir
|
||||||
* @param maildir the subdir where the message should go, relative to
|
* @param root_maildir_path file system path for the root-maildir for this message
|
||||||
|
* e.g., /home/user/Maildir
|
||||||
|
* @param target_maildir the subdir where the message should go, relative to
|
||||||
* rootmaildir. e.g. "/archive"
|
* rootmaildir. e.g. "/archive"
|
||||||
* @param flags to set for the target (influences the filename, path)
|
* @param flags to set for the target (influences the filename, path)
|
||||||
* @param silently ignore the src=target case (return TRUE)
|
* @param silently ignore the src=target case (return TRUE)
|
||||||
* @param new_name whether to create a new unique name, or keep the
|
* @param new_name whether to create a new unique name, or keep the
|
||||||
* old one
|
* old one
|
||||||
* @param err (may be NULL) may contain error information; note if the
|
* @param err receives error information
|
||||||
* function return FALSE, err is not set for all error condition
|
|
||||||
* (ie. not for parameter error
|
|
||||||
*
|
*
|
||||||
* @return TRUE if it worked, FALSE otherwise
|
* @return TRUE if it worked, FALSE otherwise
|
||||||
*/
|
*/
|
||||||
gboolean mu_msg_move_to_maildir(MuMsg* msg,
|
bool mu_msg_move_to_maildir(MuMsg* msg,
|
||||||
const char* maildir,
|
const std::string& root_maildir_path,
|
||||||
MuFlags flags,
|
const std::string& target_maildir,
|
||||||
gboolean ignore_dups,
|
MessageFlags flags,
|
||||||
gboolean new_name,
|
bool ignore_dups,
|
||||||
GError** err);
|
bool new_name,
|
||||||
|
GError** err);
|
||||||
/**
|
|
||||||
* Tickle a message -- ie., rename a message to some new semi-random name,while
|
|
||||||
* maintaining the maildir and flags. This can be useful when dealing with
|
|
||||||
* third-party tools such as mbsync that depend on changed filenames.
|
|
||||||
*
|
|
||||||
* @param msg a message with an existing file system path in an actual
|
|
||||||
* maildir
|
|
||||||
* @param err (may be NULL) may contain error information; note if the
|
|
||||||
* function return FALSE, err is not set for all error condition
|
|
||||||
* (ie. not for parameter error
|
|
||||||
*
|
|
||||||
* @return TRUE if it worked, FALSE otherwise
|
|
||||||
*/
|
|
||||||
gboolean mu_msg_tickle(MuMsg* msg, GError** err);
|
|
||||||
|
|
||||||
enum _MuMsgContactType { /* Reply-To:? */
|
enum _MuMsgContactType { /* Reply-To:? */
|
||||||
MU_MSG_CONTACT_TYPE_TO = 0,
|
MU_MSG_CONTACT_TYPE_TO = 0,
|
||||||
|
@ -545,24 +534,6 @@ void mu_msg_contact_foreach(MuMsg* msg, MuMsgContactForeachFunc func, gpointer u
|
||||||
const char* mu_str_display_contact_s(const char* str) G_GNUC_CONST;
|
const char* mu_str_display_contact_s(const char* str) G_GNUC_CONST;
|
||||||
char* mu_str_display_contact(const char* str) G_GNUC_WARN_UNUSED_RESULT;
|
char* mu_str_display_contact(const char* str) G_GNUC_WARN_UNUSED_RESULT;
|
||||||
|
|
||||||
/**
|
|
||||||
* get a display string for a given set of flags, OR'ed in
|
|
||||||
* @param flags; one character per flag:
|
|
||||||
* D=draft,F=flagged,N=new,P=passed,R=replied,S=seen,T=trashed
|
|
||||||
* a=has-attachment,s=signed, x=encrypted
|
|
||||||
*
|
|
||||||
* mu_str_file_flags_s returns a ptr to a static buffer,
|
|
||||||
* while mu_str_file_flags returns dynamically allocated
|
|
||||||
* memory that must be freed after use.
|
|
||||||
*
|
|
||||||
* @param flags file flags
|
|
||||||
*
|
|
||||||
* @return a string representation of the flags; see above
|
|
||||||
* for what to do with it
|
|
||||||
*/
|
|
||||||
const char* mu_str_flags_s(MuFlags flags) G_GNUC_CONST;
|
|
||||||
char* mu_str_flags(MuFlags flags) G_GNUC_MALLOC G_GNUC_WARN_UNUSED_RESULT;
|
|
||||||
|
|
||||||
struct QueryMatch;
|
struct QueryMatch;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -116,13 +116,13 @@ process_value(const std::string& field, const std::string& value)
|
||||||
return std::string(1, value[0]);
|
return std::string(1, value[0]);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case MU_MSG_FIELD_ID_FLAGS: {
|
case MU_MSG_FIELD_ID_FLAGS:
|
||||||
const auto flag = mu_flag_char_from_name(value.c_str());
|
if (const auto info{message_flag_info(value)}; info)
|
||||||
if (flag)
|
return std::string(1, ::tolower(info->shortcut));
|
||||||
return std::string(1, tolower(flag));
|
break;
|
||||||
} break;
|
|
||||||
|
|
||||||
default: break;
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return value; // XXX prio/flags, etc. alias
|
return value; // XXX prio/flags, etc. alias
|
||||||
|
|
105
lib/mu-store.cc
105
lib/mu-store.cc
|
@ -35,6 +35,8 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <xapian.h>
|
#include <xapian.h>
|
||||||
|
|
||||||
|
#include "mu-message-flags.hh"
|
||||||
|
#include "mu-msg-fields.h"
|
||||||
#include "mu-store.hh"
|
#include "mu-store.hh"
|
||||||
#include "mu-query.hh"
|
#include "mu-query.hh"
|
||||||
#include "utils/mu-str.h"
|
#include "utils/mu-str.h"
|
||||||
|
@ -62,6 +64,36 @@ constexpr auto DefaultMaxMessageSize = 100'000'000U;
|
||||||
|
|
||||||
constexpr auto ExpectedSchemaVersion = MU_STORE_SCHEMA_VERSION;
|
constexpr auto ExpectedSchemaVersion = MU_STORE_SCHEMA_VERSION;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* calculate a 64-bit hash for the given string, based on a combination of the
|
||||||
|
* DJB and BKDR hash functions.
|
||||||
|
*
|
||||||
|
* @param a string
|
||||||
|
*
|
||||||
|
* @return the hash
|
||||||
|
*/
|
||||||
|
size_t get_hash64 (const char* str)
|
||||||
|
{
|
||||||
|
guint32 djbhash;
|
||||||
|
guint32 bkdrhash;
|
||||||
|
guint32 bkdrseed;
|
||||||
|
guint64 hash;
|
||||||
|
|
||||||
|
djbhash = 5381;
|
||||||
|
bkdrhash = 0;
|
||||||
|
bkdrseed = 1313;
|
||||||
|
|
||||||
|
for(unsigned u = 0U; str[u]; ++u) {
|
||||||
|
djbhash = ((djbhash << 5) + djbhash) + str[u];
|
||||||
|
bkdrhash = bkdrhash * bkdrseed + str[u];
|
||||||
|
}
|
||||||
|
|
||||||
|
hash = djbhash;
|
||||||
|
return (hash<<32) | bkdrhash;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* we cache these prefix strings, so we don't have to allocate them all
|
/* we cache these prefix strings, so we don't have to allocate them all
|
||||||
* the time; this should save 10-20 string allocs per message */
|
* the time; this should save 10-20 string allocs per message */
|
||||||
G_GNUC_CONST static const std::string&
|
G_GNUC_CONST static const std::string&
|
||||||
|
@ -79,16 +111,6 @@ prefix(MuMsgFieldId mfid)
|
||||||
return fields[mfid];
|
return fields[mfid];
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
add_synonym_for_flag(MuFlags flag, Xapian::WritableDatabase* db)
|
|
||||||
{
|
|
||||||
static const std::string pfx(prefix(MU_MSG_FIELD_ID_FLAGS));
|
|
||||||
|
|
||||||
db->clear_synonyms(pfx + mu_flag_name(flag));
|
|
||||||
db->add_synonym(pfx + mu_flag_name(flag),
|
|
||||||
pfx + (std::string(1, (char)(tolower(mu_flag_char(flag))))));
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Store::Private {
|
struct Store::Private {
|
||||||
enum struct XapianOpts { ReadOnly, Open, CreateOverwrite, InMemory };
|
enum struct XapianOpts { ReadOnly, Open, CreateOverwrite, InMemory };
|
||||||
|
|
||||||
|
@ -207,8 +229,13 @@ struct Store::Private {
|
||||||
|
|
||||||
void add_synonyms()
|
void add_synonyms()
|
||||||
{
|
{
|
||||||
mu_flags_foreach((MuFlagsForeachFunc)add_synonym_for_flag,
|
for (auto&& info: AllMessageFlagInfos) {
|
||||||
&writable_db());
|
const auto s1{prefix(MU_MSG_FIELD_ID_FLAGS) + std::string{info.name}};
|
||||||
|
const auto s2{prefix(MU_MSG_FIELD_ID_FLAGS) + std::string{1,info.shortcut}};
|
||||||
|
writable_db().clear_synonyms(s1);
|
||||||
|
writable_db().clear_synonyms(s2);
|
||||||
|
writable_db().add_synonym(s1, s2);
|
||||||
|
}
|
||||||
|
|
||||||
for (auto&& prio : AllMessagePriorities) {
|
for (auto&& prio : AllMessagePriorities) {
|
||||||
const auto s1{prefix(MU_MSG_FIELD_ID_PRIO) + to_string(prio)};
|
const auto s1{prefix(MU_MSG_FIELD_ID_PRIO) + to_string(prio)};
|
||||||
|
@ -293,7 +320,7 @@ struct Store::Private {
|
||||||
static void
|
static void
|
||||||
hash_str(char* buf, size_t buf_size, const char* data)
|
hash_str(char* buf, size_t buf_size, const char* data)
|
||||||
{
|
{
|
||||||
g_snprintf(buf, buf_size, "016%" PRIx64, mu_util_get_hash(data));
|
g_snprintf(buf, buf_size, "016%" PRIx64, get_hash64(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string
|
static std::string
|
||||||
|
@ -687,45 +714,6 @@ add_terms_values_size(Xapian::Document& doc, MuMsg* msg, MuMsgFieldId mfid)
|
||||||
doc.add_value((Xapian::valueno)mfid, szstr);
|
doc.add_value((Xapian::valueno)mfid, szstr);
|
||||||
}
|
}
|
||||||
|
|
||||||
G_GNUC_CONST
|
|
||||||
static const std::string&
|
|
||||||
flag_val(char flagchar)
|
|
||||||
{
|
|
||||||
static const std::string pfx(prefix(MU_MSG_FIELD_ID_FLAGS)),
|
|
||||||
draftstr(pfx + (char)tolower(mu_flag_char(MU_FLAG_DRAFT))),
|
|
||||||
flaggedstr(pfx + (char)tolower(mu_flag_char(MU_FLAG_FLAGGED))),
|
|
||||||
passedstr(pfx + (char)tolower(mu_flag_char(MU_FLAG_PASSED))),
|
|
||||||
repliedstr(pfx + (char)tolower(mu_flag_char(MU_FLAG_REPLIED))),
|
|
||||||
seenstr(pfx + (char)tolower(mu_flag_char(MU_FLAG_SEEN))),
|
|
||||||
trashedstr(pfx + (char)tolower(mu_flag_char(MU_FLAG_TRASHED))),
|
|
||||||
newstr(pfx + (char)tolower(mu_flag_char(MU_FLAG_NEW))),
|
|
||||||
signedstr(pfx + (char)tolower(mu_flag_char(MU_FLAG_SIGNED))),
|
|
||||||
cryptstr(pfx + (char)tolower(mu_flag_char(MU_FLAG_ENCRYPTED))),
|
|
||||||
attachstr(pfx + (char)tolower(mu_flag_char(MU_FLAG_HAS_ATTACH))),
|
|
||||||
unreadstr(pfx + (char)tolower(mu_flag_char(MU_FLAG_UNREAD))),
|
|
||||||
liststr(pfx + (char)tolower(mu_flag_char(MU_FLAG_LIST)));
|
|
||||||
|
|
||||||
switch (flagchar) {
|
|
||||||
case 'D': return draftstr;
|
|
||||||
case 'F': return flaggedstr;
|
|
||||||
case 'P': return passedstr;
|
|
||||||
case 'R': return repliedstr;
|
|
||||||
case 'S': return seenstr;
|
|
||||||
case 'T': return trashedstr;
|
|
||||||
|
|
||||||
case 'N': return newstr;
|
|
||||||
|
|
||||||
case 'z': return signedstr;
|
|
||||||
case 'x': return cryptstr;
|
|
||||||
case 'a': return attachstr;
|
|
||||||
case 'l': return liststr;
|
|
||||||
|
|
||||||
case 'u': return unreadstr;
|
|
||||||
|
|
||||||
default: g_return_val_if_reached(flaggedstr); return flaggedstr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static const std::string&
|
static const std::string&
|
||||||
prio_val(MessagePriority prio)
|
prio_val(MessagePriority prio)
|
||||||
{
|
{
|
||||||
|
@ -760,13 +748,12 @@ add_terms_values_number(Xapian::Document& doc, MuMsg* msg, MuMsgFieldId mfid)
|
||||||
doc.add_value((Xapian::valueno)mfid, numstr);
|
doc.add_value((Xapian::valueno)mfid, numstr);
|
||||||
|
|
||||||
if (mfid == MU_MSG_FIELD_ID_FLAGS) {
|
if (mfid == MU_MSG_FIELD_ID_FLAGS) {
|
||||||
const char* cur = mu_flags_to_str_s((MuFlags)num, (MuFlagType)MU_FLAG_TYPE_ANY);
|
static const std::string pfx(prefix(MU_MSG_FIELD_ID_FLAGS));
|
||||||
g_return_if_fail(cur);
|
const auto flags{static_cast<MessageFlags>(num)};
|
||||||
while (*cur) {
|
for (auto&& info: AllMessageFlagInfos) {
|
||||||
add_term(doc, flag_val(*cur));
|
if (any_of(info.flag & flags))
|
||||||
++cur;
|
add_term(doc, pfx + static_cast<char>(::tolower(info.shortcut)));
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (mfid == MU_MSG_FIELD_ID_PRIO)
|
} else if (mfid == MU_MSG_FIELD_ID_PRIO)
|
||||||
add_term(doc, prio_val(static_cast<MessagePriority>(num)));
|
add_term(doc, prio_val(static_cast<MessagePriority>(num)));
|
||||||
}
|
}
|
||||||
|
@ -893,7 +880,7 @@ add_terms_values_attach(Xapian::Document& doc, MuMsg* msg, MuMsgFieldId mfid)
|
||||||
static void
|
static void
|
||||||
add_terms_values_body(Xapian::Document& doc, MuMsg* msg, MuMsgFieldId mfid)
|
add_terms_values_body(Xapian::Document& doc, MuMsg* msg, MuMsgFieldId mfid)
|
||||||
{
|
{
|
||||||
if (mu_msg_get_flags(msg) & MU_FLAG_ENCRYPTED)
|
if (any_of(mu_msg_get_flags(msg) & MessageFlags::Encrypted))
|
||||||
return; /* ignore encrypted bodies */
|
return; /* ignore encrypted bodies */
|
||||||
|
|
||||||
auto str = mu_msg_get_body_text(msg, MU_MSG_OPTION_NONE);
|
auto str = mu_msg_get_body_text(msg, MU_MSG_OPTION_NONE);
|
||||||
|
|
|
@ -43,11 +43,6 @@ test('test_query',
|
||||||
'test-query.cc',
|
'test-query.cc',
|
||||||
install: false,
|
install: false,
|
||||||
dependencies: [glib_dep, lib_mu_dep, lib_test_mu_common_dep]))
|
dependencies: [glib_dep, lib_mu_dep, lib_test_mu_common_dep]))
|
||||||
test('test_flags',
|
|
||||||
executable('test-flags',
|
|
||||||
'test-mu-flags.cc',
|
|
||||||
install: false,
|
|
||||||
dependencies: [glib_dep, lib_mu_dep, lib_test_mu_common_dep]))
|
|
||||||
|
|
||||||
test('test_tokenizer',
|
test('test_tokenizer',
|
||||||
executable('test-tokenizer',
|
executable('test-tokenizer',
|
||||||
|
|
|
@ -145,7 +145,8 @@ test_mu_msg_02(void)
|
||||||
i = 0;
|
i = 0;
|
||||||
mu_msg_contact_foreach(msg, (MuMsgContactForeachFunc)check_contact_02, &i);
|
mu_msg_contact_foreach(msg, (MuMsgContactForeachFunc)check_contact_02, &i);
|
||||||
g_assert_cmpint(i, ==, 2);
|
g_assert_cmpint(i, ==, 2);
|
||||||
g_assert_cmpuint(mu_msg_get_flags(msg), ==, MU_FLAG_SEEN | MU_FLAG_LIST);
|
g_print("flags: %s\n", Mu::message_flags_to_string(mu_msg_get_flags(msg)).c_str());
|
||||||
|
g_assert_true(mu_msg_get_flags(msg) == (MessageFlags::Seen|MessageFlags::MailingList));
|
||||||
|
|
||||||
mu_msg_unref(msg);
|
mu_msg_unref(msg);
|
||||||
}
|
}
|
||||||
|
@ -173,9 +174,7 @@ test_mu_msg_03(void)
|
||||||
g_assert_cmpstr((char*)params->data, ==, "charset");
|
g_assert_cmpstr((char*)params->data, ==, "charset");
|
||||||
params = g_slist_next(params);
|
params = g_slist_next(params);
|
||||||
g_assert_cmpstr((char*)params->data, ==, "UTF-8");
|
g_assert_cmpstr((char*)params->data, ==, "UTF-8");
|
||||||
|
g_assert_true(mu_msg_get_flags(msg) == (MessageFlags::Unread));
|
||||||
g_assert_cmpuint(mu_msg_get_flags(msg), ==, MU_FLAG_UNREAD); /* not seen => unread */
|
|
||||||
|
|
||||||
mu_msg_unref(msg);
|
mu_msg_unref(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,7 +190,11 @@ test_mu_msg_04(void)
|
||||||
g_assert_true(mu_msg_get_prio(msg) /* 'low' */
|
g_assert_true(mu_msg_get_prio(msg) /* 'low' */
|
||||||
== Mu::MessagePriority::Normal);
|
== Mu::MessagePriority::Normal);
|
||||||
g_assert_cmpuint(mu_msg_get_date(msg), ==, 0);
|
g_assert_cmpuint(mu_msg_get_date(msg), ==, 0);
|
||||||
g_assert_cmpuint(mu_msg_get_flags(msg), ==, MU_FLAG_HAS_ATTACH | MU_FLAG_UNREAD);
|
g_assert_true(mu_msg_get_flags(msg) ==
|
||||||
|
(MessageFlags::HasAttachment|MessageFlags::Unread));
|
||||||
|
|
||||||
|
g_assert_true(mu_msg_get_flags(msg) ==
|
||||||
|
(MessageFlags::HasAttachment|MessageFlags::Unread));
|
||||||
mu_msg_unref(msg);
|
mu_msg_unref(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,9 +207,9 @@ test_mu_msg_multimime(void)
|
||||||
/* ie., are text parts properly concatenated? */
|
/* ie., are text parts properly concatenated? */
|
||||||
g_assert_cmpstr(mu_msg_get_subject(msg), ==, "multimime");
|
g_assert_cmpstr(mu_msg_get_subject(msg), ==, "multimime");
|
||||||
g_assert_cmpstr(mu_msg_get_body_text(msg, MU_MSG_OPTION_NONE), ==, "abcdef");
|
g_assert_cmpstr(mu_msg_get_body_text(msg, MU_MSG_OPTION_NONE), ==, "abcdef");
|
||||||
g_assert_cmpuint(mu_msg_get_flags(msg),
|
g_assert_true(mu_msg_get_flags(msg) ==
|
||||||
==,
|
(MessageFlags::HasAttachment|MessageFlags::Flagged|MessageFlags::Seen));
|
||||||
(MuFlags)(MU_FLAG_FLAGGED | MU_FLAG_SEEN | MU_FLAG_HAS_ATTACH));
|
|
||||||
mu_msg_unref(msg);
|
mu_msg_unref(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,29 +219,21 @@ test_mu_msg_flags(void)
|
||||||
unsigned u;
|
unsigned u;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
const char* path;
|
const char* path;
|
||||||
MuFlags flags;
|
MessageFlags flags;
|
||||||
} msgflags[] = {{MU_TESTMAILDIR4 "/multimime!2,FS",
|
} msgflags[] = {{MU_TESTMAILDIR4 "/multimime!2,FS",
|
||||||
(MuFlags)(MU_FLAG_FLAGGED | MU_FLAG_SEEN | MU_FLAG_HAS_ATTACH)},
|
(MessageFlags::Flagged | MessageFlags::Seen |
|
||||||
{MU_TESTMAILDIR4 "/special!2,Sabc", MU_FLAG_SEEN}
|
MessageFlags::HasAttachment)},
|
||||||
|
{MU_TESTMAILDIR4 "/special!2,Sabc",
|
||||||
|
(MessageFlags::Seen|MessageFlags::HasAttachment)}
|
||||||
};
|
};
|
||||||
|
|
||||||
for (u = 0; u != G_N_ELEMENTS(msgflags); ++u) {
|
for (u = 0; u != G_N_ELEMENTS(msgflags); ++u) {
|
||||||
MuMsg* msg;
|
MuMsg* msg;
|
||||||
MuFlags flags;
|
|
||||||
|
|
||||||
g_assert((msg = get_msg(msgflags[u].path)));
|
g_assert((msg = get_msg(msgflags[u].path)));
|
||||||
flags = mu_msg_get_flags(msg);
|
const auto flags{mu_msg_get_flags(msg)};
|
||||||
|
//g_print("flags: %s\n", Mu::message_flags_to_string(flags).c_str());
|
||||||
if (g_test_verbose())
|
g_assert_true(flags == msgflags[u].flags);
|
||||||
g_print("=> %s [ %s, %u] <=> [ %s, %u]\n",
|
|
||||||
msgflags[u].path,
|
|
||||||
mu_flags_to_str_s(msgflags[u].flags, MU_FLAG_TYPE_ANY),
|
|
||||||
(unsigned)msgflags[u].flags,
|
|
||||||
mu_flags_to_str_s(flags, MU_FLAG_TYPE_ANY),
|
|
||||||
(unsigned)flags);
|
|
||||||
g_assert_cmpuint(flags, ==, msgflags[u].flags);
|
|
||||||
mu_msg_unref(msg);
|
mu_msg_unref(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue