Archived
1
0
This repository has been archived on 2023-08-12. You can view files and clone it, but cannot push or open issues or pull requests.
nntpchan/contrib/backends/nntpchan-daemon/libnntpchan/staticfile_frontend.cpp
2017-10-13 07:58:41 -04:00

187 lines
5.4 KiB
C++

#include <nntpchan/staticfile_frontend.hpp>
#include <nntpchan/file_handle.hpp>
#include <nntpchan/sanitize.hpp>
#include <nntpchan/mime.hpp>
#include <nntpchan/sha1.hpp>
#include <any>
#include <iostream>
#include <set>
#include <sstream>
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
auto findMsgidFunc = [](const std::pair<std::string, std::string> & item) -> bool {
auto lower = ToLower(item.first);
return (lower == "message-id") || (lower == "messageid");
};
auto msgid_itr = std::find_if(header.begin(), header.end(), findMsgidFunc);
if(msgid_itr == std::end(header))
{
std::clog << "no message id for file " << fpath << std::endl;
return;
}
std::string msgid = StripWhitespaces(msgid_itr->second);
if(!IsValidMessageID(msgid))
{
std::clog << "invalid message-id: " << msgid << std::endl;
return;
}
std::string rootmsgid;
auto findReferences = [](const std::pair<std::string, std::string> & item) -> bool {
auto lower = ToLower(item.first);
return lower == "references";
};
auto references_itr = std::find_if(header.begin(), header.end(), findReferences);
if(references_itr == std::end(header) || StripWhitespaces(references_itr->second).size() == 0)
{
rootmsgid = msgid;
}
else
{
const auto & s = references_itr->second;
auto checkfunc = [] (unsigned char ch) -> bool { return std::isspace(ch) || std::iscntrl(ch); };
if(std::count_if(s.begin(), s.end(), checkfunc))
{
/** split off first element */
auto idx = std::find_if(s.begin(), s.end(), checkfunc);
rootmsgid = s.substr(0, s.find(*idx));
}
else
{
rootmsgid = references_itr->second;
}
}
std::string rootmsgid_hash = sha1_hex(rootmsgid);
fs::path threadFilePath = m_OutDir / fs::path("thread-" + rootmsgid_hash + ".html");
nntpchan::model::Thread thread;
if(!m_MessageDB)
{
std::clog << "no message database" << std::endl;
return;
}
if(!m_MessageDB->LoadThread(thread, rootmsgid))
{
std::clog << "cannot find thread with root " << rootmsgid << std::endl;
return;
}
TemplateEngine::Args_t thread_args;
thread_args["posts"] = thread;
if(m_TemplateEngine)
{
FileHandle_ptr out = OpenFile(threadFilePath, eWrite);
if(!out || !m_TemplateEngine->WriteTemplate("thread.mustache", thread_args, out))
{
std::clog << "failed to write " << threadFilePath << std::endl;
return;
}
}
std::set<std::string> newsgroups_list;
auto findNewsgroupsFunc = [](const std::pair<std::string, std::string> & 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);
}
nntpchan::model::BoardPage page;
for(const auto & name : newsgroups_list)
{
uint32_t pageno = 0;
while(pageno < m_Pages)
{
page.clear();
if(!m_MessageDB->LoadBoardPage(page, name, 10, m_Pages))
{
std::clog << "cannot load board page "<< pageno << " for " << name << std::endl;
break;
}
TemplateEngine::Args_t page_args;
page_args["group"] = name;
page_args["threads"] = page;
page_args["pageno"] = std::to_string(pageno);
if(pageno)
page_args["prev_pageno"] = std::to_string(pageno-1);
if(pageno+1 < m_Pages)
page_args["next_pageno"] = std::to_string(pageno+1);
fs::path boardPageFilename(name + "-" + std::to_string(pageno) + ".html");
if(m_TemplateEngine)
{
fs::path outfile = m_OutDir / boardPageFilename;
FileHandle_ptr out = OpenFile(outfile, eWrite);
if(out)
m_TemplateEngine->WriteTemplate("board.mustache", page_args, out);
else
std::clog << "failed to open board page " << outfile << std::endl;
}
++pageno;
}
}
}
}
bool StaticFileFrontend::AcceptsNewsgroup(const std::string & newsgroup)
{
return IsValidNewsgroup(newsgroup);
}
bool StaticFileFrontend::AcceptsMessage(const std::string & msgid)
{
return IsValidMessageID(msgid);
}
}