1package imap 2 3import ( 4 "fmt" 5 "regexp" 6 "time" 7) 8 9// Date and time layouts. 10// Dovecot adds a leading zero to dates: 11// https://github.com/dovecot/core/blob/4fbd5c5e113078e72f29465ccc96d44955ceadc2/src/lib-imap/imap-date.c#L166 12// Cyrus adds a leading space to dates: 13// https://github.com/cyrusimap/cyrus-imapd/blob/1cb805a3bffbdf829df0964f3b802cdc917e76db/lib/times.c#L543 14// GMail doesn't support leading spaces in dates used in SEARCH commands. 15const ( 16 // Defined in RFC 3501 as date-text on page 83. 17 DateLayout = "_2-Jan-2006" 18 // Defined in RFC 3501 as date-time on page 83. 19 DateTimeLayout = "_2-Jan-2006 15:04:05 -0700" 20 // Defined in RFC 5322 section 3.3, mentioned as env-date in RFC 3501 page 84. 21 envelopeDateTimeLayout = "Mon, 02 Jan 2006 15:04:05 -0700" 22 // Use as an example in RFC 3501 page 54. 23 searchDateLayout = "2-Jan-2006" 24) 25 26// time.Time with a specific layout. 27type ( 28 Date time.Time 29 DateTime time.Time 30 envelopeDateTime time.Time 31 searchDate time.Time 32) 33 34// Permutations of the layouts defined in RFC 5322, section 3.3. 35var envelopeDateTimeLayouts = [...]string{ 36 envelopeDateTimeLayout, // popular, try it first 37 "_2 Jan 2006 15:04:05 -0700", 38 "_2 Jan 2006 15:04:05 MST", 39 "_2 Jan 2006 15:04 -0700", 40 "_2 Jan 2006 15:04 MST", 41 "_2 Jan 06 15:04:05 -0700", 42 "_2 Jan 06 15:04:05 MST", 43 "_2 Jan 06 15:04 -0700", 44 "_2 Jan 06 15:04 MST", 45 "Mon, _2 Jan 2006 15:04:05 -0700", 46 "Mon, _2 Jan 2006 15:04:05 MST", 47 "Mon, _2 Jan 2006 15:04 -0700", 48 "Mon, _2 Jan 2006 15:04 MST", 49 "Mon, _2 Jan 06 15:04:05 -0700", 50 "Mon, _2 Jan 06 15:04:05 MST", 51 "Mon, _2 Jan 06 15:04 -0700", 52 "Mon, _2 Jan 06 15:04 MST", 53} 54 55// TODO: this is a blunt way to strip any trailing CFWS (comment). A sharper 56// one would strip multiple CFWS, and only if really valid according to 57// RFC5322. 58var commentRE = regexp.MustCompile(`[ \t]+\(.*\)$`) 59 60// Try parsing the date based on the layouts defined in RFC 5322, section 3.3. 61// Inspired by https://github.com/golang/go/blob/master/src/net/mail/message.go 62func parseMessageDateTime(maybeDate string) (time.Time, error) { 63 maybeDate = commentRE.ReplaceAllString(maybeDate, "") 64 for _, layout := range envelopeDateTimeLayouts { 65 parsed, err := time.Parse(layout, maybeDate) 66 if err == nil { 67 return parsed, nil 68 } 69 } 70 return time.Time{}, fmt.Errorf("date %s could not be parsed", maybeDate) 71} 72