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.
136 lines
4.2 KiB
136 lines
4.2 KiB
#include <protocol/protocol.hpp>
|
|
#include <mail.hpp>
|
|
|
|
#include <functional>
|
|
#include <string>
|
|
#include <vector>
|
|
#include <map>
|
|
#include <unordered_map>
|
|
#include <iostream>
|
|
#include <cstdio>
|
|
|
|
const bool debug = false;
|
|
|
|
using namespace std;
|
|
|
|
mail::session_map_t sessions;
|
|
|
|
void on_ready(protocol::protocol_t& protocol, protocol::message_t message) {
|
|
protocol.send({"register", "filter", "smtp-in", "data"});
|
|
protocol.send({"register", "filter", "smtp-in", "data-line"});
|
|
protocol.send({"register", "filter", "smtp-in", "commit"});
|
|
protocol.send({"register", "ready"});
|
|
cerr << "Ready to accept messages from SMTPD" << endl;
|
|
}
|
|
|
|
void on_data(protocol::protocol_t& protocol, protocol::message_t message) {
|
|
cerr << "Accepting new message from SMTPD" << endl;
|
|
auto session_key = protocol::session_key_from(message);
|
|
auto session_token = protocol::session_token_from(message);
|
|
sessions.emplace(session_key, mail::session_t{});
|
|
protocol.proceed(session_key, session_token);
|
|
}
|
|
|
|
void on_data_line(protocol::protocol_t& protocol, protocol::message_t message) {
|
|
debug && cerr << "Received data line from SMTPD" << endl;
|
|
|
|
auto tokens = protocol::token::decompose(message.input);
|
|
auto session_key = protocol::session_key_from(tokens);
|
|
auto session_token = protocol::session_token_from(tokens);
|
|
try {
|
|
auto& session = sessions.at(session_key);
|
|
auto& data_line = tokens.at(7);
|
|
|
|
if(!session.has_header) {
|
|
if(data_line == "") {
|
|
session.has_header = true;
|
|
return;
|
|
}
|
|
|
|
if(data_line.substr(0, 6) == "X-Spam" ||
|
|
data_line.substr(0, 10) == "X-Bogosity") {
|
|
cerr << "Found and stripped incoming spam filter header:" << endl;
|
|
cerr << data_line << endl;
|
|
return;
|
|
}
|
|
|
|
if(data_line.substr(0, 5) == "From:" ||
|
|
data_line.substr(0, 8) == "Subject:") {
|
|
cerr << data_line << endl;
|
|
}
|
|
|
|
session.message.header.push_back(data_line);
|
|
return;
|
|
}
|
|
|
|
if(data_line == ".") {
|
|
FILE* f = popen("bogofilter -vu 1>&2", "w");
|
|
for(string& line : session.message.header) {
|
|
fprintf(f, "%s\n", line.c_str());
|
|
}
|
|
fwrite("\n", 1, 1, f);
|
|
for(string& line : session.message.body) {
|
|
fprintf(f, "%s\n", line.c_str());
|
|
}
|
|
int status = pclose(f);
|
|
session.status = WEXITSTATUS(status);
|
|
|
|
if(session.status == 0) {
|
|
session.message.header.push_back("X-Spam: Yes");
|
|
}
|
|
|
|
protocol.submit_message(session_key, session_token, session.message.header, session.message.body);
|
|
|
|
return;
|
|
}
|
|
|
|
if(data_line == "..") {
|
|
session.message.body.push_back(".");
|
|
return;
|
|
}
|
|
|
|
session.message.body.push_back(data_line);
|
|
} catch(out_of_range& e) {
|
|
cerr << "Unknown session key from SMTPD" << endl;
|
|
protocol.fail(session_key, session_token);
|
|
}
|
|
}
|
|
|
|
void on_commit(protocol::protocol_t& protocol, protocol::message_t message) {
|
|
debug && cerr << "Commit request from SMTPD" << endl;
|
|
auto session_key = protocol::session_key_from(message);
|
|
auto session_token = protocol::session_token_from(message);
|
|
try {
|
|
auto& session = sessions.at(session_key);
|
|
protocol.proceed(session_key, session_token);
|
|
} catch(out_of_range& e) {
|
|
cerr << "Unknown session key from SMTPD" << endl;
|
|
protocol.fail(session_key, session_token);
|
|
}
|
|
|
|
sessions.erase(session_key);
|
|
}
|
|
|
|
int main(int argc, char** argv) {
|
|
protocol::ios_protocol_t protocol(cin, cout);
|
|
protocol::handler_map_t handlers;
|
|
|
|
handlers.emplace("config|ready", on_ready);
|
|
handlers.emplace("filter|*|*|smtp-in|data", on_data);
|
|
handlers.emplace("filter|*|*|smtp-in|data-line", on_data_line);
|
|
handlers.emplace("filter|*|*|smtp-in|commit", on_commit);
|
|
|
|
if(debug) {
|
|
cerr << "Handler patterns:" << endl;
|
|
for(auto&& [first, second] : handlers) {
|
|
cerr << "\t" << first << endl;
|
|
}
|
|
}
|
|
|
|
cerr << "Bogofilter-SMTPD started" << endl;
|
|
|
|
protocol.set_handlers(handlers);
|
|
protocol.run();
|
|
|
|
return 0;
|
|
}
|
|
|