From 9f062ae482c7aeb82d89edd15c69c510daffef4f Mon Sep 17 00:00:00 2001 From: "Dirk-Jan C. Binnema" Date: Mon, 28 Mar 2022 22:14:05 +0300 Subject: [PATCH] message/flags: add flags_from_path Borrow from mu-maildir, to which we cannot link. --- lib/message/mu-flags.cc | 84 +++++++++++++++++++++++++++++++++++++++++ lib/message/mu-flags.hh | 15 +++++++- lib/mu-maildir.cc | 3 +- 3 files changed, 99 insertions(+), 3 deletions(-) diff --git a/lib/message/mu-flags.cc b/lib/message/mu-flags.cc index 05a5b0b3..7d3816a8 100644 --- a/lib/message/mu-flags.cc +++ b/lib/message/mu-flags.cc @@ -39,6 +39,90 @@ Mu::flags_to_string(Flags flags) } + +/* + * The file-components, ie. + * 1631819685.fb7b279bbb0a7b66.evergrey:2,RS + * => { + * "1631819685.fb7b279bbb0a7b66.evergrey", + * ':', + * "2,", + * "RS" + * } + */ +struct FileParts { + std::string base; + char separator; + std::string flags_suffix;; +}; + +static FileParts +message_file_parts(const std::string& file) +{ + const auto pos{file.find_last_of(":!;")}; + + /* no suffix at all? */ + if (pos == std::string::npos || + pos >= file.length() - 3 || + file[pos + 1] != '2' || + file[pos + 2] != ',') + return FileParts{ file, ':', {}}; + + return FileParts { + file.substr(0, pos), + file[pos], + file.substr(pos + 3) + }; +} + + +struct DirFile { + std::string dir; + std::string file; + bool is_new; +}; + +static Option +base_message_dir_file(const std::string& path) +{ + constexpr auto newdir{ G_DIR_SEPARATOR_S "new"}; + + if (path.empty()) + return Nothing; + + char *dirname{g_path_get_dirname(path.c_str())}; + bool is_new{!!g_str_has_suffix(dirname, newdir)}; + + std::string mdir{dirname, ::strlen(dirname) - 4}; + g_free(dirname); + + char *basename{g_path_get_basename(path.c_str())}; + std::string bname{basename}; + g_free(basename); + + return DirFile{std::move(mdir), std::move(bname), is_new}; +} + +Mu::Option +Mu::flags_from_path(const std::string& path) +{ /* + * this gets us the source maildir filesystem path, the directory + * in which new/ & cur/ lives, and the source file + */ + auto dirfile{base_message_dir_file(path)}; + if (!dirfile) + return Nothing; + + /* a message under new/ is just.. New. Filename is not considered */ + if (dirfile->is_new) + return Flags::New; + + /* it's cur/ message, so parse the file name */ + const auto parts{message_file_parts(dirfile->file)}; + return flags_from_absolute_expr(parts.flags_suffix, true/*ignore invalid*/); +} + + /* * flags & flag-info */ diff --git a/lib/message/mu-flags.hh b/lib/message/mu-flags.hh index 651ede73..dc8f5127 100644 --- a/lib/message/mu-flags.hh +++ b/lib/message/mu-flags.hh @@ -278,7 +278,7 @@ flags_from_delta_expr(std::string_view expr, Flags flags, * @return either messages flags or Nothing in case of error. */ constexpr Option -flags_from_expr(std::string_view expr, +flags_from_expr(std::string_view expr, Option flags = Nothing) { if (expr.empty()) @@ -291,6 +291,19 @@ flags_from_expr(std::string_view expr, return flags_from_absolute_expr(expr, true); } +/** + * Get the Maildir flags from the full path of a mailfile. The flags are as + * specified in http://cr.yp.to/proto/maildir.html, plus MU_MSG_FLAG_NEW for new + * messages, ie the ones that live in new/. The flags are logically OR'ed. Note + * that the file does not have to exist; the flags are based on the path only. + * + * @param pathname of a mailfile; it does not have to refer to an existing + * file/message + * + * @return the message flags or Nothing + */ +Option flags_from_path(const std::string& path); + /** * Filter out flags which are not in the given category * diff --git a/lib/mu-maildir.cc b/lib/mu-maildir.cc index 971422cf..e07591ee 100644 --- a/lib/mu-maildir.cc +++ b/lib/mu-maildir.cc @@ -305,8 +305,7 @@ base_message_dir_file(const std::string& path) return Ok(DirFile{std::move(mdir), std::move(bname), is_new}); } - - +// refactor: we have the same code in mu-flags.cc Mu::Result Mu::mu_maildir_flags_from_path(const std::string& path)