Skip to content

Commit 41de015

Browse files
wesmclaude
andcommitted
parseMsgIDList: extract only angle-bracketed msg-ids
Scan for <...> delimiters instead of splitting on whitespace, so comments, CFWS, and bare tokens in In-Reply-To/Message-ID headers are correctly ignored per RFC 2822 msg-id syntax. Previously "(comment) <root@ex>" yielded "(comment)" as the first ID; now it correctly yields "root@ex". Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 2ad7131 commit 41de015

File tree

2 files changed

+33
-8
lines changed

2 files changed

+33
-8
lines changed

internal/sync/sync.go

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -737,17 +737,27 @@ func deriveThreadKey(parsed *mime.Message) string {
737737
return ""
738738
}
739739

740-
// parseMsgIDList splits a header value containing one or more
741-
// angle-bracketed message-IDs (as in References or In-Reply-To)
742-
// and returns them with brackets stripped. Tokens without angle
743-
// brackets are ignored per RFC 2822 msg-id syntax.
740+
// parseMsgIDList extracts angle-bracketed message-IDs from a
741+
// header value (In-Reply-To, Message-ID, References). Only
742+
// content inside < > pairs is returned, with brackets stripped.
743+
// Comments, CFWS, and bare tokens are ignored per RFC 2822
744+
// msg-id syntax.
744745
func parseMsgIDList(s string) []string {
745746
var result []string
746-
for _, tok := range strings.Fields(s) {
747-
tok = strings.Trim(tok, "<>")
748-
if tok != "" {
749-
result = append(result, tok)
747+
for {
748+
open := strings.IndexByte(s, '<')
749+
if open < 0 {
750+
break
751+
}
752+
close := strings.IndexByte(s[open+1:], '>')
753+
if close < 0 {
754+
break
755+
}
756+
id := s[open+1 : open+1+close]
757+
if id != "" {
758+
result = append(result, id)
750759
}
760+
s = s[open+1+close+1:]
751761
}
752762
return result
753763
}

internal/sync/sync_test.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1581,6 +1581,21 @@ func TestDeriveThreadKey(t *testing.T) {
15811581
msg: &mime.Message{InReplyTo: "<a@ex> <b@ex>", MessageID: "<self@ex>"},
15821582
wantKey: "a@ex",
15831583
},
1584+
{
1585+
name: "InReplyTo with leading comment",
1586+
msg: &mime.Message{InReplyTo: "(comment) <root@ex>"},
1587+
wantKey: "root@ex",
1588+
},
1589+
{
1590+
name: "InReplyTo with folded whitespace",
1591+
msg: &mime.Message{InReplyTo: "\r\n <root@ex>"},
1592+
wantKey: "root@ex",
1593+
},
1594+
{
1595+
name: "Bare token without angle brackets ignored",
1596+
msg: &mime.Message{InReplyTo: "bare-token"},
1597+
wantEmpty: true,
1598+
},
15841599
{
15851600
name: "Empty when no threading info",
15861601
msg: &mime.Message{},

0 commit comments

Comments
 (0)