Library for parsring/generating Maildir filenames.
This commit is contained in:
parent
003605a430
commit
8523965168
80
maildir.go
Normal file
80
maildir.go
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
// 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 email
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"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
|
||||||
|
}
|
||||||
91
maildir_test.go
Normal file
91
maildir_test.go
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
package email
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user