1 #include "MessageStore.hpp"
7 #include <fmt/format.h>
8 #include <fmt/ostream.h>
11 auto locate_maildir() -> fs::path
13 auto const maildir_ev
{getenv("MAILDIR")};
18 return osutil::get_home_dir() / "Maildir";
23 void MessageStore::open(std::string_view fqdn
,
24 std::streamsize max_size
,
25 std::string_view folder
)
27 auto maildir
= locate_maildir();
29 if (!folder
.empty()) {
33 newfn_
= maildir
/ "new";
34 tmpfn_
= maildir
/ "tmp";
35 tmp2fn_
= maildir
/ "tmp";
38 create_directories(newfn_
, ec
);
39 create_directories(tmpfn_
, ec
);
41 // Unique name, see: <https://cr.yp.to/proto/maildir.html>
43 fmt::format("{}.R{}.{}", then_
.sec(), s_
.as_string_view(), fqdn
)};
48 fmt::format("{}.R{}2.{}", then_
.sec(), s_
.as_string_view(), fqdn
)};
52 ofs_
.exceptions(std::ifstream::failbit
| std::ifstream::badbit
);
59 std::ostream
& MessageStore::write(char const* s
, std::streamsize count
)
61 if (!size_error_
&& (size_
+ count
) <= max_size_
) {
63 return ofs_
.write(s
, count
);
71 void MessageStore::try_close_()
77 catch (std::system_error
const& e
) {
78 LOG(ERROR
) << e
.what() << "code: " << e
.code();
80 catch (std::exception
const& e
) {
81 LOG(ERROR
) << e
.what();
85 std::string_view
MessageStore::freeze()
89 if (fs::exists(tmp2fn_
)) {
90 fs::remove(tmp2fn_
, ec
);
92 LOG(WARNING
) << "problem removing " << tmp2fn_
<< ": " << ec
;
95 rename(tmpfn_
, tmp2fn_
, ec
);
97 LOG(ERROR
) << "can't rename " << tmpfn_
<< " to " << tmp2fn_
<< ": " << ec
;
100 mapping_
.open(tmp2fn_
);
102 return std::string_view(mapping_
.data(), mapping_
.size());
105 void MessageStore::deliver()
108 LOG(WARNING
) << "message size error: " << size() << " exceeds "
115 rename(tmpfn_
, newfn_
, ec
);
117 LOG(ERROR
) << "can't rename " << tmpfn_
<< " to " << newfn_
<< ": " << ec
;
120 if (fs::exists(newfn_
)) {
121 LOG(INFO
) << "successfully deliverd " << newfn_
;
124 LOG(ERROR
) << "failed to deliver " << newfn_
;
128 void MessageStore::close()
133 fs::remove(tmpfn_
, ec
);
135 LOG(ERROR
) << "can't remove " << tmpfn_
<< ": " << ec
;
137 if (fs::exists(tmp2fn_
)) {
138 fs::remove(tmp2fn_
, ec
);
140 LOG(ERROR
) << "can't remove " << tmp2fn_
<< ": " << ec
;
143 if (mapping_
.is_open()) {