Repository: emersion/go-imap
Pull request #395 (2020-09-24 08:44:06)

#389 utf7: reset ascii boolean at EOF while destination is short
Fix for #389.


Patch:
diff --git a/message.go b/message.go
index 3d762c7..c9beb82 100644
--- a/message.go
+++ b/message.go
@@ -674,12 +674,18 @@ func (addr *Address) Parse(fields []interface{}) error {
 	if s, err := ParseString(fields[1]); err == nil {
 		addr.AtDomainList, _ = decodeHeader(s)
 	}
-	if s, err := ParseString(fields[2]); err == nil {
-		addr.MailboxName, _ = decodeHeader(s)
+
+	s, err := ParseString(fields[2])
+	if err != nil {
+		return errors.New("Mailbox name could not be parsed")
 	}
-	if s, err := ParseString(fields[3]); err == nil {
-		addr.HostName, _ = decodeHeader(s)
+	addr.MailboxName, _ = decodeHeader(s)
+
+	s, err = ParseString(fields[3])
+	if err != nil {
+		return errors.New("Host name could not be parsed")
 	}
+	addr.HostName, _ = decodeHeader(s)
 
 	return nil
 }
@@ -706,13 +712,11 @@ func (addr *Address) Format() []interface{} {
 
 // Parse an address list from fields.
 func ParseAddressList(fields []interface{}) (addrs []*Address) {
-	addrs = make([]*Address, len(fields))
-
-	for i, f := range fields {
+	for _, f := range fields {
 		if addrFields, ok := f.([]interface{}); ok {
 			addr := &Address{}
 			if err := addr.Parse(addrFields); err == nil {
-				addrs[i] = addr
+				addrs = append(addrs, addr)
 			}
 		}
 	}
diff --git a/utf7/decoder.go b/utf7/decoder.go
index 1c5f1c4..843fb8e 100644
--- a/utf7/decoder.go
+++ b/utf7/decoder.go
@@ -77,6 +77,9 @@ func (d *decoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err er
 		}
 
 		if nDst+len(b) > len(dst) {
+			if atEOF {
+				d.ascii = true
+			}
 			err = transform.ErrShortDst
 			return
 		}


Test patch:
diff --git a/message_test.go b/message_test.go
index aeae249..e81a3b0 100644
--- a/message_test.go
+++ b/message_test.go
@@ -372,6 +372,24 @@ func TestAddress_Format(t *testing.T) {
 	}
 }
 
+func TestEmptyAddress(t *testing.T) {
+	fields := []interface{}{nil, nil, nil, nil}
+	addr := &Address{}
+	err := addr.Parse(fields)
+	if err == nil {
+		t.Error("A nil address did not return an error")
+	}
+}
+
+func TestEmptyGroupAddress(t *testing.T) {
+	fields := []interface{}{nil, nil, "undisclosed-recipients", nil}
+	addr := &Address{}
+	err := addr.Parse(fields)
+	if err == nil {
+		t.Error("An empty group did not return an error when parsed as address")
+	}
+}
+
 func TestAddressList(t *testing.T) {
 	fields := make([]interface{}, len(addrTests))
 	addrs := make([]*Address, len(addrTests))
@@ -400,6 +418,7 @@ func TestEmptyAddressList(t *testing.T) {
 	}
 }
 
+
 var paramsListTest = []struct {
 	fields []interface{}
 	params map[string]string
diff --git a/utf7/decoder_test.go b/utf7/decoder_test.go
index f8728f1..483f704 100644
--- a/utf7/decoder_test.go
+++ b/utf7/decoder_test.go
@@ -72,6 +72,10 @@ var decode = []struct {
 	{"&AGE-&Jjo-", "", false},
 	{"&U,BTFw-&ZeVnLIqe-", "", false},
 
+	// Long input with Base64 at the end
+	{"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa &2D3eCg- &2D3eCw- &2D3eDg-",
+		"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa \U0001f60a \U0001f60b \U0001f60e", true},
+
 	// ASCII in Base64
 	{"&AGE-", "", false},            // "a"
 	{"&ACY-", "", false},            // "&"