#include #include #include #include #include #include #include #include "mailfront.h" static RESPONSE(no_sender,550,"5.1.0 Mail system is not configured to accept that sender"); static RESPONSE(no_rcpt,550,"5.1.0 Mail system is not configured to accept that recipient"); const char UNKNOWN[] = "unknown"; const int msg_show_pid = 1; const char program[] = "mailfront"; const int authenticating = 0; extern void set_timeout(void); extern void report_io_bytes(void); static str tmp_prefix; #define MODULE_CALL(NAME,PARAMS,SHORT) do{ \ struct plugin* plugin; \ const response* tmp; \ for (plugin = plugin_list; plugin != 0; plugin = plugin->next) { \ if (plugin->NAME != 0) { \ if ((tmp = plugin->NAME PARAMS) != 0) { \ resp = tmp; \ if (!response_ok(resp)) \ return resp; \ else if (SHORT) \ break; \ } \ } \ } \ } while(0) const response* handle_init(void) { const response* resp; atexit(report_io_bytes); set_timeout(); MODULE_CALL(init, (), 0); if (session.backend->init != 0) return session.backend->init(); return 0; } const response* handle_helo(str* host) { const response* resp; MODULE_CALL(helo, (host), 0); session_setstr("helo_domain", host->s); return 0; } const response* handle_reset(void) { const response* resp = 0; if (session.backend->reset != 0) session.backend->reset(); MODULE_CALL(reset, (), 0); return resp; } const response* handle_sender(str* sender) { const response* resp = 0; const response* tmpresp = 0; MODULE_CALL(sender, (sender), 1); if (resp == 0) return &resp_no_sender; if (session.backend->sender != 0) if (!response_ok(tmpresp = session.backend->sender(sender))) return tmpresp; if (resp == 0 || resp->message == 0) resp = tmpresp; return resp; } const response* handle_recipient(str* recip) { const response* resp = 0; const response* hresp = 0; MODULE_CALL(recipient, (recip), 1); if (resp == 0) return &resp_no_rcpt; if (session.backend->recipient != 0) if (!response_ok(hresp = session.backend->recipient(recip))) return hresp; if (resp == 0 || resp->message == 0) resp = hresp; return resp; } static const response* data_response; const response* handle_data_start(void) { const response* resp = 0; if (module_flags & FLAG_NEED_FILE) { if ((session.fd = scratchfile()) == -1) return &resp_internal; } else session.fd = -1; if (session.backend->data_start != 0) resp = session.backend->data_start(session.fd); if (response_ok(resp)) MODULE_CALL(data_start, (session.fd), 0); data_response = response_ok(resp) ? 0 : resp; return resp; } void handle_data_bytes(const char* bytes, unsigned len) { const response* r; struct plugin* plugin; if (!response_ok(data_response)) return; for (plugin = plugin_list; plugin != 0; plugin = plugin->next) if (plugin->data_block != 0) if ((r = plugin->data_block(bytes, len)) != 0 && !response_ok(r)) { data_response = r; return; } if (session.backend->data_block != 0) session.backend->data_block(bytes, len); if (session.fd >= 0) if (write(session.fd, bytes, len) != (ssize_t)len) data_response = &resp_internal; } const response* handle_message_end(void) { const response* resp = 0; if (!response_ok(data_response)) return data_response; MODULE_CALL(message_end, (session.fd), 0); if (session.backend->message_end != 0) resp = session.backend->message_end(session.fd); if (session.fd >= 0) close(session.fd); session.fd = -1; return resp; } int respond_line(unsigned number, int final, const char* msg, unsigned long len) { static str line; if (number >= 400) { line.len = 0; str_catu(&line, number); str_catc(&line, ' '); str_catb(&line, msg, len); msg1(line.s); } if (!session.protocol->respond_line(number, final, msg, len)) return 0; if (final) if (!obuf_flush(&outbuf)) return 0; return 1; } int respond(const response* resp) { const char* msg; const char* nl; for (msg = resp->message; (nl = strchr(msg, '\n')) != 0; msg = nl + 1) respond_line(resp->number, 0, msg, nl-msg); return respond_line(resp->number, 1, msg, strlen(msg)); } int scratchfile(void) { str filename = {0,0,0}; int fd; if ((fd = path_mktemp(tmp_prefix.s, &filename)) != -1) unlink(filename.s); str_free(&filename); return fd; } int main(int argc, char* argv[]) { const response* resp; const char* tmp; if (argc < 3) die1(111, "Protocol or backend name are missing from the command line"); if ((tmp = getenv("TMPDIR")) == 0) tmp = "/tmp"; if (!str_copy2s(&tmp_prefix, tmp, "/mailfront.tmp.")) die_oom(111); session_init(); if ((resp = load_modules(argv[1], argv[2], (const char**)(argv+3))) != 0 || (resp = handle_init()) != 0) { if (session.protocol != 0) { respond(resp); return 1; } else die1(1, resp->message); } if (session.protocol->init != 0) if (session.protocol->init()) return 1; return session.protocol->mainloop(); }