Add missing maildir package.

This commit is contained in:
Bill Thiede 2023-02-24 21:03:17 -08:00
parent 2f306b70c7
commit 4c531d1f2e
2 changed files with 194 additions and 0 deletions

103
maildir/maildir.go Normal file
View File

@ -0,0 +1,103 @@
// Package email helps manage emails stored in Maildir format. A good
// write-up on the format is available at http://cr.yp.to/proto/maildir.html
package maildir
import (
"bytes"
"fmt"
"os"
"path/filepath"
"strings"
)
// Info represents the info bits encoded as the suffix of a Maildir file. info
// starting with "2,": Each character after the comma is an independent flag.
// Flag "P" (passed): the user has resent/forwarded/bounced this message to someone else.
// Flag "R" (replied): the user has replied to this message.
// Flag "S" (seen): the user has viewed this message, though perhaps he didn't read all the way through it.
// Flag "T" (trashed): the user has moved this message to the trash; the trash will be emptied by a later user action.
// Flag "D" (draft): the user considers this message a draft; toggled at user discretion.
// Flag "F" (flagged): user-defined flag; toggled at user discretion.
// New flags may be defined later. Flags must be stored in ASCII order: e.g., "2,FRS".
type Info struct {
Base string // The portion of the filename before the ':'.
Passed bool
Replied bool
Seen bool
Trashed bool
Draft bool
Flagged bool
}
// NewInfo returns an Info containing the version 2 Maildir flags parsed from
// fn's suffix.
func NewInfo(fn string) (info Info) {
info.Base = fn
i := strings.LastIndex(fn, ":")
if i != -1 {
info.Base = fn[:i]
infoStr := fn[i:]
i = strings.Index(infoStr, ",")
if i == -1 {
return
}
flags := infoStr[i:]
info.Passed = strings.Contains(flags, "P")
info.Replied = strings.Contains(flags, "R")
info.Seen = strings.Contains(flags, "S")
info.Trashed = strings.Contains(flags, "T")
info.Draft = strings.Contains(flags, "D")
info.Flagged = strings.Contains(flags, "F")
}
return
}
func (i Info) String() string {
if i.Passed || i.Replied || i.Seen || i.Trashed || i.Draft || i.Flagged {
b := new(bytes.Buffer)
fmt.Fprintf(b, "%s:2,", i.Base)
if i.Passed {
fmt.Fprint(b, "P")
}
if i.Replied {
fmt.Fprint(b, "R")
}
if i.Seen {
fmt.Fprint(b, "S")
}
if i.Trashed {
fmt.Fprint(b, "T")
}
if i.Draft {
fmt.Fprint(b, "D")
}
if i.Flagged {
fmt.Fprint(b, "F")
}
return b.String()
}
return i.Base
}
func Walk(root string, walker func(path string) error) error {
return filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
if !info.Mode().IsRegular() {
return nil
}
okDirs := map[string]bool{
"cur": true,
"tmp": true,
"new": true,
}
dirPath := filepath.Dir(path)
dir := filepath.Base(dirPath)
if !okDirs[dir] {
return nil
}
return walker(path)
})
}

91
maildir/maildir_test.go Normal file
View File

@ -0,0 +1,91 @@
package maildir
import (
"reflect"
"testing"
)
func TestInfo(t *testing.T) {
datum := []struct {
input string
want Info
clean string // Expected result from .String(), empty defaults to input.
}{
{
input: "mail:2,PRSTDF",
want: Info{
Base: "mail",
Passed: true,
Replied: true,
Seen: true,
Trashed: true,
Draft: true,
Flagged: true,
},
},
{
input: "mail:2,PRTDF",
want: Info{
Base: "mail",
Passed: true,
Replied: true,
Seen: false,
Trashed: true,
Draft: true,
Flagged: true,
},
},
{
input: "mail:2,PRSTD",
want: Info{
Base: "mail",
Passed: true,
Replied: true,
Seen: true,
Trashed: true,
Draft: true,
Flagged: false,
},
},
{
input: "mail:2,RSTDF",
want: Info{
Base: "mail",
Passed: false,
Replied: true,
Seen: true,
Trashed: true,
Draft: true,
Flagged: true,
},
},
{
input: "mail",
want: Info{
Base: "mail",
},
},
{
input: "mail:2,",
want: Info{
Base: "mail",
},
clean: "mail",
},
}
for i, d := range datum {
got := NewInfo(d.input)
if !reflect.DeepEqual(d.want, got) {
t.Errorf("%d. Got %#v want %#v", i, got, d.want)
}
expected := d.input
if d.clean != "" {
expected = d.clean
}
if gotStr := got.String(); gotStr != expected {
t.Errorf("%d. Got %q want %q", i, gotStr, expected)
}
}
}