7// ThreadSubject returns the base subject to use for matching against other
 
8// messages, to see if they belong to the same thread. A matching subject is
 
9// always required to match to an existing thread, both if
 
10// References/In-Reply-To header(s) are present, and if not.
 
12// isResponse indicates if this message is a response, such as a reply or a
 
15// Subject should already be q/b-word-decoded.
 
17// If allowNull is true, base subjects with a \0 can be returned. If not set,
 
18// an empty string is returned if a base subject would have a \0.
 
19func ThreadSubject(subject string, allowNull bool) (threadSubject string, isResponse bool) {
 
20	subject = strings.ToLower(subject)
 
24	for _, c := range subject {
 
27		} else if c == ' ' || c == '\n' || c == '\t' {
 
28			if !strings.HasSuffix(s, " ") {
 
37	removeBlob := func(s string) string {
 
46				s = s[i+1:]                     // Past [...].
 
47				s = strings.TrimRight(s, " \t") // *WSP
 
54	removeLeader := func(s string) string {
 
55		if strings.HasPrefix(s, " ") || strings.HasPrefix(s, "\t") {
 
61		// Remove zero or more subj-blob
 
70		if strings.HasPrefix(s, "re") {
 
72		} else if strings.HasPrefix(s, "fwd") {
 
74		} else if strings.HasPrefix(s, "fw") {
 
79		s = strings.TrimLeft(s, " \t") // *WSP
 
81		if !strings.HasPrefix(s, ":") {
 
93			s = strings.TrimRight(s, " \t")
 
94			if strings.HasSuffix(s, "(fwd)") {
 
95				s = strings.TrimSuffix(s, "(fwd)")
 
105			s = removeLeader(s) // Step 3.
 
106			if ns := removeBlob(s); ns != "" {
 
116		if strings.HasPrefix(s, "[fwd:") && strings.HasSuffix(s, "]") {
 
117			s = s[len("[fwd:") : len(s)-1]
 
119			continue // From step 2 again.
 
123	if !allowNull && strings.ContainsRune(s, 0) {