mirror of
https://blitiri.com.ar/repos/chasquid
synced 2025-12-17 14:37:02 +00:00
chasquid: Minor fixes to MAIL FROM and RCPT TO handling
This patch tidies up the MAIL FROM and RCPT TO handling, in particular: - Preserve the case on received email. It could be outgoing and we should not change it. - Accept (but ignore) RCPT TO options, instead of failing. - Fix some error codes to make them follow the RFC.
This commit is contained in:
23
chasquid.go
23
chasquid.go
@@ -595,8 +595,8 @@ func (c *Conn) NOOP(params string) (code int, msg string) {
|
|||||||
|
|
||||||
func (c *Conn) MAIL(params string) (code int, msg string) {
|
func (c *Conn) MAIL(params string) (code int, msg string) {
|
||||||
// params should be: "FROM:<name@host>", and possibly followed by
|
// params should be: "FROM:<name@host>", and possibly followed by
|
||||||
// "BODY=8BITMIME" (which we ignore).
|
// options such as "BODY=8BITMIME" (which we ignore).
|
||||||
// Check that it begins with "FROM:" first, otherwise it's pointless.
|
// Check that it begins with "FROM:" first, it's mandatory.
|
||||||
if !strings.HasPrefix(strings.ToLower(params), "from:") {
|
if !strings.HasPrefix(strings.ToLower(params), "from:") {
|
||||||
return 500, "unknown command"
|
return 500, "unknown command"
|
||||||
}
|
}
|
||||||
@@ -655,23 +655,30 @@ func (c *Conn) MAIL(params string) (code int, msg string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Conn) RCPT(params string) (code int, msg string) {
|
func (c *Conn) RCPT(params string) (code int, msg string) {
|
||||||
// params should be: "TO:<name@host>"
|
// params should be: "TO:<name@host>", and possibly followed by options
|
||||||
// First, get rid of the "TO:" part (but check it, it's mandatory).
|
// such as "NOTIFY=SUCCESS,DELAY" (which we ignore).
|
||||||
sp := strings.SplitN(strings.ToLower(params), ":", 2)
|
// Check that it begins with "TO:" first, it's mandatory.
|
||||||
if len(sp) != 2 || sp[0] != "to" {
|
if !strings.HasPrefix(strings.ToLower(params), "to:") {
|
||||||
return 500, "unknown command"
|
return 500, "unknown command"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rawAddr := ""
|
||||||
|
_, err := fmt.Sscanf(params[3:], "%s ", &rawAddr)
|
||||||
|
if err != nil {
|
||||||
|
return 500, "malformed command - " + err.Error()
|
||||||
|
}
|
||||||
|
|
||||||
// RFC says 100 is the minimum limit for this, but it seems excessive.
|
// RFC says 100 is the minimum limit for this, but it seems excessive.
|
||||||
|
// https://tools.ietf.org/html/rfc5321#section-4.5.3.1.8
|
||||||
if len(c.rcptTo) > 100 {
|
if len(c.rcptTo) > 100 {
|
||||||
return 503, "too many recipients"
|
return 452, "too many recipients"
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Write our own parser (we have different needs, mail.ParseAddress
|
// TODO: Write our own parser (we have different needs, mail.ParseAddress
|
||||||
// is useful for other things).
|
// is useful for other things).
|
||||||
// Allow utf8, but prevent "control" characters.
|
// Allow utf8, but prevent "control" characters.
|
||||||
|
|
||||||
e, err := mail.ParseAddress(sp[1])
|
e, err := mail.ParseAddress(rawAddr)
|
||||||
if err != nil || e.Address == "" {
|
if err != nil || e.Address == "" {
|
||||||
return 501, "malformed address"
|
return 501, "malformed address"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -184,11 +184,9 @@ func TestNullMailFrom(t *testing.T) {
|
|||||||
c := mustDial(t, ModeSMTP, false)
|
c := mustDial(t, ModeSMTP, false)
|
||||||
defer c.Close()
|
defer c.Close()
|
||||||
|
|
||||||
addrs := []string{"", "<>", " <>", " < > "}
|
addrs := []string{"<>", " <>", "<> OPTION"}
|
||||||
for _, addr := range addrs {
|
for _, addr := range addrs {
|
||||||
if err := c.Text.PrintfLine(addr); err != nil {
|
simpleCmd(t, c, fmt.Sprintf("MAIL FROM:%s", addr), 250)
|
||||||
t.Fatalf("MAIL FROM failed with addr %q: %v", addr, err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,6 +199,21 @@ func TestRcptBeforeMail(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRcptOption(t *testing.T) {
|
||||||
|
c := mustDial(t, ModeSMTP, false)
|
||||||
|
defer c.Close()
|
||||||
|
|
||||||
|
if err := c.Mail("from@localhost"); err != nil {
|
||||||
|
t.Errorf("Mail: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
params := []string{
|
||||||
|
"<to@localhost>", " <to@localhost>", "<to@localhost> OPTION"}
|
||||||
|
for _, p := range params {
|
||||||
|
simpleCmd(t, c, fmt.Sprintf("RCPT TO:%s", p), 250)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestRelayForbidden(t *testing.T) {
|
func TestRelayForbidden(t *testing.T) {
|
||||||
c := mustDial(t, ModeSMTP, false)
|
c := mustDial(t, ModeSMTP, false)
|
||||||
defer c.Close()
|
defer c.Close()
|
||||||
|
|||||||
Reference in New Issue
Block a user