Bogofilter adapter for OpenSMTPD in C++
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

134 lines
4.3 KiB

// OpenSMTPD filter protocol documentation:
// https://man7.org/linux/man-pages/man7/smtpd-filters.7.html
#include <util.hpp>
#include <protocol/protocol.hpp>
#include <iostream>
#include <string>
using namespace std;
using namespace util;
const bool debug = true;
namespace protocol {
void protocol_t::set_handlers(const handler_map_t handlers) {
size_t length = 0;
for(auto&& [pattern, handler] : handlers) {
for(auto&& [index, token] : pattern) {
if(index + 1 > length) {
length = index + 1;
}
}
}
max_pattern_length = length;
debug && cerr << "Maximum handler pattern length is " << length << endl;
this->handlers = handlers;
}
void protocol_t::send(const token::list_t& tokens) {
debug && cerr << "Sent pattern " << protocol::token::pattern_t(tokens) << endl;
this->emit(token::compose(tokens));
}
void protocol_t::absorb(const std::string& input) {
auto tokens = token::decompose(input, debug ? -1 : max_pattern_length);
auto pattern = token::pattern_t(tokens, false);
debug && cerr << "Received pattern " << pattern << endl;
if(tokens.size() >= 2 && tokens.at(0) == "filter") {
version = tokens.at(1);
}
auto element = handlers.find(pattern);
if(element == handlers.end()) {
debug && cerr << "Unknown pattern " << pattern << endl;
} else {
element->second(*this, {input, element->first});
}
}
void protocol_t::send_result(const session_key_t& session_key, const token::string_t& session_token, token::list_t tokens) {
token::list_t result{"filter-result"};
if(version < "0.5") {
result.insert(result.end(), {session_token, session_key});
} else {
result.insert(result.end(), {session_key, session_token});
}
for(auto& token : tokens) {
result.push_back(token);
}
send(result);
}
void protocol_t::proceed(const session_key_t& session_key, const token::string_t& session_token) {
send_result(session_key, session_token, {"proceed"});
}
void protocol_t::junk(const session_key_t& session_key, const token::string_t& session_token) {
send_result(session_key, session_token, {"junk"});
}
void protocol_t::fail(const session_key_t& session_key, const token::string_t& session_token) {
send_result(session_key, session_token, {"disconnect", "451 Aborted"});
}
void protocol_t::send_data_line(const session_key_t& session_key, const token::string_t& session_token, const string& data_line) {
send({"filter-dataline", session_key, session_token, data_line});
}
void protocol_t::submit_message(const session_key_t& session_key, const token::string_t& session_token, const vector<string>& header, const vector<string>& body) {
for(auto& data_line : header) {
send_data_line(session_key, session_token, data_line);
}
send_data_line(session_key, session_token, "");
for(auto& data_line : body) {
if(data_line == ".") {
send_data_line(session_key, session_token, "..");
continue;
}
send_data_line(session_key, session_token, data_line);
}
send_data_line(session_key, session_token, ".");
}
ios_protocol_t::ios_protocol_t(std::istream& in, std::ostream& out) :
in(in), out(out) { }
void ios_protocol_t::emit(const std::string& output) {
out << output << endl;
}
void ios_protocol_t::run() {
while(!in.eof()) {
string line;
std::getline(in, line);
absorb(line);
}
}
session_key_t session_key_from(const token::list_t& tokens) {
return tokens.at(5);
}
session_key_t session_key_from(const message_t& message) {
auto tokens = token::decompose(message.input, 6);
return session_key_from(tokens);
}
token::string_t session_token_from(const token::list_t& tokens) {
return tokens.at(6);
}
token::string_t session_token_from(const message_t& message) {
auto tokens = token::decompose(message.input, 7);
return session_token_from(tokens);
}
}