clang format
This commit is contained in:
		
							
								
								
									
										14
									
								
								contrib/backends/nntpchan-daemon/.clang-format
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								contrib/backends/nntpchan-daemon/.clang-format
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					TabWidth: 2
 | 
				
			||||||
 | 
					UseTab: Never
 | 
				
			||||||
 | 
					ColumnLimit: 120
 | 
				
			||||||
 | 
					IndentWidth: 2
 | 
				
			||||||
 | 
					Language: Cpp
 | 
				
			||||||
 | 
					BreakBeforeBraces: Custom
 | 
				
			||||||
 | 
					BraceWrapping:
 | 
				
			||||||
 | 
					  AfterClass: true
 | 
				
			||||||
 | 
					  AfterControlStatement: true
 | 
				
			||||||
 | 
					  AfterEnum: true
 | 
				
			||||||
 | 
					  AfterFunction: true
 | 
				
			||||||
 | 
					  AfterNamespace: true
 | 
				
			||||||
 | 
					  AfterStruct: true
 | 
				
			||||||
 | 
					  BeforeElse: true
 | 
				
			||||||
@@ -31,14 +31,16 @@ PKGS := libuv libsodium
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
LD_FLAGS := $(shell pkg-config --libs $(PKGS)) -lstdc++fs
 | 
					LD_FLAGS := $(shell pkg-config --libs $(PKGS)) -lstdc++fs
 | 
				
			||||||
INC_FLAGS := $(shell pkg-config --cflags $(PKGS)) -I$(HEADERS_PATH)
 | 
					INC_FLAGS := $(shell pkg-config --cflags $(PKGS)) -I$(HEADERS_PATH)
 | 
				
			||||||
CXXFLAGS := -std=c++17 -Wall -Wextra -Werror -pedantic $(INC_FLAGS)
 | 
					REQUIRED_CXXFLAGS = -std=c++17 -Wall -Wextra -Werror -pedantic $(INC_FLAGS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEBUG = 1
 | 
					DEBUG = 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ifeq ($(DEBUG),1)
 | 
					ifeq ($(DEBUG),1)
 | 
				
			||||||
	CXXFLAGS += -g
 | 
						REQUIRED_CXXFLAGS += -g
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CXXFLAGS += $(REQUIRED_CXXFLAGS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
NNTPCHAN_LIB = $(REPO)/libnntpchan.a
 | 
					NNTPCHAN_LIB = $(REPO)/libnntpchan.a
 | 
				
			||||||
MUSTACHE_LIB = $(REPO)/libmustache.a
 | 
					MUSTACHE_LIB = $(REPO)/libmustache.a
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -26,15 +26,16 @@
 | 
				
			|||||||
#define INI_HPP
 | 
					#define INI_HPP
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <cassert>
 | 
					#include <cassert>
 | 
				
			||||||
#include <map>
 | 
					#include <cstring>
 | 
				
			||||||
 | 
					#include <fstream>
 | 
				
			||||||
 | 
					#include <iostream>
 | 
				
			||||||
#include <list>
 | 
					#include <list>
 | 
				
			||||||
 | 
					#include <map>
 | 
				
			||||||
#include <stdexcept>
 | 
					#include <stdexcept>
 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
#include <cstring>
 | 
					 | 
				
			||||||
#include <iostream>
 | 
					 | 
				
			||||||
#include <fstream>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace INI {
 | 
					namespace INI
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct Level
 | 
					struct Level
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -78,8 +79,7 @@ private:
 | 
				
			|||||||
  size_t ln_;
 | 
					  size_t ln_;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
inline void
 | 
					inline void Parser::err(const char *s)
 | 
				
			||||||
Parser::err(const char* s)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  char buf[256];
 | 
					  char buf[256];
 | 
				
			||||||
  sprintf(buf, "%s on line #%ld", s, ln_);
 | 
					  sprintf(buf, "%s on line #%ld", s, ln_);
 | 
				
			||||||
@@ -92,14 +92,15 @@ inline std::string trim(const std::string& s)
 | 
				
			|||||||
  long sp = 0;
 | 
					  long sp = 0;
 | 
				
			||||||
  long ep = s.length() - 1;
 | 
					  long ep = s.length() - 1;
 | 
				
			||||||
  for (; sp <= ep; ++sp)
 | 
					  for (; sp <= ep; ++sp)
 | 
				
			||||||
    if (!strchr(p, s[sp])) break;
 | 
					    if (!strchr(p, s[sp]))
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
  for (; ep >= 0; --ep)
 | 
					  for (; ep >= 0; --ep)
 | 
				
			||||||
    if (!strchr(p, s[ep])) break;
 | 
					    if (!strchr(p, s[ep]))
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
  return s.substr(sp, ep - sp + 1);
 | 
					  return s.substr(sp, ep - sp + 1);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
inline 
 | 
					inline Parser::Parser(const char *fn) : f0_(fn), f_(&f0_), ln_(0)
 | 
				
			||||||
Parser::Parser(const char* fn) : f0_(fn), f_(&f0_), ln_(0)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  if (!f0_)
 | 
					  if (!f0_)
 | 
				
			||||||
    throw std::runtime_error(std::string("failed to open file: ") + fn);
 | 
					    throw std::runtime_error(std::string("failed to open file: ") + fn);
 | 
				
			||||||
@@ -107,25 +108,28 @@ Parser::Parser(const char* fn) : f0_(fn), f_(&f0_), ln_(0)
 | 
				
			|||||||
  parse(top_);
 | 
					  parse(top_);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
inline void 
 | 
					inline void Parser::parseSLine(std::string &sname, size_t &depth)
 | 
				
			||||||
Parser::parseSLine(std::string& sname, size_t& depth)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  depth = 0;
 | 
					  depth = 0;
 | 
				
			||||||
  for (; depth < line_.length(); ++depth)
 | 
					  for (; depth < line_.length(); ++depth)
 | 
				
			||||||
    if (line_[depth] != '[') break;
 | 
					    if (line_[depth] != '[')
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  sname = line_.substr(depth, line_.length() - 2 * depth);
 | 
					  sname = line_.substr(depth, line_.length() - 2 * depth);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
inline void
 | 
					inline void Parser::parse(Level &l)
 | 
				
			||||||
Parser::parse(Level& l)
 | 
					{
 | 
				
			||||||
 | 
					  while (std::getline(*f_, line_))
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
  while (std::getline(*f_, line_)) {
 | 
					 | 
				
			||||||
    ++ln_;
 | 
					    ++ln_;
 | 
				
			||||||
    if (line_[0] == '#' || line_[0] == ';') continue;
 | 
					    if (line_[0] == '#' || line_[0] == ';')
 | 
				
			||||||
 | 
					      continue;
 | 
				
			||||||
    line_ = trim(line_);
 | 
					    line_ = trim(line_);
 | 
				
			||||||
    if (line_.empty()) continue;
 | 
					    if (line_.empty())
 | 
				
			||||||
    if (line_[0] == '[') {
 | 
					      continue;
 | 
				
			||||||
 | 
					    if (line_[0] == '[')
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
      size_t depth;
 | 
					      size_t depth;
 | 
				
			||||||
      std::string sname;
 | 
					      std::string sname;
 | 
				
			||||||
      parseSLine(sname, depth);
 | 
					      parseSLine(sname, depth);
 | 
				
			||||||
@@ -135,28 +139,32 @@ Parser::parse(Level& l)
 | 
				
			|||||||
        err("section with wrong depth");
 | 
					        err("section with wrong depth");
 | 
				
			||||||
      if (l.depth == depth - 1)
 | 
					      if (l.depth == depth - 1)
 | 
				
			||||||
        lp = &l.sections[sname];
 | 
					        lp = &l.sections[sname];
 | 
				
			||||||
      else {
 | 
					      else
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
        lp = l.parent;
 | 
					        lp = l.parent;
 | 
				
			||||||
        size_t n = l.depth - depth;
 | 
					        size_t n = l.depth - depth;
 | 
				
			||||||
        for (size_t i = 0; i < n; ++i) lp = lp->parent;
 | 
					        for (size_t i = 0; i < n; ++i)
 | 
				
			||||||
 | 
					          lp = lp->parent;
 | 
				
			||||||
        parent = lp;
 | 
					        parent = lp;
 | 
				
			||||||
        lp = &lp->sections[sname];
 | 
					        lp = &lp->sections[sname];
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      if (lp->depth != 0)
 | 
					      if (lp->depth != 0)
 | 
				
			||||||
        err("duplicate section name on the same level");
 | 
					        err("duplicate section name on the same level");
 | 
				
			||||||
      if (!lp->parent) {
 | 
					      if (!lp->parent)
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
        lp->depth = depth;
 | 
					        lp->depth = depth;
 | 
				
			||||||
        lp->parent = parent;
 | 
					        lp->parent = parent;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      parent->ordered_sections.push_back(parent->sections.find(sname));
 | 
					      parent->ordered_sections.push_back(parent->sections.find(sname));
 | 
				
			||||||
      parse(*lp);
 | 
					      parse(*lp);
 | 
				
			||||||
    } else {
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
      size_t n = line_.find('=');
 | 
					      size_t n = line_.find('=');
 | 
				
			||||||
      if (n == std::string::npos)
 | 
					      if (n == std::string::npos)
 | 
				
			||||||
        err("no '=' found");
 | 
					        err("no '=' found");
 | 
				
			||||||
      std::pair<Level::value_map_t::const_iterator, bool> res =
 | 
					      std::pair<Level::value_map_t::const_iterator, bool> res =
 | 
				
			||||||
        l.values.insert(std::make_pair(trim(line_.substr(0, n)), 
 | 
					          l.values.insert(std::make_pair(trim(line_.substr(0, n)), trim(line_.substr(n + 1, line_.length() - n - 1))));
 | 
				
			||||||
              trim(line_.substr(n+1, line_.length()-n-1))));
 | 
					 | 
				
			||||||
      if (!res.second)
 | 
					      if (!res.second)
 | 
				
			||||||
        err("duplicated key found");
 | 
					        err("duplicated key found");
 | 
				
			||||||
      l.ordered_values.push_back(res.first);
 | 
					      l.ordered_values.push_back(res.first);
 | 
				
			||||||
@@ -164,23 +172,26 @@ Parser::parse(Level& l)
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
inline void
 | 
					inline void Parser::dump(std::ostream &s, const Level &l, const std::string &sname)
 | 
				
			||||||
Parser::dump(std::ostream& s, const Level& l, const std::string& sname)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  if (!sname.empty()) s << '\n';
 | 
					  if (!sname.empty())
 | 
				
			||||||
  for (size_t i = 0; i < l.depth; ++i) s << '[';
 | 
					    s << '\n';
 | 
				
			||||||
  if (!sname.empty()) s << sname;
 | 
					  for (size_t i = 0; i < l.depth; ++i)
 | 
				
			||||||
  for (size_t i = 0; i < l.depth; ++i) s << ']';
 | 
					    s << '[';
 | 
				
			||||||
  if (!sname.empty()) s << std::endl;
 | 
					  if (!sname.empty())
 | 
				
			||||||
 | 
					    s << sname;
 | 
				
			||||||
 | 
					  for (size_t i = 0; i < l.depth; ++i)
 | 
				
			||||||
 | 
					    s << ']';
 | 
				
			||||||
 | 
					  if (!sname.empty())
 | 
				
			||||||
 | 
					    s << std::endl;
 | 
				
			||||||
  for (Level::values_t::const_iterator it = l.ordered_values.begin(); it != l.ordered_values.end(); ++it)
 | 
					  for (Level::values_t::const_iterator it = l.ordered_values.begin(); it != l.ordered_values.end(); ++it)
 | 
				
			||||||
    s << (*it)->first << '=' << (*it)->second << std::endl;
 | 
					    s << (*it)->first << '=' << (*it)->second << std::endl;
 | 
				
			||||||
  for (Level::sections_t::const_iterator it = l.ordered_sections.begin(); it != l.ordered_sections.end(); ++it) {
 | 
					  for (Level::sections_t::const_iterator it = l.ordered_sections.begin(); it != l.ordered_sections.end(); ++it)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
    assert((*it)->second.depth == l.depth + 1);
 | 
					    assert((*it)->second.depth == l.depth + 1);
 | 
				
			||||||
    dump(s, (*it)->second, (*it)->first);
 | 
					    dump(s, (*it)->second, (*it)->first);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif // INI_HPP
 | 
					#endif // INI_HPP
 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,18 +1,19 @@
 | 
				
			|||||||
#include "ini.hpp"
 | 
					#include "ini.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <nntpchan/crypto.hpp>
 | 
					#include <nntpchan/crypto.hpp>
 | 
				
			||||||
#include <nntpchan/storage.hpp>
 | 
					 | 
				
			||||||
#include <nntpchan/nntp_server.hpp>
 | 
					 | 
				
			||||||
#include <nntpchan/event.hpp>
 | 
					#include <nntpchan/event.hpp>
 | 
				
			||||||
#include <nntpchan/exec_frontend.hpp>
 | 
					#include <nntpchan/exec_frontend.hpp>
 | 
				
			||||||
 | 
					#include <nntpchan/nntp_server.hpp>
 | 
				
			||||||
#include <nntpchan/staticfile_frontend.hpp>
 | 
					#include <nntpchan/staticfile_frontend.hpp>
 | 
				
			||||||
 | 
					#include <nntpchan/storage.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <vector>
 | 
					 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main(int argc, char *argv[])
 | 
				
			||||||
int main(int argc, char * argv[]) {
 | 
					{
 | 
				
			||||||
  if (argc != 2) {
 | 
					  if (argc != 2)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
    std::cerr << "usage: " << argv[0] << " config.ini" << std::endl;
 | 
					    std::cerr << "usage: " << argv[0] << " config.ini" << std::endl;
 | 
				
			||||||
    return 1;
 | 
					    return 1;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -23,20 +24,22 @@ int main(int argc, char * argv[]) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  nntpchan::NNTPServer nntp(loop);
 | 
					  nntpchan::NNTPServer nntp(loop);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
  std::string fname(argv[1]);
 | 
					  std::string fname(argv[1]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  std::ifstream i(fname);
 | 
					  std::ifstream i(fname);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if(i.is_open()) {
 | 
					  if (i.is_open())
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
    INI::Parser conf(i);
 | 
					    INI::Parser conf(i);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::vector<std::string> requiredSections = {"nntp", "articles"};
 | 
					    std::vector<std::string> requiredSections = {"nntp", "articles"};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    auto &level = conf.top();
 | 
					    auto &level = conf.top();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for ( const auto & section : requiredSections ) {
 | 
					    for (const auto §ion : requiredSections)
 | 
				
			||||||
      if(level.sections.find(section) == level.sections.end()) {
 | 
					    {
 | 
				
			||||||
 | 
					      if (level.sections.find(section) == level.sections.end())
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
        std::cerr << "config file " << fname << " does not have required section: ";
 | 
					        std::cerr << "config file " << fname << " does not have required section: ";
 | 
				
			||||||
        std::cerr << section << std::endl;
 | 
					        std::cerr << section << std::endl;
 | 
				
			||||||
        return 1;
 | 
					        return 1;
 | 
				
			||||||
@@ -45,7 +48,8 @@ int main(int argc, char * argv[]) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    auto &storeconf = level.sections["articles"].values;
 | 
					    auto &storeconf = level.sections["articles"].values;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (storeconf.find("store_path") == storeconf.end()) {
 | 
					    if (storeconf.find("store_path") == storeconf.end())
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
      std::cerr << "storage section does not have 'store_path' value" << std::endl;
 | 
					      std::cerr << "storage section does not have 'store_path' value" << std::endl;
 | 
				
			||||||
      return 1;
 | 
					      return 1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -54,19 +58,22 @@ int main(int argc, char * argv[]) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    auto &nntpconf = level.sections["nntp"].values;
 | 
					    auto &nntpconf = level.sections["nntp"].values;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (nntpconf.find("bind") == nntpconf.end()) {
 | 
					    if (nntpconf.find("bind") == nntpconf.end())
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
      std::cerr << "nntp section does not have 'bind' value" << std::endl;
 | 
					      std::cerr << "nntp section does not have 'bind' value" << std::endl;
 | 
				
			||||||
      return 1;
 | 
					      return 1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if(nntpconf.find("instance_name") == nntpconf.end()) {
 | 
					    if (nntpconf.find("instance_name") == nntpconf.end())
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
      std::cerr << "nntp section lacks 'instance_name' value" << std::endl;
 | 
					      std::cerr << "nntp section lacks 'instance_name' value" << std::endl;
 | 
				
			||||||
      return 1;
 | 
					      return 1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    nntp.SetInstanceName(nntpconf["instance_name"]);
 | 
					    nntp.SetInstanceName(nntpconf["instance_name"]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (nntpconf.find("authdb") != nntpconf.end()) {
 | 
					    if (nntpconf.find("authdb") != nntpconf.end())
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
      nntp.SetLoginDB(nntpconf["authdb"]);
 | 
					      nntp.SetLoginDB(nntpconf["authdb"]);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -91,9 +98,7 @@ int main(int argc, char * argv[]) {
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
      else if (ftype == "staticfile")
 | 
					      else if (ftype == "staticfile")
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
        auto required = { 
 | 
					        auto required = {"template_dir", "out_dir", "template_dialect", "max_pages"};
 | 
				
			||||||
          "template_dir", "out_dir", "template_dialect", "max_pages"
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
        for (const auto &opt : required)
 | 
					        for (const auto &opt : required)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
          if (frontconf.find(opt) == frontconf.end())
 | 
					          if (frontconf.find(opt) == frontconf.end())
 | 
				
			||||||
@@ -108,21 +113,23 @@ int main(int argc, char * argv[]) {
 | 
				
			|||||||
          std::cerr << "max_pages invalid value '" << frontconf["max_pages"] << "'" << std::endl;
 | 
					          std::cerr << "max_pages invalid value '" << frontconf["max_pages"] << "'" << std::endl;
 | 
				
			||||||
          return 1;
 | 
					          return 1;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        nntp.SetFrontend(new nntpchan::StaticFileFrontend(nntpchan::CreateTemplateEngine(frontconf["template_dialect"]), frontconf["template_dir"], frontconf["out_dir"], maxPages));
 | 
					        nntp.SetFrontend(new nntpchan::StaticFileFrontend(nntpchan::CreateTemplateEngine(frontconf["template_dialect"]),
 | 
				
			||||||
 | 
					                                                          frontconf["template_dir"], frontconf["out_dir"], maxPages));
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      else
 | 
					      else
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
        std::cerr << "unknown frontend type '" << ftype << "'" << std::endl;
 | 
					        std::cerr << "unknown frontend type '" << ftype << "'" << std::endl;
 | 
				
			||||||
        return 1;
 | 
					        return 1;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    auto &a = nntpconf["bind"];
 | 
					    auto &a = nntpconf["bind"];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    try {
 | 
					    try
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
      nntp.Bind(a);
 | 
					      nntp.Bind(a);
 | 
				
			||||||
    } catch ( std::exception & ex ) {
 | 
					    } catch (std::exception &ex)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
      std::cerr << "failed to bind: " << ex.what() << std::endl;
 | 
					      std::cerr << "failed to bind: " << ex.what() << std::endl;
 | 
				
			||||||
      return 1;
 | 
					      return 1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -130,11 +137,10 @@ int main(int argc, char * argv[]) {
 | 
				
			|||||||
    std::cerr << "nntpd for " << nntp.InstanceName() << " bound to " << a << std::endl;
 | 
					    std::cerr << "nntpd for " << nntp.InstanceName() << " bound to " << a << std::endl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    loop.Run();
 | 
					    loop.Run();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
  } else {
 | 
					  else
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
    std::cerr << "failed to open " << fname << std::endl;
 | 
					    std::cerr << "failed to open " << fname << std::endl;
 | 
				
			||||||
    return 1;
 | 
					    return 1;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,8 +10,6 @@ namespace nntpchan
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/** @brief returns true if decode was successful */
 | 
					/** @brief returns true if decode was successful */
 | 
				
			||||||
bool B64Decode(const std::string &data, std::vector<uint8_t> &out);
 | 
					bool B64Decode(const std::string &data, std::vector<uint8_t> &out);
 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
#ifndef NNTPCHAN_BUFFER_HPP
 | 
					#ifndef NNTPCHAN_BUFFER_HPP
 | 
				
			||||||
#define NNTPCHAN_BUFFER_HPP
 | 
					#define NNTPCHAN_BUFFER_HPP
 | 
				
			||||||
#include <uv.h>
 | 
					 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
 | 
					#include <uv.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace nntpchan
 | 
					namespace nntpchan
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,8 +1,8 @@
 | 
				
			|||||||
#ifndef NNTPCHAN_CRYPTO_HPP
 | 
					#ifndef NNTPCHAN_CRYPTO_HPP
 | 
				
			||||||
#define NNTPCHAN_CRYPTO_HPP
 | 
					#define NNTPCHAN_CRYPTO_HPP
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <sodium/crypto_hash.h>
 | 
					 | 
				
			||||||
#include <array>
 | 
					#include <array>
 | 
				
			||||||
 | 
					#include <sodium/crypto_hash.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace nntpchan
 | 
					namespace nntpchan
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -18,5 +18,4 @@ namespace nntpchan
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,6 @@ namespace nntpchan
 | 
				
			|||||||
class Mainloop
 | 
					class Mainloop
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
 | 
					 | 
				
			||||||
  Mainloop();
 | 
					  Mainloop();
 | 
				
			||||||
  ~Mainloop();
 | 
					  ~Mainloop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -17,9 +16,7 @@ namespace nntpchan
 | 
				
			|||||||
  void Stop();
 | 
					  void Stop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
 | 
					 | 
				
			||||||
  uv_loop_t *m_loop;
 | 
					  uv_loop_t *m_loop;
 | 
				
			||||||
    
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,7 +8,6 @@ namespace nntpchan
 | 
				
			|||||||
class ExecFrontend : public Frontend
 | 
					class ExecFrontend : public Frontend
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
 | 
					 | 
				
			||||||
  ExecFrontend(const std::string &exe);
 | 
					  ExecFrontend(const std::string &exe);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ~ExecFrontend();
 | 
					  ~ExecFrontend();
 | 
				
			||||||
@@ -18,12 +17,10 @@ namespace nntpchan
 | 
				
			|||||||
  bool AcceptsMessage(const std::string &msgid);
 | 
					  bool AcceptsMessage(const std::string &msgid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
 | 
					 | 
				
			||||||
  int Exec(std::deque<std::string> args);
 | 
					  int Exec(std::deque<std::string> args);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
  std::string m_exec;
 | 
					  std::string m_exec;
 | 
				
			||||||
    
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,9 +1,9 @@
 | 
				
			|||||||
#ifndef NNTPCHAN_FILE_HANDLE_HPP
 | 
					#ifndef NNTPCHAN_FILE_HANDLE_HPP
 | 
				
			||||||
#define NNTPCHAN_FILE_HANDLE_HPP
 | 
					#define NNTPCHAN_FILE_HANDLE_HPP
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <memory>
 | 
					 | 
				
			||||||
#include <fstream>
 | 
					 | 
				
			||||||
#include <experimental/filesystem>
 | 
					#include <experimental/filesystem>
 | 
				
			||||||
 | 
					#include <fstream>
 | 
				
			||||||
 | 
					#include <memory>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace nntpchan
 | 
					namespace nntpchan
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,8 +1,8 @@
 | 
				
			|||||||
#ifndef NNTPCHAN_FRONTEND_HPP
 | 
					#ifndef NNTPCHAN_FRONTEND_HPP
 | 
				
			||||||
#define NNTPCHAN_FRONTEND_HPP
 | 
					#define NNTPCHAN_FRONTEND_HPP
 | 
				
			||||||
#include <string>
 | 
					 | 
				
			||||||
#include <memory>
 | 
					 | 
				
			||||||
#include <experimental/filesystem>
 | 
					#include <experimental/filesystem>
 | 
				
			||||||
 | 
					#include <memory>
 | 
				
			||||||
 | 
					#include <string>
 | 
				
			||||||
namespace nntpchan
 | 
					namespace nntpchan
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -11,7 +11,6 @@ namespace nntpchan
 | 
				
			|||||||
class Frontend
 | 
					class Frontend
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
 | 
					 | 
				
			||||||
  /** @brief process an inbound message stored at fpath that we have accepted. */
 | 
					  /** @brief process an inbound message stored at fpath that we have accepted. */
 | 
				
			||||||
  virtual void ProcessNewMessage(const fs::path &fpath) = 0;
 | 
					  virtual void ProcessNewMessage(const fs::path &fpath) = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -20,7 +19,6 @@ namespace nntpchan
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  /** @brief return true if we will accept a message given its message-id */
 | 
					  /** @brief return true if we will accept a message given its message-id */
 | 
				
			||||||
  virtual bool AcceptsMessage(const std::string &msgid) = 0;
 | 
					  virtual bool AcceptsMessage(const std::string &msgid) = 0;
 | 
				
			||||||
    
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef std::unique_ptr<Frontend> Frontend_ptr;
 | 
					typedef std::unique_ptr<Frontend> Frontend_ptr;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,4 @@
 | 
				
			|||||||
#ifndef NNTPCHAN_HTTP_HPP
 | 
					#ifndef NNTPCHAN_HTTP_HPP
 | 
				
			||||||
#define NNTPCHAN_HTTP_HPP
 | 
					#define NNTPCHAN_HTTP_HPP
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,4 @@
 | 
				
			|||||||
#ifndef NNTPCHAN_HTTP_CLIENT_HPP
 | 
					#ifndef NNTPCHAN_HTTP_CLIENT_HPP
 | 
				
			||||||
#define NNTPCHAN_HTTP_CLIENT_HPP
 | 
					#define NNTPCHAN_HTTP_CLIENT_HPP
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,4 @@
 | 
				
			|||||||
#ifndef NNTPCHAN_HTTP_SERVER_HPP
 | 
					#ifndef NNTPCHAN_HTTP_SERVER_HPP
 | 
				
			||||||
#define NNTPCHAN_HTTP_SERVER_HPP
 | 
					#define NNTPCHAN_HTTP_SERVER_HPP
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,12 +1,11 @@
 | 
				
			|||||||
#ifndef NNTPCHAN_IO_HANDLE_HPP
 | 
					#ifndef NNTPCHAN_IO_HANDLE_HPP
 | 
				
			||||||
#define NNTPCHAN_IO_HANDLE_HPP
 | 
					#define NNTPCHAN_IO_HANDLE_HPP
 | 
				
			||||||
#include <memory>
 | 
					 | 
				
			||||||
#include <iostream>
 | 
					#include <iostream>
 | 
				
			||||||
 | 
					#include <memory>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace nntpchan
 | 
					namespace nntpchan
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
typedef std::unique_ptr<std::iostream> IOHandle_ptr;
 | 
					typedef std::unique_ptr<std::iostream> IOHandle_ptr;
 | 
				
			||||||
  
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,7 +9,6 @@ namespace nntpchan
 | 
				
			|||||||
class LineReader
 | 
					class LineReader
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
 | 
					 | 
				
			||||||
  LineReader(size_t lineLimit);
 | 
					  LineReader(size_t lineLimit);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /** @brief queue inbound data from connection */
 | 
					  /** @brief queue inbound data from connection */
 | 
				
			||||||
@@ -22,7 +21,6 @@ namespace nntpchan
 | 
				
			|||||||
  /** @brief handle a line from the client */
 | 
					  /** @brief handle a line from the client */
 | 
				
			||||||
  virtual void HandleLine(const std::string &line) = 0;
 | 
					  virtual void HandleLine(const std::string &line) = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
  void OnLine(const char *d, const size_t l);
 | 
					  void OnLine(const char *d, const size_t l);
 | 
				
			||||||
  std::string m_leftovers;
 | 
					  std::string m_leftovers;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,7 +13,6 @@ namespace nntpchan
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
bool ReadHeader(const FileHandle_ptr &f, RawHeader &h);
 | 
					bool ReadHeader(const FileHandle_ptr &f, RawHeader &h);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
struct MimePart
 | 
					struct MimePart
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  virtual RawHeader &Header() = 0;
 | 
					  virtual RawHeader &Header() = 0;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,12 +2,12 @@
 | 
				
			|||||||
#define NNTPCHAN_MODEL_HPP
 | 
					#define NNTPCHAN_MODEL_HPP
 | 
				
			||||||
#include <algorithm>
 | 
					#include <algorithm>
 | 
				
			||||||
#include <map>
 | 
					#include <map>
 | 
				
			||||||
 | 
					#include <nntpchan/sanitize.hpp>
 | 
				
			||||||
#include <set>
 | 
					#include <set>
 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
#include <tuple>
 | 
					#include <tuple>
 | 
				
			||||||
#include <vector>
 | 
					 | 
				
			||||||
#include <variant>
 | 
					#include <variant>
 | 
				
			||||||
#include <nntpchan/sanitize.hpp>
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace nntpchan
 | 
					namespace nntpchan
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -28,40 +28,24 @@ namespace nntpchan
 | 
				
			|||||||
// a board page is many threads in bump order
 | 
					// a board page is many threads in bump order
 | 
				
			||||||
typedef std::vector<Thread> BoardPage;
 | 
					typedef std::vector<Thread> BoardPage;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static inline const std::string & GetFilename(const PostAttachment & att)
 | 
					static inline const std::string &GetFilename(const PostAttachment &att) { return std::get<0>(att); }
 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      return std::get<0>(att);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static inline const std::string & GetHexDigest(const PostAttachment & att)
 | 
					static inline const std::string &GetHexDigest(const PostAttachment &att) { return std::get<1>(att); }
 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      return std::get<1>(att);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static inline const std::string & GetThumbnail(const PostAttachment & att)
 | 
					static inline const std::string &GetThumbnail(const PostAttachment &att) { return std::get<2>(att); }
 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      return std::get<2>(att);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static inline const PostHeader & GetHeader(const Post & post)
 | 
					static inline const PostHeader &GetHeader(const Post &post) { return std::get<0>(post); }
 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      return std::get<0>(post);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static inline const PostBody & GetBody(const Post & post)
 | 
					static inline const PostBody &GetBody(const Post &post) { return std::get<1>(post); }
 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      return std::get<1>(post);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static inline const Attachments & GetAttachments(const Post & post)
 | 
					static inline const Attachments &GetAttachments(const Post &post) { return std::get<2>(post); }
 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      return std::get<2>(post);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static inline const std::string & HeaderIFind(const PostHeader & header, const std::string & val, const std::string & fallback)
 | 
					static inline const std::string &HeaderIFind(const PostHeader &header, const std::string &val,
 | 
				
			||||||
 | 
					                                             const std::string &fallback)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  std::string ival = ToLower(val);
 | 
					  std::string ival = ToLower(val);
 | 
				
			||||||
      auto itr = std::find_if(header.begin(), header.end(), [ival](const auto & item) -> bool { return ToLower(item.first) == ival; });
 | 
					  auto itr = std::find_if(header.begin(), header.end(),
 | 
				
			||||||
 | 
					                          [ival](const auto &item) -> bool { return ToLower(item.first) == ival; });
 | 
				
			||||||
  if (itr == std::end(header))
 | 
					  if (itr == std::end(header))
 | 
				
			||||||
    return fallback;
 | 
					    return fallback;
 | 
				
			||||||
  else
 | 
					  else
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,9 +1,9 @@
 | 
				
			|||||||
#ifndef NNTPCHAN_NET_HPP
 | 
					#ifndef NNTPCHAN_NET_HPP
 | 
				
			||||||
#define NNTPCHAN_NET_HPP
 | 
					#define NNTPCHAN_NET_HPP
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <sys/types.h>
 | 
					 | 
				
			||||||
#include <netinet/in.h>
 | 
					#include <netinet/in.h>
 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
 | 
					#include <sys/types.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace nntpchan
 | 
					namespace nntpchan
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,11 +1,11 @@
 | 
				
			|||||||
#ifndef NNTPCHAN_NNTP_AUTH_HPP
 | 
					#ifndef NNTPCHAN_NNTP_AUTH_HPP
 | 
				
			||||||
#define NNTPCHAN_NNTP_AUTH_HPP
 | 
					#define NNTPCHAN_NNTP_AUTH_HPP
 | 
				
			||||||
#include <string>
 | 
					 | 
				
			||||||
#include <iostream>
 | 
					 | 
				
			||||||
#include <fstream>
 | 
					 | 
				
			||||||
#include <mutex>
 | 
					 | 
				
			||||||
#include <memory>
 | 
					 | 
				
			||||||
#include "line.hpp"
 | 
					#include "line.hpp"
 | 
				
			||||||
 | 
					#include <fstream>
 | 
				
			||||||
 | 
					#include <iostream>
 | 
				
			||||||
 | 
					#include <memory>
 | 
				
			||||||
 | 
					#include <mutex>
 | 
				
			||||||
 | 
					#include <string>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace nntpchan
 | 
					namespace nntpchan
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -30,11 +30,13 @@ namespace nntpchan
 | 
				
			|||||||
public:
 | 
					public:
 | 
				
			||||||
  HashedCredDB();
 | 
					  HashedCredDB();
 | 
				
			||||||
  bool CheckLogin(const std::string &user, const std::string &passwd);
 | 
					  bool CheckLogin(const std::string &user, const std::string &passwd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
protected:
 | 
					protected:
 | 
				
			||||||
  void SetStream(std::istream *i);
 | 
					  void SetStream(std::istream *i);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  std::string Hash(const std::string &data, const std::string &salt);
 | 
					  std::string Hash(const std::string &data, const std::string &salt);
 | 
				
			||||||
  void HandleLine(const std::string &line);
 | 
					  void HandleLine(const std::string &line);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
  bool ProcessLine(const std::string &line);
 | 
					  bool ProcessLine(const std::string &line);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -52,6 +54,7 @@ namespace nntpchan
 | 
				
			|||||||
  ~HashedFileDB();
 | 
					  ~HashedFileDB();
 | 
				
			||||||
  bool Open();
 | 
					  bool Open();
 | 
				
			||||||
  void Close();
 | 
					  void Close();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
  std::string m_fname;
 | 
					  std::string m_fname;
 | 
				
			||||||
  std::ifstream f;
 | 
					  std::ifstream f;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,10 +1,10 @@
 | 
				
			|||||||
#ifndef NNTPCHAN_NNTP_HANDLER_HPP
 | 
					#ifndef NNTPCHAN_NNTP_HANDLER_HPP
 | 
				
			||||||
#define NNTPCHAN_NNTP_HANDLER_HPP
 | 
					#define NNTPCHAN_NNTP_HANDLER_HPP
 | 
				
			||||||
#include <deque>
 | 
					 | 
				
			||||||
#include <string>
 | 
					 | 
				
			||||||
#include "line.hpp"
 | 
					#include "line.hpp"
 | 
				
			||||||
#include "nntp_auth.hpp"
 | 
					#include "nntp_auth.hpp"
 | 
				
			||||||
#include "storage.hpp"
 | 
					#include "storage.hpp"
 | 
				
			||||||
 | 
					#include <deque>
 | 
				
			||||||
 | 
					#include <string>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace nntpchan
 | 
					namespace nntpchan
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -25,16 +25,16 @@ namespace nntpchan
 | 
				
			|||||||
protected:
 | 
					protected:
 | 
				
			||||||
  void HandleLine(const std::string &line);
 | 
					  void HandleLine(const std::string &line);
 | 
				
			||||||
  void HandleCommand(const std::deque<std::string> &command);
 | 
					  void HandleCommand(const std::deque<std::string> &command);
 | 
				
			||||||
  private:
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    enum State {
 | 
					private:
 | 
				
			||||||
 | 
					  enum State
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
    eStateReadCommand,
 | 
					    eStateReadCommand,
 | 
				
			||||||
    eStateStoreArticle,
 | 
					    eStateStoreArticle,
 | 
				
			||||||
    eStateQuit
 | 
					    eStateQuit
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
 | 
					 | 
				
			||||||
  void EnterState(State st);
 | 
					  void EnterState(State st);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void ArticleObtained();
 | 
					  void ArticleObtained();
 | 
				
			||||||
@@ -58,5 +58,4 @@ namespace nntpchan
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,10 +1,10 @@
 | 
				
			|||||||
#ifndef NNTPCHAN_NNTP_SERVER_HPP
 | 
					#ifndef NNTPCHAN_NNTP_SERVER_HPP
 | 
				
			||||||
#define NNTPCHAN_NNTP_SERVER_HPP
 | 
					#define NNTPCHAN_NNTP_SERVER_HPP
 | 
				
			||||||
#include <uv.h>
 | 
					 | 
				
			||||||
#include <string>
 | 
					 | 
				
			||||||
#include <deque>
 | 
					 | 
				
			||||||
#include "frontend.hpp"
 | 
					#include "frontend.hpp"
 | 
				
			||||||
#include "server.hpp"
 | 
					#include "server.hpp"
 | 
				
			||||||
 | 
					#include <deque>
 | 
				
			||||||
 | 
					#include <string>
 | 
				
			||||||
 | 
					#include <uv.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace nntpchan
 | 
					namespace nntpchan
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -12,7 +12,6 @@ namespace nntpchan
 | 
				
			|||||||
class NNTPServer : public Server
 | 
					class NNTPServer : public Server
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
 | 
					 | 
				
			||||||
  NNTPServer(uv_loop_t *loop);
 | 
					  NNTPServer(uv_loop_t *loop);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  virtual ~NNTPServer();
 | 
					  virtual ~NNTPServer();
 | 
				
			||||||
@@ -34,19 +33,16 @@ namespace nntpchan
 | 
				
			|||||||
  void SetFrontend(Frontend *f);
 | 
					  void SetFrontend(Frontend *f);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
 | 
					 | 
				
			||||||
  std::string m_logindbpath;
 | 
					  std::string m_logindbpath;
 | 
				
			||||||
  std::string m_storagePath;
 | 
					  std::string m_storagePath;
 | 
				
			||||||
  std::string m_servername;
 | 
					  std::string m_servername;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Frontend_ptr m_frontend;
 | 
					  Frontend_ptr m_frontend;
 | 
				
			||||||
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class NNTPServerConn : public IServerConn
 | 
					class NNTPServerConn : public IServerConn
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
 | 
					 | 
				
			||||||
  NNTPServerConn(uv_loop_t *l, uv_stream_t *s, Server *parent, IConnHandler *h) : IServerConn(l, s, parent, h) {}
 | 
					  NNTPServerConn(uv_loop_t *l, uv_stream_t *s, Server *parent, IConnHandler *h) : IServerConn(l, s, parent, h) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  virtual bool IsTimedOut() { return false; };
 | 
					  virtual bool IsTimedOut() { return false; };
 | 
				
			||||||
@@ -55,7 +51,6 @@ namespace nntpchan
 | 
				
			|||||||
  virtual void SendNextReply();
 | 
					  virtual void SendNextReply();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  virtual void Greet();
 | 
					  virtual void Greet();
 | 
				
			||||||
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,16 +1,15 @@
 | 
				
			|||||||
#ifndef NNTPCHAN_SERVER_HPP
 | 
					#ifndef NNTPCHAN_SERVER_HPP
 | 
				
			||||||
#define NNTPCHAN_SERVER_HPP
 | 
					#define NNTPCHAN_SERVER_HPP
 | 
				
			||||||
#include <uv.h>
 | 
					 | 
				
			||||||
#include <deque>
 | 
					#include <deque>
 | 
				
			||||||
#include <functional>
 | 
					#include <functional>
 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
 | 
					#include <uv.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace nntpchan
 | 
					namespace nntpchan
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Server;
 | 
					class Server;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
struct IConnHandler
 | 
					struct IConnHandler
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -33,7 +32,6 @@ namespace nntpchan
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  virtual void Greet() = 0;
 | 
					  virtual void Greet() = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
  std::deque<std::string> m_sendlines;
 | 
					  std::deque<std::string> m_sendlines;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@@ -51,6 +49,7 @@ namespace nntpchan
 | 
				
			|||||||
  Server *Parent() { return m_parent; };
 | 
					  Server *Parent() { return m_parent; };
 | 
				
			||||||
  IConnHandler *GetHandler() { return m_handler; };
 | 
					  IConnHandler *GetHandler() { return m_handler; };
 | 
				
			||||||
  uv_loop_t *GetLoop() { return m_loop; };
 | 
					  uv_loop_t *GetLoop() { return m_loop; };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
  uv_tcp_t m_conn;
 | 
					  uv_tcp_t m_conn;
 | 
				
			||||||
  uv_loop_t *m_loop;
 | 
					  uv_loop_t *m_loop;
 | 
				
			||||||
@@ -82,6 +81,7 @@ namespace nntpchan
 | 
				
			|||||||
protected:
 | 
					protected:
 | 
				
			||||||
  uv_loop_t *GetLoop() { return m_loop; }
 | 
					  uv_loop_t *GetLoop() { return m_loop; }
 | 
				
			||||||
  virtual void OnAcceptError(int status) = 0;
 | 
					  virtual void OnAcceptError(int status) = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
  operator uv_handle_t *() { return (uv_handle_t *)&m_server; }
 | 
					  operator uv_handle_t *() { return (uv_handle_t *)&m_server; }
 | 
				
			||||||
  operator uv_tcp_t *() { return &m_server; }
 | 
					  operator uv_tcp_t *() { return &m_server; }
 | 
				
			||||||
@@ -94,5 +94,4 @@ namespace nntpchan
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,8 +2,8 @@
 | 
				
			|||||||
#define NNTPCHAN_STATICFILE_FRONTEND_HPP
 | 
					#define NNTPCHAN_STATICFILE_FRONTEND_HPP
 | 
				
			||||||
#include "frontend.hpp"
 | 
					#include "frontend.hpp"
 | 
				
			||||||
#include "message.hpp"
 | 
					#include "message.hpp"
 | 
				
			||||||
#include "template_engine.hpp"
 | 
					 | 
				
			||||||
#include "model.hpp"
 | 
					#include "model.hpp"
 | 
				
			||||||
 | 
					#include "template_engine.hpp"
 | 
				
			||||||
#include <experimental/filesystem>
 | 
					#include <experimental/filesystem>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace nntpchan
 | 
					namespace nntpchan
 | 
				
			||||||
@@ -14,7 +14,6 @@ namespace nntpchan
 | 
				
			|||||||
class StaticFileFrontend : public Frontend
 | 
					class StaticFileFrontend : public Frontend
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
 | 
					 | 
				
			||||||
  StaticFileFrontend(TemplateEngine *tmpl, const std::string &templateDir, const std::string &outDir, uint32_t pages);
 | 
					  StaticFileFrontend(TemplateEngine *tmpl, const std::string &templateDir, const std::string &outDir, uint32_t pages);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ~StaticFileFrontend();
 | 
					  ~StaticFileFrontend();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,10 +1,10 @@
 | 
				
			|||||||
#ifndef NNTPCHAN_STORAGE_HPP
 | 
					#ifndef NNTPCHAN_STORAGE_HPP
 | 
				
			||||||
#define NNTPCHAN_STORAGE_HPP
 | 
					#define NNTPCHAN_STORAGE_HPP
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <experimental/filesystem>
 | 
					 | 
				
			||||||
#include <string>
 | 
					 | 
				
			||||||
#include "file_handle.hpp"
 | 
					#include "file_handle.hpp"
 | 
				
			||||||
#include "message.hpp"
 | 
					#include "message.hpp"
 | 
				
			||||||
 | 
					#include <experimental/filesystem>
 | 
				
			||||||
 | 
					#include <string>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace nntpchan
 | 
					namespace nntpchan
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -14,7 +14,6 @@ namespace nntpchan
 | 
				
			|||||||
class ArticleStorage : public MessageDB
 | 
					class ArticleStorage : public MessageDB
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
    ArticleStorage();
 | 
					 | 
				
			||||||
  ArticleStorage(const fs::path &fpath);
 | 
					  ArticleStorage(const fs::path &fpath);
 | 
				
			||||||
  ~ArticleStorage();
 | 
					  ~ArticleStorage();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -43,11 +42,9 @@ namespace nntpchan
 | 
				
			|||||||
  fs::path skiplist_root(const std::string &name) const;
 | 
					  fs::path skiplist_root(const std::string &name) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  fs::path basedir;
 | 
					  fs::path basedir;
 | 
				
			||||||
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef std::unique_ptr<ArticleStorage> ArticleStorage_ptr;
 | 
					typedef std::unique_ptr<ArticleStorage> ArticleStorage_ptr;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,35 +6,29 @@ using namespace mstch;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const mstch::node render_context::null_node;
 | 
					const mstch::node render_context::null_node;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
render_context::push::push(render_context& context, const mstch::node& node):
 | 
					render_context::push::push(render_context &context, const mstch::node &node) : m_context(context)
 | 
				
			||||||
    m_context(context)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  context.m_nodes.emplace_front(node);
 | 
					  context.m_nodes.emplace_front(node);
 | 
				
			||||||
  context.m_node_ptrs.emplace_front(&node);
 | 
					  context.m_node_ptrs.emplace_front(&node);
 | 
				
			||||||
  context.m_state.push(std::unique_ptr<render_state>(new outside_section));
 | 
					  context.m_state.push(std::unique_ptr<render_state>(new outside_section));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
render_context::push::~push() {
 | 
					render_context::push::~push()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
  m_context.m_nodes.pop_front();
 | 
					  m_context.m_nodes.pop_front();
 | 
				
			||||||
  m_context.m_node_ptrs.pop_front();
 | 
					  m_context.m_node_ptrs.pop_front();
 | 
				
			||||||
  m_context.m_state.pop();
 | 
					  m_context.m_state.pop();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::string render_context::push::render(const template_type& templt) {
 | 
					std::string render_context::push::render(const template_type &templt) { return m_context.render(templt); }
 | 
				
			||||||
  return m_context.render(templt);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
render_context::render_context(
 | 
					render_context::render_context(const mstch::node &node, const std::map<std::string, template_type> &partials)
 | 
				
			||||||
    const mstch::node& node,
 | 
					    : m_partials(partials), m_nodes(1, node), m_node_ptrs(1, &node)
 | 
				
			||||||
    const std::map<std::string, template_type>& partials):
 | 
					 | 
				
			||||||
    m_partials(partials), m_nodes(1, node), m_node_ptrs(1, &node)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  m_state.push(std::unique_ptr<render_state>(new outside_section));
 | 
					  m_state.push(std::unique_ptr<render_state>(new outside_section));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const mstch::node& render_context::find_node(
 | 
					const mstch::node &render_context::find_node(const std::string &token, std::list<node const *> current_nodes)
 | 
				
			||||||
    const std::string& token,
 | 
					 | 
				
			||||||
    std::list<node const*> current_nodes)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  if (token != "." && token.find('.') != std::string::npos)
 | 
					  if (token != "." && token.find('.') != std::string::npos)
 | 
				
			||||||
    return find_node(token.substr(token.rfind('.') + 1),
 | 
					    return find_node(token.substr(token.rfind('.') + 1),
 | 
				
			||||||
@@ -46,16 +40,14 @@ const mstch::node& render_context::find_node(
 | 
				
			|||||||
  return null_node;
 | 
					  return null_node;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const mstch::node& render_context::get_node(const std::string& token) {
 | 
					const mstch::node &render_context::get_node(const std::string &token) { return find_node(token, m_node_ptrs); }
 | 
				
			||||||
    return find_node(token, m_node_ptrs);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::string render_context::render(
 | 
					std::string render_context::render(const template_type &templt, const std::string &prefix)
 | 
				
			||||||
    const template_type& templt, const std::string& prefix)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  std::string output;
 | 
					  std::string output;
 | 
				
			||||||
  bool prev_eol = true;
 | 
					  bool prev_eol = true;
 | 
				
			||||||
  for (auto& token: templt) {
 | 
					  for (auto &token : templt)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
    if (prev_eol && prefix.length() != 0)
 | 
					    if (prev_eol && prefix.length() != 0)
 | 
				
			||||||
      output += m_state.top()->render(*this, {prefix});
 | 
					      output += m_state.top()->render(*this, {prefix});
 | 
				
			||||||
    output += m_state.top()->render(*this, token);
 | 
					    output += m_state.top()->render(*this, token);
 | 
				
			||||||
@@ -64,9 +56,7 @@ std::string render_context::render(
 | 
				
			|||||||
  return output;
 | 
					  return output;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::string render_context::render_partial(
 | 
					std::string render_context::render_partial(const std::string &partial_name, const std::string &prefix)
 | 
				
			||||||
    const std::string& partial_name, const std::string& prefix)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  return m_partials.count(partial_name) ?
 | 
					  return m_partials.count(partial_name) ? render(m_partials.at(partial_name), prefix) : "";
 | 
				
			||||||
      render(m_partials.at(partial_name), prefix) : "";
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,49 +3,45 @@
 | 
				
			|||||||
#include <deque>
 | 
					#include <deque>
 | 
				
			||||||
#include <list>
 | 
					#include <list>
 | 
				
			||||||
#include <sstream>
 | 
					#include <sstream>
 | 
				
			||||||
#include <string>
 | 
					 | 
				
			||||||
#include <stack>
 | 
					#include <stack>
 | 
				
			||||||
 | 
					#include <string>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <mstch/mstch.hpp>
 | 
					 | 
				
			||||||
#include "state/render_state.hpp"
 | 
					#include "state/render_state.hpp"
 | 
				
			||||||
#include "template_type.hpp"
 | 
					#include "template_type.hpp"
 | 
				
			||||||
 | 
					#include <mstch/mstch.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace mstch {
 | 
					namespace mstch
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class render_context {
 | 
					class render_context
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
  class push {
 | 
					  class push
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
  public:
 | 
					  public:
 | 
				
			||||||
    push(render_context &context, const mstch::node &node = {});
 | 
					    push(render_context &context, const mstch::node &node = {});
 | 
				
			||||||
    ~push();
 | 
					    ~push();
 | 
				
			||||||
    std::string render(const template_type &templt);
 | 
					    std::string render(const template_type &templt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private:
 | 
					  private:
 | 
				
			||||||
    render_context &m_context;
 | 
					    render_context &m_context;
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  render_context(
 | 
					  render_context(const mstch::node &node, const std::map<std::string, template_type> &partials);
 | 
				
			||||||
      const mstch::node& node,
 | 
					 | 
				
			||||||
      const std::map<std::string, template_type>& partials);
 | 
					 | 
				
			||||||
  const mstch::node &get_node(const std::string &token);
 | 
					  const mstch::node &get_node(const std::string &token);
 | 
				
			||||||
  std::string render(
 | 
					  std::string render(const template_type &templt, const std::string &prefix = "");
 | 
				
			||||||
      const template_type& templt, const std::string& prefix = "");
 | 
					  std::string render_partial(const std::string &partial_name, const std::string &prefix);
 | 
				
			||||||
  std::string render_partial(
 | 
					  template <class T, class... Args> void set_state(Args &&... args)
 | 
				
			||||||
      const std::string& partial_name, const std::string& prefix);
 | 
					  {
 | 
				
			||||||
  template<class T, class... Args>
 | 
					    m_state.top() = std::unique_ptr<render_state>(new T(std::forward<Args>(args)...));
 | 
				
			||||||
  void set_state(Args&& ... args) {
 | 
					 | 
				
			||||||
    m_state.top() = std::unique_ptr<render_state>(
 | 
					 | 
				
			||||||
        new T(std::forward<Args>(args)...));
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
  static const mstch::node null_node;
 | 
					  static const mstch::node null_node;
 | 
				
			||||||
  const mstch::node& find_node(
 | 
					  const mstch::node &find_node(const std::string &token, std::list<node const *> current_nodes);
 | 
				
			||||||
      const std::string& token,
 | 
					 | 
				
			||||||
      std::list<node const*> current_nodes);
 | 
					 | 
				
			||||||
  std::map<std::string, template_type> m_partials;
 | 
					  std::map<std::string, template_type> m_partials;
 | 
				
			||||||
  std::deque<mstch::node> m_nodes;
 | 
					  std::deque<mstch::node> m_nodes;
 | 
				
			||||||
  std::list<const mstch::node *> m_node_ptrs;
 | 
					  std::list<const mstch::node *> m_node_ptrs;
 | 
				
			||||||
  std::stack<std::unique_ptr<render_state>> m_state;
 | 
					  std::stack<std::unique_ptr<render_state>> m_state;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,18 +1,20 @@
 | 
				
			|||||||
#include "in_section.hpp"
 | 
					#include "in_section.hpp"
 | 
				
			||||||
#include "outside_section.hpp"
 | 
					 | 
				
			||||||
#include "../visitor/is_node_empty.hpp"
 | 
					#include "../visitor/is_node_empty.hpp"
 | 
				
			||||||
#include "../visitor/render_section.hpp"
 | 
					#include "../visitor/render_section.hpp"
 | 
				
			||||||
 | 
					#include "outside_section.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace mstch;
 | 
					using namespace mstch;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
in_section::in_section(type type, const token& start_token):
 | 
					in_section::in_section(type type, const token &start_token)
 | 
				
			||||||
    m_type(type), m_start_token(start_token), m_skipped_openings(0)
 | 
					    : m_type(type), m_start_token(start_token), m_skipped_openings(0)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::string in_section::render(render_context& ctx, const token& token) {
 | 
					std::string in_section::render(render_context &ctx, const token &token)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
  if (token.token_type() == token::type::section_close)
 | 
					  if (token.token_type() == token::type::section_close)
 | 
				
			||||||
    if (token.name() == m_start_token.name() && m_skipped_openings == 0) {
 | 
					    if (token.name() == m_start_token.name() && m_skipped_openings == 0)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
      auto &node = ctx.get_node(m_start_token.name());
 | 
					      auto &node = ctx.get_node(m_start_token.name());
 | 
				
			||||||
      std::string out;
 | 
					      std::string out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -23,10 +25,10 @@ std::string in_section::render(render_context& ctx, const token& token) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      ctx.set_state<outside_section>();
 | 
					      ctx.set_state<outside_section>();
 | 
				
			||||||
      return out;
 | 
					      return out;
 | 
				
			||||||
    } else
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
      m_skipped_openings--;
 | 
					      m_skipped_openings--;
 | 
				
			||||||
  else if (token.token_type() == token::type::inverted_section_open ||
 | 
					  else if (token.token_type() == token::type::inverted_section_open || token.token_type() == token::type::section_open)
 | 
				
			||||||
      token.token_type() == token::type::section_open)
 | 
					 | 
				
			||||||
    m_skipped_openings++;
 | 
					    m_skipped_openings++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  m_section << token;
 | 
					  m_section << token;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,14 +3,20 @@
 | 
				
			|||||||
#include <sstream>
 | 
					#include <sstream>
 | 
				
			||||||
#include <vector>
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "render_state.hpp"
 | 
					 | 
				
			||||||
#include "../template_type.hpp"
 | 
					#include "../template_type.hpp"
 | 
				
			||||||
 | 
					#include "render_state.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace mstch {
 | 
					namespace mstch
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class in_section: public render_state {
 | 
					class in_section : public render_state
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
  enum class type { inverted, normal };
 | 
					  enum class type
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    inverted,
 | 
				
			||||||
 | 
					    normal
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
  in_section(type type, const token &start_token);
 | 
					  in_section(type type, const token &start_token);
 | 
				
			||||||
  std::string render(render_context &context, const token &token) override;
 | 
					  std::string render(render_context &context, const token &token) override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -20,5 +26,4 @@ class in_section: public render_state {
 | 
				
			|||||||
  template_type m_section;
 | 
					  template_type m_section;
 | 
				
			||||||
  int m_skipped_openings;
 | 
					  int m_skipped_openings;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,16 +1,16 @@
 | 
				
			|||||||
#include "outside_section.hpp"
 | 
					#include "outside_section.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "../render_context.hpp"
 | 
				
			||||||
#include "../visitor/render_node.hpp"
 | 
					#include "../visitor/render_node.hpp"
 | 
				
			||||||
#include "in_section.hpp"
 | 
					#include "in_section.hpp"
 | 
				
			||||||
#include "../render_context.hpp"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace mstch;
 | 
					using namespace mstch;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::string outside_section::render(
 | 
					std::string outside_section::render(render_context &ctx, const token &token)
 | 
				
			||||||
    render_context& ctx, const token& token)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  using flag = render_node::flag;
 | 
					  using flag = render_node::flag;
 | 
				
			||||||
  switch (token.token_type()) {
 | 
					  switch (token.token_type())
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
  case token::type::section_open:
 | 
					  case token::type::section_open:
 | 
				
			||||||
    ctx.set_state<in_section>(in_section::type::normal, token);
 | 
					    ctx.set_state<in_section>(in_section::type::normal, token);
 | 
				
			||||||
    break;
 | 
					    break;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,11 +2,12 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "render_state.hpp"
 | 
					#include "render_state.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace mstch {
 | 
					namespace mstch
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class outside_section: public render_state {
 | 
					class outside_section : public render_state
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
  std::string render(render_context &context, const token &token) override;
 | 
					  std::string render(render_context &context, const token &token) override;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,14 +4,15 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "../token.hpp"
 | 
					#include "../token.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace mstch {
 | 
					namespace mstch
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class render_context;
 | 
					class render_context;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class render_state {
 | 
					class render_state
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
  virtual ~render_state() {}
 | 
					  virtual ~render_state() {}
 | 
				
			||||||
  virtual std::string render(render_context &context, const token &token) = 0;
 | 
					  virtual std::string render(render_context &context, const token &token) = 0;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,57 +2,58 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
using namespace mstch;
 | 
					using namespace mstch;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template_type::template_type(const std::string& str, const delim_type& delims):
 | 
					template_type::template_type(const std::string &str, const delim_type &delims)
 | 
				
			||||||
    m_open(delims.first), m_close(delims.second)
 | 
					    : m_open(delims.first), m_close(delims.second)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  tokenize(str);
 | 
					  tokenize(str);
 | 
				
			||||||
  strip_whitespace();
 | 
					  strip_whitespace();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template_type::template_type(const std::string& str):
 | 
					template_type::template_type(const std::string &str) : m_open("{{"), m_close("}}")
 | 
				
			||||||
    m_open("{{"), m_close("}}")
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  tokenize(str);
 | 
					  tokenize(str);
 | 
				
			||||||
  strip_whitespace();
 | 
					  strip_whitespace();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void template_type::process_text(citer begin, citer end) {
 | 
					void template_type::process_text(citer begin, citer end)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
  if (begin == end)
 | 
					  if (begin == end)
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
  auto start = begin;
 | 
					  auto start = begin;
 | 
				
			||||||
  for (auto it = begin; it != end; ++it)
 | 
					  for (auto it = begin; it != end; ++it)
 | 
				
			||||||
    if (*it == '\n' || it == end - 1) {
 | 
					    if (*it == '\n' || it == end - 1)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
      m_tokens.push_back({{start, it + 1}});
 | 
					      m_tokens.push_back({{start, it + 1}});
 | 
				
			||||||
      start = it + 1;
 | 
					      start = it + 1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void template_type::tokenize(const std::string& tmp) {
 | 
					void template_type::tokenize(const std::string &tmp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
  citer beg = tmp.begin();
 | 
					  citer beg = tmp.begin();
 | 
				
			||||||
  auto npos = std::string::npos;
 | 
					  auto npos = std::string::npos;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  for (std::size_t cur_pos = 0; cur_pos < tmp.size();) {
 | 
					  for (std::size_t cur_pos = 0; cur_pos < tmp.size();)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
    auto open_pos = tmp.find(m_open, cur_pos);
 | 
					    auto open_pos = tmp.find(m_open, cur_pos);
 | 
				
			||||||
    auto close_pos = tmp.find(
 | 
					    auto close_pos = tmp.find(m_close, open_pos == npos ? open_pos : open_pos + 1);
 | 
				
			||||||
        m_close, open_pos == npos ? open_pos : open_pos + 1);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (close_pos != npos && open_pos != npos) {
 | 
					    if (close_pos != npos && open_pos != npos)
 | 
				
			||||||
      if (*(beg + open_pos + m_open.size()) == '{' &&
 | 
					    {
 | 
				
			||||||
          *(beg + close_pos + m_close.size()) == '}')
 | 
					      if (*(beg + open_pos + m_open.size()) == '{' && *(beg + close_pos + m_close.size()) == '}')
 | 
				
			||||||
        ++close_pos;
 | 
					        ++close_pos;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      process_text(beg + cur_pos, beg + open_pos);
 | 
					      process_text(beg + cur_pos, beg + open_pos);
 | 
				
			||||||
      cur_pos = close_pos + m_close.size();
 | 
					      cur_pos = close_pos + m_close.size();
 | 
				
			||||||
      m_tokens.push_back({{beg + open_pos, beg + close_pos + m_close.size()},
 | 
					      m_tokens.push_back({{beg + open_pos, beg + close_pos + m_close.size()}, m_open.size(), m_close.size()});
 | 
				
			||||||
          m_open.size(), m_close.size()});
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (cur_pos == tmp.size()) {
 | 
					      if (cur_pos == tmp.size())
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
        m_tokens.push_back({{""}});
 | 
					        m_tokens.push_back({{""}});
 | 
				
			||||||
        m_tokens.back().eol(true);
 | 
					        m_tokens.back().eol(true);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (*(beg + open_pos + m_open.size()) == '=' &&
 | 
					      if (*(beg + open_pos + m_open.size()) == '=' && *(beg + close_pos - 1) == '=')
 | 
				
			||||||
          *(beg + close_pos - 1) == '=')
 | 
					 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
        auto tok_beg = beg + open_pos + m_open.size() + 1;
 | 
					        auto tok_beg = beg + open_pos + m_open.size() + 1;
 | 
				
			||||||
        auto tok_end = beg + close_pos - 1;
 | 
					        auto tok_end = beg + close_pos - 1;
 | 
				
			||||||
@@ -61,27 +62,32 @@ void template_type::tokenize(const std::string& tmp) {
 | 
				
			|||||||
        m_open = {front_skip, beg + tmp.find(' ', front_skip - beg)};
 | 
					        m_open = {front_skip, beg + tmp.find(' ', front_skip - beg)};
 | 
				
			||||||
        m_close = {beg + tmp.rfind(' ', back_skip - beg) + 1, back_skip + 1};
 | 
					        m_close = {beg + tmp.rfind(' ', back_skip - beg) + 1, back_skip + 1};
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    } else {
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
      process_text(beg + cur_pos, tmp.end());
 | 
					      process_text(beg + cur_pos, tmp.end());
 | 
				
			||||||
      cur_pos = close_pos;
 | 
					      cur_pos = close_pos;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void template_type::strip_whitespace() {
 | 
					void template_type::strip_whitespace()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
  auto line_begin = m_tokens.begin();
 | 
					  auto line_begin = m_tokens.begin();
 | 
				
			||||||
  bool has_tag = false, non_space = false;
 | 
					  bool has_tag = false, non_space = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  for (auto it = m_tokens.begin(); it != m_tokens.end(); ++it) {
 | 
					  for (auto it = m_tokens.begin(); it != m_tokens.end(); ++it)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
    auto type = (*it).token_type();
 | 
					    auto type = (*it).token_type();
 | 
				
			||||||
    if (type != token::type::text && type != token::type::variable &&
 | 
					    if (type != token::type::text && type != token::type::variable && type != token::type::unescaped_variable)
 | 
				
			||||||
        type != token::type::unescaped_variable)
 | 
					 | 
				
			||||||
      has_tag = true;
 | 
					      has_tag = true;
 | 
				
			||||||
    else if (!(*it).ws_only())
 | 
					    else if (!(*it).ws_only())
 | 
				
			||||||
      non_space = true;
 | 
					      non_space = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if ((*it).eol()) {
 | 
					    if ((*it).eol())
 | 
				
			||||||
      if (has_tag && !non_space) {
 | 
					    {
 | 
				
			||||||
 | 
					      if (has_tag && !non_space)
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
        store_prefixes(line_begin);
 | 
					        store_prefixes(line_begin);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        auto c = line_begin;
 | 
					        auto c = line_begin;
 | 
				
			||||||
@@ -96,9 +102,9 @@ void template_type::strip_whitespace() {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void template_type::store_prefixes(std::vector<token>::iterator beg) {
 | 
					void template_type::store_prefixes(std::vector<token>::iterator beg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
  for (auto cur = beg; !(*cur).eol(); ++cur)
 | 
					  for (auto cur = beg; !(*cur).eol(); ++cur)
 | 
				
			||||||
    if ((*cur).token_type() == token::type::partial &&
 | 
					    if ((*cur).token_type() == token::type::partial && cur != beg && (*(cur - 1)).ws_only())
 | 
				
			||||||
        cur != beg && (*(cur - 1)).ws_only())
 | 
					 | 
				
			||||||
      (*cur).partial_prefix((*(cur - 1)).raw());
 | 
					      (*cur).partial_prefix((*(cur - 1)).raw());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,9 +6,11 @@
 | 
				
			|||||||
#include "token.hpp"
 | 
					#include "token.hpp"
 | 
				
			||||||
#include "utils.hpp"
 | 
					#include "utils.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace mstch {
 | 
					namespace mstch
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class template_type {
 | 
					class template_type
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
  template_type() = default;
 | 
					  template_type() = default;
 | 
				
			||||||
  template_type(const std::string &str);
 | 
					  template_type(const std::string &str);
 | 
				
			||||||
@@ -26,5 +28,4 @@ class template_type {
 | 
				
			|||||||
  void tokenize(const std::string &tmp);
 | 
					  void tokenize(const std::string &tmp);
 | 
				
			||||||
  void store_prefixes(std::vector<token>::iterator beg);
 | 
					  void store_prefixes(std::vector<token>::iterator beg);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,38 +3,53 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
using namespace mstch;
 | 
					using namespace mstch;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
token::type token::token_info(char c) {
 | 
					token::type token::token_info(char c)
 | 
				
			||||||
  switch (c) {
 | 
					{
 | 
				
			||||||
    case '>': return type::partial;
 | 
					  switch (c)
 | 
				
			||||||
    case '^': return type::inverted_section_open;
 | 
					  {
 | 
				
			||||||
    case '/': return type::section_close;
 | 
					  case '>':
 | 
				
			||||||
    case '&': return type::unescaped_variable;
 | 
					    return type::partial;
 | 
				
			||||||
    case '#': return type::section_open;
 | 
					  case '^':
 | 
				
			||||||
    case '!': return type::comment;
 | 
					    return type::inverted_section_open;
 | 
				
			||||||
    default: return type::variable;
 | 
					  case '/':
 | 
				
			||||||
 | 
					    return type::section_close;
 | 
				
			||||||
 | 
					  case '&':
 | 
				
			||||||
 | 
					    return type::unescaped_variable;
 | 
				
			||||||
 | 
					  case '#':
 | 
				
			||||||
 | 
					    return type::section_open;
 | 
				
			||||||
 | 
					  case '!':
 | 
				
			||||||
 | 
					    return type::comment;
 | 
				
			||||||
 | 
					  default:
 | 
				
			||||||
 | 
					    return type::variable;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
token::token(const std::string& str, std::size_t left, std::size_t right):
 | 
					token::token(const std::string &str, std::size_t left, std::size_t right) : m_raw(str), m_eol(false), m_ws_only(false)
 | 
				
			||||||
    m_raw(str), m_eol(false), m_ws_only(false)
 | 
					{
 | 
				
			||||||
 | 
					  if (left != 0 && right != 0)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    if (str[left] == '=' && str[str.size() - right - 1] == '=')
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
  if (left != 0 && right != 0) {
 | 
					 | 
				
			||||||
    if (str[left] == '=' && str[str.size() - right - 1] == '=') {
 | 
					 | 
				
			||||||
      m_type = type::delimiter_change;
 | 
					      m_type = type::delimiter_change;
 | 
				
			||||||
    } else if (str[left] == '{' && str[str.size() - right - 1] == '}') {
 | 
					    }
 | 
				
			||||||
 | 
					    else if (str[left] == '{' && str[str.size() - right - 1] == '}')
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
      m_type = type::unescaped_variable;
 | 
					      m_type = type::unescaped_variable;
 | 
				
			||||||
      m_name = {first_not_ws(str.begin() + left + 1, str.end() - right),
 | 
					      m_name = {first_not_ws(str.begin() + left + 1, str.end() - right),
 | 
				
			||||||
                first_not_ws(str.rbegin() + 1 + right, str.rend() - left) + 1};
 | 
					                first_not_ws(str.rbegin() + 1 + right, str.rend() - left) + 1};
 | 
				
			||||||
    } else {
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
      auto c = first_not_ws(str.begin() + left, str.end() - right);
 | 
					      auto c = first_not_ws(str.begin() + left, str.end() - right);
 | 
				
			||||||
      m_type = token_info(*c);
 | 
					      m_type = token_info(*c);
 | 
				
			||||||
      if (m_type != type::variable)
 | 
					      if (m_type != type::variable)
 | 
				
			||||||
        c = first_not_ws(c + 1, str.end() - right);
 | 
					        c = first_not_ws(c + 1, str.end() - right);
 | 
				
			||||||
      m_name = {c, first_not_ws(str.rbegin() + right, str.rend() - left) + 1};
 | 
					      m_name = {c, first_not_ws(str.rbegin() + right, str.rend() - left) + 1};
 | 
				
			||||||
      m_delims = {{str.begin(), str.begin() + left},
 | 
					      m_delims = {{str.begin(), str.begin() + left}, {str.end() - right, str.end()}};
 | 
				
			||||||
          {str.end() - right, str.end()}};
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  } else {
 | 
					  }
 | 
				
			||||||
 | 
					  else
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
    m_type = type::text;
 | 
					    m_type = type::text;
 | 
				
			||||||
    m_eol = (str.size() > 0 && str[str.size() - 1] == '\n');
 | 
					    m_eol = (str.size() > 0 && str[str.size() - 1] == '\n');
 | 
				
			||||||
    m_ws_only = (str.find_first_not_of(" \r\n\t") == std::string::npos);
 | 
					    m_ws_only = (str.find_first_not_of(" \r\n\t") == std::string::npos);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,15 +2,25 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace mstch {
 | 
					namespace mstch
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using delim_type = std::pair<std::string, std::string>;
 | 
					using delim_type = std::pair<std::string, std::string>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class token {
 | 
					class token
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
  enum class type {
 | 
					  enum class type
 | 
				
			||||||
    text, variable, section_open, section_close, inverted_section_open,
 | 
					  {
 | 
				
			||||||
    unescaped_variable, comment, partial, delimiter_change
 | 
					    text,
 | 
				
			||||||
 | 
					    variable,
 | 
				
			||||||
 | 
					    section_open,
 | 
				
			||||||
 | 
					    section_close,
 | 
				
			||||||
 | 
					    inverted_section_open,
 | 
				
			||||||
 | 
					    unescaped_variable,
 | 
				
			||||||
 | 
					    comment,
 | 
				
			||||||
 | 
					    partial,
 | 
				
			||||||
 | 
					    delimiter_change
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
  token(const std::string &str, std::size_t left = 0, std::size_t right = 0);
 | 
					  token(const std::string &str, std::size_t left = 0, std::size_t right = 0);
 | 
				
			||||||
  type token_type() const { return m_type; };
 | 
					  type token_type() const { return m_type; };
 | 
				
			||||||
@@ -18,9 +28,7 @@ class token {
 | 
				
			|||||||
  const std::string &name() const { return m_name; };
 | 
					  const std::string &name() const { return m_name; };
 | 
				
			||||||
  const std::string &partial_prefix() const { return m_partial_prefix; };
 | 
					  const std::string &partial_prefix() const { return m_partial_prefix; };
 | 
				
			||||||
  const delim_type &delims() const { return m_delims; };
 | 
					  const delim_type &delims() const { return m_delims; };
 | 
				
			||||||
  void partial_prefix(const std::string& p_partial_prefix) {
 | 
					  void partial_prefix(const std::string &p_partial_prefix) { m_partial_prefix = p_partial_prefix; };
 | 
				
			||||||
    m_partial_prefix = p_partial_prefix;
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
  bool eol() const { return m_eol; }
 | 
					  bool eol() const { return m_eol; }
 | 
				
			||||||
  void eol(bool eol) { m_eol = eol; }
 | 
					  void eol(bool eol) { m_eol = eol; }
 | 
				
			||||||
  bool ws_only() const { return m_ws_only; }
 | 
					  bool ws_only() const { return m_ws_only; }
 | 
				
			||||||
@@ -35,5 +43,4 @@ class token {
 | 
				
			|||||||
  bool m_ws_only;
 | 
					  bool m_ws_only;
 | 
				
			||||||
  type token_info(char c);
 | 
					  type token_info(char c);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,23 +1,26 @@
 | 
				
			|||||||
#include "utils.hpp"
 | 
					#include "utils.hpp"
 | 
				
			||||||
#include "mstch/mstch.hpp"
 | 
					#include "mstch/mstch.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mstch::citer mstch::first_not_ws(mstch::citer begin, mstch::citer end) {
 | 
					mstch::citer mstch::first_not_ws(mstch::citer begin, mstch::citer end)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
  for (auto it = begin; it != end; ++it)
 | 
					  for (auto it = begin; it != end; ++it)
 | 
				
			||||||
    if (*it != ' ') return it;
 | 
					    if (*it != ' ')
 | 
				
			||||||
 | 
					      return it;
 | 
				
			||||||
  return end;
 | 
					  return end;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mstch::citer mstch::first_not_ws(mstch::criter begin, mstch::criter end) {
 | 
					mstch::citer mstch::first_not_ws(mstch::criter begin, mstch::criter end)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
  for (auto rit = begin; rit != end; ++rit)
 | 
					  for (auto rit = begin; rit != end; ++rit)
 | 
				
			||||||
    if (*rit != ' ') return --(rit.base());
 | 
					    if (*rit != ' ')
 | 
				
			||||||
 | 
					      return --(rit.base());
 | 
				
			||||||
  return --(end.base());
 | 
					  return --(end.base());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mstch::criter mstch::reverse(mstch::citer it) {
 | 
					mstch::criter mstch::reverse(mstch::citer it) { return std::reverse_iterator<mstch::citer>(it); }
 | 
				
			||||||
  return std::reverse_iterator<mstch::citer>(it);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::string mstch::html_escape(const std::string& str) {
 | 
					std::string mstch::html_escape(const std::string &str)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
  if (mstch::config::escape)
 | 
					  if (mstch::config::escape)
 | 
				
			||||||
    return mstch::config::escape(str);
 | 
					    return mstch::config::escape(str);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -30,14 +33,28 @@ std::string mstch::html_escape(const std::string& str) {
 | 
				
			|||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  for (auto it = str.begin(); it != str.end(); ++it)
 | 
					  for (auto it = str.begin(); it != str.end(); ++it)
 | 
				
			||||||
    switch (*it) {
 | 
					    switch (*it)
 | 
				
			||||||
      case '&': add_escape("&", it); break;
 | 
					    {
 | 
				
			||||||
      case '\'': add_escape("'", it); break;
 | 
					    case '&':
 | 
				
			||||||
      case '"': add_escape(""", it); break;
 | 
					      add_escape("&", it);
 | 
				
			||||||
      case '<': add_escape("<", it); break;
 | 
					      break;
 | 
				
			||||||
      case '>': add_escape(">", it); break;
 | 
					    case '\'':
 | 
				
			||||||
      case '/': add_escape("/", it); break;
 | 
					      add_escape("'", it);
 | 
				
			||||||
      default: break;
 | 
					      break;
 | 
				
			||||||
 | 
					    case '"':
 | 
				
			||||||
 | 
					      add_escape(""", it);
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case '<':
 | 
				
			||||||
 | 
					      add_escape("<", it);
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case '>':
 | 
				
			||||||
 | 
					      add_escape(">", it);
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case '/':
 | 
				
			||||||
 | 
					      add_escape("/", it);
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return out + std::string{start, str.end()};
 | 
					  return out + std::string{start, str.end()};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,9 +1,10 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <string>
 | 
					 | 
				
			||||||
#include <boost/variant/apply_visitor.hpp>
 | 
					#include <boost/variant/apply_visitor.hpp>
 | 
				
			||||||
 | 
					#include <string>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace mstch {
 | 
					namespace mstch
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using citer = std::string::const_iterator;
 | 
					using citer = std::string::const_iterator;
 | 
				
			||||||
using criter = std::string::const_reverse_iterator;
 | 
					using criter = std::string::const_reverse_iterator;
 | 
				
			||||||
@@ -13,11 +14,8 @@ citer first_not_ws(criter begin, criter end);
 | 
				
			|||||||
std::string html_escape(const std::string &str);
 | 
					std::string html_escape(const std::string &str);
 | 
				
			||||||
criter reverse(citer it);
 | 
					criter reverse(citer it);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template<class... Args>
 | 
					template <class... Args> auto visit(Args &&... args) -> decltype(boost::apply_visitor(std::forward<Args>(args)...))
 | 
				
			||||||
auto visit(Args&&... args) -> decltype(boost::apply_visitor(
 | 
					 | 
				
			||||||
    std::forward<Args>(args)...))
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  return boost::apply_visitor(std::forward<Args>(args)...);
 | 
					  return boost::apply_visitor(std::forward<Args>(args)...);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,34 +2,25 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <boost/variant/static_visitor.hpp>
 | 
					#include <boost/variant/static_visitor.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "mstch/mstch.hpp"
 | 
					 | 
				
			||||||
#include "has_token.hpp"
 | 
					#include "has_token.hpp"
 | 
				
			||||||
 | 
					#include "mstch/mstch.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace mstch {
 | 
					namespace mstch
 | 
				
			||||||
 | 
					 | 
				
			||||||
class get_token: public boost::static_visitor<const mstch::node&> {
 | 
					 | 
				
			||||||
 public:
 | 
					 | 
				
			||||||
  get_token(const std::string& token, const mstch::node& node):
 | 
					 | 
				
			||||||
      m_token(token), m_node(node)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  template<class T>
 | 
					class get_token : public boost::static_visitor<const mstch::node &>
 | 
				
			||||||
  const mstch::node& operator()(const T&) const {
 | 
					{
 | 
				
			||||||
    return m_node;
 | 
					public:
 | 
				
			||||||
  }
 | 
					  get_token(const std::string &token, const mstch::node &node) : m_token(token), m_node(node) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const mstch::node& operator()(const map& map) const {
 | 
					  template <class T> const mstch::node &operator()(const T &) const { return m_node; }
 | 
				
			||||||
    return map.at(m_token);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const mstch::node& operator()(const std::shared_ptr<object>& object) const {
 | 
					  const mstch::node &operator()(const map &map) const { return map.at(m_token); }
 | 
				
			||||||
    return object->at(m_token);
 | 
					
 | 
				
			||||||
  }
 | 
					  const mstch::node &operator()(const std::shared_ptr<object> &object) const { return object->at(m_token); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
  const std::string &m_token;
 | 
					  const std::string &m_token;
 | 
				
			||||||
  const mstch::node &m_node;
 | 
					  const mstch::node &m_node;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,28 +4,21 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "mstch/mstch.hpp"
 | 
					#include "mstch/mstch.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace mstch {
 | 
					namespace mstch
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class has_token: public boost::static_visitor<bool> {
 | 
					class has_token : public boost::static_visitor<bool>
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
  has_token(const std::string& token): m_token(token) {
 | 
					  has_token(const std::string &token) : m_token(token) {}
 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  template<class T>
 | 
					  template <class T> bool operator()(const T &) const { return m_token == "."; }
 | 
				
			||||||
  bool operator()(const T&) const {
 | 
					 | 
				
			||||||
    return m_token == ".";
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  bool operator()(const map& map) const {
 | 
					  bool operator()(const map &map) const { return map.count(m_token) == 1; }
 | 
				
			||||||
    return map.count(m_token) == 1;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  bool operator()(const std::shared_ptr<object>& object) const {
 | 
					  bool operator()(const std::shared_ptr<object> &object) const { return object->has(m_token); }
 | 
				
			||||||
    return object->has(m_token);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
  const std::string &m_token;
 | 
					  const std::string &m_token;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,38 +4,24 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "mstch/mstch.hpp"
 | 
					#include "mstch/mstch.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace mstch {
 | 
					namespace mstch
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class is_node_empty: public boost::static_visitor<bool> {
 | 
					class is_node_empty : public boost::static_visitor<bool>
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
  template<class T>
 | 
					  template <class T> bool operator()(const T &) const { return false; }
 | 
				
			||||||
  bool operator()(const T&) const {
 | 
					 | 
				
			||||||
    return false;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  bool operator()(const std::nullptr_t&) const {
 | 
					  bool operator()(const std::nullptr_t &) const { return true; }
 | 
				
			||||||
    return true;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  bool operator()(const int& value) const {
 | 
					  bool operator()(const int &value) const { return value == 0; }
 | 
				
			||||||
    return value == 0;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  bool operator()(const double& value) const {
 | 
					  bool operator()(const double &value) const { return value == 0; }
 | 
				
			||||||
    return value == 0;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  bool operator()(const bool& value) const {
 | 
					  bool operator()(const bool &value) const { return !value; }
 | 
				
			||||||
    return !value;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  bool operator()(const std::string& value) const {
 | 
					  bool operator()(const std::string &value) const { return value == ""; }
 | 
				
			||||||
    return value == "";
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  bool operator()(const array& array) const {
 | 
					  bool operator()(const array &array) const { return array.size() == 0; }
 | 
				
			||||||
    return array.size() == 0;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,50 +1,47 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <sstream>
 | 
					 | 
				
			||||||
#include <boost/variant/static_visitor.hpp>
 | 
					#include <boost/variant/static_visitor.hpp>
 | 
				
			||||||
 | 
					#include <sstream>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "../render_context.hpp"
 | 
					#include "../render_context.hpp"
 | 
				
			||||||
#include "mstch/mstch.hpp"
 | 
					 | 
				
			||||||
#include "../utils.hpp"
 | 
					#include "../utils.hpp"
 | 
				
			||||||
 | 
					#include "mstch/mstch.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace mstch {
 | 
					namespace mstch
 | 
				
			||||||
 | 
					 | 
				
			||||||
class render_node: public boost::static_visitor<std::string> {
 | 
					 | 
				
			||||||
 public:
 | 
					 | 
				
			||||||
  enum class flag { none, escape_html };
 | 
					 | 
				
			||||||
  render_node(render_context& ctx, flag p_flag = flag::none):
 | 
					 | 
				
			||||||
      m_ctx(ctx), m_flag(p_flag)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  template<class T>
 | 
					class render_node : public boost::static_visitor<std::string>
 | 
				
			||||||
  std::string operator()(const T&) const {
 | 
					{
 | 
				
			||||||
    return "";
 | 
					public:
 | 
				
			||||||
  }
 | 
					  enum class flag
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    none,
 | 
				
			||||||
 | 
					    escape_html
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  render_node(render_context &ctx, flag p_flag = flag::none) : m_ctx(ctx), m_flag(p_flag) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  std::string operator()(const int& value) const {
 | 
					  template <class T> std::string operator()(const T &) const { return ""; }
 | 
				
			||||||
    return std::to_string(value);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  std::string operator()(const double& value) const {
 | 
					  std::string operator()(const int &value) const { return std::to_string(value); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  std::string operator()(const double &value) const
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
    std::stringstream ss;
 | 
					    std::stringstream ss;
 | 
				
			||||||
    ss << value;
 | 
					    ss << value;
 | 
				
			||||||
    return ss.str();
 | 
					    return ss.str();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  std::string operator()(const bool& value) const {
 | 
					  std::string operator()(const bool &value) const { return value ? "true" : "false"; }
 | 
				
			||||||
    return value ? "true" : "false";
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  std::string operator()(const lambda& value) const {
 | 
					  std::string operator()(const lambda &value) const
 | 
				
			||||||
    template_type interpreted{value([this](const mstch::node& n) {
 | 
					  {
 | 
				
			||||||
      return visit(render_node(m_ctx), n);
 | 
					    template_type interpreted{value([this](const mstch::node &n) { return visit(render_node(m_ctx), n); })};
 | 
				
			||||||
    })};
 | 
					 | 
				
			||||||
    auto rendered = render_context::push(m_ctx).render(interpreted);
 | 
					    auto rendered = render_context::push(m_ctx).render(interpreted);
 | 
				
			||||||
    return (m_flag == flag::escape_html) ? html_escape(rendered) : rendered;
 | 
					    return (m_flag == flag::escape_html) ? html_escape(rendered) : rendered;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  std::string operator()(const std::string& value) const {
 | 
					  std::string operator()(const std::string &value) const
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
    return (m_flag == flag::escape_html) ? html_escape(value) : value;
 | 
					    return (m_flag == flag::escape_html) ? html_escape(value) : value;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -52,5 +49,4 @@ class render_node: public boost::static_visitor<std::string> {
 | 
				
			|||||||
  render_context &m_ctx;
 | 
					  render_context &m_ctx;
 | 
				
			||||||
  flag m_flag;
 | 
					  flag m_flag;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,47 +3,49 @@
 | 
				
			|||||||
#include <boost/variant/static_visitor.hpp>
 | 
					#include <boost/variant/static_visitor.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "../render_context.hpp"
 | 
					#include "../render_context.hpp"
 | 
				
			||||||
#include "mstch/mstch.hpp"
 | 
					 | 
				
			||||||
#include "../utils.hpp"
 | 
					#include "../utils.hpp"
 | 
				
			||||||
 | 
					#include "mstch/mstch.hpp"
 | 
				
			||||||
#include "render_node.hpp"
 | 
					#include "render_node.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace mstch {
 | 
					namespace mstch
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class render_section: public boost::static_visitor<std::string> {
 | 
					class render_section : public boost::static_visitor<std::string>
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
  enum class flag { none, keep_array };
 | 
					  enum class flag
 | 
				
			||||||
  render_section(
 | 
					  {
 | 
				
			||||||
      render_context& ctx,
 | 
					    none,
 | 
				
			||||||
      const template_type& section,
 | 
					    keep_array
 | 
				
			||||||
      const delim_type& delims,
 | 
					  };
 | 
				
			||||||
      flag p_flag = flag::none):
 | 
					  render_section(render_context &ctx, const template_type §ion, const delim_type &delims, flag p_flag = flag::none)
 | 
				
			||||||
      m_ctx(ctx), m_section(section), m_delims(delims), m_flag(p_flag)
 | 
					      : m_ctx(ctx), m_section(section), m_delims(delims), m_flag(p_flag)
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  template<class T>
 | 
					  template <class T> std::string operator()(const T &t) const
 | 
				
			||||||
  std::string operator()(const T& t) const {
 | 
					  {
 | 
				
			||||||
    return render_context::push(m_ctx, t).render(m_section);
 | 
					    return render_context::push(m_ctx, t).render(m_section);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  std::string operator()(const lambda& fun) const {
 | 
					  std::string operator()(const lambda &fun) const
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
    std::string section_str;
 | 
					    std::string section_str;
 | 
				
			||||||
    for (auto &token : m_section)
 | 
					    for (auto &token : m_section)
 | 
				
			||||||
      section_str += token.raw();
 | 
					      section_str += token.raw();
 | 
				
			||||||
    template_type interpreted{fun([this](const mstch::node& n) {
 | 
					    template_type interpreted{fun([this](const mstch::node &n) { return visit(render_node(m_ctx), n); }, section_str),
 | 
				
			||||||
      return visit(render_node(m_ctx), n);
 | 
					                              m_delims};
 | 
				
			||||||
    }, section_str), m_delims};
 | 
					 | 
				
			||||||
    return render_context::push(m_ctx).render(interpreted);
 | 
					    return render_context::push(m_ctx).render(interpreted);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  std::string operator()(const array& array) const {
 | 
					  std::string operator()(const array &array) const
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
    std::string out;
 | 
					    std::string out;
 | 
				
			||||||
    if (m_flag == flag::keep_array)
 | 
					    if (m_flag == flag::keep_array)
 | 
				
			||||||
      return render_context::push(m_ctx, array).render(m_section);
 | 
					      return render_context::push(m_ctx, array).render(m_section);
 | 
				
			||||||
    else
 | 
					    else
 | 
				
			||||||
      for (auto &item : array)
 | 
					      for (auto &item : array)
 | 
				
			||||||
        out += visit(render_section(
 | 
					        out += visit(render_section(m_ctx, m_section, m_delims, flag::keep_array), item);
 | 
				
			||||||
            m_ctx, m_section, m_delims, flag::keep_array), item);
 | 
					 | 
				
			||||||
    return out;
 | 
					    return out;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -53,5 +55,4 @@ class render_section: public boost::static_visitor<std::string> {
 | 
				
			|||||||
  const delim_type &m_delims;
 | 
					  const delim_type &m_delims;
 | 
				
			||||||
  flag m_flag;
 | 
					  flag m_flag;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,5 @@
 | 
				
			|||||||
#include <nntpchan/base64.hpp>
 | 
					#include <nntpchan/base64.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
// taken from i2pd
 | 
					// taken from i2pd
 | 
				
			||||||
namespace i2p
 | 
					namespace i2p
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -16,17 +15,10 @@ namespace data
 | 
				
			|||||||
* Direct Substitution Table
 | 
					* Direct Substitution Table
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	static const char T64[64] = {
 | 
					static const char T64[64] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
 | 
				
			||||||
		       'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
 | 
					                             'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
 | 
				
			||||||
		       'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
 | 
					                             'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
 | 
				
			||||||
		       'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
 | 
					                             'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
 | 
				
			||||||
		       'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
 | 
					 | 
				
			||||||
		       'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
 | 
					 | 
				
			||||||
		       'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
 | 
					 | 
				
			||||||
		       'w', 'x', 'y', 'z', '0', '1', '2', '3',
 | 
					 | 
				
			||||||
		       '4', '5', '6', '7', '8', '9', '+', '/'
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
* Reverse Substitution Table (built in run time)
 | 
					* Reverse Substitution Table (built in run time)
 | 
				
			||||||
@@ -50,8 +42,7 @@ namespace data
 | 
				
			|||||||
*
 | 
					*
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
static size_t                                   /* Number of bytes in the encoded buffer */
 | 
					static size_t                                   /* Number of bytes in the encoded buffer */
 | 
				
			||||||
	ByteStreamToBase64 ( 
 | 
					    ByteStreamToBase64(const uint8_t *InBuffer, /* Input buffer, binary data */
 | 
				
			||||||
		    const uint8_t * InBuffer,           /* Input buffer, binary data */
 | 
					 | 
				
			||||||
                       size_t InCount,          /* Number of bytes in the input buffer */
 | 
					                       size_t InCount,          /* Number of bytes in the input buffer */
 | 
				
			||||||
                       char *OutBuffer,         /* output buffer */
 | 
					                       char *OutBuffer,         /* output buffer */
 | 
				
			||||||
                       size_t len               /* length of output buffer */
 | 
					                       size_t len               /* length of output buffer */
 | 
				
			||||||
@@ -74,9 +65,11 @@ namespace data
 | 
				
			|||||||
    outCount = 4 * n;
 | 
					    outCount = 4 * n;
 | 
				
			||||||
  else
 | 
					  else
 | 
				
			||||||
    outCount = 4 * (n + 1);
 | 
					    outCount = 4 * (n + 1);
 | 
				
			||||||
		if (outCount > len) return 0;
 | 
					  if (outCount > len)
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
  pd = (unsigned char *)OutBuffer;
 | 
					  pd = (unsigned char *)OutBuffer;
 | 
				
			||||||
		for ( i = 0; i<n; i++ ){
 | 
					  for (i = 0; i < n; i++)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
    acc_1 = *ps++;
 | 
					    acc_1 = *ps++;
 | 
				
			||||||
    acc_2 = (acc_1 << 4) & 0x30;
 | 
					    acc_2 = (acc_1 << 4) & 0x30;
 | 
				
			||||||
    acc_1 >>= 2; /* base64 digit #1 */
 | 
					    acc_1 >>= 2; /* base64 digit #1 */
 | 
				
			||||||
@@ -92,7 +85,8 @@ namespace data
 | 
				
			|||||||
    acc_2 &= 0x3f; /* base64 digit #4 */
 | 
					    acc_2 &= 0x3f; /* base64 digit #4 */
 | 
				
			||||||
    *pd++ = T64[acc_2];
 | 
					    *pd++ = T64[acc_2];
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
		if ( m == 1 ){
 | 
					  if (m == 1)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
    acc_1 = *ps++;
 | 
					    acc_1 = *ps++;
 | 
				
			||||||
    acc_2 = (acc_1 << 4) & 0x3f; /* base64 digit #2 */
 | 
					    acc_2 = (acc_1 << 4) & 0x3f; /* base64 digit #2 */
 | 
				
			||||||
    acc_1 >>= 2;                 /* base64 digit #1 */
 | 
					    acc_1 >>= 2;                 /* base64 digit #1 */
 | 
				
			||||||
@@ -100,9 +94,9 @@ namespace data
 | 
				
			|||||||
    *pd++ = T64[acc_2];
 | 
					    *pd++ = T64[acc_2];
 | 
				
			||||||
    *pd++ = P64;
 | 
					    *pd++ = P64;
 | 
				
			||||||
    *pd++ = P64;
 | 
					    *pd++ = P64;
 | 
				
			||||||
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
		else if ( m == 2 ){
 | 
					  else if (m == 2)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
    acc_1 = *ps++;
 | 
					    acc_1 = *ps++;
 | 
				
			||||||
    acc_2 = (acc_1 << 4) & 0x3f;
 | 
					    acc_2 = (acc_1 << 4) & 0x3f;
 | 
				
			||||||
    acc_1 >>= 2; /* base64 digit #1 */
 | 
					    acc_1 >>= 2; /* base64 digit #1 */
 | 
				
			||||||
@@ -128,10 +122,8 @@ namespace data
 | 
				
			|||||||
* not properly padded, buffer of negative length is returned
 | 
					* not properly padded, buffer of negative length is returned
 | 
				
			||||||
*
 | 
					*
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
  static
 | 
					static ssize_t                               /* Number of output bytes */
 | 
				
			||||||
	ssize_t                              /* Number of output bytes */
 | 
					    Base64ToByteStream(const char *InBuffer, /* BASE64 encoded buffer */
 | 
				
			||||||
	Base64ToByteStream ( 
 | 
					 | 
				
			||||||
		      const char * InBuffer,           /* BASE64 encoded buffer */
 | 
					 | 
				
			||||||
                       size_t InCount,       /* Number of input bytes */
 | 
					                       size_t InCount,       /* Number of input bytes */
 | 
				
			||||||
                       uint8_t *OutBuffer,   /* output buffer length */
 | 
					                       uint8_t *OutBuffer,   /* output buffer length */
 | 
				
			||||||
                       size_t len            /* length of output buffer */
 | 
					                       size_t len            /* length of output buffer */
 | 
				
			||||||
@@ -146,36 +138,43 @@ namespace data
 | 
				
			|||||||
  int m;
 | 
					  int m;
 | 
				
			||||||
  size_t outCount;
 | 
					  size_t outCount;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (isFirstTime) iT64Build();
 | 
					  if (isFirstTime)
 | 
				
			||||||
 | 
					    iT64Build();
 | 
				
			||||||
  n = InCount / 4;
 | 
					  n = InCount / 4;
 | 
				
			||||||
  m = InCount % 4;
 | 
					  m = InCount % 4;
 | 
				
			||||||
  if (InCount && !m)
 | 
					  if (InCount && !m)
 | 
				
			||||||
    outCount = 3 * n;
 | 
					    outCount = 3 * n;
 | 
				
			||||||
		else {
 | 
					  else
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
    outCount = 0;
 | 
					    outCount = 0;
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ps = (unsigned char *)(InBuffer + InCount - 1);
 | 
					  ps = (unsigned char *)(InBuffer + InCount - 1);
 | 
				
			||||||
		while ( *ps-- == P64 ) outCount--;
 | 
					  while (*ps-- == P64)
 | 
				
			||||||
 | 
					    outCount--;
 | 
				
			||||||
  ps = (unsigned char *)InBuffer;
 | 
					  ps = (unsigned char *)InBuffer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (outCount > len) return -1;
 | 
					  if (outCount > len)
 | 
				
			||||||
 | 
					    return -1;
 | 
				
			||||||
  pd = OutBuffer;
 | 
					  pd = OutBuffer;
 | 
				
			||||||
  auto endOfOutBuffer = OutBuffer + outCount;
 | 
					  auto endOfOutBuffer = OutBuffer + outCount;
 | 
				
			||||||
		for ( i = 0; i < n; i++ ){
 | 
					  for (i = 0; i < n; i++)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
    acc_1 = iT64[*ps++];
 | 
					    acc_1 = iT64[*ps++];
 | 
				
			||||||
    acc_2 = iT64[*ps++];
 | 
					    acc_2 = iT64[*ps++];
 | 
				
			||||||
    acc_1 <<= 2;
 | 
					    acc_1 <<= 2;
 | 
				
			||||||
    acc_1 |= acc_2 >> 4;
 | 
					    acc_1 |= acc_2 >> 4;
 | 
				
			||||||
    *pd++ = acc_1;
 | 
					    *pd++ = acc_1;
 | 
				
			||||||
			 if (pd >= endOfOutBuffer) break;
 | 
					    if (pd >= endOfOutBuffer)
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    acc_2 <<= 4;
 | 
					    acc_2 <<= 4;
 | 
				
			||||||
    acc_1 = iT64[*ps++];
 | 
					    acc_1 = iT64[*ps++];
 | 
				
			||||||
    acc_2 |= acc_1 >> 2;
 | 
					    acc_2 |= acc_1 >> 2;
 | 
				
			||||||
    *pd++ = acc_2;
 | 
					    *pd++ = acc_2;
 | 
				
			||||||
			  if (pd >= endOfOutBuffer) break;	
 | 
					    if (pd >= endOfOutBuffer)
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    acc_2 = iT64[*ps++];
 | 
					    acc_2 = iT64[*ps++];
 | 
				
			||||||
    acc_2 |= acc_1 << 6;
 | 
					    acc_2 |= acc_1 << 6;
 | 
				
			||||||
@@ -188,7 +187,8 @@ namespace data
 | 
				
			|||||||
static size_t Base64EncodingBufferSize(const size_t input_size)
 | 
					static size_t Base64EncodingBufferSize(const size_t input_size)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  auto d = div(input_size, 3);
 | 
					  auto d = div(input_size, 3);
 | 
				
			||||||
		if (d.rem) d.quot++;
 | 
					  if (d.rem)
 | 
				
			||||||
 | 
					    d.quot++;
 | 
				
			||||||
  return 4 * d.quot;
 | 
					  return 4 * d.quot;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -205,12 +205,12 @@ namespace data
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  int i;
 | 
					  int i;
 | 
				
			||||||
  isFirstTime = 0;
 | 
					  isFirstTime = 0;
 | 
				
			||||||
		for ( i=0; i<256; i++ ) iT64[i] = -1;
 | 
					  for (i = 0; i < 256; i++)
 | 
				
			||||||
		for ( i=0; i<64; i++ ) iT64[(int)T64[i]] = i;
 | 
					    iT64[i] = -1;
 | 
				
			||||||
 | 
					  for (i = 0; i < 64; i++)
 | 
				
			||||||
 | 
					    iT64[(int)T64[i]] = i;
 | 
				
			||||||
  iT64[(int)P64] = 0;
 | 
					  iT64[(int)P64] = 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -227,7 +227,8 @@ namespace nntpchan
 | 
				
			|||||||
bool B64Decode(const std::string &data, std::vector<uint8_t> &out)
 | 
					bool B64Decode(const std::string &data, std::vector<uint8_t> &out)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  out.resize(data.size());
 | 
					  out.resize(data.size());
 | 
				
			||||||
    if(i2p::data::Base64ToByteStream(data.c_str(), data.size(), &out[0], out.size()) == -1) return false;
 | 
					  if (i2p::data::Base64ToByteStream(data.c_str(), data.size(), &out[0], out.size()) == -1)
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
  out.shrink_to_fit();
 | 
					  out.shrink_to_fit();
 | 
				
			||||||
  return true;
 | 
					  return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
#include <nntpchan/buffer.hpp>
 | 
					 | 
				
			||||||
#include <cstring>
 | 
					#include <cstring>
 | 
				
			||||||
 | 
					#include <nntpchan/buffer.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace nntpchan
 | 
					namespace nntpchan
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -13,9 +13,5 @@ namespace nntpchan
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
WriteBuffer::WriteBuffer(const std::string &s) : WriteBuffer(s.c_str(), s.size()) {}
 | 
					WriteBuffer::WriteBuffer(const std::string &s) : WriteBuffer(s.c_str(), s.size()) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  WriteBuffer::~WriteBuffer()
 | 
					WriteBuffer::~WriteBuffer() { delete[] b.base; }
 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    delete [] b.base;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,20 +1,12 @@
 | 
				
			|||||||
 | 
					#include <cassert>
 | 
				
			||||||
#include <nntpchan/crypto.hpp>
 | 
					#include <nntpchan/crypto.hpp>
 | 
				
			||||||
#include <sodium.h>
 | 
					#include <sodium.h>
 | 
				
			||||||
#include <cassert>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace nntpchan
 | 
					namespace nntpchan
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  void SHA512(const uint8_t * d, const std::size_t l, SHA512Digest & h)
 | 
					void SHA512(const uint8_t *d, const std::size_t l, SHA512Digest &h) { crypto_hash(h.data(), d, l); }
 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    crypto_hash(h.data(), d, l);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Crypto::Crypto()
 | 
					Crypto::Crypto() { assert(sodium_init() == 0); }
 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    assert(sodium_init() == 0);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Crypto::~Crypto()
 | 
					Crypto::~Crypto() {}
 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,31 +14,15 @@ typedef struct
 | 
				
			|||||||
  unsigned char buffer[64];
 | 
					  unsigned char buffer[64];
 | 
				
			||||||
} SHA1_CTX;
 | 
					} SHA1_CTX;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void SHA1Transform(
 | 
					void SHA1Transform(uint32_t state[5], const unsigned char buffer[64]);
 | 
				
			||||||
  uint32_t state[5],
 | 
					 | 
				
			||||||
  const unsigned char buffer[64]
 | 
					 | 
				
			||||||
);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
void SHA1Init(
 | 
					void SHA1Init(SHA1_CTX *context);
 | 
				
			||||||
  SHA1_CTX * context
 | 
					 | 
				
			||||||
);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
void SHA1Update(
 | 
					void SHA1Update(SHA1_CTX *context, const unsigned char *data, uint32_t len);
 | 
				
			||||||
    SHA1_CTX * context,
 | 
					 | 
				
			||||||
    const unsigned char *data,
 | 
					 | 
				
			||||||
    uint32_t len
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
void SHA1Final(
 | 
					void SHA1Final(unsigned char digest[20], SHA1_CTX *context);
 | 
				
			||||||
    unsigned char digest[20],
 | 
					 | 
				
			||||||
    SHA1_CTX * context
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void sha1(
 | 
					 | 
				
			||||||
    uint8_t *hash_out,
 | 
					 | 
				
			||||||
    const uint8_t *str,
 | 
					 | 
				
			||||||
    size_t len);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void sha1(uint8_t *hash_out, const uint8_t *str, size_t len);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
#include <nntpchan/event.hpp>
 | 
					 | 
				
			||||||
#include <cassert>
 | 
					#include <cassert>
 | 
				
			||||||
 | 
					#include <nntpchan/event.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace nntpchan
 | 
					namespace nntpchan
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -9,19 +9,9 @@ namespace nntpchan
 | 
				
			|||||||
  assert(uv_loop_init(m_loop) == 0);
 | 
					  assert(uv_loop_init(m_loop) == 0);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Mainloop::~Mainloop()
 | 
					Mainloop::~Mainloop() { uv_loop_close(m_loop); }
 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    uv_loop_close(m_loop);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void Mainloop::Stop()
 | 
					void Mainloop::Stop() { uv_stop(m_loop); }
 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    uv_stop(m_loop);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  void Mainloop::Run(uv_run_mode mode)
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    assert(uv_run(m_loop, mode) == 0);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Mainloop::Run(uv_run_mode mode) { assert(uv_run(m_loop, mode) == 0); }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,33 +1,21 @@
 | 
				
			|||||||
#include <nntpchan/exec_frontend.hpp>
 | 
					 | 
				
			||||||
#include <cstring>
 | 
					#include <cstring>
 | 
				
			||||||
#include <iostream>
 | 
					 | 
				
			||||||
#include <errno.h>
 | 
					#include <errno.h>
 | 
				
			||||||
#include <unistd.h>
 | 
					#include <iostream>
 | 
				
			||||||
 | 
					#include <nntpchan/exec_frontend.hpp>
 | 
				
			||||||
#include <sys/wait.h>
 | 
					#include <sys/wait.h>
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace nntpchan
 | 
					namespace nntpchan
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  ExecFrontend::ExecFrontend(const std::string & fname) :
 | 
					ExecFrontend::ExecFrontend(const std::string &fname) : m_exec(fname) {}
 | 
				
			||||||
    m_exec(fname)
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
ExecFrontend::~ExecFrontend() {}
 | 
					ExecFrontend::~ExecFrontend() {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void ExecFrontend::ProcessNewMessage(const fs::path  & fpath)
 | 
					void ExecFrontend::ProcessNewMessage(const fs::path &fpath) { Exec({"post", fpath}); }
 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    Exec({"post", fpath});
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  bool ExecFrontend::AcceptsNewsgroup(const std::string & newsgroup)
 | 
					bool ExecFrontend::AcceptsNewsgroup(const std::string &newsgroup) { return Exec({"newsgroup", newsgroup}) == 0; }
 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    return Exec({"newsgroup", newsgroup}) == 0;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  bool ExecFrontend::AcceptsMessage(const std::string & msgid)
 | 
					bool ExecFrontend::AcceptsMessage(const std::string &msgid) { return Exec({"msgid", msgid}) == 0; }
 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    return Exec({"msgid", msgid}) == 0;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
int ExecFrontend::Exec(std::deque<std::string> args)
 | 
					int ExecFrontend::Exec(std::deque<std::string> args)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -35,21 +23,27 @@ namespace nntpchan
 | 
				
			|||||||
  const char **cargs = new char const *[args.size() + 2];
 | 
					  const char **cargs = new char const *[args.size() + 2];
 | 
				
			||||||
  std::size_t l = 0;
 | 
					  std::size_t l = 0;
 | 
				
			||||||
  cargs[l++] = m_exec.c_str();
 | 
					  cargs[l++] = m_exec.c_str();
 | 
				
			||||||
    while (args.size()) {
 | 
					  while (args.size())
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
    cargs[l++] = args.front().c_str();
 | 
					    cargs[l++] = args.front().c_str();
 | 
				
			||||||
    args.pop_front();
 | 
					    args.pop_front();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  cargs[l] = 0;
 | 
					  cargs[l] = 0;
 | 
				
			||||||
  int retcode = 0;
 | 
					  int retcode = 0;
 | 
				
			||||||
  pid_t child = fork();
 | 
					  pid_t child = fork();
 | 
				
			||||||
    if(child) {
 | 
					  if (child)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
    waitpid(child, &retcode, 0);
 | 
					    waitpid(child, &retcode, 0);
 | 
				
			||||||
    } else {
 | 
					  }
 | 
				
			||||||
 | 
					  else
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
    int r = execvpe(m_exec.c_str(), (char *const *)cargs, environ);
 | 
					    int r = execvpe(m_exec.c_str(), (char *const *)cargs, environ);
 | 
				
			||||||
      if ( r == -1 ) {
 | 
					    if (r == -1)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
      std::cout << strerror(errno) << std::endl;
 | 
					      std::cout << strerror(errno) << std::endl;
 | 
				
			||||||
      exit(errno);
 | 
					      exit(errno);
 | 
				
			||||||
      } else
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
      exit(r);
 | 
					      exit(r);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  return retcode;
 | 
					  return retcode;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,5 @@
 | 
				
			|||||||
#include <nntpchan/file_handle.hpp>
 | 
					#include <nntpchan/file_handle.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace nntpchan
 | 
					namespace nntpchan
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
FileHandle_ptr OpenFile(const fs::path &fname, FileMode mode)
 | 
					FileHandle_ptr OpenFile(const fs::path &fname, FileMode mode)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,26 +1,34 @@
 | 
				
			|||||||
#include <nntpchan/line.hpp>
 | 
					#include <nntpchan/line.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace nntpchan {
 | 
					namespace nntpchan
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
LineReader::LineReader(size_t limit) : m_close(false), lineLimit(limit) {}
 | 
					LineReader::LineReader(size_t limit) : m_close(false), lineLimit(limit) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void LineReader::Data(const char *data, ssize_t l)
 | 
					void LineReader::Data(const char *data, ssize_t l)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    if(l <= 0) return;
 | 
					  if (l <= 0)
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
  // process leftovers
 | 
					  // process leftovers
 | 
				
			||||||
  std::size_t idx = 0;
 | 
					  std::size_t idx = 0;
 | 
				
			||||||
  std::size_t pos = 0;
 | 
					  std::size_t pos = 0;
 | 
				
			||||||
    while(l-- > 0) {
 | 
					  while (l-- > 0)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
    char c = data[idx++];
 | 
					    char c = data[idx++];
 | 
				
			||||||
      if(c == '\n') {
 | 
					    if (c == '\n')
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
      OnLine(data, pos);
 | 
					      OnLine(data, pos);
 | 
				
			||||||
      pos = 0;
 | 
					      pos = 0;
 | 
				
			||||||
      data += idx;
 | 
					      data += idx;
 | 
				
			||||||
      } else if (c == '\r' && data[idx] == '\n') {
 | 
					    }
 | 
				
			||||||
 | 
					    else if (c == '\r' && data[idx] == '\n')
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
      OnLine(data, pos);
 | 
					      OnLine(data, pos);
 | 
				
			||||||
      data += idx + 1;
 | 
					      data += idx + 1;
 | 
				
			||||||
      pos = 0;
 | 
					      pos = 0;
 | 
				
			||||||
      } else {
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
      pos++;
 | 
					      pos++;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -33,8 +41,5 @@ namespace nntpchan {
 | 
				
			|||||||
  HandleLine(line);
 | 
					  HandleLine(line);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  bool LineReader::ShouldClose()
 | 
					bool LineReader::ShouldClose() { return m_close; }
 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    return m_close;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,7 +11,8 @@ namespace nntpchan
 | 
				
			|||||||
    auto idx = line.find(": ");
 | 
					    auto idx = line.find(": ");
 | 
				
			||||||
    auto endidx = line.size() - 1;
 | 
					    auto endidx = line.size() - 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      while(line[endidx] == '\r') --endidx;
 | 
					    while (line[endidx] == '\r')
 | 
				
			||||||
 | 
					      --endidx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (idx != std::string::npos && idx + 2 < endidx)
 | 
					    if (idx != std::string::npos && idx + 2 < endidx)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
@@ -22,5 +23,4 @@ namespace nntpchan
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
  return file->good();
 | 
					  return file->good();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,8 +1,8 @@
 | 
				
			|||||||
 | 
					#include <cstring>
 | 
				
			||||||
#include <nntpchan/net.hpp>
 | 
					#include <nntpchan/net.hpp>
 | 
				
			||||||
#include <uv.h>
 | 
					 | 
				
			||||||
#include <sstream>
 | 
					#include <sstream>
 | 
				
			||||||
#include <stdexcept>
 | 
					#include <stdexcept>
 | 
				
			||||||
#include <cstring>
 | 
					#include <uv.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace nntpchan
 | 
					namespace nntpchan
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -11,7 +11,8 @@ namespace nntpchan
 | 
				
			|||||||
  std::string str("invalid");
 | 
					  std::string str("invalid");
 | 
				
			||||||
  const size_t s = 128;
 | 
					  const size_t s = 128;
 | 
				
			||||||
  char *buff = new char[s];
 | 
					  char *buff = new char[s];
 | 
				
			||||||
    if(uv_ip6_name(&addr, buff, s) == 0) {
 | 
					  if (uv_ip6_name(&addr, buff, s) == 0)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
    str = std::string(buff);
 | 
					    str = std::string(buff);
 | 
				
			||||||
    delete[] buff;
 | 
					    delete[] buff;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -20,19 +21,18 @@ namespace nntpchan
 | 
				
			|||||||
  return ss.str();
 | 
					  return ss.str();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  NetAddr::NetAddr()
 | 
					NetAddr::NetAddr() { std::memset(&addr, 0, sizeof(addr)); }
 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    std::memset(&addr, 0, sizeof(addr));
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
NetAddr ParseAddr(const std::string &addr)
 | 
					NetAddr ParseAddr(const std::string &addr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  NetAddr saddr;
 | 
					  NetAddr saddr;
 | 
				
			||||||
  auto n = addr.rfind("]:");
 | 
					  auto n = addr.rfind("]:");
 | 
				
			||||||
    if (n == std::string::npos) {
 | 
					  if (n == std::string::npos)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
    throw std::runtime_error("invalid address: " + addr);
 | 
					    throw std::runtime_error("invalid address: " + addr);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
    if (addr[0] != '[') {
 | 
					  if (addr[0] != '[')
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
    throw std::runtime_error("invalid address: " + addr);
 | 
					    throw std::runtime_error("invalid address: " + addr);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  auto p = addr.substr(n + 2);
 | 
					  auto p = addr.substr(n + 2);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,9 +1,9 @@
 | 
				
			|||||||
#include <nntpchan/nntp_auth.hpp>
 | 
					 | 
				
			||||||
#include <nntpchan/crypto.hpp>
 | 
					 | 
				
			||||||
#include <nntpchan/base64.hpp>
 | 
					 | 
				
			||||||
#include <array>
 | 
					#include <array>
 | 
				
			||||||
#include <iostream>
 | 
					 | 
				
			||||||
#include <fstream>
 | 
					#include <fstream>
 | 
				
			||||||
 | 
					#include <iostream>
 | 
				
			||||||
 | 
					#include <nntpchan/base64.hpp>
 | 
				
			||||||
 | 
					#include <nntpchan/crypto.hpp>
 | 
				
			||||||
 | 
					#include <nntpchan/nntp_auth.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace nntpchan
 | 
					namespace nntpchan
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -31,19 +31,25 @@ namespace nntpchan
 | 
				
			|||||||
  // strip comments
 | 
					  // strip comments
 | 
				
			||||||
  auto comment = line.find("#");
 | 
					  auto comment = line.find("#");
 | 
				
			||||||
  std::string part = line;
 | 
					  std::string part = line;
 | 
				
			||||||
    for (; comment != std::string::npos; comment = part.find("#")) {
 | 
					  for (; comment != std::string::npos; comment = part.find("#"))
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
    if (comment)
 | 
					    if (comment)
 | 
				
			||||||
      part = part.substr(0, comment);
 | 
					      part = part.substr(0, comment);
 | 
				
			||||||
      else break;
 | 
					    else
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
    if(!part.size()) return false; // empty line after comments
 | 
					  if (!part.size())
 | 
				
			||||||
 | 
					    return false; // empty line after comments
 | 
				
			||||||
  auto idx = part.find(":");
 | 
					  auto idx = part.find(":");
 | 
				
			||||||
    if (idx == std::string::npos) return false; // bad format
 | 
					  if (idx == std::string::npos)
 | 
				
			||||||
    if (m_user != part.substr(0, idx)) return false; // username mismatch
 | 
					    return false; // bad format
 | 
				
			||||||
 | 
					  if (m_user != part.substr(0, idx))
 | 
				
			||||||
 | 
					    return false; // username mismatch
 | 
				
			||||||
  part = part.substr(idx + 1);
 | 
					  part = part.substr(idx + 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  idx = part.find(":");
 | 
					  idx = part.find(":");
 | 
				
			||||||
    if (idx == std::string::npos) return false; // bad format
 | 
					  if (idx == std::string::npos)
 | 
				
			||||||
 | 
					    return false; // bad format
 | 
				
			||||||
  std::string cred = part.substr(0, idx);
 | 
					  std::string cred = part.substr(0, idx);
 | 
				
			||||||
  std::string salt = part.substr(idx + 1);
 | 
					  std::string salt = part.substr(idx + 1);
 | 
				
			||||||
  return Hash(m_passwd, salt) == cred;
 | 
					  return Hash(m_passwd, salt) == cred;
 | 
				
			||||||
@@ -51,15 +57,13 @@ namespace nntpchan
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void HashedCredDB::HandleLine(const std::string &line)
 | 
					void HashedCredDB::HandleLine(const std::string &line)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    if(m_found) return;
 | 
					  if (m_found)
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
  if (ProcessLine(line))
 | 
					  if (ProcessLine(line))
 | 
				
			||||||
    m_found = true;
 | 
					    m_found = true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void HashedCredDB::SetStream(std::istream * s)
 | 
					void HashedCredDB::SetStream(std::istream *s) { m_instream = s; }
 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    m_instream = s;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::string HashedCredDB::Hash(const std::string &data, const std::string &salt)
 | 
					std::string HashedCredDB::Hash(const std::string &data, const std::string &salt)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -69,16 +73,9 @@ namespace nntpchan
 | 
				
			|||||||
  return B64Encode(h.data(), h.size());
 | 
					  return B64Encode(h.data(), h.size());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  HashedFileDB::HashedFileDB(const std::string & fname) :
 | 
					HashedFileDB::HashedFileDB(const std::string &fname) : m_fname(fname), f(nullptr) {}
 | 
				
			||||||
    m_fname(fname),
 | 
					 | 
				
			||||||
    f(nullptr)
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  }
 | 
					HashedFileDB::~HashedFileDB() {}
 | 
				
			||||||
 | 
					 | 
				
			||||||
  HashedFileDB::~HashedFileDB()
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
void HashedFileDB::Close()
 | 
					void HashedFileDB::Close()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -90,7 +87,8 @@ namespace nntpchan
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  if (!f.is_open())
 | 
					  if (!f.is_open())
 | 
				
			||||||
    f.open(m_fname);
 | 
					    f.open(m_fname);
 | 
				
			||||||
    if(f.is_open()) {
 | 
					  if (f.is_open())
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
    SetStream(&f);
 | 
					    SetStream(&f);
 | 
				
			||||||
    return true;
 | 
					    return true;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,27 +1,21 @@
 | 
				
			|||||||
#include <nntpchan/nntp_handler.hpp>
 | 
					 | 
				
			||||||
#include <nntpchan/sanitize.hpp>
 | 
					 | 
				
			||||||
#include <algorithm>
 | 
					#include <algorithm>
 | 
				
			||||||
#include <cctype>
 | 
					#include <cctype>
 | 
				
			||||||
#include <cstring>
 | 
					#include <cstring>
 | 
				
			||||||
#include <string>
 | 
					 | 
				
			||||||
#include <sstream>
 | 
					 | 
				
			||||||
#include <iostream>
 | 
					#include <iostream>
 | 
				
			||||||
 | 
					#include <nntpchan/nntp_handler.hpp>
 | 
				
			||||||
 | 
					#include <nntpchan/sanitize.hpp>
 | 
				
			||||||
 | 
					#include <sstream>
 | 
				
			||||||
 | 
					#include <string>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace nntpchan
 | 
					namespace nntpchan
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  NNTPServerHandler::NNTPServerHandler(const fs::path & storage) :
 | 
					NNTPServerHandler::NNTPServerHandler(const fs::path &storage)
 | 
				
			||||||
    LineReader(1024),
 | 
					    : LineReader(1024), m_article(nullptr), m_auth(nullptr), m_store(std::make_unique<ArticleStorage>(storage)),
 | 
				
			||||||
    m_article(nullptr),
 | 
					      m_authed(false), m_state(eStateReadCommand)
 | 
				
			||||||
    m_auth(nullptr),
 | 
					 | 
				
			||||||
    m_store(std::make_unique<ArticleStorage>(storage)),
 | 
					 | 
				
			||||||
    m_authed(false),
 | 
					 | 
				
			||||||
    m_state(eStateReadCommand)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  NNTPServerHandler::~NNTPServerHandler()
 | 
					NNTPServerHandler::~NNTPServerHandler() {}
 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
void NNTPServerHandler::HandleLine(const std::string &line)
 | 
					void NNTPServerHandler::HandleLine(const std::string &line)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -30,8 +24,10 @@ namespace nntpchan
 | 
				
			|||||||
    std::deque<std::string> command;
 | 
					    std::deque<std::string> command;
 | 
				
			||||||
    std::istringstream s;
 | 
					    std::istringstream s;
 | 
				
			||||||
    s.str(line);
 | 
					    s.str(line);
 | 
				
			||||||
      for (std::string part; std::getline(s, part, ' '); ) {
 | 
					    for (std::string part; std::getline(s, part, ' ');)
 | 
				
			||||||
          if(part.size()) command.push_back(part);
 | 
					    {
 | 
				
			||||||
 | 
					      if (part.size())
 | 
				
			||||||
 | 
					        command.push_back(part);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (command.size())
 | 
					    if (command.size())
 | 
				
			||||||
      HandleCommand(command);
 | 
					      HandleCommand(command);
 | 
				
			||||||
@@ -51,7 +47,8 @@ namespace nntpchan
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void NNTPServerHandler::OnData(const char *data, ssize_t l)
 | 
					void NNTPServerHandler::OnData(const char *data, ssize_t l)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    if(l <= 0 ) return;
 | 
					  if (l <= 0)
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
  if (m_state == eStateStoreArticle)
 | 
					  if (m_state == eStateStoreArticle)
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    const char *end = strstr(data, "\r\n.\r\n");
 | 
					    const char *end = strstr(data, "\r\n.\r\n");
 | 
				
			||||||
@@ -86,7 +83,8 @@ namespace nntpchan
 | 
				
			|||||||
  for (const auto &part : command)
 | 
					  for (const auto &part : command)
 | 
				
			||||||
    std::cerr << " " << part;
 | 
					    std::cerr << " " << part;
 | 
				
			||||||
  std::cerr << std::endl;
 | 
					  std::cerr << std::endl;
 | 
				
			||||||
    if (cmd == "QUIT") {
 | 
					  if (cmd == "QUIT")
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
    Quit();
 | 
					    Quit();
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -94,26 +92,37 @@ namespace nntpchan
 | 
				
			|||||||
  {
 | 
					  {
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
    else if (cmd == "MODE" ) {
 | 
					  else if (cmd == "MODE")
 | 
				
			||||||
      if(cmdlen == 2) {
 | 
					  {
 | 
				
			||||||
 | 
					    if (cmdlen == 2)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
      // set mode
 | 
					      // set mode
 | 
				
			||||||
      SwitchMode(command[1]);
 | 
					      SwitchMode(command[1]);
 | 
				
			||||||
      } else if(cmdlen) {
 | 
					    }
 | 
				
			||||||
 | 
					    else if (cmdlen)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
      // too many arguments
 | 
					      // too many arguments
 | 
				
			||||||
      QueueLine("500 too many arguments");
 | 
					      QueueLine("500 too many arguments");
 | 
				
			||||||
      } else {
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
      // get mode
 | 
					      // get mode
 | 
				
			||||||
      QueueLine("500 wrong arguments");
 | 
					      QueueLine("500 wrong arguments");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    } else if(cmd == "CAPABILITIES") {
 | 
					  }
 | 
				
			||||||
 | 
					  else if (cmd == "CAPABILITIES")
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
    QueueLine("101 I support the following:");
 | 
					    QueueLine("101 I support the following:");
 | 
				
			||||||
    QueueLine("READER");
 | 
					    QueueLine("READER");
 | 
				
			||||||
    QueueLine("IMPLEMENTATION nntpchan-daemon");
 | 
					    QueueLine("IMPLEMENTATION nntpchan-daemon");
 | 
				
			||||||
    QueueLine("VERSION 2");
 | 
					    QueueLine("VERSION 2");
 | 
				
			||||||
    QueueLine("STREAMING");
 | 
					    QueueLine("STREAMING");
 | 
				
			||||||
    QueueLine(".");
 | 
					    QueueLine(".");
 | 
				
			||||||
    } else if (cmd == "CHECK") {
 | 
					  }
 | 
				
			||||||
      if(cmdlen >= 2) {
 | 
					  else if (cmd == "CHECK")
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    if (cmdlen >= 2)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
      const std::string &msgid = command[1];
 | 
					      const std::string &msgid = command[1];
 | 
				
			||||||
      if (IsValidMessageID(msgid) && m_store->Accept(msgid))
 | 
					      if (IsValidMessageID(msgid) && m_store->Accept(msgid))
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
@@ -124,7 +133,9 @@ namespace nntpchan
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    else
 | 
					    else
 | 
				
			||||||
      QueueLine("501 syntax error");
 | 
					      QueueLine("501 syntax error");
 | 
				
			||||||
    } else if (cmd == "TAKETHIS") {
 | 
					  }
 | 
				
			||||||
 | 
					  else if (cmd == "TAKETHIS")
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
    if (cmdlen >= 2)
 | 
					    if (cmdlen >= 2)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      const std::string &msgid = command[1];
 | 
					      const std::string &msgid = command[1];
 | 
				
			||||||
@@ -137,7 +148,9 @@ namespace nntpchan
 | 
				
			|||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    QueueLine("501 invalid syntax");
 | 
					    QueueLine("501 invalid syntax");
 | 
				
			||||||
    } else {
 | 
					  }
 | 
				
			||||||
 | 
					  else
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
    // unknown command
 | 
					    // unknown command
 | 
				
			||||||
    QueueLine("500 Unknown Command");
 | 
					    QueueLine("500 Unknown Command");
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -162,21 +175,32 @@ namespace nntpchan
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  std::string m = mode;
 | 
					  std::string m = mode;
 | 
				
			||||||
  std::transform(m.begin(), m.end(), m.begin(), ::toupper);
 | 
					  std::transform(m.begin(), m.end(), m.begin(), ::toupper);
 | 
				
			||||||
    if (m == "READER") {
 | 
					  if (m == "READER")
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
    m_mode = m;
 | 
					    m_mode = m;
 | 
				
			||||||
      if(PostingAllowed()) {
 | 
					    if (PostingAllowed())
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
      QueueLine("200 Posting is permitted yo");
 | 
					      QueueLine("200 Posting is permitted yo");
 | 
				
			||||||
      } else {
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
      QueueLine("201 Posting is not permitted yo");
 | 
					      QueueLine("201 Posting is not permitted yo");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    } else if (m == "STREAM") {
 | 
					  }
 | 
				
			||||||
 | 
					  else if (m == "STREAM")
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
    m_mode = m;
 | 
					    m_mode = m;
 | 
				
			||||||
      if (PostingAllowed()) {
 | 
					    if (PostingAllowed())
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
      QueueLine("203 Streaming enabled");
 | 
					      QueueLine("203 Streaming enabled");
 | 
				
			||||||
      } else {
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
      QueueLine("483 Streaming Denied");
 | 
					      QueueLine("483 Streaming Denied");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    } else {
 | 
					  }
 | 
				
			||||||
 | 
					  else
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
    // unknown mode
 | 
					    // unknown mode
 | 
				
			||||||
    QueueLine("500 Unknown mode");
 | 
					    QueueLine("500 Unknown mode");
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -194,15 +218,9 @@ namespace nntpchan
 | 
				
			|||||||
  QueueLine("205 quitting");
 | 
					  QueueLine("205 quitting");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  bool NNTPServerHandler::ShouldClose()
 | 
					bool NNTPServerHandler::ShouldClose() { return m_state == eStateQuit; }
 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    return m_state == eStateQuit;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  bool NNTPServerHandler::PostingAllowed()
 | 
					bool NNTPServerHandler::PostingAllowed() { return m_authed || m_auth == nullptr; }
 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    return m_authed || m_auth == nullptr;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
void NNTPServerHandler::Greet()
 | 
					void NNTPServerHandler::Greet()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -212,8 +230,5 @@ namespace nntpchan
 | 
				
			|||||||
    QueueLine("201 Posting not allowed");
 | 
					    QueueLine("201 Posting not allowed");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void NNTPServerHandler::SetAuth(CredDB_ptr creds)
 | 
					void NNTPServerHandler::SetAuth(CredDB_ptr creds) { m_auth = creds; }
 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    m_auth = creds;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,10 +1,10 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <nntpchan/nntp_server.hpp>
 | 
					 | 
				
			||||||
#include <nntpchan/nntp_auth.hpp>
 | 
					 | 
				
			||||||
#include <nntpchan/nntp_handler.hpp>
 | 
					 | 
				
			||||||
#include <nntpchan/net.hpp>
 | 
					 | 
				
			||||||
#include <cassert>
 | 
					#include <cassert>
 | 
				
			||||||
#include <iostream>
 | 
					#include <iostream>
 | 
				
			||||||
 | 
					#include <nntpchan/net.hpp>
 | 
				
			||||||
 | 
					#include <nntpchan/nntp_auth.hpp>
 | 
				
			||||||
 | 
					#include <nntpchan/nntp_handler.hpp>
 | 
				
			||||||
 | 
					#include <nntpchan/nntp_server.hpp>
 | 
				
			||||||
#include <sstream>
 | 
					#include <sstream>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace nntpchan
 | 
					namespace nntpchan
 | 
				
			||||||
@@ -12,9 +12,7 @@ namespace nntpchan
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
NNTPServer::NNTPServer(uv_loop_t *loop) : Server(loop), m_frontend(nullptr) {}
 | 
					NNTPServer::NNTPServer(uv_loop_t *loop) : Server(loop), m_frontend(nullptr) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  NNTPServer::~NNTPServer()
 | 
					NNTPServer::~NNTPServer() {}
 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
IServerConn *NNTPServer::CreateConn(uv_stream_t *s)
 | 
					IServerConn *NNTPServer::CreateConn(uv_stream_t *s)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -22,7 +20,8 @@ namespace nntpchan
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  std::ifstream i;
 | 
					  std::ifstream i;
 | 
				
			||||||
  i.open(m_logindbpath);
 | 
					  i.open(m_logindbpath);
 | 
				
			||||||
    if(i.is_open()) creds = std::make_shared<HashedFileDB>(m_logindbpath);
 | 
					  if (i.is_open())
 | 
				
			||||||
 | 
					    creds = std::make_shared<HashedFileDB>(m_logindbpath);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  NNTPServerHandler *handler = new NNTPServerHandler(m_storagePath);
 | 
					  NNTPServerHandler *handler = new NNTPServerHandler(m_storagePath);
 | 
				
			||||||
  if (creds)
 | 
					  if (creds)
 | 
				
			||||||
@@ -32,54 +31,32 @@ namespace nntpchan
 | 
				
			|||||||
  return conn;
 | 
					  return conn;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void NNTPServer::SetLoginDB(const std::string path)
 | 
					void NNTPServer::SetLoginDB(const std::string path) { m_logindbpath = path; }
 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    m_logindbpath = path;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void NNTPServer::SetStoragePath(const std::string &path) { m_storagePath = path; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void NNTPServer::SetStoragePath(const std::string & path)
 | 
					void NNTPServer::SetInstanceName(const std::string &name) { m_servername = name; }
 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    m_storagePath = path;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void NNTPServer::SetInstanceName(const std::string & name)
 | 
					void NNTPServer::SetFrontend(Frontend *f) { m_frontend.reset(f); }
 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    m_servername = name;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void NNTPServer::SetFrontend(Frontend * f)
 | 
					std::string NNTPServer::InstanceName() const { return m_servername; }
 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    m_frontend.reset(f);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  std::string NNTPServer::InstanceName() const
 | 
					void NNTPServer::OnAcceptError(int status) { std::cerr << "nntpserver::accept() " << uv_strerror(status) << std::endl; }
 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    return m_servername;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  void NNTPServer::OnAcceptError(int status)
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    std::cerr << "nntpserver::accept() " << uv_strerror(status) << std::endl;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
void NNTPServerConn::SendNextReply()
 | 
					void NNTPServerConn::SendNextReply()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  IConnHandler *handler = GetHandler();
 | 
					  IConnHandler *handler = GetHandler();
 | 
				
			||||||
    while(handler->HasNextLine()) {
 | 
					  while (handler->HasNextLine())
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
    auto line = handler->GetNextLine();
 | 
					    auto line = handler->GetNextLine();
 | 
				
			||||||
    SendString(line + "\r\n");
 | 
					    SendString(line + "\r\n");
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
void NNTPServerConn::Greet()
 | 
					void NNTPServerConn::Greet()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  IConnHandler *handler = GetHandler();
 | 
					  IConnHandler *handler = GetHandler();
 | 
				
			||||||
  handler->Greet();
 | 
					  handler->Greet();
 | 
				
			||||||
  SendNextReply();
 | 
					  SendNextReply();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,14 +1,15 @@
 | 
				
			|||||||
#include <nntpchan/sanitize.hpp>
 | 
					 | 
				
			||||||
#include <algorithm>
 | 
					#include <algorithm>
 | 
				
			||||||
#include <regex>
 | 
					 | 
				
			||||||
#include <cctype>
 | 
					#include <cctype>
 | 
				
			||||||
 | 
					#include <nntpchan/sanitize.hpp>
 | 
				
			||||||
 | 
					#include <regex>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace nntpchan
 | 
					namespace nntpchan
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::string NNTPSanitizeLine(const std::string &str)
 | 
					std::string NNTPSanitizeLine(const std::string &str)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    if(str == ".") return " .";
 | 
					  if (str == ".")
 | 
				
			||||||
 | 
					    return " .";
 | 
				
			||||||
  std::string sane;
 | 
					  std::string sane;
 | 
				
			||||||
  sane += str;
 | 
					  sane += str;
 | 
				
			||||||
  const char ch = ' ';
 | 
					  const char ch = ' ';
 | 
				
			||||||
@@ -19,23 +20,18 @@ namespace nntpchan
 | 
				
			|||||||
std::string ToLower(const std::string &str)
 | 
					std::string ToLower(const std::string &str)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  std::string lower = str;
 | 
					  std::string lower = str;
 | 
				
			||||||
    std::transform(lower.begin(), lower.end(), lower.begin(), [](unsigned char ch) -> unsigned char { return std::tolower(ch); } );
 | 
					  std::transform(lower.begin(), lower.end(), lower.begin(),
 | 
				
			||||||
 | 
					                 [](unsigned char ch) -> unsigned char { return std::tolower(ch); });
 | 
				
			||||||
  return lower;
 | 
					  return lower;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const std::regex re_ValidMessageID("^<[a-zA-Z0-9$\\._]{2,128}@[a-zA-Z0-9\\-\\.]{2,63}>$");
 | 
					static const std::regex re_ValidMessageID("^<[a-zA-Z0-9$\\._]{2,128}@[a-zA-Z0-9\\-\\.]{2,63}>$");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  bool IsValidMessageID(const std::string & msgid)
 | 
					bool IsValidMessageID(const std::string &msgid) { return std::regex_search(msgid, re_ValidMessageID) == 1; }
 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    return std::regex_search(msgid, re_ValidMessageID) == 1;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const std::regex re_ValidNewsgroup("^[a-zA-Z][a-zA-Z0-9.]{1,128}$");
 | 
					static const std::regex re_ValidNewsgroup("^[a-zA-Z][a-zA-Z0-9.]{1,128}$");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  bool IsValidNewsgroup(const std::string & msgid)
 | 
					bool IsValidNewsgroup(const std::string &msgid) { return std::regex_search(msgid, re_ValidNewsgroup) == 1; }
 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    return std::regex_search(msgid, re_ValidNewsgroup) == 1;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::string StripWhitespaces(const std::string &str)
 | 
					std::string StripWhitespaces(const std::string &str)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,8 +1,8 @@
 | 
				
			|||||||
#include <nntpchan/buffer.hpp>
 | 
					 | 
				
			||||||
#include <nntpchan/server.hpp>
 | 
					 | 
				
			||||||
#include <nntpchan/net.hpp>
 | 
					 | 
				
			||||||
#include <cassert>
 | 
					#include <cassert>
 | 
				
			||||||
#include <iostream>
 | 
					#include <iostream>
 | 
				
			||||||
 | 
					#include <nntpchan/buffer.hpp>
 | 
				
			||||||
 | 
					#include <nntpchan/net.hpp>
 | 
				
			||||||
 | 
					#include <nntpchan/server.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace nntpchan
 | 
					namespace nntpchan
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -18,7 +18,8 @@ namespace nntpchan
 | 
				
			|||||||
  std::cout << "Close server" << std::endl;
 | 
					  std::cout << "Close server" << std::endl;
 | 
				
			||||||
  uv_close((uv_handle_t *)&m_server, [](uv_handle_t *s) {
 | 
					  uv_close((uv_handle_t *)&m_server, [](uv_handle_t *s) {
 | 
				
			||||||
    Server *self = (Server *)s->data;
 | 
					    Server *self = (Server *)s->data;
 | 
				
			||||||
      if (self) delete self;
 | 
					    if (self)
 | 
				
			||||||
 | 
					      delete self;
 | 
				
			||||||
    s->data = nullptr;
 | 
					    s->data = nullptr;
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -36,7 +37,8 @@ namespace nntpchan
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void Server::OnAccept(uv_stream_t *s, int status)
 | 
					void Server::OnAccept(uv_stream_t *s, int status)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    if(status < 0) {
 | 
					  if (status < 0)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
    OnAcceptError(status);
 | 
					    OnAcceptError(status);
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -58,15 +60,9 @@ namespace nntpchan
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void IConnHandler::QueueLine(const std::string & line)
 | 
					void IConnHandler::QueueLine(const std::string &line) { m_sendlines.push_back(line); }
 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    m_sendlines.push_back(line);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  bool IConnHandler::HasNextLine()
 | 
					bool IConnHandler::HasNextLine() { return m_sendlines.size() > 0; }
 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    return m_sendlines.size() > 0;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::string IConnHandler::GetNextLine()
 | 
					std::string IConnHandler::GetNextLine()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -83,25 +79,33 @@ namespace nntpchan
 | 
				
			|||||||
  uv_tcp_init(l, &m_conn);
 | 
					  uv_tcp_init(l, &m_conn);
 | 
				
			||||||
  m_conn.data = this;
 | 
					  m_conn.data = this;
 | 
				
			||||||
  uv_accept(st, (uv_stream_t *)&m_conn);
 | 
					  uv_accept(st, (uv_stream_t *)&m_conn);
 | 
				
			||||||
    uv_read_start((uv_stream_t*) &m_conn, [] (uv_handle_t * h, size_t s, uv_buf_t * b) {
 | 
					  uv_read_start((uv_stream_t *)&m_conn,
 | 
				
			||||||
 | 
					                [](uv_handle_t *h, size_t s, uv_buf_t *b) {
 | 
				
			||||||
                  IServerConn *self = (IServerConn *)h->data;
 | 
					                  IServerConn *self = (IServerConn *)h->data;
 | 
				
			||||||
        if(self == nullptr) return;
 | 
					                  if (self == nullptr)
 | 
				
			||||||
 | 
					                    return;
 | 
				
			||||||
                  b->base = new char[s];
 | 
					                  b->base = new char[s];
 | 
				
			||||||
      }, [] (uv_stream_t * s, ssize_t nread, const uv_buf_t * b) {
 | 
					                },
 | 
				
			||||||
 | 
					                [](uv_stream_t *s, ssize_t nread, const uv_buf_t *b) {
 | 
				
			||||||
                  IServerConn *self = (IServerConn *)s->data;
 | 
					                  IServerConn *self = (IServerConn *)s->data;
 | 
				
			||||||
        if(self == nullptr) {
 | 
					                  if (self == nullptr)
 | 
				
			||||||
 | 
					                  {
 | 
				
			||||||
                    if (b->base)
 | 
					                    if (b->base)
 | 
				
			||||||
                      delete[] b->base;
 | 
					                      delete[] b->base;
 | 
				
			||||||
                    return;
 | 
					                    return;
 | 
				
			||||||
                  }
 | 
					                  }
 | 
				
			||||||
        if(nread > 0) {
 | 
					                  if (nread > 0)
 | 
				
			||||||
 | 
					                  {
 | 
				
			||||||
                    self->m_handler->OnData(b->base, nread);
 | 
					                    self->m_handler->OnData(b->base, nread);
 | 
				
			||||||
                    self->SendNextReply();
 | 
					                    self->SendNextReply();
 | 
				
			||||||
                    if (self->m_handler->ShouldClose())
 | 
					                    if (self->m_handler->ShouldClose())
 | 
				
			||||||
                      self->Close();
 | 
					                      self->Close();
 | 
				
			||||||
                    delete[] b->base;
 | 
					                    delete[] b->base;
 | 
				
			||||||
        } else {
 | 
					                  }
 | 
				
			||||||
          if (nread != UV_EOF) {
 | 
					                  else
 | 
				
			||||||
 | 
					                  {
 | 
				
			||||||
 | 
					                    if (nread != UV_EOF)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
                      std::cerr << "error in nntp server conn alloc: ";
 | 
					                      std::cerr << "error in nntp server conn alloc: ";
 | 
				
			||||||
                      std::cerr << uv_strerror(nread);
 | 
					                      std::cerr << uv_strerror(nread);
 | 
				
			||||||
                      std::cerr << std::endl;
 | 
					                      std::cerr << std::endl;
 | 
				
			||||||
@@ -112,10 +116,7 @@ namespace nntpchan
 | 
				
			|||||||
                });
 | 
					                });
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  IServerConn::~IServerConn()
 | 
					IServerConn::~IServerConn() { delete m_handler; }
 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    delete m_handler;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
void IServerConn::SendString(const std::string &str)
 | 
					void IServerConn::SendString(const std::string &str)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -27,42 +27,45 @@ extern "C" {
 | 
				
			|||||||
/* for uint32_t */
 | 
					/* for uint32_t */
 | 
				
			||||||
#include <stdint.h>
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
  
 | 
					 | 
				
			||||||
#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
 | 
					#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* blk0() and blk() perform the initial expand. */
 | 
					/* blk0() and blk() perform the initial expand. */
 | 
				
			||||||
/* I got the idea of expanding during the round function from SSLeay */
 | 
					/* I got the idea of expanding during the round function from SSLeay */
 | 
				
			||||||
#if BYTE_ORDER == LITTLE_ENDIAN
 | 
					#if BYTE_ORDER == LITTLE_ENDIAN
 | 
				
			||||||
#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \
 | 
					#define blk0(i) (block->l[i] = (rol(block->l[i], 24) & 0xFF00FF00) | (rol(block->l[i], 8) & 0x00FF00FF))
 | 
				
			||||||
    |(rol(block->l[i],8)&0x00FF00FF))
 | 
					 | 
				
			||||||
#elif BYTE_ORDER == BIG_ENDIAN
 | 
					#elif BYTE_ORDER == BIG_ENDIAN
 | 
				
			||||||
#define blk0(i) block->l[i]
 | 
					#define blk0(i) block->l[i]
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
#error "Endianness not defined!"
 | 
					#error "Endianness not defined!"
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
 | 
					#define blk(i)                                                                                                         \
 | 
				
			||||||
    ^block->l[(i+2)&15]^block->l[i&15],1))
 | 
					  (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 */
 | 
					/* (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 R0(v, w, x, y, z, i)                                                                                           \
 | 
				
			||||||
#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
 | 
					  z += ((w & (x ^ y)) ^ y) + blk0(i) + 0x5A827999 + rol(v, 5);                                                         \
 | 
				
			||||||
#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
 | 
					  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 R1(v, w, x, y, z, i)                                                                                           \
 | 
				
			||||||
#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
 | 
					  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. */
 | 
					/* Hash a single 512-bit block. This is the core of the algorithm. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void SHA1Transform(
 | 
					void SHA1Transform(uint32_t state[5], const unsigned char buffer[64])
 | 
				
			||||||
    uint32_t state[5],
 | 
					 | 
				
			||||||
    const unsigned char buffer[64]
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  uint32_t a, b, c, d, e;
 | 
					  uint32_t a, b, c, d, e;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    typedef union
 | 
					  typedef union {
 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
    unsigned char c[64];
 | 
					    unsigned char c[64];
 | 
				
			||||||
    uint32_t l[16];
 | 
					    uint32_t l[16];
 | 
				
			||||||
  } CHAR64LONG16;
 | 
					  } CHAR64LONG16;
 | 
				
			||||||
@@ -179,12 +182,9 @@ void SHA1Transform(
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
/* SHA1Init - Initialize new context */
 | 
					/* SHA1Init - Initialize new context */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void SHA1Init(
 | 
					void SHA1Init(SHA1_CTX *context)
 | 
				
			||||||
    SHA1_CTX * context
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  /* SHA1 initialization constants */
 | 
					  /* SHA1 initialization constants */
 | 
				
			||||||
  context->state[0] = 0x67452301;
 | 
					  context->state[0] = 0x67452301;
 | 
				
			||||||
@@ -195,14 +195,9 @@ void SHA1Init(
 | 
				
			|||||||
  context->count[0] = context->count[1] = 0;
 | 
					  context->count[0] = context->count[1] = 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Run your data through this. */
 | 
					/* Run your data through this. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void SHA1Update(
 | 
					void SHA1Update(SHA1_CTX *context, const unsigned char *data, uint32_t len)
 | 
				
			||||||
    SHA1_CTX * context,
 | 
					 | 
				
			||||||
    const unsigned char *data,
 | 
					 | 
				
			||||||
    uint32_t len
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  uint32_t i;
 | 
					  uint32_t i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -228,13 +223,9 @@ void SHA1Update(
 | 
				
			|||||||
  memcpy(&context->buffer[j], &data[i], len - i);
 | 
					  memcpy(&context->buffer[j], &data[i], len - i);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Add padding and return the message digest. */
 | 
					/* Add padding and return the message digest. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void SHA1Final(
 | 
					void SHA1Final(unsigned char digest[20], SHA1_CTX *context)
 | 
				
			||||||
    unsigned char digest[20],
 | 
					 | 
				
			||||||
    SHA1_CTX * context
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  unsigned i;
 | 
					  unsigned i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -261,7 +252,8 @@ void SHA1Final(
 | 
				
			|||||||
#else
 | 
					#else
 | 
				
			||||||
  for (i = 0; i < 8; i++)
 | 
					  for (i = 0; i < 8; i++)
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
        finalcount[i] = (unsigned char) ((context->count[(i >= 4 ? 0 : 1)] >> ((3 - (i & 3)) * 8)) & 255);      /* Endian independent */
 | 
					    finalcount[i] =
 | 
				
			||||||
 | 
					        (unsigned char)((context->count[(i >= 4 ? 0 : 1)] >> ((3 - (i & 3)) * 8)) & 255); /* Endian independent */
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
  c = 0200;
 | 
					  c = 0200;
 | 
				
			||||||
@@ -274,18 +266,14 @@ void SHA1Final(
 | 
				
			|||||||
  SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */
 | 
					  SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */
 | 
				
			||||||
  for (i = 0; i < 20; i++)
 | 
					  for (i = 0; i < 20; i++)
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
        digest[i] = (unsigned char)
 | 
					    digest[i] = (unsigned char)((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255);
 | 
				
			||||||
            ((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255);
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  /* Wipe variables */
 | 
					  /* Wipe variables */
 | 
				
			||||||
  memset(context, '\0', sizeof(*context));
 | 
					  memset(context, '\0', sizeof(*context));
 | 
				
			||||||
  memset(&finalcount, '\0', sizeof(finalcount));
 | 
					  memset(&finalcount, '\0', sizeof(finalcount));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void sha1(
 | 
					void sha1(uint8_t *hash_out, const uint8_t *str, size_t len)
 | 
				
			||||||
    uint8_t *hash_out,
 | 
					 | 
				
			||||||
    const uint8_t *str,
 | 
					 | 
				
			||||||
    size_t len)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  SHA1_CTX ctx;
 | 
					  SHA1_CTX ctx;
 | 
				
			||||||
  size_t ii;
 | 
					  size_t ii;
 | 
				
			||||||
@@ -295,7 +283,6 @@ void sha1(
 | 
				
			|||||||
    SHA1Update(&ctx, str + ii, 1);
 | 
					    SHA1Update(&ctx, str + ii, 1);
 | 
				
			||||||
  SHA1Final(hash_out, &ctx);
 | 
					  SHA1Final(hash_out, &ctx);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace nntpchan
 | 
					namespace nntpchan
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,22 +1,19 @@
 | 
				
			|||||||
#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 <any>
 | 
				
			||||||
#include <iostream>
 | 
					#include <iostream>
 | 
				
			||||||
 | 
					#include <nntpchan/file_handle.hpp>
 | 
				
			||||||
 | 
					#include <nntpchan/mime.hpp>
 | 
				
			||||||
 | 
					#include <nntpchan/sanitize.hpp>
 | 
				
			||||||
 | 
					#include <nntpchan/sha1.hpp>
 | 
				
			||||||
 | 
					#include <nntpchan/staticfile_frontend.hpp>
 | 
				
			||||||
#include <set>
 | 
					#include <set>
 | 
				
			||||||
#include <sstream>
 | 
					#include <sstream>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace nntpchan
 | 
					namespace nntpchan
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					StaticFileFrontend::StaticFileFrontend(TemplateEngine *tmpl, const std::string &templateDir, const std::string &outDir,
 | 
				
			||||||
  StaticFileFrontend::StaticFileFrontend(TemplateEngine * tmpl, const std::string & templateDir, const std::string & outDir, uint32_t pages) :
 | 
					                                       uint32_t pages)
 | 
				
			||||||
    m_TemplateEngine(tmpl),
 | 
					    : m_TemplateEngine(tmpl), m_TemplateDir(templateDir), m_OutDir(outDir), m_Pages(pages)
 | 
				
			||||||
    m_TemplateDir(templateDir),
 | 
					 | 
				
			||||||
    m_OutDir(outDir),
 | 
					 | 
				
			||||||
    m_Pages(pages)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -36,7 +33,6 @@ namespace nntpchan
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    // read body
 | 
					    // read body
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      
 | 
					 | 
				
			||||||
    auto findMsgidFunc = [](const std::pair<std::string, std::string> &item) -> bool {
 | 
					    auto findMsgidFunc = [](const std::pair<std::string, std::string> &item) -> bool {
 | 
				
			||||||
      auto lower = ToLower(item.first);
 | 
					      auto lower = ToLower(item.first);
 | 
				
			||||||
      return (lower == "message-id") || (lower == "messageid");
 | 
					      return (lower == "message-id") || (lower == "messageid");
 | 
				
			||||||
@@ -85,10 +81,29 @@ namespace nntpchan
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  
 | 
					 | 
				
			||||||
      
 | 
					 | 
				
			||||||
    std::string rootmsgid_hash = sha1_hex(rootmsgid);
 | 
					    std::string rootmsgid_hash = sha1_hex(rootmsgid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fs::path threadFilePath = m_OutDir / fs::path("thread-" + rootmsgid_hash + ".html");
 | 
					    fs::path threadFilePath = m_OutDir / fs::path("thread-" + rootmsgid_hash + ".html");
 | 
				
			||||||
    nntpchan::model::Thread thread;
 | 
					    nntpchan::model::Thread thread;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -114,27 +129,6 @@ namespace nntpchan
 | 
				
			|||||||
        return;
 | 
					        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;
 | 
					    nntpchan::model::BoardPage page;
 | 
				
			||||||
    for (const auto &name : newsgroups_list)
 | 
					    for (const auto &name : newsgroups_list)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
@@ -172,15 +166,7 @@ namespace nntpchan
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool StaticFileFrontend::AcceptsNewsgroup(const std::string &newsgroup) { return IsValidNewsgroup(newsgroup); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  bool StaticFileFrontend::AcceptsNewsgroup(const std::string & newsgroup)
 | 
					bool StaticFileFrontend::AcceptsMessage(const std::string &msgid) { return IsValidMessageID(msgid); }
 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    return IsValidNewsgroup(newsgroup);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  bool StaticFileFrontend::AcceptsMessage(const std::string & msgid)
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    return IsValidMessageID(msgid);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,21 +1,14 @@
 | 
				
			|||||||
#include <nntpchan/storage.hpp>
 | 
					 | 
				
			||||||
#include <nntpchan/sanitize.hpp>
 | 
					 | 
				
			||||||
#include <cassert>
 | 
					#include <cassert>
 | 
				
			||||||
 | 
					#include <nntpchan/sanitize.hpp>
 | 
				
			||||||
 | 
					#include <nntpchan/storage.hpp>
 | 
				
			||||||
#include <sstream>
 | 
					#include <sstream>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace nntpchan
 | 
					namespace nntpchan
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  ArticleStorage::ArticleStorage()
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ArticleStorage::ArticleStorage(const fs::path & fpath) {
 | 
					ArticleStorage::ArticleStorage(const fs::path &fpath) { SetPath(fpath); }
 | 
				
			||||||
    SetPath(fpath);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ArticleStorage::~ArticleStorage()
 | 
					ArticleStorage::~ArticleStorage() {}
 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ArticleStorage::SetPath(const fs::path &fpath)
 | 
					void ArticleStorage::SetPath(const fs::path &fpath)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -36,24 +29,43 @@ namespace nntpchan
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
bool ArticleStorage::Accept(const std::string &msgid) const
 | 
					bool ArticleStorage::Accept(const std::string &msgid) const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    if (!IsValidMessageID(msgid)) return false;
 | 
					  if (!IsValidMessageID(msgid))
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
  auto p = MessagePath(msgid);
 | 
					  auto p = MessagePath(msgid);
 | 
				
			||||||
  return !fs::exists(p);
 | 
					  return !fs::exists(p);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  fs::path ArticleStorage::MessagePath(const std::string & msgid) const
 | 
					fs::path ArticleStorage::MessagePath(const std::string &msgid) const { return basedir / msgid; }
 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    return basedir / msgid;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  FileHandle_ptr ArticleStorage::OpenRead(const std::string & msgid) const
 | 
					FileHandle_ptr ArticleStorage::OpenRead(const std::string &msgid) const { return OpenFile(MessagePath(msgid), eRead); }
 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    return OpenFile(MessagePath(msgid), eRead);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
FileHandle_ptr ArticleStorage::OpenWrite(const std::string &msgid) const
 | 
					FileHandle_ptr ArticleStorage::OpenWrite(const std::string &msgid) const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  return OpenFile(MessagePath(msgid), eWrite);
 | 
					  return OpenFile(MessagePath(msgid), eWrite);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool ArticleStorage::LoadBoardPage(BoardPage &board, const std::string &newsgroup, uint32_t perpage,
 | 
				
			||||||
 | 
					                                   uint32_t page) const
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  (void)board;
 | 
				
			||||||
 | 
					  (void)newsgroup;
 | 
				
			||||||
 | 
					  (void)perpage;
 | 
				
			||||||
 | 
					  (void)page;
 | 
				
			||||||
 | 
					  return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					bool ArticleStorage::FindThreadByHash(const std::string &hashhex, std::string &msgid) const
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  (void)hashhex;
 | 
				
			||||||
 | 
					  (void)msgid;
 | 
				
			||||||
 | 
					  return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					bool ArticleStorage::LoadThread(Thread &thread, const std::string &rootmsgid) const
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  (void)thread;
 | 
				
			||||||
 | 
					  (void)rootmsgid;
 | 
				
			||||||
 | 
					  return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** ensure symlinks are formed for this article by message id */
 | 
				
			||||||
 | 
					void ArticleStorage::EnsureSymlinks(const std::string &msgid) const { (void)msgid; }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,13 +1,16 @@
 | 
				
			|||||||
#include <nntpchan/template_engine.hpp>
 | 
					 | 
				
			||||||
#include <nntpchan/sanitize.hpp>
 | 
					 | 
				
			||||||
#include <mstch/mstch.hpp>
 | 
					 | 
				
			||||||
#include <iostream>
 | 
					#include <iostream>
 | 
				
			||||||
 | 
					#include <mstch/mstch.hpp>
 | 
				
			||||||
 | 
					#include <nntpchan/sanitize.hpp>
 | 
				
			||||||
 | 
					#include <nntpchan/template_engine.hpp>
 | 
				
			||||||
#include <sstream>
 | 
					#include <sstream>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace nntpchan
 | 
					namespace nntpchan
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
 | 
					template <class... Ts> struct overloaded : Ts...
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  using Ts::operator()...;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
template <class... Ts> overloaded(Ts...)->overloaded<Ts...>;
 | 
					template <class... Ts> overloaded(Ts...)->overloaded<Ts...>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace mustache = mstch;
 | 
					namespace mustache = mstch;
 | 
				
			||||||
@@ -77,10 +80,8 @@ namespace nntpchan
 | 
				
			|||||||
      mustache::map obj;
 | 
					      mustache::map obj;
 | 
				
			||||||
      for (const auto &item : args)
 | 
					      for (const auto &item : args)
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
          std::visit(overloaded {
 | 
					        std::visit(overloaded{[&obj, item](const nntpchan::model::Model &m) {
 | 
				
			||||||
            [&obj, item](const nntpchan::model::Model & m) {
 | 
					                                std::visit(overloaded{[&obj, item](const nntpchan::model::BoardPage &p) {
 | 
				
			||||||
              std::visit(overloaded {
 | 
					 | 
				
			||||||
                [&obj, item](const nntpchan::model::BoardPage & p) {
 | 
					 | 
				
			||||||
                                                        mustache::array threads;
 | 
					                                                        mustache::array threads;
 | 
				
			||||||
                                                        for (const auto &thread : p)
 | 
					                                                        for (const auto &thread : p)
 | 
				
			||||||
                                                        {
 | 
					                                                        {
 | 
				
			||||||
@@ -90,13 +91,11 @@ namespace nntpchan
 | 
				
			|||||||
                                                      },
 | 
					                                                      },
 | 
				
			||||||
                                                      [&obj, item](const nntpchan::model::Thread &t) {
 | 
					                                                      [&obj, item](const nntpchan::model::Thread &t) {
 | 
				
			||||||
                                                        obj[item.first] = thread_to_map(t);
 | 
					                                                        obj[item.first] = thread_to_map(t);
 | 
				
			||||||
                }
 | 
					                                                      }},
 | 
				
			||||||
              }, m);
 | 
					                                           m);
 | 
				
			||||||
            }
 | 
					                              },
 | 
				
			||||||
            ,[&obj, item](const std::string & str) {
 | 
					                              [&obj, item](const std::string &str) { obj[item.first] = str; }},
 | 
				
			||||||
              obj[item.first] = str;
 | 
					                   item.second);
 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
          }, item.second);
 | 
					 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      std::string str = mustache::render(m_tmplString, obj);
 | 
					      std::string str = mustache::render(m_tmplString, obj);
 | 
				
			||||||
@@ -141,7 +140,8 @@ namespace nntpchan
 | 
				
			|||||||
    for (const auto &fname : partial_files)
 | 
					    for (const auto &fname : partial_files)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      auto file = OpenFile(dir / fs::path(fname + std::string(".html")), eRead);
 | 
					      auto file = OpenFile(dir / fs::path(fname + std::string(".html")), eRead);
 | 
				
			||||||
        if(!file) {
 | 
					      if (!file)
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
        std::clog << "no such partial: " << fname << std::endl;
 | 
					        std::clog << "no such partial: " << fname << std::endl;
 | 
				
			||||||
        return false;
 | 
					        return false;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,9 +1,7 @@
 | 
				
			|||||||
#include <nntpchan/exec_frontend.hpp>
 | 
					 | 
				
			||||||
#include <nntpchan/sanitize.hpp>
 | 
					 | 
				
			||||||
#include <cassert>
 | 
					#include <cassert>
 | 
				
			||||||
#include <iostream>
 | 
					#include <iostream>
 | 
				
			||||||
 | 
					#include <nntpchan/exec_frontend.hpp>
 | 
				
			||||||
 | 
					#include <nntpchan/sanitize.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int main(int, char *[])
 | 
					int main(int, char *[])
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,19 +3,16 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <cassert>
 | 
					#include <cassert>
 | 
				
			||||||
#include <cstring>
 | 
					#include <cstring>
 | 
				
			||||||
#include <string>
 | 
					 | 
				
			||||||
#include <iostream>
 | 
					#include <iostream>
 | 
				
			||||||
#include <sodium.h>
 | 
					#include <sodium.h>
 | 
				
			||||||
 | 
					#include <string>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void print_help(const std::string &exename)
 | 
					static void print_help(const std::string &exename)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  std::cout << "usage: " << exename << " [help|gen|check]" << std::endl;
 | 
					  std::cout << "usage: " << exename << " [help|gen|check]" << std::endl;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void print_long_help()
 | 
					static void print_long_help() {}
 | 
				
			||||||
{
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void gen_passwd(const std::string &username, const std::string &passwd)
 | 
					static void gen_passwd(const std::string &username, const std::string &passwd)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -29,18 +26,20 @@ static void gen_passwd(const std::string & username, const std::string & passwd)
 | 
				
			|||||||
  std::cout << username << ":" << hash << ":" << salt << std::endl;
 | 
					  std::cout << username << ":" << hash << ":" << salt << std::endl;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
static bool check_cred(const std::string &cred, const std::string &passwd)
 | 
					static bool check_cred(const std::string &cred, const std::string &passwd)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  auto idx = cred.find(":");
 | 
					  auto idx = cred.find(":");
 | 
				
			||||||
  if(idx == std::string::npos || idx == 0) return false;
 | 
					  if (idx == std::string::npos || idx == 0)
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
  std::string part = cred.substr(idx + 1);
 | 
					  std::string part = cred.substr(idx + 1);
 | 
				
			||||||
  idx = part.find(":");
 | 
					  idx = part.find(":");
 | 
				
			||||||
  if(idx == std::string::npos || idx == 0) return false;
 | 
					  if (idx == std::string::npos || idx == 0)
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
  std::string salt = part.substr(idx + 1);
 | 
					  std::string salt = part.substr(idx + 1);
 | 
				
			||||||
  std::string hash = part.substr(0, idx);
 | 
					  std::string hash = part.substr(0, idx);
 | 
				
			||||||
  std::vector<uint8_t> h;
 | 
					  std::vector<uint8_t> h;
 | 
				
			||||||
  if(!nntpchan::B64Decode(hash, h)) return false;
 | 
					  if (!nntpchan::B64Decode(hash, h))
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
  nntpchan::SHA512Digest d;
 | 
					  nntpchan::SHA512Digest d;
 | 
				
			||||||
  std::string l = passwd + salt;
 | 
					  std::string l = passwd + salt;
 | 
				
			||||||
  nntpchan::SHA512((const uint8_t *)l.data(), l.size(), d);
 | 
					  nntpchan::SHA512((const uint8_t *)l.data(), l.size(), d);
 | 
				
			||||||
@@ -50,36 +49,46 @@ static bool check_cred(const std::string & cred, const std::string & passwd)
 | 
				
			|||||||
int main(int argc, char *argv[])
 | 
					int main(int argc, char *argv[])
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  assert(sodium_init() == 0);
 | 
					  assert(sodium_init() == 0);
 | 
				
			||||||
  if(argc == 1) {
 | 
					  if (argc == 1)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
    print_help(argv[0]);
 | 
					    print_help(argv[0]);
 | 
				
			||||||
    return 1;
 | 
					    return 1;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  std::string cmd(argv[1]);
 | 
					  std::string cmd(argv[1]);
 | 
				
			||||||
  if (cmd == "help") {
 | 
					  if (cmd == "help")
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
    print_long_help();
 | 
					    print_long_help();
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  if (cmd == "gen") {
 | 
					  if (cmd == "gen")
 | 
				
			||||||
    if(argc == 4) {
 | 
					  {
 | 
				
			||||||
 | 
					    if (argc == 4)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
      gen_passwd(argv[2], argv[3]);
 | 
					      gen_passwd(argv[2], argv[3]);
 | 
				
			||||||
      return 0;
 | 
					      return 0;
 | 
				
			||||||
    } else {
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
      std::cout << "usage: " << argv[0] << " gen username password" << std::endl;
 | 
					      std::cout << "usage: " << argv[0] << " gen username password" << std::endl;
 | 
				
			||||||
      return 1;
 | 
					      return 1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  if(cmd == "check" ) {
 | 
					  if (cmd == "check")
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
    std::string cred;
 | 
					    std::string cred;
 | 
				
			||||||
    std::cout << "credential: ";
 | 
					    std::cout << "credential: ";
 | 
				
			||||||
    if(!std::getline(std::cin, cred)) {
 | 
					    if (!std::getline(std::cin, cred))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
      return 1;
 | 
					      return 1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    std::string passwd;
 | 
					    std::string passwd;
 | 
				
			||||||
    std::cout << "password: ";
 | 
					    std::cout << "password: ";
 | 
				
			||||||
    if(!std::getline(std::cin, passwd)) {
 | 
					    if (!std::getline(std::cin, passwd))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
      return 1;
 | 
					      return 1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if(check_cred(cred, passwd)) {
 | 
					    if (check_cred(cred, passwd))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
      std::cout << "okay" << std::endl;
 | 
					      std::cout << "okay" << std::endl;
 | 
				
			||||||
      return 0;
 | 
					      return 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,9 +1,7 @@
 | 
				
			|||||||
#include <nntpchan/exec_frontend.hpp>
 | 
					 | 
				
			||||||
#include <nntpchan/sanitize.hpp>
 | 
					 | 
				
			||||||
#include <cassert>
 | 
					#include <cassert>
 | 
				
			||||||
#include <iostream>
 | 
					#include <iostream>
 | 
				
			||||||
 | 
					#include <nntpchan/exec_frontend.hpp>
 | 
				
			||||||
 | 
					#include <nntpchan/sanitize.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int main(int, char *[])
 | 
					int main(int, char *[])
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user