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.
121 lines
3.6 KiB
121 lines
3.6 KiB
#include <util.hpp>
|
|
|
|
#include <protocol/protocol.hpp>
|
|
|
|
#include <iostream>
|
|
#include <string>
|
|
|
|
using namespace std;
|
|
using namespace util;
|
|
|
|
// OpenSMTPD filter protocol documentation:
|
|
// https://man7.org/linux/man-pages/man7/smtpd-filters.7.html
|
|
|
|
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) {
|
|
this->emit(token::compose(tokens));
|
|
}
|
|
|
|
void protocol_t::absorb(const std::string& input) {
|
|
auto tokens = token::decompose(input, max_pattern_length);
|
|
auto pattern = token::pattern_t(tokens, false);
|
|
debug && cerr << "Received pattern " << pattern << endl;
|
|
|
|
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, token::list_t tokens) {
|
|
token::list_t result{"filter-result", session_key.session, session_key.token};
|
|
for(auto& token : tokens) {
|
|
result.push_back(token);
|
|
}
|
|
send(result);
|
|
}
|
|
|
|
void protocol_t::proceed(const session_key_t& session_key) {
|
|
send_result(session_key, {"proceed"});
|
|
}
|
|
|
|
void protocol_t::junk(const session_key_t& session_key) {
|
|
send_result(session_key, {"junk"});
|
|
}
|
|
|
|
void protocol_t::fail(const session_key_t& session_key) {
|
|
send_result(session_key, {"disconnect", "451 Aborted"});
|
|
}
|
|
|
|
void protocol_t::send_data_line(const session_key_t& session_key, const string& data_line) {
|
|
send({"filter-dataline", session_key.session, session_key.token, data_line});
|
|
}
|
|
|
|
void protocol_t::submit_message(const session_key_t& session_key, const vector<string>& header, const vector<string>& body) {
|
|
for(auto& data_line : header) {
|
|
send_data_line(session_key, data_line);
|
|
}
|
|
|
|
send_data_line(session_key, "");
|
|
|
|
for(auto& data_line : body) {
|
|
if(data_line == ".") {
|
|
send_data_line(session_key, "..");
|
|
continue;
|
|
}
|
|
|
|
send_data_line(session_key, data_line);
|
|
}
|
|
|
|
send_data_line(session_key, ".");
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
bool operator==(const session_key_t& l, const session_key_t& r) {
|
|
return l.session == r.session && l.token == r.token;
|
|
}
|
|
|
|
session_key_t session_key_from(const token::list_t& tokens) {
|
|
auto session_id = tokens.at(5);
|
|
auto session_token = tokens.at(6);
|
|
return {session_id, session_token};
|
|
}
|
|
|
|
session_key_t session_key_from(const message_t& message) {
|
|
auto tokens = token::decompose(message.input);
|
|
return session_key_from(tokens);
|
|
}
|
|
}
|
|
|