summaryrefslogtreecommitdiff
path: root/cmd/generate/forge_pipermail.go
diff options
context:
space:
mode:
authorLuke T. Shumaker <lukeshu@lukeshu.com>2024-06-08 21:29:36 -0600
committerLuke T. Shumaker <lukeshu@lukeshu.com>2024-06-08 21:29:36 -0600
commit8cc4eb82796727f20accfce8d049f677e6210824 (patch)
treef6d1986b3cf0898a5a1aae24e1b9e7658853abcc /cmd/generate/forge_pipermail.go
parent5dc2e9533a111d75ff91a56dd50af8e03ebf5f5f (diff)
wip pipermail threading
Diffstat (limited to 'cmd/generate/forge_pipermail.go')
-rw-r--r--cmd/generate/forge_pipermail.go69
1 files changed, 62 insertions, 7 deletions
diff --git a/cmd/generate/forge_pipermail.go b/cmd/generate/forge_pipermail.go
index e015bb5..56e7ef2 100644
--- a/cmd/generate/forge_pipermail.go
+++ b/cmd/generate/forge_pipermail.go
@@ -1,12 +1,17 @@
package main
import (
+ "errors"
"fmt"
+ "net/mail"
"net/url"
+ "os"
"regexp"
"strconv"
"strings"
"time"
+
+ "git.lukeshu.com/www/cmd/generate/mailstuff"
)
var (
@@ -77,9 +82,20 @@ func (PiperMail) nextMonth(ym string) string {
}
}
-func (PiperMail) messageID(u string) (string, error) {
-}
+func (p PiperMail) threadLen(thread *mailstuff.ThreadedMessage) int {
+ if thread == nil {
+ return 0
+ }
+ ret := 0
+ if thread.Message != nil {
+ ret++
+ }
+ for child := range thread.Children {
+ ret += p.threadLen(child)
+ }
+ return ret
+}
func (p PiperMail) FetchLastUpdated(urls []string) (time.Time, User, error) {
for _, u := range urls {
@@ -95,14 +111,14 @@ func (p PiperMail) FetchLastUpdated(urls []string) (time.Time, User, error) {
if err != nil {
return time.Time{}, User{}, err
}
- var msgid string
+ var msgid mailstuff.MessageID
for _, line := range strings.Split(htmlStr, "\n") {
if m := rePiperMailReply.FindStringSubmatch(line); m != nil {
ru, err := url.Parse(m[1])
if err != nil {
continue
}
- if msgid = ru.Query().Get("In-Reply-To"); msgid != "" {
+ if msgid = mailstuff.MessageID(ru.Query().Get("In-Reply-To")); msgid != "" {
break
}
}
@@ -110,9 +126,48 @@ func (p PiperMail) FetchLastUpdated(urls []string) (time.Time, User, error) {
if msgid == "" {
continue
}
- mboxStr, err := httpGet(uBase+uYM+".txt.gz", nil)
- if err != nil {
- return time.Time{}, User{}, err
+
+ var thread *mailstuff.ThreadedMessage
+ for ym, mbox := uYM, []*mail.Message(nil); true; ym = p.nextMonth(ym) {
+ lenBefore := p.threadLen(thread)
+
+ mboxStr, err := httpGet(uBase+ym+".txt.gz", nil)
+ if err != nil && (ym == uYM || !errors.Is(err, os.ErrNotExist)) {
+ return time.Time{}, User{}, err
+ }
+ _mbox, err := mailstuff.ReadMBox(strings.NewReader(mboxStr))
+ if err != nil {
+ return time.Time{}, User{}, err
+ }
+ mbox = append(mbox, _mbox...)
+ _, messages := mailstuff.ThreadMessages(mbox)
+ thread = messages[msgid]
+
+ if p.threadLen(thread) == lenBefore {
+ break
+ }
+ }
+
+ var retTime time.Time
+ var retUser User
+
+ var walk func(*mailstuff.ThreadedMessage)
+ walk = func(msg *mailstuff.ThreadedMessage) {
+ date, dateErr := msg.Header.Date()
+ froms, fromErr := msg.Header.AddressList("From")
+ if dateErr == nil && fromErr == nil && len(froms) > 0 && (retTime.IsZero() || date.After(retTime)) {
+ retTime = date
+ retUser.Name = froms[0].Name
+ if retUser.Name == "" {
+ retUser.Name = froms[0].Address
+ }
+ retUser.URL = "mailto:" + froms[0].Address
+ }
+ }
+ walk(thread)
+
+ if !retTime.IsZero() {
+ return retTime, retUser, nil
}
}
return time.Time{}, User{}, nil