Archived
1
0
This commit is contained in:
Jeff Becker 2016-10-18 08:17:40 -04:00
parent 3c4ad2fe50
commit fde7ed3d3b
No known key found for this signature in database
GPG Key ID: AB950234D6EA286B
12 changed files with 132 additions and 51 deletions

View File

@ -1,4 +1,5 @@
*.o *.o
nntpd nntpd
nntpchan-tool nntpchan-tool
test
.gdb_history .gdb_history

View File

@ -27,8 +27,14 @@ $(EXE): $(OBJECTS)
$(TOOL): $(OBJECTS) $(TOOL): $(OBJECTS)
$(CXX) -o $(TOOL) $(LD_FLAGS) $(OBJECTS) $(CXXFLAGS) tool.cpp $(CXX) -o $(TOOL) $(LD_FLAGS) $(OBJECTS) $(CXXFLAGS) tool.cpp
build-test: $(OBJECTS)
$(CXX) -o test $(LD_FLAGS) $(OBJECTS) $(CXXFLAGS) test.cpp
test: build-test
./test
%.o: src/%.cpp %.o: src/%.cpp
$(CXX) $(CXXFLAGS) -c -o $@ $(CXX) $(CXXFLAGS) -c -o $@
clean: clean:
rm -f $(OBJECTS) $(EXE) $(TOOL) rm -f $(OBJECTS) $(EXE) $(TOOL) test

View File

@ -0,0 +1,2 @@
#!/bin/sh
exit 0

View File

@ -60,18 +60,18 @@ int main(int argc, char * argv[]) {
if ( level.sections.find("frontend") != level.sections.end()) { if ( level.sections.find("frontend") != level.sections.end()) {
// frontend enabled // frontend enabled
auto & frontconf = level.sections["frontend"]; auto & frontconf = level.sections["frontend"].values;
if (frontconf.find("type") == frontconf.end()) { if (frontconf.find("type") == frontconf.end()) {
std::cerr << "frontend section provided but 'type' value not provided" << std::endl; std::cerr << "frontend section provided but 'type' value not provided" << std::endl;
return 1; return 1;
} }
auto & ftype = frontconf.find("type"); auto ftype = frontconf["type"];
if (ftype == "exec") { if (ftype == "exec") {
if (frontconf.find("exec") == frontconf.end()) { if (frontconf.find("exec") == frontconf.end()) {
std::cerr << "exec frontend specified but no 'exec' value provided" << std::endl; std::cerr << "exec frontend specified but no 'exec' value provided" << std::endl;
return 1; return 1;
} }
nntp.SetFrontend(new nntpchan::ExecFrontend(loop, frontconf["exec"])); nntp.SetFrontend(new nntpchan::ExecFrontend(frontconf["exec"]));
} else { } else {
std::cerr << "unknown frontend type '" << ftype << "'" << std::endl; std::cerr << "unknown frontend type '" << ftype << "'" << std::endl;
} }

View File

@ -0,0 +1,57 @@
#include "exec_frontend.hpp"
#include <cstring>
#include <iostream>
#include <errno.h>
#include <unistd.h>
#include <sys/wait.h>
namespace nntpchan
{
ExecFrontend::ExecFrontend(const std::string & fname) :
m_exec(fname)
{
}
ExecFrontend::~ExecFrontend() {}
void ExecFrontend::ProcessNewMessage(const std::string & fpath)
{
Exec({"post", fpath});
}
bool ExecFrontend::AcceptsNewsgroup(const std::string & newsgroup)
{
return Exec({"newsgroup", newsgroup}) == 0;
}
bool ExecFrontend::AcceptsMessage(const std::string & msgid)
{
return Exec({"msgid", msgid}) == 0;
}
int ExecFrontend::Exec(std::deque<std::string> args)
{
// set up arguments
const char ** cargs = new char const *[args.size() +2];
std::size_t l = 0;
cargs[l++] = m_exec.c_str();
while (args.size()) {
cargs[l++] = args.front().c_str();
args.pop_front();
}
cargs[l] = 0;
int retcode = 0;
pid_t child = fork();
if(child) {
waitpid(child, &retcode, 0);
} else {
int r = execvpe(m_exec.c_str(),(char * const *) cargs, environ);
if ( r == -1 ) {
std::cout << strerror(errno) << std::endl;
exit( errno );
} else
exit(r);
}
return retcode;
}
}

View File

@ -1,9 +1,30 @@
#ifndef NNTPCHAN_EXEC_FRONTEND_HPP #ifndef NNTPCHAN_EXEC_FRONTEND_HPP
#define NNTPCHAN_EXEC_FRONTEND_HPP #define NNTPCHAN_EXEC_FRONTEND_HPP
#include "frontend.hpp"
#include <deque>
namespace nntpchan namespace nntpchan
{ {
class ExecFrontend : public Frontend
{
public:
ExecFrontend(const std::string & exe);
~ExecFrontend();
void ProcessNewMessage(const std::string & fpath);
bool AcceptsNewsgroup(const std::string & newsgroup);
bool AcceptsMessage(const std::string & msgid);
private:
int Exec(std::deque<std::string> args);
private:
std::string m_exec;
};
} }
#endif #endif

View File

@ -1,5 +1,6 @@
#ifndef NNTPCHAN_FRONTEND_HPP #ifndef NNTPCHAN_FRONTEND_HPP
#define NNTPCHAN_FRONTEND_HPP #define NNTPCHAN_FRONTEND_HPP
#include <string>
namespace nntpchan namespace nntpchan
{ {
@ -10,14 +11,13 @@ namespace nntpchan
virtual ~Frontend() {} virtual ~Frontend() {}
/** @brief process an inbound message stored at fpath that we have accepted. */ /** @brief process an inbound message stored at fpath that we have accepted. */
void ProcessNewMessage(const std::string & fpath) = 0; virtual void ProcessNewMessage(const std::string & fpath) = 0;
/** @brief return true if we take posts in a newsgroup */ /** @brief return true if we take posts in a newsgroup */
bool AcceptsNewsgroup(const std::string & newsgroup) = 0; virtual bool AcceptsNewsgroup(const std::string & newsgroup) = 0;
/** @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 */
bool AcceptsMessage(const std::string & msgid) = 0; virtual bool AcceptsMessage(const std::string & msgid) = 0;
}; };
} }

View File

@ -12,11 +12,21 @@ namespace nntpchan
{ {
uv_tcp_init(loop, &m_server); uv_tcp_init(loop, &m_server);
m_loop = loop; m_loop = loop;
m_server.data = this;
} }
NNTPServer::~NNTPServer() NNTPServer::~NNTPServer()
{ {
uv_close((uv_handle_t*)&m_server, [](uv_handle_t *) {}); if (m_frontend) delete m_frontend;
}
void NNTPServer::Close()
{
uv_close((uv_handle_t*)&m_server, [](uv_handle_t * s) {
NNTPServer * self = (NNTPServer*)s->data;
if (self) delete self;
s->data = nullptr;
});
} }
void NNTPServer::Bind(const std::string & addr) void NNTPServer::Bind(const std::string & addr)
@ -24,7 +34,6 @@ namespace nntpchan
auto saddr = ParseAddr(addr); auto saddr = ParseAddr(addr);
assert(uv_tcp_bind(*this, saddr, 0) == 0); assert(uv_tcp_bind(*this, saddr, 0) == 0);
std::cerr << "nntp server bound to " << saddr.to_string() << std::endl; std::cerr << "nntp server bound to " << saddr.to_string() << std::endl;
m_server.data = this;
auto cb = [] (uv_stream_t * s, int status) { auto cb = [] (uv_stream_t * s, int status) {
NNTPServer * self = (NNTPServer *) s->data; NNTPServer * self = (NNTPServer *) s->data;
self->OnAccept(s, status); self->OnAccept(s, status);
@ -60,6 +69,12 @@ namespace nntpchan
{ {
m_storagePath = path; m_storagePath = path;
} }
void NNTPServer::SetFrontend(Frontend * f)
{
if(m_frontend) delete m_frontend;
m_frontend = f;
}
NNTPServerConn::NNTPServerConn(uv_loop_t * l, uv_stream_t * s, const std::string & storage, NNTPCredentialDB * creds) : NNTPServerConn::NNTPServerConn(uv_loop_t * l, uv_stream_t * s, const std::string & storage, NNTPCredentialDB * creds) :
m_handler(storage) m_handler(storage)

View File

@ -4,6 +4,7 @@
#include <string> #include <string>
#include <deque> #include <deque>
#include "storage.hpp" #include "storage.hpp"
#include "frontend.hpp"
#include "nntp_auth.hpp" #include "nntp_auth.hpp"
#include "nntp_handler.hpp" #include "nntp_handler.hpp"
@ -25,6 +26,10 @@ namespace nntpchan
void SetStoragePath(const std::string & path); void SetStoragePath(const std::string & path);
void SetLoginDB(const std::string path); void SetLoginDB(const std::string path);
void SetFrontend(Frontend * f);
void Close();
private: private:
@ -39,6 +44,8 @@ namespace nntpchan
std::string m_logindbpath; std::string m_logindbpath;
std::string m_storagePath; std::string m_storagePath;
Frontend * m_frontend;
}; };

View File

@ -0,0 +1,13 @@
#include "exec_frontend.hpp"
#include <cassert>
#include <iostream>
int main(int , char * [])
{
nntpchan::Frontend * f = new nntpchan::ExecFrontend("./contrib/nntpchan.sh");
assert(f->AcceptsMessage("<test@server>"));
assert(f->AcceptsNewsgroup("overchan.test"));
std::cout << "all good" << std::endl;
}

0
contrib/frontends/py/frontend.py Normal file → Executable file
View File

View File

@ -1,42 +1 @@
from nntpchan import store
from nntpchan import message
from nntpchan import preprocess
def addArticle(msgid, group):
"""
add article to system
:return True if we need to regenerate otherwise False:
"""
msg = None
# open message
with store.openArticle(msgid) as f:
# read article header
hdr = message.readHeader(f)
mclass = message.MultipartMessage
if hdr.isTextOnly:
# treat as text message instead of multipart
mclass = message.TextMessage
elif hdr.isSigned:
# treat as signed message
mclass = message.TripcodeMessage
# create messgae
msg = mclass(hdr, f)
if msg is not None:
# we got a message that is valid
store.storeMessage(msg)
else:
# invalid message
print("invalid message: {}".format(msgid))
return msg is not None
def regenerate(msgid, group):
"""
regenerate markup
"""
pass