package main import ( "fmt" "net/url" "regexp" "strconv" "strings" "time" ) var ( rePiperMailMessage = regexp.MustCompile(`^(https?://.*/pipermail/.*/)([0-4]{4}-(?:January|February|March|April|May|June|July|August|September|October|November|December))/([0-9]+)\.html$`) rePiperMailDate = regexp.MustCompile(`^\s*([^<]+)\s*$`) rePiperMailReply = regexp.MustCompile(`^\s*\s$`) ) type PiperMail struct{} var _ Forge = PiperMail{} func (PiperMail) FetchStatus(urls []string) (string, error) { return "", nil } func (PiperMail) FetchSubmittedAt(urls []string) (time.Time, error) { for _, u := range urls { if !rePiperMailMessage.MatchString(u) { continue } htmlStr, err := httpGet(u, nil) if err != nil { return time.Time{}, err } for _, line := range strings.Split(htmlStr, "\n") { if m := rePiperMailDate.FindStringSubmatch(line); m != nil { return time.Parse(time.UnixDate, m[1]) } } } return time.Time{}, nil } func (PiperMail) nextMonth(ym string) string { yStr, mStr, ok := strings.Cut(ym, "-") if !ok { panic(fmt.Errorf("invalid year-month: %q", ym)) } switch mStr { case "January": return yStr + "-February" case "February": return yStr + "-March" case "March": return yStr + "-April" case "April": return yStr + "-May" case "May": return yStr + "-June" case "June": return yStr + "-July" case "July": return yStr + "-August" case "August": return yStr + "-September" case "September": return yStr + "-October" case "October": return yStr + "-November" case "November": return yStr + "-December" case "December": y, _ := strconv.Atoi(yStr) return fmt.Sprintf("%d-January", y+1) default: panic(fmt.Errorf("invalid year-month: %q", ym)) } } func (PiperMail) messageID(u string) (string, error) { } func (p PiperMail) FetchLastUpdated(urls []string) (time.Time, User, error) { for _, u := range urls { m := rePiperMailMessage.FindStringSubmatch(u) if m == nil { continue } uBase := m[1] uYM := m[2] //uInt := m[3] htmlStr, err := httpGet(u, nil) if err != nil { return time.Time{}, User{}, err } var msgid string 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 != "" { break } } } if msgid == "" { continue } mboxStr, err := httpGet(uBase+uYM+".txt.gz", nil) if err != nil { return time.Time{}, User{}, err } } return time.Time{}, User{}, nil }