1package smtp
2
3import "strconv"
4
5// http://www.rfc-editor.org/rfc/rfc5321.txt
6
7// Reply is a struct representing an SMTP reply (status code + lines)
8type Reply struct {
9	Status int
10	lines  []string
11	Done   func()
12}
13
14// Lines returns the formatted SMTP reply
15func (r Reply) Lines() []string {
16	var lines []string
17
18	if len(r.lines) == 0 {
19		l := strconv.Itoa(r.Status)
20		lines = append(lines, l+"\n")
21		return lines
22	}
23
24	for i, line := range r.lines {
25		l := ""
26		if i == len(r.lines)-1 {
27			l = strconv.Itoa(r.Status) + " " + line + "\r\n"
28		} else {
29			l = strconv.Itoa(r.Status) + "-" + line + "\r\n"
30		}
31		lines = append(lines, l)
32	}
33
34	return lines
35}
36
37// ReplyIdent creates a 220 welcome reply
38func ReplyIdent(ident string) *Reply { return &Reply{220, []string{ident}, nil} }
39
40// ReplyReadyToStartTLS creates a 220 ready to start TLS reply
41func ReplyReadyToStartTLS(callback func()) *Reply {
42	return &Reply{220, []string{"Ready to start TLS"}, callback}
43}
44
45// ReplyBye creates a 221 Bye reply
46func ReplyBye() *Reply { return &Reply{221, []string{"Bye"}, nil} }
47
48// ReplyAuthOk creates a 235 authentication successful reply
49func ReplyAuthOk() *Reply { return &Reply{235, []string{"Authentication successful"}, nil} }
50
51// ReplyOk creates a 250 Ok reply
52func ReplyOk(message ...string) *Reply {
53	if len(message) == 0 {
54		message = []string{"Ok"}
55	}
56	return &Reply{250, message, nil}
57}
58
59// ReplySenderOk creates a 250 Sender ok reply
60func ReplySenderOk(sender string) *Reply {
61	return &Reply{250, []string{"Sender " + sender + " ok"}, nil}
62}
63
64// ReplyRecipientOk creates a 250 Sender ok reply
65func ReplyRecipientOk(recipient string) *Reply {
66	return &Reply{250, []string{"Recipient " + recipient + " ok"}, nil}
67}
68
69// ReplyAuthResponse creates a 334 authentication reply
70func ReplyAuthResponse(response string) *Reply { return &Reply{334, []string{response}, nil} }
71
72// ReplyDataResponse creates a 354 data reply
73func ReplyDataResponse() *Reply { return &Reply{354, []string{"End data with <CR><LF>.<CR><LF>"}, nil} }
74
75// ReplyStorageFailed creates a 452 error reply
76func ReplyStorageFailed(reason string) *Reply { return &Reply{452, []string{reason}, nil} }
77
78// ReplyUnrecognisedCommand creates a 500 Unrecognised command reply
79func ReplyUnrecognisedCommand() *Reply { return &Reply{500, []string{"Unrecognised command"}, nil} }
80
81// ReplyLineTooLong creates a 500 Line too long reply
82func ReplyLineTooLong() *Reply { return &Reply{500, []string{"Line too long"}, nil} }
83
84// ReplySyntaxError creates a 501 Syntax error reply
85func ReplySyntaxError(response string) *Reply {
86	if len(response) > 0 {
87		response = " (" + response + ")"
88	}
89	return &Reply{501, []string{"Syntax error" + response}, nil}
90}
91
92// ReplyUnsupportedAuth creates a 504 unsupported authentication reply
93func ReplyUnsupportedAuth() *Reply {
94	return &Reply{504, []string{"Unsupported authentication mechanism"}, nil}
95}
96
97// ReplyMustIssueSTARTTLSFirst creates a 530 reply for RFC3207
98func ReplyMustIssueSTARTTLSFirst() *Reply {
99	return &Reply{530, []string{"Must issue a STARTTLS command first"}, nil}
100}
101
102// ReplyInvalidAuth creates a 535 error reply
103func ReplyInvalidAuth() *Reply {
104	return &Reply{535, []string{"Authentication credentials invalid"}, nil}
105}
106
107// ReplyError creates a 500 error reply
108func ReplyError(err error) *Reply { return &Reply{550, []string{err.Error()}, nil} }
109
110// ReplyTooManyRecipients creates a 552 too many recipients reply
111func ReplyTooManyRecipients() *Reply { return &Reply{552, []string{"Too many recipients"}, nil} }
112