#include #include #include #include #include #include #include #include #include namespace nntpchan { StaticFileFrontend::StaticFileFrontend(TemplateEngine * tmpl, const std::string & templateDir, const std::string & outDir, uint32_t pages) : m_TemplateEngine(tmpl), m_TemplateDir(templateDir), m_OutDir(outDir), m_Pages(pages) { } void StaticFileFrontend::ProcessNewMessage(const fs::path & fpath) { std::clog << "process message " << fpath << std::endl; auto file = OpenFile(fpath, eRead); if(file) { // read header RawHeader header; if(!ReadHeader(file, header)) { std::clog << "failed to read mime header" << std::endl; return; } // read body std::map thread_args; auto findMsgidFunc = [](const std::pair & item) -> bool { auto lower = ToLower(item.first); return (lower == "message-id") || (lower == "messageid"); }; auto msgid = std::find_if(header.begin(), header.end(), findMsgidFunc); if(!IsValidMessageID(msgid->second)) { std::clog << "invalid message-id: " << msgid->second << std::endl; return; } std::string msgid_hash = sha1_hex(msgid->second); fs::path threadFilePath = m_OutDir / fs::path("thread-" + msgid_hash + ".html"); if(m_TemplateEngine) { FileHandle_ptr out = OpenFile(threadFilePath, eWrite); if(!m_TemplateEngine->WriteTemplate("thread.mustache", thread_args, out)) { std::clog << "failed to write " << threadFilePath << std::endl; return; } } std::set newsgroups_list; auto findNewsgroupsFunc = [](const std::pair & item) -> bool { return ToLower(item.first) == "newsgroups"; }; auto group = std::find_if(header.begin(), header.end(), findNewsgroupsFunc); if(group == std::end(header)) { std::clog << "no newsgroups header" << std::endl; return; } std::istringstream input(group->second); std::string newsgroup; while(std::getline(input, newsgroup, ' ')) { if(IsValidNewsgroup(newsgroup)) newsgroups_list.insert(newsgroup); } for(const auto & name : newsgroups_list) { auto board = GetThreadsPaginated(name, 10, m_Pages); uint32_t pageno = 0; for(Threads_t threads : board) { std::map board_args; board_args["group"] = std::make_any(name); board_args["pageno"] = std::make_any(pageno); board_args["threads"] = std::make_any(threads); fs::path boardPageFilename(newsgroup + "-" + std::to_string(pageno) + ".html"); if(m_TemplateEngine) { FileHandle_ptr out = OpenFile(m_OutDir / boardPageFilename, eWrite); m_TemplateEngine->WriteTemplate("board.mustache", board_args, out); } ++pageno; } } } } bool StaticFileFrontend::AcceptsNewsgroup(const std::string & newsgroup) { return IsValidNewsgroup(newsgroup); } bool StaticFileFrontend::AcceptsMessage(const std::string & msgid) { return IsValidMessageID(msgid); } StaticFileFrontend::BoardPage_t StaticFileFrontend::GetThreadsPaginated(const std::string & group, uint32_t perpage, uint32_t pages) { return {}; } }