diff --git a/NEWS b/NEWS index 968dd7b..11e621e 100644 --- a/NEWS +++ b/NEWS @@ -1,8 +1,13 @@ ------------------------------------------------------------------------------- Changes in version 2.00 -- This version updates the API to add new features. Plugins compiled - for previous versions of mailfront will not work without recompiling. +- This version updates the plugin API to add new features: + + - Capabilities reported by the SMTP EHLO response can be added by + plugins. + + Plugins compiled for previous versions of mailfront will not work + without recompiling. Development of this version has been sponsored by FutureQuest, Inc. ossi@FutureQuest.net http://www.FutureQuest.net/ diff --git a/TODO b/TODO index b2dafd5..8ebaccb 100644 --- a/TODO +++ b/TODO @@ -14,6 +14,10 @@ Plugin: clamav - Add tests (not sure how to emulate the daemon properly) +Plugin: lua + + - Fix hooks that can modify strings to actually allow modification + Plugin: patterns - Add better MIME attachment discrimination to patterns, instead of diff --git a/mailfront.c b/mailfront.c index e0ea324..6d843a1 100644 --- a/mailfront.c +++ b/mailfront.c @@ -57,11 +57,13 @@ static const response* handle_init(void) return 0; } -const response* handle_helo(str* host) +const response* handle_helo(str* host, str* capabilities) { const response* resp; - MODULE_CALL(helo, (host), 0, 0); + MODULE_CALL(helo, (host, capabilities), 0, 0); session_setstr("helo_domain", host->s); + if (session.backend->helo != 0) + return session.backend->helo(host, capabilities); return 0; } @@ -188,13 +190,20 @@ int respond_line(unsigned number, int final, return 1; } -int respond(const response* resp) +int respond_multiline(unsigned number, int final, const char* msg) { - 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)); + while ((nl = strchr(msg, '\n')) != 0) { + if (!respond_line(number, 0, msg, nl-msg)) + return 0; + msg = nl + 1; + } + return respond_line(number, final, msg, strlen(msg)); +} + +int respond(const response* resp) +{ + return respond_multiline(resp->number, 1, resp->message); } const response* backend_data_block(const char* data, unsigned long len) diff --git a/mailfront.h b/mailfront.h index 4b4522f..9926604 100644 --- a/mailfront.h +++ b/mailfront.h @@ -17,7 +17,7 @@ struct plugin const char* name; unsigned flags; const response* (*init)(void); - const response* (*helo)(str*); + const response* (*helo)(str* hostname, str* capabilities); const response* (*reset)(void); const response* (*sender)(str*); const response* (*recipient)(str*); @@ -43,7 +43,7 @@ extern const char* getprotoenv(const char*); /* From mailfront.c */ extern const char UNKNOWN[]; -extern const response* handle_helo(str* host); +extern const response* handle_helo(str* host, str* capabilities); extern const response* handle_reset(void); extern const response* handle_sender(str* sender); extern const response* handle_recipient(str* recip); @@ -53,6 +53,7 @@ extern const response* handle_message_end(void); extern int respond(const response*); extern int respond_line(unsigned number, int final, const char* msg, unsigned long len); +extern int respond_multiline(unsigned number, int final, const char* msg); extern const response* backend_data_block(const char* data, unsigned long len); extern int scratchfile(void); diff --git a/plugin-api.html b/plugin-api.html index f2ffb97..63ae4e5 100644 --- a/plugin-api.html +++ b/plugin-api.html @@ -121,10 +121,12 @@

Hook Functions

responses to the sender address or data, and after the SMTP HELO command. -
const response* helo(str* hostname)
This hook is -called when the SMTP HELO or EHLO commands are issued. -As yet nothing actually uses the hostname string. Other -protocols will not call this hook.
+
const response* helo(str* hostname, str* capabilities)
+
This hook is called when the SMTP HELO or EHLO +commands are issued. As yet nothing actually uses the hostname +string. Other protocols will not call this hook. +The capabilities variable contains a list of SMTP EHLO response +capabilities, each followed by a newline.
const response* sender(str* address)
This hook is called after a sender email address is transmitted by the client, and is diff --git a/plugin-lua.c b/plugin-lua.c index 0863a01..c9f58e5 100644 --- a/plugin-lua.c +++ b/plugin-lua.c @@ -225,11 +225,12 @@ static const response* reset(void) return 0; } -static const response* helo(str* hostname) +static const response* helo(str* hostname, str* capabilities) { if (setup("helo")) { lua_pushlstring(L, hostname->s, hostname->len); - return callit(1); + lua_pushlstring(L, capabilities->s, capabilities->len); + return callit(2); } return 0; } diff --git a/plugin-template.c b/plugin-template.c index 98409ed..779d614 100644 --- a/plugin-template.c +++ b/plugin-template.c @@ -13,7 +13,7 @@ static const response* init(void) /* The helo function is called once by the SMTP protocol when either the * HELO or EHLO command is issued. The parameter is the hostname given * in the command. */ -static const response* helo(str* hostname) +static const response* helo(str* hostname, str* capabilities) { return 0; } diff --git a/protocol-smtp.c b/protocol-smtp.c index de604df..aa7a4d9 100644 --- a/protocol-smtp.c +++ b/protocol-smtp.c @@ -26,6 +26,7 @@ static str cmd; static str arg; static str addr; static str params; +static str init_capabilities; static RESPONSE(no_mail, 503, "5.5.1 You must send MAIL FROM: first"); static RESPONSE(vrfy, 252, "2.5.2 Send some mail, I'll try my best."); @@ -42,7 +43,6 @@ static RESPONSE(toobig, 552, "5.2.3 The message would exceed the maximum message static RESPONSE(toomanyunimp, 503, "5.5.0 Too many unimplemented commands.\n5.5.0 Closing connection."); static RESPONSE(goodbye, 221, "2.0.0 Good bye."); static RESPONSE(authenticated, 235, "2.7.0 Authentication succeeded."); -static RESPONSE(ehlo, 250, "8BITMIME\nENHANCEDSTATUSCODES\nPIPELINING"); static int saw_mail = 0; static int saw_rcpt = 0; @@ -126,32 +126,26 @@ static int HELO(void) { const response* resp; if (response_ok(resp = handle_reset())) - resp = handle_helo(&arg); + resp = handle_helo(&arg, &line); return (resp != 0) ? respond(resp) : respond_line(250, 1, domain_name.s, domain_name.len); } static int EHLO(void) { - static str auth_resp; const response* resp; protocol.name = "ESMTP"; + line.len = 0; if (!response_ok(resp = handle_reset()) - || !response_ok(resp = handle_helo(&arg))) + || !response_ok(resp = handle_helo(&arg, &line))) return respond(resp); + if (!str_cat(&line, &init_capabilities)) { + respond(&resp_oom); + return 0; + } if (!respond_line(250, 0, domain_name.s, domain_name.len)) return 0; - switch (sasl_auth_caps(&auth_resp)) { - case 0: break; - case 1: - if (!respond_line(250, 0, auth_resp.s, auth_resp.len)) return 0; - break; - default: return respond(&resp_internal); - } - if (!str_copys(&line, "SIZE ")) return 0; - if (!str_catu(&line, session_getnum("maxdatabytes", 0))) return 0; - if (!respond_line(250, 0, line.s, line.len)) return 0; - return respond(&resp_ehlo); + return respond_multiline(250, 1, line.s); } static void do_reset(void) @@ -391,14 +385,31 @@ static int init(void) if ((tmp = getenv("MAXNOTIMPL")) != 0) maxnotimpl = strtoul(tmp, 0, 10); + if (!sasl_auth_init(&saslauth)) { + respond(&resp_authfail); + return 1; + } + switch (sasl_auth_caps(&init_capabilities)) { + case 0: break; + case 1: break; + default: + respond(&resp_authfail); + return 1; + } + + if (!str_copys(&init_capabilities, "SIZE ") + || !str_catu(&init_capabilities, session_getnum("maxdatabytes", 0)) + || !str_catc(&init_capabilities, '\n') + || !str_cats(&init_capabilities, "8BITMIME\nENHANCEDSTATUSCODES\nPIPELINING")) { + respond(&resp_oom); + return 1; + } + return 0; } static int mainloop(void) { - if (!sasl_auth_init(&saslauth)) - return respond(&resp_authfail); - if (!respond_line(220, 1, str_welcome.s, str_welcome.len)) return 0; while (ibuf_getstr_crlf(&inbuf, &line)) if (!smtp_dispatch()) {