blob: dd96fbbe5cf80b3d65dcb2d1eab3601df3a557af (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
|
// Package rfc822 provides a writer that ensures the intrinsics of RFC 822.
//
// Rationale
//
// Cyrus IMAP really cares about the hard specifics of RFC 822, namely not allowing single \r and \n.
//
// See also: https://www.cyrusimap.org/imap/reference/faqs/interop-barenewlines.html
// and: https://github.com/Necoro/feed2imap-go/issues/46
//
// NB: This package currently only cares about the newlines.
package rfc822
import "io"
type rfc822Writer struct {
w io.Writer
}
var lf = []byte{'\n'}
var cr = []byte{'\r'}
func (f rfc822Writer) Write(p []byte) (n int, err error) {
crFound := false
start := 0
write := func(str []byte, count bool) {
var j int
j, err = f.w.Write(str)
if count {
n += j
}
}
for idx, b := range p {
if crFound && b != '\n' {
// insert '\n'
if write(p[start:idx], true); err != nil {
return
}
if write(lf, false); err != nil {
return
}
start = idx
} else if !crFound && b == '\n' {
// insert '\r'
if write(p[start:idx], true); err != nil {
return
}
if write(cr, false); err != nil {
return
}
start = idx
}
crFound = b == '\r'
}
// write the remainder
if write(p[start:], true); err != nil {
return
}
if crFound { // dangling \r
write(lf, false)
}
return
}
// Writer creates a new RFC 822 conform writer.
func Writer(w io.Writer) io.Writer {
return rfc822Writer{w}
}
|