From e67e7a20bd2ddc093ab5a106a64cd8a05c1194b9 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Mon, 9 Oct 2017 11:48:10 -0400 Subject: [PATCH] * more nntpchan-daemon code * fix keepalive --- contrib/backends/nntpchan-daemon/Makefile | 12 +- contrib/backends/nntpchan-daemon/README.md | 19 + .../backends/nntpchan-daemon/daemon/main.cpp | 40 ++- .../{src => libnntpchan}/base64.cpp | 0 .../{src => libnntpchan}/base64.hpp | 0 .../{src => libnntpchan}/buffer.cpp | 0 .../{src => libnntpchan}/buffer.hpp | 0 .../{src => libnntpchan}/crypto.cpp | 0 .../{src => libnntpchan}/crypto.hpp | 0 .../libnntpchan/crypto_old.hpp | 44 +++ .../{src => libnntpchan}/event.cpp | 0 .../{src => libnntpchan}/event.hpp | 0 .../{src => libnntpchan}/exec_frontend.cpp | 2 +- .../{src => libnntpchan}/exec_frontend.hpp | 2 +- .../libnntpchan/file_handle.cpp | 22 ++ .../libnntpchan/file_handle.hpp | 23 ++ .../{src => libnntpchan}/frontend.hpp | 10 +- .../{src => libnntpchan}/http.hpp | 0 .../{src => libnntpchan}/http_client.hpp | 0 .../{src => libnntpchan}/http_server.hpp | 0 .../{src => libnntpchan}/ini.hpp | 0 .../nntpchan-daemon/libnntpchan/io_handle.hpp | 12 + .../{src => libnntpchan}/line.cpp | 0 .../{src => libnntpchan}/line.hpp | 0 .../nntpchan-daemon/libnntpchan/mime.cpp | 26 ++ .../nntpchan-daemon/libnntpchan/mime.hpp | 30 ++ .../nntpchan-daemon/libnntpchan/model.hpp | 59 ++++ .../{src => libnntpchan}/net.cpp | 0 .../{src => libnntpchan}/net.hpp | 0 .../{src => libnntpchan}/nntp_auth.cpp | 0 .../{src => libnntpchan}/nntp_auth.hpp | 3 + .../{src => libnntpchan}/nntp_handler.cpp | 7 +- .../{src => libnntpchan}/nntp_handler.hpp | 6 +- .../{src => libnntpchan}/nntp_server.cpp | 18 +- .../{src => libnntpchan}/nntp_server.hpp | 6 +- .../nntpchan-daemon/libnntpchan/sanitize.cpp | 24 ++ .../nntpchan-daemon/libnntpchan/sanitize.hpp | 12 + .../{src => libnntpchan}/server.cpp | 0 .../{src => libnntpchan}/server.hpp | 0 .../nntpchan-daemon/libnntpchan/sha1.cpp | 327 ++++++++++++++++++ .../nntpchan-daemon/libnntpchan/sha1.hpp | 11 + .../libnntpchan/staticfile_frontend.cpp | 108 ++++++ .../libnntpchan/staticfile_frontend.hpp | 44 +++ .../nntpchan-daemon/libnntpchan/storage.cpp | 47 +++ .../nntpchan-daemon/libnntpchan/storage.hpp | 40 +++ .../libnntpchan/template_engine.cpp | 35 ++ .../libnntpchan/template_engine.hpp | 23 ++ .../backends/nntpchan-daemon/src/message.cpp | 28 -- .../backends/nntpchan-daemon/src/message.hpp | 34 -- .../backends/nntpchan-daemon/src/mustache.cpp | 262 -------------- .../backends/nntpchan-daemon/src/mustache.hpp | 96 ----- .../backends/nntpchan-daemon/src/storage.cpp | 59 ---- .../backends/nntpchan-daemon/src/storage.hpp | 55 --- contrib/backends/nntpchan-daemon/test.cpp | 5 +- .../nntpchan-daemon/tools/testtool.cpp | 4 +- .../backends/srndv2/src/srnd/frontend_http.go | 2 +- contrib/backends/srndv2/src/srnd/nntp.go | 6 +- 57 files changed, 987 insertions(+), 576 deletions(-) create mode 100644 contrib/backends/nntpchan-daemon/README.md rename contrib/backends/nntpchan-daemon/{src => libnntpchan}/base64.cpp (100%) rename contrib/backends/nntpchan-daemon/{src => libnntpchan}/base64.hpp (100%) rename contrib/backends/nntpchan-daemon/{src => libnntpchan}/buffer.cpp (100%) rename contrib/backends/nntpchan-daemon/{src => libnntpchan}/buffer.hpp (100%) rename contrib/backends/nntpchan-daemon/{src => libnntpchan}/crypto.cpp (100%) rename contrib/backends/nntpchan-daemon/{src => libnntpchan}/crypto.hpp (100%) create mode 100644 contrib/backends/nntpchan-daemon/libnntpchan/crypto_old.hpp rename contrib/backends/nntpchan-daemon/{src => libnntpchan}/event.cpp (100%) rename contrib/backends/nntpchan-daemon/{src => libnntpchan}/event.hpp (100%) rename contrib/backends/nntpchan-daemon/{src => libnntpchan}/exec_frontend.cpp (94%) rename contrib/backends/nntpchan-daemon/{src => libnntpchan}/exec_frontend.hpp (89%) create mode 100644 contrib/backends/nntpchan-daemon/libnntpchan/file_handle.cpp create mode 100644 contrib/backends/nntpchan-daemon/libnntpchan/file_handle.hpp rename contrib/backends/nntpchan-daemon/{src => libnntpchan}/frontend.hpp (72%) rename contrib/backends/nntpchan-daemon/{src => libnntpchan}/http.hpp (100%) rename contrib/backends/nntpchan-daemon/{src => libnntpchan}/http_client.hpp (100%) rename contrib/backends/nntpchan-daemon/{src => libnntpchan}/http_server.hpp (100%) rename contrib/backends/nntpchan-daemon/{src => libnntpchan}/ini.hpp (100%) create mode 100644 contrib/backends/nntpchan-daemon/libnntpchan/io_handle.hpp rename contrib/backends/nntpchan-daemon/{src => libnntpchan}/line.cpp (100%) rename contrib/backends/nntpchan-daemon/{src => libnntpchan}/line.hpp (100%) create mode 100644 contrib/backends/nntpchan-daemon/libnntpchan/mime.cpp create mode 100644 contrib/backends/nntpchan-daemon/libnntpchan/mime.hpp create mode 100644 contrib/backends/nntpchan-daemon/libnntpchan/model.hpp rename contrib/backends/nntpchan-daemon/{src => libnntpchan}/net.cpp (100%) rename contrib/backends/nntpchan-daemon/{src => libnntpchan}/net.hpp (100%) rename contrib/backends/nntpchan-daemon/{src => libnntpchan}/nntp_auth.cpp (100%) rename contrib/backends/nntpchan-daemon/{src => libnntpchan}/nntp_auth.hpp (95%) rename contrib/backends/nntpchan-daemon/{src => libnntpchan}/nntp_handler.cpp (96%) rename contrib/backends/nntpchan-daemon/{src => libnntpchan}/nntp_handler.hpp (91%) rename contrib/backends/nntpchan-daemon/{src => libnntpchan}/nntp_server.cpp (86%) rename contrib/backends/nntpchan-daemon/{src => libnntpchan}/nntp_server.hpp (97%) create mode 100644 contrib/backends/nntpchan-daemon/libnntpchan/sanitize.cpp create mode 100644 contrib/backends/nntpchan-daemon/libnntpchan/sanitize.hpp rename contrib/backends/nntpchan-daemon/{src => libnntpchan}/server.cpp (100%) rename contrib/backends/nntpchan-daemon/{src => libnntpchan}/server.hpp (100%) create mode 100644 contrib/backends/nntpchan-daemon/libnntpchan/sha1.cpp create mode 100644 contrib/backends/nntpchan-daemon/libnntpchan/sha1.hpp create mode 100644 contrib/backends/nntpchan-daemon/libnntpchan/staticfile_frontend.cpp create mode 100644 contrib/backends/nntpchan-daemon/libnntpchan/staticfile_frontend.hpp create mode 100644 contrib/backends/nntpchan-daemon/libnntpchan/storage.cpp create mode 100644 contrib/backends/nntpchan-daemon/libnntpchan/storage.hpp create mode 100644 contrib/backends/nntpchan-daemon/libnntpchan/template_engine.cpp create mode 100644 contrib/backends/nntpchan-daemon/libnntpchan/template_engine.hpp delete mode 100644 contrib/backends/nntpchan-daemon/src/message.cpp delete mode 100644 contrib/backends/nntpchan-daemon/src/message.hpp delete mode 100644 contrib/backends/nntpchan-daemon/src/mustache.cpp delete mode 100644 contrib/backends/nntpchan-daemon/src/mustache.hpp delete mode 100644 contrib/backends/nntpchan-daemon/src/storage.cpp delete mode 100644 contrib/backends/nntpchan-daemon/src/storage.hpp diff --git a/contrib/backends/nntpchan-daemon/Makefile b/contrib/backends/nntpchan-daemon/Makefile index 8fc6249..eb5610d 100644 --- a/contrib/backends/nntpchan-daemon/Makefile +++ b/contrib/backends/nntpchan-daemon/Makefile @@ -1,6 +1,6 @@ REPO=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))) -SRC_PATH = $(REPO)/src +SRC_PATH = $(REPO)/libnntpchan SOURCES := $(wildcard $(SRC_PATH)/*.cpp) HEADERS := $(wildcard $(SRC_PATH)/*.hpp) @@ -15,9 +15,9 @@ DAEMON_SRC = $(REPO)/daemon PKGS := libuv libsodium -LD_FLAGS := $(shell pkg-config --libs $(PKGS)) -INC_FLAGS := $(shell pkg-config --cflags $(PKGS)) -I $(REPO)/src -CXXFLAGS := -std=c++11 -Wall -Wextra $(INC_FLAGS) +LD_FLAGS := $(shell pkg-config --libs $(PKGS)) -lstdc++fs +INC_FLAGS := $(shell pkg-config --cflags $(PKGS)) -I$(SRC_PATH) +CXXFLAGS := -std=c++17 -Wall -Wextra -pedantic $(INC_FLAGS) ifeq ($(DEBUG),1) CXXFLAGS += -g @@ -28,7 +28,9 @@ LIB = $(REPO)/libnntpchan.a EXE = $(REPO)/nntpd -all: $(EXE) $(TOOLS) +all: build + +build: $(EXE) $(TOOLS) $(LIB): $(OBJECTS) $(AR) -r $(LIB) $(OBJECTS) diff --git a/contrib/backends/nntpchan-daemon/README.md b/contrib/backends/nntpchan-daemon/README.md new file mode 100644 index 0000000..e3844f6 --- /dev/null +++ b/contrib/backends/nntpchan-daemon/README.md @@ -0,0 +1,19 @@ +# nntpchan-daemon + +C++ rewrite + +requirements: + +* g++ 7.2.0 >= or clang 5.x >= + +* pkg-config + +* libsodium 1.x + +* libuv 1.x + +* GNU Make + +building: + + $ make diff --git a/contrib/backends/nntpchan-daemon/daemon/main.cpp b/contrib/backends/nntpchan-daemon/daemon/main.cpp index aedc90b..4b69d0d 100644 --- a/contrib/backends/nntpchan-daemon/daemon/main.cpp +++ b/contrib/backends/nntpchan-daemon/daemon/main.cpp @@ -5,6 +5,7 @@ #include "nntp_server.hpp" #include "event.hpp" #include "exec_frontend.hpp" +#include "staticfile_frontend.hpp" #include #include @@ -16,7 +17,7 @@ int main(int argc, char * argv[]) { return 1; } - nntpchan::Crypto crypto(); + nntpchan::Crypto crypto; nntpchan::Mainloop loop; @@ -69,21 +70,48 @@ int main(int argc, char * argv[]) { nntp.SetLoginDB(nntpconf["authdb"]); } - if ( level.sections.find("frontend") != level.sections.end()) { + if ( level.sections.find("frontend") != level.sections.end()) + { // frontend enabled auto & frontconf = level.sections["frontend"].values; - if (frontconf.find("type") == frontconf.end()) { + if (frontconf.find("type") == frontconf.end()) + { std::cerr << "frontend section provided but 'type' value not provided" << std::endl; return 1; } auto ftype = frontconf["type"]; - if (ftype == "exec") { - if (frontconf.find("exec") == frontconf.end()) { + if (ftype == "exec") + { + if (frontconf.find("exec") == frontconf.end()) + { std::cerr << "exec frontend specified but no 'exec' value provided" << std::endl; return 1; } nntp.SetFrontend(new nntpchan::ExecFrontend(frontconf["exec"])); - } else { + } + else if (ftype == "staticfile") + { + auto required = { + "template_dir", "out_dir", "template_dialect", "max_pages" + }; + for (const auto & opt : required) + { + if(frontconf.find(opt) == frontconf.end()) + { + std::cerr << "staticfile frontend specified but no '" << opt << "' value provided" << std::endl; + return 1; + } + } + auto maxPages = std::stoi(frontconf["max_pages"]); + if(maxPages <= 0) + { + std::cerr << "max_pages invalid value '" << frontconf["max_pages"] << "'" << std::endl; + return 1; + } + nntp.SetFrontend(new nntpchan::StaticFileFrontend(nntpchan::CreateTemplateEngine(frontconf["template_dialect"]), frontconf["template_dir"], frontconf["out_dir"], maxPages)); + } + else + { std::cerr << "unknown frontend type '" << ftype << "'" << std::endl; return 1; } diff --git a/contrib/backends/nntpchan-daemon/src/base64.cpp b/contrib/backends/nntpchan-daemon/libnntpchan/base64.cpp similarity index 100% rename from contrib/backends/nntpchan-daemon/src/base64.cpp rename to contrib/backends/nntpchan-daemon/libnntpchan/base64.cpp diff --git a/contrib/backends/nntpchan-daemon/src/base64.hpp b/contrib/backends/nntpchan-daemon/libnntpchan/base64.hpp similarity index 100% rename from contrib/backends/nntpchan-daemon/src/base64.hpp rename to contrib/backends/nntpchan-daemon/libnntpchan/base64.hpp diff --git a/contrib/backends/nntpchan-daemon/src/buffer.cpp b/contrib/backends/nntpchan-daemon/libnntpchan/buffer.cpp similarity index 100% rename from contrib/backends/nntpchan-daemon/src/buffer.cpp rename to contrib/backends/nntpchan-daemon/libnntpchan/buffer.cpp diff --git a/contrib/backends/nntpchan-daemon/src/buffer.hpp b/contrib/backends/nntpchan-daemon/libnntpchan/buffer.hpp similarity index 100% rename from contrib/backends/nntpchan-daemon/src/buffer.hpp rename to contrib/backends/nntpchan-daemon/libnntpchan/buffer.hpp diff --git a/contrib/backends/nntpchan-daemon/src/crypto.cpp b/contrib/backends/nntpchan-daemon/libnntpchan/crypto.cpp similarity index 100% rename from contrib/backends/nntpchan-daemon/src/crypto.cpp rename to contrib/backends/nntpchan-daemon/libnntpchan/crypto.cpp diff --git a/contrib/backends/nntpchan-daemon/src/crypto.hpp b/contrib/backends/nntpchan-daemon/libnntpchan/crypto.hpp similarity index 100% rename from contrib/backends/nntpchan-daemon/src/crypto.hpp rename to contrib/backends/nntpchan-daemon/libnntpchan/crypto.hpp diff --git a/contrib/backends/nntpchan-daemon/libnntpchan/crypto_old.hpp b/contrib/backends/nntpchan-daemon/libnntpchan/crypto_old.hpp new file mode 100644 index 0000000..25649d9 --- /dev/null +++ b/contrib/backends/nntpchan-daemon/libnntpchan/crypto_old.hpp @@ -0,0 +1,44 @@ + + +#ifndef NNTPCHAN_CRYPTO_OLD_HPP +#define NNTPCHAN_CRYPTO_OLD_HPP + +#include +#include +extern "C" { + +typedef struct +{ + uint32_t state[5]; + uint32_t count[2]; + unsigned char buffer[64]; +} SHA1_CTX; + +void SHA1Transform( + uint32_t state[5], + const unsigned char buffer[64] +); + +void SHA1Init( + SHA1_CTX * context +); + +void SHA1Update( + SHA1_CTX * context, + const unsigned char *data, + uint32_t len + ); + +void SHA1Final( + unsigned char digest[20], + SHA1_CTX * context + ); + +void sha1( + uint8_t *hash_out, + const uint8_t *str, + size_t len); + +} + +#endif diff --git a/contrib/backends/nntpchan-daemon/src/event.cpp b/contrib/backends/nntpchan-daemon/libnntpchan/event.cpp similarity index 100% rename from contrib/backends/nntpchan-daemon/src/event.cpp rename to contrib/backends/nntpchan-daemon/libnntpchan/event.cpp diff --git a/contrib/backends/nntpchan-daemon/src/event.hpp b/contrib/backends/nntpchan-daemon/libnntpchan/event.hpp similarity index 100% rename from contrib/backends/nntpchan-daemon/src/event.hpp rename to contrib/backends/nntpchan-daemon/libnntpchan/event.hpp diff --git a/contrib/backends/nntpchan-daemon/src/exec_frontend.cpp b/contrib/backends/nntpchan-daemon/libnntpchan/exec_frontend.cpp similarity index 94% rename from contrib/backends/nntpchan-daemon/src/exec_frontend.cpp rename to contrib/backends/nntpchan-daemon/libnntpchan/exec_frontend.cpp index 220fcdd..2ae9d97 100644 --- a/contrib/backends/nntpchan-daemon/src/exec_frontend.cpp +++ b/contrib/backends/nntpchan-daemon/libnntpchan/exec_frontend.cpp @@ -14,7 +14,7 @@ namespace nntpchan ExecFrontend::~ExecFrontend() {} - void ExecFrontend::ProcessNewMessage(const std::string & fpath) + void ExecFrontend::ProcessNewMessage(const fs::path & fpath) { Exec({"post", fpath}); } diff --git a/contrib/backends/nntpchan-daemon/src/exec_frontend.hpp b/contrib/backends/nntpchan-daemon/libnntpchan/exec_frontend.hpp similarity index 89% rename from contrib/backends/nntpchan-daemon/src/exec_frontend.hpp rename to contrib/backends/nntpchan-daemon/libnntpchan/exec_frontend.hpp index 322b6ed..4c04307 100644 --- a/contrib/backends/nntpchan-daemon/src/exec_frontend.hpp +++ b/contrib/backends/nntpchan-daemon/libnntpchan/exec_frontend.hpp @@ -13,7 +13,7 @@ namespace nntpchan ~ExecFrontend(); - void ProcessNewMessage(const std::string & fpath); + void ProcessNewMessage(const fs::path & fpath); bool AcceptsNewsgroup(const std::string & newsgroup); bool AcceptsMessage(const std::string & msgid); diff --git a/contrib/backends/nntpchan-daemon/libnntpchan/file_handle.cpp b/contrib/backends/nntpchan-daemon/libnntpchan/file_handle.cpp new file mode 100644 index 0000000..86d8d51 --- /dev/null +++ b/contrib/backends/nntpchan-daemon/libnntpchan/file_handle.cpp @@ -0,0 +1,22 @@ +#include "file_handle.hpp" + + +namespace nntpchan +{ + FileHandle_ptr OpenFile(const fs::path & fname, FileMode mode) + { + std::fstream * f = new std::fstream; + if(mode == eRead) + { + f->open(fname, std::ios::in); + } + else if (mode == eWrite) + { + f->open(fname, std::ios::out); + } + if(f->is_open()) + return FileHandle_ptr(f); + delete f; + return nullptr; + } +} diff --git a/contrib/backends/nntpchan-daemon/libnntpchan/file_handle.hpp b/contrib/backends/nntpchan-daemon/libnntpchan/file_handle.hpp new file mode 100644 index 0000000..a842421 --- /dev/null +++ b/contrib/backends/nntpchan-daemon/libnntpchan/file_handle.hpp @@ -0,0 +1,23 @@ +#ifndef NNTPCHAN_FILE_HANDLE_HPP +#define NNTPCHAN_FILE_HANDLE_HPP + +#include +#include +#include + +namespace nntpchan +{ + typedef std::unique_ptr FileHandle_ptr; + + enum FileMode + { + eRead, + eWrite + }; + + namespace fs = std::experimental::filesystem; + + FileHandle_ptr OpenFile(const fs::path & fname, FileMode mode); +} + +#endif diff --git a/contrib/backends/nntpchan-daemon/src/frontend.hpp b/contrib/backends/nntpchan-daemon/libnntpchan/frontend.hpp similarity index 72% rename from contrib/backends/nntpchan-daemon/src/frontend.hpp rename to contrib/backends/nntpchan-daemon/libnntpchan/frontend.hpp index fed48f6..c9dfb86 100644 --- a/contrib/backends/nntpchan-daemon/src/frontend.hpp +++ b/contrib/backends/nntpchan-daemon/libnntpchan/frontend.hpp @@ -1,17 +1,19 @@ #ifndef NNTPCHAN_FRONTEND_HPP #define NNTPCHAN_FRONTEND_HPP #include - +#include +#include namespace nntpchan { + + namespace fs = std::experimental::filesystem; /** @brief nntpchan frontend ui interface */ class Frontend { public: - virtual ~Frontend() {} /** @brief process an inbound message stored at fpath that we have accepted. */ - virtual void ProcessNewMessage(const std::string & fpath) = 0; + virtual void ProcessNewMessage(const fs::path & fpath) = 0; /** @brief return true if we take posts in a newsgroup */ virtual bool AcceptsNewsgroup(const std::string & newsgroup) = 0; @@ -20,6 +22,8 @@ namespace nntpchan virtual bool AcceptsMessage(const std::string & msgid) = 0; }; + + typedef std::unique_ptr Frontend_ptr; } #endif diff --git a/contrib/backends/nntpchan-daemon/src/http.hpp b/contrib/backends/nntpchan-daemon/libnntpchan/http.hpp similarity index 100% rename from contrib/backends/nntpchan-daemon/src/http.hpp rename to contrib/backends/nntpchan-daemon/libnntpchan/http.hpp diff --git a/contrib/backends/nntpchan-daemon/src/http_client.hpp b/contrib/backends/nntpchan-daemon/libnntpchan/http_client.hpp similarity index 100% rename from contrib/backends/nntpchan-daemon/src/http_client.hpp rename to contrib/backends/nntpchan-daemon/libnntpchan/http_client.hpp diff --git a/contrib/backends/nntpchan-daemon/src/http_server.hpp b/contrib/backends/nntpchan-daemon/libnntpchan/http_server.hpp similarity index 100% rename from contrib/backends/nntpchan-daemon/src/http_server.hpp rename to contrib/backends/nntpchan-daemon/libnntpchan/http_server.hpp diff --git a/contrib/backends/nntpchan-daemon/src/ini.hpp b/contrib/backends/nntpchan-daemon/libnntpchan/ini.hpp similarity index 100% rename from contrib/backends/nntpchan-daemon/src/ini.hpp rename to contrib/backends/nntpchan-daemon/libnntpchan/ini.hpp diff --git a/contrib/backends/nntpchan-daemon/libnntpchan/io_handle.hpp b/contrib/backends/nntpchan-daemon/libnntpchan/io_handle.hpp new file mode 100644 index 0000000..4012f2d --- /dev/null +++ b/contrib/backends/nntpchan-daemon/libnntpchan/io_handle.hpp @@ -0,0 +1,12 @@ +#ifndef NNTPCHAN_IO_HANDLE_HPP +#define NNTPCHAN_IO_HANDLE_HPP +#include +#include + +namespace nntpchan +{ + typedef std::unique_ptr IOHandle_ptr; + +} + +#endif diff --git a/contrib/backends/nntpchan-daemon/src/line.cpp b/contrib/backends/nntpchan-daemon/libnntpchan/line.cpp similarity index 100% rename from contrib/backends/nntpchan-daemon/src/line.cpp rename to contrib/backends/nntpchan-daemon/libnntpchan/line.cpp diff --git a/contrib/backends/nntpchan-daemon/src/line.hpp b/contrib/backends/nntpchan-daemon/libnntpchan/line.hpp similarity index 100% rename from contrib/backends/nntpchan-daemon/src/line.hpp rename to contrib/backends/nntpchan-daemon/libnntpchan/line.hpp diff --git a/contrib/backends/nntpchan-daemon/libnntpchan/mime.cpp b/contrib/backends/nntpchan-daemon/libnntpchan/mime.cpp new file mode 100644 index 0000000..f1d79dd --- /dev/null +++ b/contrib/backends/nntpchan-daemon/libnntpchan/mime.cpp @@ -0,0 +1,26 @@ +#include "mime.hpp" + +namespace nntpchan +{ + bool ReadHeader(const FileHandle_ptr & file, RawHeader & header) + { + std::string line; + while(std::getline(*file, line) && !(line == "\r" || line == "")) + { + std::string k, v; + auto idx = line.find(": "); + auto endidx = line.size() - 1; + + while(line[endidx] == '\r') --endidx; + + if(idx != std::string::npos && idx + 2 < endidx) + { + k = line.substr(0, idx); + v = line.substr(idx+2, endidx); + header[k] = v; + } + } + return file->good(); + } + +} diff --git a/contrib/backends/nntpchan-daemon/libnntpchan/mime.hpp b/contrib/backends/nntpchan-daemon/libnntpchan/mime.hpp new file mode 100644 index 0000000..f50e96c --- /dev/null +++ b/contrib/backends/nntpchan-daemon/libnntpchan/mime.hpp @@ -0,0 +1,30 @@ +#ifndef NNTPCHAN_MIME_HPP +#define NNTPCHAN_MIME_HPP +#include "file_handle.hpp" +#include "io_handle.hpp" +#include +#include +#include + +namespace nntpchan +{ + + typedef std::map RawHeader; + + bool ReadHeader(const FileHandle_ptr & f, RawHeader & h); + + + struct MimePart + { + virtual RawHeader & Header() = 0; + virtual IOHandle_ptr OpenPart() = 0; + }; + + typedef std::unique_ptr MimePart_ptr; + + typedef std::function PartReader; + + bool ReadParts(const FileHandle_ptr & f, PartReader r); +} + +#endif diff --git a/contrib/backends/nntpchan-daemon/libnntpchan/model.hpp b/contrib/backends/nntpchan-daemon/libnntpchan/model.hpp new file mode 100644 index 0000000..ffaf22c --- /dev/null +++ b/contrib/backends/nntpchan-daemon/libnntpchan/model.hpp @@ -0,0 +1,59 @@ +#ifndef NNTPCHAN_MODEL_HPP +#define NNTPCHAN_MODEL_HPP +#include +#include +#include +#include +#include + +namespace nntpchan +{ + namespace model + { + // MIME Header + typedef std::map > PostHeader; + // text post contents + typedef std::string PostBody; + // single file attachment, (orig_filename, hexdigest, thumb_filename) + typedef std::tuple PostAttachment; + // all attachments on a post + typedef std::vector Attachments; + // a post (header, Post Text, Attachments) + typedef std::tuple Post; + // a thread (many posts in post order) + typedef std::vector Thread; + + + static inline std::string & GetFilename(PostAttachment & att) + { + return std::get<0>(att); + } + + static inline std::string & GetHexDigest(PostAttachment & att) + { + return std::get<1>(att); + } + + static inline std::string & GetThumbnail(PostAttachment & att) + { + return std::get<2>(att); + } + + static inline PostHeader & GetHeader(Post & post) + { + return std::get<0>(post); + } + + static inline PostBody & GetBody(Post & post) + { + return std::get<1>(post); + } + + static inline Attachments & GetAttachments(Post & post) + { + return std::get<2>(post); + } + } +} + +#endif diff --git a/contrib/backends/nntpchan-daemon/src/net.cpp b/contrib/backends/nntpchan-daemon/libnntpchan/net.cpp similarity index 100% rename from contrib/backends/nntpchan-daemon/src/net.cpp rename to contrib/backends/nntpchan-daemon/libnntpchan/net.cpp diff --git a/contrib/backends/nntpchan-daemon/src/net.hpp b/contrib/backends/nntpchan-daemon/libnntpchan/net.hpp similarity index 100% rename from contrib/backends/nntpchan-daemon/src/net.hpp rename to contrib/backends/nntpchan-daemon/libnntpchan/net.hpp diff --git a/contrib/backends/nntpchan-daemon/src/nntp_auth.cpp b/contrib/backends/nntpchan-daemon/libnntpchan/nntp_auth.cpp similarity index 100% rename from contrib/backends/nntpchan-daemon/src/nntp_auth.cpp rename to contrib/backends/nntpchan-daemon/libnntpchan/nntp_auth.cpp diff --git a/contrib/backends/nntpchan-daemon/src/nntp_auth.hpp b/contrib/backends/nntpchan-daemon/libnntpchan/nntp_auth.hpp similarity index 95% rename from contrib/backends/nntpchan-daemon/src/nntp_auth.hpp rename to contrib/backends/nntpchan-daemon/libnntpchan/nntp_auth.hpp index 05890c1..19297e2 100644 --- a/contrib/backends/nntpchan-daemon/src/nntp_auth.hpp +++ b/contrib/backends/nntpchan-daemon/libnntpchan/nntp_auth.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "line.hpp" namespace nntpchan @@ -21,6 +22,8 @@ namespace nntpchan virtual ~NNTPCredentialDB() {} }; + typedef std::shared_ptr CredDB_ptr; + /** @brief nntp credential db using hashed+salted passwords */ class HashedCredDB : public NNTPCredentialDB, public LineReader { diff --git a/contrib/backends/nntpchan-daemon/src/nntp_handler.cpp b/contrib/backends/nntpchan-daemon/libnntpchan/nntp_handler.cpp similarity index 96% rename from contrib/backends/nntpchan-daemon/src/nntp_handler.cpp rename to contrib/backends/nntpchan-daemon/libnntpchan/nntp_handler.cpp index 327cd49..fdf2f3e 100644 --- a/contrib/backends/nntpchan-daemon/src/nntp_handler.cpp +++ b/contrib/backends/nntpchan-daemon/libnntpchan/nntp_handler.cpp @@ -1,5 +1,5 @@ #include "nntp_handler.hpp" -#include "message.hpp" +#include "sanitize.hpp" #include #include #include @@ -21,7 +21,6 @@ namespace nntpchan NNTPServerHandler::~NNTPServerHandler() { - if(m_auth) delete m_auth; } void NNTPServerHandler::HandleLine(const std::string &line) @@ -144,7 +143,6 @@ namespace nntpchan { m_article->flush(); m_article->close(); - delete m_article; m_article = nullptr; QueueLine("239 "+m_articleName); std::cerr << "stored " << m_articleName << std::endl; @@ -209,9 +207,8 @@ namespace nntpchan QueueLine("201 Posting not allowed"); } - void NNTPServerHandler::SetAuth(NNTPCredentialDB *creds) + void NNTPServerHandler::SetAuth(CredDB_ptr creds) { - if(m_auth) delete m_auth; m_auth = creds; } } diff --git a/contrib/backends/nntpchan-daemon/src/nntp_handler.hpp b/contrib/backends/nntpchan-daemon/libnntpchan/nntp_handler.hpp similarity index 91% rename from contrib/backends/nntpchan-daemon/src/nntp_handler.hpp rename to contrib/backends/nntpchan-daemon/libnntpchan/nntp_handler.hpp index 64d708d..fa12c80 100644 --- a/contrib/backends/nntpchan-daemon/src/nntp_handler.hpp +++ b/contrib/backends/nntpchan-daemon/libnntpchan/nntp_handler.hpp @@ -16,7 +16,7 @@ namespace nntpchan virtual bool ShouldClose(); - void SetAuth(NNTPCredentialDB * creds); + void SetAuth(CredDB_ptr creds); virtual void OnData(const char *, ssize_t); @@ -49,8 +49,8 @@ namespace nntpchan private: std::string m_articleName; - std::fstream * m_article; - NNTPCredentialDB * m_auth; + FileHandle_ptr m_article; + CredDB_ptr m_auth; ArticleStorage m_store; std::string m_mode; bool m_authed; diff --git a/contrib/backends/nntpchan-daemon/src/nntp_server.cpp b/contrib/backends/nntpchan-daemon/libnntpchan/nntp_server.cpp similarity index 86% rename from contrib/backends/nntpchan-daemon/src/nntp_server.cpp rename to contrib/backends/nntpchan-daemon/libnntpchan/nntp_server.cpp index 9f9e41e..19c10da 100644 --- a/contrib/backends/nntpchan-daemon/src/nntp_server.cpp +++ b/contrib/backends/nntpchan-daemon/libnntpchan/nntp_server.cpp @@ -14,16 +14,15 @@ namespace nntpchan NNTPServer::~NNTPServer() { - if (m_frontend) delete m_frontend; } IServerConn * NNTPServer::CreateConn(uv_stream_t * s) { - NNTPCredentialDB * creds = nullptr; + CredDB_ptr creds; std::ifstream i; i.open(m_logindbpath); - if(i.is_open()) creds = new HashedFileDB(m_logindbpath); + if(i.is_open()) creds = std::make_shared(m_logindbpath); NNTPServerHandler * handler = new NNTPServerHandler(m_storagePath); if(creds) @@ -49,17 +48,16 @@ namespace nntpchan m_servername = name; } + void NNTPServer::SetFrontend(Frontend * f) + { + m_frontend.reset(f); + } + std::string NNTPServer::InstanceName() const { return m_servername; } - void NNTPServer::SetFrontend(Frontend * f) - { - if(m_frontend) delete m_frontend; - m_frontend = f; - } - void NNTPServer::OnAcceptError(int status) { std::cerr << "nntpserver::accept() " << uv_strerror(status) << std::endl; @@ -70,7 +68,7 @@ namespace nntpchan IConnHandler * handler = GetHandler(); while(handler->HasNextLine()) { auto line = handler->GetNextLine(); - SendString(line + "\n"); + SendString(line + "\r\n"); } } diff --git a/contrib/backends/nntpchan-daemon/src/nntp_server.hpp b/contrib/backends/nntpchan-daemon/libnntpchan/nntp_server.hpp similarity index 97% rename from contrib/backends/nntpchan-daemon/src/nntp_server.hpp rename to contrib/backends/nntpchan-daemon/libnntpchan/nntp_server.hpp index f049a1e..abd5a82 100644 --- a/contrib/backends/nntpchan-daemon/src/nntp_server.hpp +++ b/contrib/backends/nntpchan-daemon/libnntpchan/nntp_server.hpp @@ -25,21 +25,21 @@ namespace nntpchan std::string InstanceName() const; - void SetFrontend(Frontend * f); - void Close(); virtual IServerConn * CreateConn(uv_stream_t * s); virtual void OnAcceptError(int status); + void SetFrontend(Frontend * f); + private: std::string m_logindbpath; std::string m_storagePath; std::string m_servername; - Frontend * m_frontend; + Frontend_ptr m_frontend; }; diff --git a/contrib/backends/nntpchan-daemon/libnntpchan/sanitize.cpp b/contrib/backends/nntpchan-daemon/libnntpchan/sanitize.cpp new file mode 100644 index 0000000..ef9424c --- /dev/null +++ b/contrib/backends/nntpchan-daemon/libnntpchan/sanitize.cpp @@ -0,0 +1,24 @@ +#include "sanitize.hpp" +#include +#include + +namespace nntpchan +{ + std::string NNTPSanitize(const std::string & str) + { + } + + std::string ToLower(const std::string & str) + { + std::string lower = str; + std::transform(lower.begin(), lower.end(), lower.begin(), [](unsigned char ch) -> unsigned char { return std::tolower(ch); } ); + return lower; + } + + static const std::regex re_ValidMessageID("^<[a-zA-Z0-9$\\._]{2,128}@[a-zA-Z0-9\\-\\.]{2,63}>$"); + + bool IsValidMessageID(const std::string & msgid) + { + return std::regex_search(msgid, re_ValidMessageID) == 1; + } +} diff --git a/contrib/backends/nntpchan-daemon/libnntpchan/sanitize.hpp b/contrib/backends/nntpchan-daemon/libnntpchan/sanitize.hpp new file mode 100644 index 0000000..4f0a52c --- /dev/null +++ b/contrib/backends/nntpchan-daemon/libnntpchan/sanitize.hpp @@ -0,0 +1,12 @@ +#ifndef NNTPCHAN_SANITIZE_HPP +#define NNTPCHAN_SANITIZE_HPP +#include + +namespace nntpchan +{ + std::string NNTPSanitize(const std::string & str); + std::string ToLower(const std::string & str); + bool IsValidMessageID(const std::string & msgid); +} + +#endif diff --git a/contrib/backends/nntpchan-daemon/src/server.cpp b/contrib/backends/nntpchan-daemon/libnntpchan/server.cpp similarity index 100% rename from contrib/backends/nntpchan-daemon/src/server.cpp rename to contrib/backends/nntpchan-daemon/libnntpchan/server.cpp diff --git a/contrib/backends/nntpchan-daemon/src/server.hpp b/contrib/backends/nntpchan-daemon/libnntpchan/server.hpp similarity index 100% rename from contrib/backends/nntpchan-daemon/src/server.hpp rename to contrib/backends/nntpchan-daemon/libnntpchan/server.hpp diff --git a/contrib/backends/nntpchan-daemon/libnntpchan/sha1.cpp b/contrib/backends/nntpchan-daemon/libnntpchan/sha1.cpp new file mode 100644 index 0000000..c5c87fe --- /dev/null +++ b/contrib/backends/nntpchan-daemon/libnntpchan/sha1.cpp @@ -0,0 +1,327 @@ +/* +SHA-1 in C +By Steve Reid +100% Public Domain + +Test Vectors (from FIPS PUB 180-1) +"abc" + A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D +"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" + 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 +A million repetitions of "a" + 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F +*/ + +/* #define LITTLE_ENDIAN * This should be #define'd already, if true. */ +/* #define SHA1HANDSOFF * Copies data before messing with it. */ + +#include "crypto_old.hpp" +#include + +extern "C" { +#define SHA1HANDSOFF + +#include +#include + +/* for uint32_t */ +#include + + + +#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) + +/* blk0() and blk() perform the initial expand. */ +/* I got the idea of expanding during the round function from SSLeay */ +#if BYTE_ORDER == LITTLE_ENDIAN +#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \ + |(rol(block->l[i],8)&0x00FF00FF)) +#elif BYTE_ORDER == BIG_ENDIAN +#define blk0(i) block->l[i] +#else +#error "Endianness not defined!" +#endif +#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \ + ^block->l[(i+2)&15]^block->l[i&15],1)) + +/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ +#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); +#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30); +#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); +#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); +#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); + + +/* Hash a single 512-bit block. This is the core of the algorithm. */ + +void SHA1Transform( + uint32_t state[5], + const unsigned char buffer[64] +) +{ + uint32_t a, b, c, d, e; + + typedef union + { + unsigned char c[64]; + uint32_t l[16]; + } CHAR64LONG16; + +#ifdef SHA1HANDSOFF + CHAR64LONG16 block[1]; /* use array to appear as a pointer */ + + memcpy(block, buffer, 64); +#else + /* The following had better never be used because it causes the + * pointer-to-const buffer to be cast into a pointer to non-const. + * And the result is written through. I threw a "const" in, hoping + * this will cause a diagnostic. + */ + CHAR64LONG16 *block = (const CHAR64LONG16 *) buffer; +#endif + /* Copy context->state[] to working vars */ + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + /* 4 rounds of 20 operations each. Loop unrolled. */ + R0(a, b, c, d, e, 0); + R0(e, a, b, c, d, 1); + R0(d, e, a, b, c, 2); + R0(c, d, e, a, b, 3); + R0(b, c, d, e, a, 4); + R0(a, b, c, d, e, 5); + R0(e, a, b, c, d, 6); + R0(d, e, a, b, c, 7); + R0(c, d, e, a, b, 8); + R0(b, c, d, e, a, 9); + R0(a, b, c, d, e, 10); + R0(e, a, b, c, d, 11); + R0(d, e, a, b, c, 12); + R0(c, d, e, a, b, 13); + R0(b, c, d, e, a, 14); + R0(a, b, c, d, e, 15); + R1(e, a, b, c, d, 16); + R1(d, e, a, b, c, 17); + R1(c, d, e, a, b, 18); + R1(b, c, d, e, a, 19); + R2(a, b, c, d, e, 20); + R2(e, a, b, c, d, 21); + R2(d, e, a, b, c, 22); + R2(c, d, e, a, b, 23); + R2(b, c, d, e, a, 24); + R2(a, b, c, d, e, 25); + R2(e, a, b, c, d, 26); + R2(d, e, a, b, c, 27); + R2(c, d, e, a, b, 28); + R2(b, c, d, e, a, 29); + R2(a, b, c, d, e, 30); + R2(e, a, b, c, d, 31); + R2(d, e, a, b, c, 32); + R2(c, d, e, a, b, 33); + R2(b, c, d, e, a, 34); + R2(a, b, c, d, e, 35); + R2(e, a, b, c, d, 36); + R2(d, e, a, b, c, 37); + R2(c, d, e, a, b, 38); + R2(b, c, d, e, a, 39); + R3(a, b, c, d, e, 40); + R3(e, a, b, c, d, 41); + R3(d, e, a, b, c, 42); + R3(c, d, e, a, b, 43); + R3(b, c, d, e, a, 44); + R3(a, b, c, d, e, 45); + R3(e, a, b, c, d, 46); + R3(d, e, a, b, c, 47); + R3(c, d, e, a, b, 48); + R3(b, c, d, e, a, 49); + R3(a, b, c, d, e, 50); + R3(e, a, b, c, d, 51); + R3(d, e, a, b, c, 52); + R3(c, d, e, a, b, 53); + R3(b, c, d, e, a, 54); + R3(a, b, c, d, e, 55); + R3(e, a, b, c, d, 56); + R3(d, e, a, b, c, 57); + R3(c, d, e, a, b, 58); + R3(b, c, d, e, a, 59); + R4(a, b, c, d, e, 60); + R4(e, a, b, c, d, 61); + R4(d, e, a, b, c, 62); + R4(c, d, e, a, b, 63); + R4(b, c, d, e, a, 64); + R4(a, b, c, d, e, 65); + R4(e, a, b, c, d, 66); + R4(d, e, a, b, c, 67); + R4(c, d, e, a, b, 68); + R4(b, c, d, e, a, 69); + R4(a, b, c, d, e, 70); + R4(e, a, b, c, d, 71); + R4(d, e, a, b, c, 72); + R4(c, d, e, a, b, 73); + R4(b, c, d, e, a, 74); + R4(a, b, c, d, e, 75); + R4(e, a, b, c, d, 76); + R4(d, e, a, b, c, 77); + R4(c, d, e, a, b, 78); + R4(b, c, d, e, a, 79); + /* Add the working vars back into context.state[] */ + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + /* Wipe variables */ + a = b = c = d = e = 0; +#ifdef SHA1HANDSOFF + memset(block, '\0', sizeof(block)); +#endif +} + + +/* SHA1Init - Initialize new context */ + +void SHA1Init( + SHA1_CTX * context +) +{ + /* SHA1 initialization constants */ + context->state[0] = 0x67452301; + context->state[1] = 0xEFCDAB89; + context->state[2] = 0x98BADCFE; + context->state[3] = 0x10325476; + context->state[4] = 0xC3D2E1F0; + context->count[0] = context->count[1] = 0; +} + + +/* Run your data through this. */ + +void SHA1Update( + SHA1_CTX * context, + const unsigned char *data, + uint32_t len +) +{ + uint32_t i; + + uint32_t j; + + j = context->count[0]; + if ((context->count[0] += len << 3) < j) + context->count[1]++; + context->count[1] += (len >> 29); + j = (j >> 3) & 63; + if ((j + len) > 63) + { + memcpy(&context->buffer[j], data, (i = 64 - j)); + SHA1Transform(context->state, context->buffer); + for (; i + 63 < len; i += 64) + { + SHA1Transform(context->state, &data[i]); + } + j = 0; + } + else + i = 0; + memcpy(&context->buffer[j], &data[i], len - i); +} + + +/* Add padding and return the message digest. */ + +void SHA1Final( + unsigned char digest[20], + SHA1_CTX * context +) +{ + unsigned i; + + unsigned char finalcount[8]; + + unsigned char c; + +#if 0 /* untested "improvement" by DHR */ + /* Convert context->count to a sequence of bytes + * in finalcount. Second element first, but + * big-endian order within element. + * But we do it all backwards. + */ + unsigned char *fcp = &finalcount[8]; + + for (i = 0; i < 2; i++) + { + uint32_t t = context->count[i]; + + int j; + + for (j = 0; j < 4; t >>= 8, j++) + *--fcp = (unsigned char) t} +#else + for (i = 0; i < 8; i++) + { + finalcount[i] = (unsigned char) ((context->count[(i >= 4 ? 0 : 1)] >> ((3 - (i & 3)) * 8)) & 255); /* Endian independent */ + } +#endif + c = 0200; + SHA1Update(context, &c, 1); + while ((context->count[0] & 504) != 448) + { + c = 0000; + SHA1Update(context, &c, 1); + } + SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */ + for (i = 0; i < 20; i++) + { + digest[i] = (unsigned char) + ((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255); + } + /* Wipe variables */ + memset(context, '\0', sizeof(*context)); + memset(&finalcount, '\0', sizeof(finalcount)); +} + +void sha1( + uint8_t *hash_out, + const uint8_t *str, + size_t len) +{ + SHA1_CTX ctx; + size_t ii; + + SHA1Init(&ctx); + for (ii=0; ii= 10) + return n + 87; + else + return n + 48; + } + + std::string sha1_hex(const std::string & data) + { + uint8_t digest[20]; + const uint8_t * ptr = (uint8_t*) data.c_str(); + sha1(digest, ptr, data.size()); + std::string out; + std::size_t idx = 0; + while(idx < 20) + { + out += nibble_to_char((digest[idx] & 0xf0) >> 8) + nibble_to_char(digest[idx] & 0x0f); + ++idx; + } + + return out; + } +} diff --git a/contrib/backends/nntpchan-daemon/libnntpchan/sha1.hpp b/contrib/backends/nntpchan-daemon/libnntpchan/sha1.hpp new file mode 100644 index 0000000..923abbe --- /dev/null +++ b/contrib/backends/nntpchan-daemon/libnntpchan/sha1.hpp @@ -0,0 +1,11 @@ +#ifndef NNTPCHAN_SHA1_HPP +#define NNTPCHAN_SHA1_HPP + +#include + +namespace nntpchan +{ + std::string sha1_hex(const std::string & data); +} + +#endif diff --git a/contrib/backends/nntpchan-daemon/libnntpchan/staticfile_frontend.cpp b/contrib/backends/nntpchan-daemon/libnntpchan/staticfile_frontend.cpp new file mode 100644 index 0000000..ecaece9 --- /dev/null +++ b/contrib/backends/nntpchan-daemon/libnntpchan/staticfile_frontend.cpp @@ -0,0 +1,108 @@ +#include "staticfile_frontend.hpp" +#include "file_handle.hpp" +#include "sanitize.hpp" +#include "mime.hpp" +#include "sha1.hpp" +#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 + + // render templates + if(m_TemplateEngine) + { + 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); + + std::string msgid_hash = sha1_hex(msgid->second); + + fs::path threadFilePath = m_OutDir / fs::path("thread-" + msgid_hash + ".html"); + 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, ' ')) + { + newsgroups_list.insert(NNTPSanitize(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"); + out = OpenFile(m_OutDir / boardPageFilename, eWrite); + m_TemplateEngine->WriteTemplate("board.mustache", board_args, out); + + ++pageno; + } + } + } + } + } + + StaticFileFrontend::BoardPage_t StaticFileFrontend::GetThreadsPaginated(const std::string & group, uint32_t perpage, uint32_t pages) + { + return {}; + } +} diff --git a/contrib/backends/nntpchan-daemon/libnntpchan/staticfile_frontend.hpp b/contrib/backends/nntpchan-daemon/libnntpchan/staticfile_frontend.hpp new file mode 100644 index 0000000..871a8b3 --- /dev/null +++ b/contrib/backends/nntpchan-daemon/libnntpchan/staticfile_frontend.hpp @@ -0,0 +1,44 @@ +#ifndef NNTPCHAN_STATICFILE_FRONTEND_HPP +#define NNTPCHAN_STATICFILE_FRONTEND_HPP +#include "frontend.hpp" +#include "template_engine.hpp" +#include "model.hpp" +#include + +namespace nntpchan +{ + + namespace fs = std::experimental::filesystem; + + class StaticFileFrontend : public Frontend + { + public: + + StaticFileFrontend(TemplateEngine * tmpl, const std::string & templateDir, const std::string & outDir, uint32_t pages); + + ~StaticFileFrontend(); + + void ProcessNewMessage(const fs::path & fpath); + bool AcceptsNewsgroup(const std::string & newsgroup) { (void) newsgroup; return true; } + bool AcceptsMessage(const std::string & msgid) { (void) msgid; return true; } + + private: + + typedef nntpchan::model::Thread Thread_t; + + typedef std::vector Threads_t; + + typedef std::vector BoardPage_t; + + BoardPage_t GetThreadsPaginated(const std::string & group, uint32_t perpage, uint32_t pages); + + private: + + TemplateEngine_ptr m_TemplateEngine; + fs::path m_TemplateDir; + fs::path m_OutDir; + uint32_t m_Pages; + }; +} + +#endif diff --git a/contrib/backends/nntpchan-daemon/libnntpchan/storage.cpp b/contrib/backends/nntpchan-daemon/libnntpchan/storage.cpp new file mode 100644 index 0000000..7e8f927 --- /dev/null +++ b/contrib/backends/nntpchan-daemon/libnntpchan/storage.cpp @@ -0,0 +1,47 @@ +#include "storage.hpp" +#include "sanitize.hpp" +#include + +namespace nntpchan +{ + ArticleStorage::ArticleStorage() + { + } + + ArticleStorage::ArticleStorage(const fs::path & fpath) { + SetPath(fpath); + } + + ArticleStorage::~ArticleStorage() + { + } + + void ArticleStorage::SetPath(const fs::path & fpath) + { + basedir = fpath; + fs::create_directories(basedir); + } + + bool ArticleStorage::Accept(const std::string& msgid) + { + if (!IsValidMessageID(msgid)) return false; + auto p = MessagePath(msgid); + return !fs::exists(p); + } + + fs::path ArticleStorage::MessagePath(const std::string & msgid) + { + return basedir / msgid; + } + + FileHandle_ptr ArticleStorage::OpenRead(const std::string & msgid) + { + return OpenFile(MessagePath(msgid), eRead); + } + + FileHandle_ptr ArticleStorage::OpenWrite(const std::string & msgid) + { + return OpenFile(MessagePath(msgid), eWrite); + } + +} diff --git a/contrib/backends/nntpchan-daemon/libnntpchan/storage.hpp b/contrib/backends/nntpchan-daemon/libnntpchan/storage.hpp new file mode 100644 index 0000000..74f659a --- /dev/null +++ b/contrib/backends/nntpchan-daemon/libnntpchan/storage.hpp @@ -0,0 +1,40 @@ +#ifndef NNTPCHAN_STORAGE_HPP +#define NNTPCHAN_STORAGE_HPP + +#include +#include +#include "file_handle.hpp" + +namespace nntpchan +{ + + namespace fs = std::experimental::filesystem; + + class ArticleStorage + { + public: + ArticleStorage(); + ArticleStorage(const fs::path & fpath); + ~ArticleStorage(); + + void SetPath(const fs::path & fpath); + + FileHandle_ptr OpenWrite(const std::string & msgid); + FileHandle_ptr OpenRead(const std::string & msgid); + + /** + return true if we should accept a new message give its message id + */ + bool Accept(const std::string & msgid); + + private: + + fs::path MessagePath(const std::string & msgid); + + fs::path basedir; + + }; +} + + +#endif diff --git a/contrib/backends/nntpchan-daemon/libnntpchan/template_engine.cpp b/contrib/backends/nntpchan-daemon/libnntpchan/template_engine.cpp new file mode 100644 index 0000000..f603e72 --- /dev/null +++ b/contrib/backends/nntpchan-daemon/libnntpchan/template_engine.cpp @@ -0,0 +1,35 @@ +#include "template_engine.hpp" +#include "sanitize.hpp" + +namespace nntpchan +{ + + struct MustacheTemplateEngine : public TemplateEngine + { + struct Impl + { + bool RenderFile(const std::string & fname, const Args_t & args, const FileHandle_ptr & out) + { + auto file = OpenFile(fname, eRead); + + + return true; + } + }; + + virtual bool WriteTemplate(const std::string & fname, const Args_t & args, const FileHandle_ptr & out) + { + auto impl = std::make_unique(); + return impl->RenderFile(fname, args, out); + } + }; + + TemplateEngine * CreateTemplateEngine(const std::string & dialect) + { + auto d = ToLower(dialect); + if(d == "mustache") + return new MustacheTemplateEngine; + else + return nullptr; + } +} diff --git a/contrib/backends/nntpchan-daemon/libnntpchan/template_engine.hpp b/contrib/backends/nntpchan-daemon/libnntpchan/template_engine.hpp new file mode 100644 index 0000000..5047b55 --- /dev/null +++ b/contrib/backends/nntpchan-daemon/libnntpchan/template_engine.hpp @@ -0,0 +1,23 @@ +#ifndef NNTPCHAN_TEMPLATE_ENGINE_HPP +#define NNTPCHAN_TEMPLATE_ENGINE_HPP +#include "file_handle.hpp" +#include +#include +#include +#include + +namespace nntpchan +{ + + struct TemplateEngine + { + using Args_t = std::map; + virtual bool WriteTemplate(const std::string & template_fname, const Args_t & args, const FileHandle_ptr & out) = 0; + }; + + TemplateEngine * CreateTemplateEngine(const std::string & dialect); + + typedef std::unique_ptr TemplateEngine_ptr; +} + +#endif diff --git a/contrib/backends/nntpchan-daemon/src/message.cpp b/contrib/backends/nntpchan-daemon/src/message.cpp deleted file mode 100644 index dcbf4b9..0000000 --- a/contrib/backends/nntpchan-daemon/src/message.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include "message.hpp" - -namespace nntpchan -{ - bool IsValidMessageID(const std::string & msgid) - { - if(msgid[0] != '<') return false; - if(msgid[msgid.size()-1] != '>') return false; - auto itr = msgid.begin() + 1; - auto end = msgid.end() - 1; - bool atfound = false; - while(itr != end) { - auto c = *itr; - ++itr; - if(atfound && c == '@') return false; - if(c == '@') { - atfound = true; - continue; - } - if (c == '$' || c == '_' || c == '-' || c == '.') continue; - if (c >= '0' && c <= '9') continue; - if (c >= 'A' && c <= 'Z') continue; - if (c >= 'a' && c <= 'z') continue; - return false; - } - return true; - } -} diff --git a/contrib/backends/nntpchan-daemon/src/message.hpp b/contrib/backends/nntpchan-daemon/src/message.hpp deleted file mode 100644 index d9aa49b..0000000 --- a/contrib/backends/nntpchan-daemon/src/message.hpp +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef NNTPCHAN_MESSAGE_HPP -#define NNTPCHAN_MESSAGE_HPP - -#include -#include -#include -#include - -namespace nntpchan -{ - bool IsValidMessageID(const std::string & msgid); - - typedef std::pair MessageHeader; - - typedef std::map MIMEPartHeader; - - typedef std::function MessageHeaderFilter; - - typedef std::function MIMEPartFilter; - - /** - read MIME message from i, - filter each header with h, - filter each part with p, - store result in o - - return true if we read the whole message, return false if there is remaining - */ - bool StoreMIMEMessage(std::istream & i, MessageHeaderFilter h, MIMEPartHeader p, std::ostream & o); - -} - - -#endif diff --git a/contrib/backends/nntpchan-daemon/src/mustache.cpp b/contrib/backends/nntpchan-daemon/src/mustache.cpp deleted file mode 100644 index 0bf86a3..0000000 --- a/contrib/backends/nntpchan-daemon/src/mustache.cpp +++ /dev/null @@ -1,262 +0,0 @@ -/* - Author: José Bollo - Author: José Bollo - - https://gitlab.com/jobol/mustach - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -#include -#include -#include -#include -#include - -#include "mustache.hpp" - -#define NAME_LENGTH_MAX 1024 -#define DEPTH_MAX 256 - -namespace nntpchan -{ -namespace mustache -{ - - -static int getpartial(struct mustach_itf *itf, void *closure, const char *name, char **result) -{ - int rc; - FILE *file; - size_t size; - - *result = NULL; - file = open_memstream(result, &size); - if (file == NULL) - rc = MUSTACH_ERROR_SYSTEM; - else { - rc = itf->put(closure, name, 0, file); - if (rc == 0) - /* adds terminating null */ - rc = fputc(0, file) ? MUSTACH_ERROR_SYSTEM : 0; - fclose(file); - if (rc < 0) { - free(*result); - *result = NULL; - } - } - return rc; -} - -static int process(const char *templ, struct mustach_itf *itf, void *closure, FILE *file, const char *opstr, const char *clstr) -{ - char name[NAME_LENGTH_MAX + 1], *partial, c; - const char *beg, *term; - struct { const char *name, *again; size_t length; int emit, entered; } stack[DEPTH_MAX]; - size_t oplen, cllen, len, l; - int depth, rc, emit; - - emit = 1; - oplen = strlen(opstr); - cllen = strlen(clstr); - depth = 0; - for(;;) { - beg = strstr(templ, opstr); - if (beg == NULL) { - /* no more mustach */ - if (emit) - fwrite(templ, strlen(templ), 1, file); - return depth ? MUSTACH_ERROR_UNEXPECTED_END : 0; - } - if (emit) - fwrite(templ, (size_t)(beg - templ), 1, file); - beg += oplen; - term = strstr(beg, clstr); - if (term == NULL) - return MUSTACH_ERROR_UNEXPECTED_END; - templ = term + cllen; - len = (size_t)(term - beg); - c = *beg; - switch(c) { - case '!': - case '=': - break; - case '{': - for (l = 0 ; clstr[l] == '}' ; l++); - if (clstr[l]) { - if (!len || beg[len-1] != '}') - return MUSTACH_ERROR_BAD_UNESCAPE_TAG; - len--; - } else { - if (term[l] != '}') - return MUSTACH_ERROR_BAD_UNESCAPE_TAG; - templ++; - } - c = '&'; - case '^': - case '#': - case '/': - case '&': - case '>': -#if !defined(NO_EXTENSION_FOR_MUSTACH) && !defined(NO_COLON_EXTENSION_FOR_MUSTACH) - case ':': -#endif - beg++; len--; - default: - while (len && isspace(beg[0])) { beg++; len--; } - while (len && isspace(beg[len-1])) len--; - if (len == 0) - return MUSTACH_ERROR_EMPTY_TAG; - if (len > NAME_LENGTH_MAX) - return MUSTACH_ERROR_TAG_TOO_LONG; - memcpy(name, beg, len); - name[len] = 0; - break; - } - switch(c) { - case '!': - /* comment */ - /* nothing to do */ - break; - case '=': - /* defines separators */ - if (len < 5 || beg[len - 1] != '=') - return MUSTACH_ERROR_BAD_SEPARATORS; - beg++; - len -= 2; - for (l = 0; l < len && !isspace(beg[l]) ; l++); - if (l == len) - return MUSTACH_ERROR_BAD_SEPARATORS; - opstr = strndupa(beg, l); - while (l < len && isspace(beg[l])) l++; - if (l == len) - return MUSTACH_ERROR_BAD_SEPARATORS; - clstr = strndupa(beg + l, len - l); - oplen = strlen(opstr); - cllen = strlen(clstr); - break; - case '^': - case '#': - /* begin section */ - if (depth == DEPTH_MAX) - return MUSTACH_ERROR_TOO_DEPTH; - rc = emit; - if (rc) { - rc = itf->enter(closure, name); - if (rc < 0) - return rc; - } - stack[depth].name = beg; - stack[depth].again = templ; - stack[depth].length = len; - stack[depth].emit = emit; - stack[depth].entered = rc; - if ((c == '#') == (rc == 0)) - emit = 0; - depth++; - break; - case '/': - /* end section */ - if (depth-- == 0 || len != stack[depth].length || memcmp(stack[depth].name, name, len)) - return MUSTACH_ERROR_CLOSING; - rc = emit && stack[depth].entered ? itf->next(closure) : 0; - if (rc < 0) - return rc; - if (rc) { - templ = stack[depth++].again; - } else { - emit = stack[depth].emit; - if (emit && stack[depth].entered) - itf->leave(closure); - } - break; - case '>': - /* partials */ - if (emit) { - rc = getpartial(itf, closure, name, &partial); - if (rc == 0) { - rc = process(partial, itf, closure, file, opstr, clstr); - free(partial); - } - if (rc < 0) - return rc; - } - break; - default: - /* replacement */ - if (emit) { - rc = itf->put(closure, name, c != '&', file); - if (rc < 0) - return rc; - } - break; - } - } -} - -int fmustach(const char *templ, struct mustach_itf *itf, void *closure, FILE *file) -{ - int rc = itf->start ? itf->start(closure) : 0; - if (rc == 0) - rc = process(templ, itf, closure, file, "{{", "}}"); - return rc; -} - -int fdmustach(const char *templ, struct mustach_itf *itf, void *closure, int fd) -{ - int rc; - FILE *file; - - file = fdopen(fd, "w"); - if (file == NULL) { - rc = MUSTACH_ERROR_SYSTEM; - errno = ENOMEM; - } else { - rc = fmustach(templ, itf, closure, file); - fclose(file); - } - return rc; -} - -int mustach(const char *templ, struct mustach_itf *itf, void *closure, char **result, size_t *size) -{ - int rc; - FILE *file; - size_t s; - - *result = NULL; - if (size == NULL) - size = &s; - file = open_memstream(result, size); - if (file == NULL) { - rc = MUSTACH_ERROR_SYSTEM; - errno = ENOMEM; - } else { - rc = fmustach(templ, itf, closure, file); - if (rc == 0) - /* adds terminating null */ - rc = fputc(0, file) ? MUSTACH_ERROR_SYSTEM : 0; - fclose(file); - if (rc >= 0) - /* removes terminating null of the length */ - (*size)--; - else { - free(*result); - *result = NULL; - *size = 0; - } - } - return rc; -} -} -} diff --git a/contrib/backends/nntpchan-daemon/src/mustache.hpp b/contrib/backends/nntpchan-daemon/src/mustache.hpp deleted file mode 100644 index 68d4277..0000000 --- a/contrib/backends/nntpchan-daemon/src/mustache.hpp +++ /dev/null @@ -1,96 +0,0 @@ -#ifndef NNTPCHAN_MUSTACHE -#define NNTPCHAN_MUSTACHE - -/* - Author: José Bollo - Author: José Bollo - - https://gitlab.com/jobol/mustach - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - - - -#define MUSTACH_OK 0 -#define MUSTACH_ERROR_SYSTEM -1 -#define MUSTACH_ERROR_UNEXPECTED_END -2 -#define MUSTACH_ERROR_EMPTY_TAG -3 -#define MUSTACH_ERROR_TAG_TOO_LONG -4 -#define MUSTACH_ERROR_BAD_SEPARATORS -5 -#define MUSTACH_ERROR_TOO_DEPTH -6 -#define MUSTACH_ERROR_CLOSING -7 -#define MUSTACH_ERROR_BAD_UNESCAPE_TAG -8 - -#include - - -namespace nntpchan -{ - namespace mustache - { - - /** - * mustach_itf - interface for callbacks - * - * All of this function should return a negative value to stop - * the mustache processing. The returned negative value will be - * then returned to the caller of mustach as is. - * - * The functions enter and next should return 0 or 1. - * - * All other functions should normally return 0. - * - * @start: Starts the mustach processing of the closure - * 'start' is optional (can be NULL) - * - * @put: Writes the value of 'name' to 'file' with 'escape' or not - * - * @enter: Enters the section of 'name' if possible. - * Musts return 1 if entered or 0 if not entered. - * When 1 is returned, the function 'leave' will always be called. - * Conversely 'leave' is never called when enter returns 0 or - * a negative value. - * When 1 is returned, the function must activate the first - * item of the section. - * - * @next: Activates the next item of the section if it exists. - * Musts return 1 when the next item is activated. - * Musts return 0 when there is no item to activate. - * - * @leave: Leaves the last entered section - */ - struct mustach_itf { - int (*start)(void *closure); - int (*put)(void *closure, const char *name, int escape, FILE *file); - int (*enter)(void *closure, const char *name); - int (*next)(void *closure); - int (*leave)(void *closure); - }; - /** - * fmustach - Renders the mustache 'template' in 'file' for 'itf' and 'closure'. - * - * @template: the template string to instanciate - * @itf: the interface to the functions that mustach calls - * @closure: the closure to pass to functions called - * @file: the file where to write the result - * - * Returns 0 in case of success, -1 with errno set in case of system error - * a other negative value in case of error. - */ - int fmustach(const char *templ, struct mustach_itf *itf, void *closure, FILE *file); - - } -} - -#endif diff --git a/contrib/backends/nntpchan-daemon/src/storage.cpp b/contrib/backends/nntpchan-daemon/src/storage.cpp deleted file mode 100644 index 201cd5c..0000000 --- a/contrib/backends/nntpchan-daemon/src/storage.cpp +++ /dev/null @@ -1,59 +0,0 @@ -#include "storage.hpp" -#include -#include -#include - -namespace nntpchan -{ - ArticleStorage::ArticleStorage() - { - } - - ArticleStorage::ArticleStorage(const std::string & fpath) { - SetPath(fpath); - } - - ArticleStorage::~ArticleStorage() - { - } - - void ArticleStorage::SetPath(const std::string & fpath) - { - basedir = fpath; - // quiet fail - // TODO: check for errors - mkdir(basedir.c_str(), 0700); - } - - bool ArticleStorage::Accept(const std::string& msgid) - { - if (!IsValidMessageID(msgid)) return false; - auto s = MessagePath(msgid); - FILE * f = fopen(s.c_str(), "r"); - if ( f == nullptr) return errno == ENOENT; - fclose(f); - return false; - } - - std::string ArticleStorage::MessagePath(const std::string & msgid) - { - return basedir + GetPathSep() + msgid; - } - - std::fstream * ArticleStorage::OpenRead(const std::string & msgid) - { - return OpenMode(msgid, std::ios::in); - } - - std::fstream * ArticleStorage::OpenWrite(const std::string & msgid) - { - return OpenMode(msgid, std::ios::out); - } - - char ArticleStorage::GetPathSep() - { - return '/'; - } - - -} diff --git a/contrib/backends/nntpchan-daemon/src/storage.hpp b/contrib/backends/nntpchan-daemon/src/storage.hpp deleted file mode 100644 index 98f2882..0000000 --- a/contrib/backends/nntpchan-daemon/src/storage.hpp +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef NNTPCHAN_STORAGE_HPP -#define NNTPCHAN_STORAGE_HPP - -#include -#include -#include "message.hpp" - -namespace nntpchan -{ - class ArticleStorage - { - public: - ArticleStorage(); - ArticleStorage(const std::string & fpath); - ~ArticleStorage(); - - void SetPath(const std::string & fpath); - - std::fstream * OpenWrite(const std::string & msgid); - std::fstream * OpenRead(const std::string & msgid); - - /** - return true if we should accept a new message give its message id - */ - bool Accept(const std::string & msgid); - - private: - - template - std::fstream * OpenMode(const std::string & msgid, const Mode & m) - { - if(IsValidMessageID(msgid)) - { - std::fstream * f = new std::fstream; - f->open(MessagePath(msgid), m); - if(f->is_open()) - return f; - delete f; - return nullptr; - } - else - return nullptr; - }; - - std::string MessagePath(const std::string & msgid); - - static char GetPathSep(); - - std::string basedir; - - }; -} - - -#endif diff --git a/contrib/backends/nntpchan-daemon/test.cpp b/contrib/backends/nntpchan-daemon/test.cpp index a84c670..777a695 100644 --- a/contrib/backends/nntpchan-daemon/test.cpp +++ b/contrib/backends/nntpchan-daemon/test.cpp @@ -1,4 +1,5 @@ #include "exec_frontend.hpp" +#include "sanitize.hpp" #include #include @@ -6,8 +7,10 @@ int main(int , char * []) { - nntpchan::Frontend * f = new nntpchan::ExecFrontend("./contrib/nntpchan.sh"); + nntpchan::Frontend_ptr f (new nntpchan::ExecFrontend("./contrib/nntpchan.sh")); assert(f->AcceptsMessage("")); assert(f->AcceptsNewsgroup("overchan.test")); + assert(nntpchan::IsValidMessageID("")); + assert(!nntpchan::IsValidMessageID("asd")); std::cout << "all good" << std::endl; } diff --git a/contrib/backends/nntpchan-daemon/tools/testtool.cpp b/contrib/backends/nntpchan-daemon/tools/testtool.cpp index aac4297..e09d633 100644 --- a/contrib/backends/nntpchan-daemon/tools/testtool.cpp +++ b/contrib/backends/nntpchan-daemon/tools/testtool.cpp @@ -1,5 +1,5 @@ #include "exec_frontend.hpp" -#include "message.hpp" +#include "sanitize.hpp" #include #include @@ -7,7 +7,7 @@ int main(int , char * []) { - nntpchan::Frontend * f = new nntpchan::ExecFrontend("./contrib/nntpchan.sh"); + nntpchan::Frontend_ptr f(new nntpchan::ExecFrontend("./contrib/nntpchan.sh")); assert(nntpchan::IsValidMessageID("")); assert(f->AcceptsNewsgroup("overchan.test")); std::cout << "all good" << std::endl; diff --git a/contrib/backends/srndv2/src/srnd/frontend_http.go b/contrib/backends/srndv2/src/srnd/frontend_http.go index 1003df9..f813104 100644 --- a/contrib/backends/srndv2/src/srnd/frontend_http.go +++ b/contrib/backends/srndv2/src/srnd/frontend_http.go @@ -862,7 +862,7 @@ func (self *httpFrontend) handle_postRequest(pr *postRequest, b bannedFunc, e er } if len(cites) > 0 { - nntp.headers.Set("In-Reply-To", strings.Join(cites, " ")) + nntp.headers.Set("Reply-To", strings.Join(cites, " ")) } // set date diff --git a/contrib/backends/srndv2/src/srnd/nntp.go b/contrib/backends/srndv2/src/srnd/nntp.go index 497a945..6200959 100644 --- a/contrib/backends/srndv2/src/srnd/nntp.go +++ b/contrib/backends/srndv2/src/srnd/nntp.go @@ -353,12 +353,16 @@ func (self *nntpConnection) handleStreaming(daemon *NNTPDaemon, conn *textproto. select { case chnl := <-self.die: // someone asked us to die + self.pending_access.Lock() conn.PrintfLine("QUIT") conn.Close() + self.pending_access.Unlock() chnl <- true return case <-self.keepalive.C: + self.pending_access.Lock() err = conn.PrintfLine("CHECK %s", nntpDummyArticle) + self.pending_access.Unlock() default: if len(self.pending) > 0 { self.pending_access.Lock() @@ -562,7 +566,7 @@ func (self *nntpConnection) storeMessage(daemon *NNTPDaemon, hdr textproto.MIMEH } // ask for replies - replyTos := strings.Split(hdr.Get("In-Reply-To"), " ") + replyTos := strings.Split(hdr.Get("Reply-To"), " ") for _, reply := range replyTos { if ValidMessageID(reply) { if !daemon.store.HasArticle(reply) {