M cmd/mb/main.go +9 -10
@@ 34,7 34,7 @@ func main() {
err = missingParams
break
}
- var msgs mb.Matcher
+ var msgs *mb.Sequence
folder, seq := path.Split(os.Args[2])
msgs, err = mb.ParseSequence(seq)
os.Stdout.WriteString("Folder: " + folder)
@@ 47,7 47,7 @@ func main() {
if len(os.Args) > 2 {
folder = os.Args[2]
}
- err = mb.List(mbox, os.Stdout, folder, new(mb.AlwaysMatcher))
+ err = mb.List(mbox, os.Stdout, folder, mb.NewAlwaysMatcher())
case "raw":
var src io.ReadCloser = os.Stdin
if len(os.Args) > 2 {
@@ 182,7 182,7 @@ func main() {
break
}
var folder string
- var match mb.Matcher
+ var match *mb.Regexp
if folder, match, err = parseRegexpCmd(os.Args[2:]); err != nil {
break
}
@@ 274,7 274,7 @@ func main() {
break
}
var folder string
- var msgs mb.Matcher
+ var msgs *mb.Sequence
folder, msgs, err = parseSequence(mbox, os.Args[2])
if err != nil {
break
@@ 286,7 286,7 @@ func main() {
break
}
var folder string
- var msgs mb.Matcher
+ var msgs *mb.Sequence
folder, msgs, err = parseSequence(mbox, os.Args[2])
if err != nil {
break
@@ 327,14 327,13 @@ func openMsg(mbox mb.Mailbox, msg string
return mbox.Open(f, b)
}
-func parseSequence(mbox mb.Mailbox, value string) (string, mb.Matcher, error) {
- var msgs mb.Matcher = new(mb.AlwaysMatcher)
+func parseSequence(mbox mb.Mailbox, value string) (string, *mb.Sequence, error) {
folder, seq := path.Split(value)
if len(folder) == 0 {
folder = mbox.Default()
}
- var err error
- if msgs, err = mb.ParseSequence(seq); err != nil {
+ msgs, err := mb.ParseSequence(seq)
+ if err != nil {
return "", nil, err
}
return folder, msgs, nil
@@ 342,7 341,7 @@ func parseSequence(mbox mb.Mailbox, valu
// todo: when len(args) == 0, then return alwaysmatcher
// bullshit, give just one string here
-func parseRegexpCmd(args []string) (string, mb.Matcher, error) {
+func parseRegexpCmd(args []string) (string, *mb.Regexp, error) {
var i int
var folder string
if len(args) == 2 {
M command.go +10 -7
@@ 17,19 17,18 @@ import (
)
// its not an error if no match is found.
-func walk(mbox Mailbox, folder string, seq Matcher, proc func(string) error) error {
+func walk(mbox Mailbox, folder string, seq *Sequence, proc func(string) error) error {
// todo: let only sorted msgs out here
msgs, err := mbox.ReadFolder(folder)
if err != nil {
return err
}
-
// we need a sorted list, so the "Move" cmd will will process the msgs
// in the correct time order
// todo: see above, need sorted list
for j := range msgs {
- if seq.Matches(msgs[j]) {
- if err := proc(strconv.FormatInt(msgs[j].Id(), 10)); err != nil {
+ if seq.Matches(msgs[j].Id()) {
+ if err = proc(strconv.FormatInt(msgs[j].Id(), 10)); err != nil {
return err
}
}
@@ 37,14 36,14 @@ func walk(mbox Mailbox, folder string, s
return nil
}
-func Move(mbox Mailbox, srcFolder string, msgs Matcher, dst string) error {
+func Move(mbox Mailbox, srcFolder string, msgs *Sequence, dst string) error {
proc := func(id string) error {
return mbox.Move(srcFolder, dst, id)
}
return walk(mbox, srcFolder, msgs, proc)
}
-func Remove(mbox Mailbox, folder string, msgs Matcher) error {
+func Remove(mbox Mailbox, folder string, msgs *Sequence) error {
proc := func(id string) error {
return mbox.Remove(folder, id)
}
@@ 63,6 62,7 @@ func partError(no int, msg string) error
return errors.New("mime part " + strconv.Itoa(no) + ": " + msg)
}
+// todo: we need a part matcher or what?
func Save(files chan string, msg *mail.Message, number int) error {
saver := func(p part, no int) error {
if no != number {
@@ 89,7 89,10 @@ func Save(files chan string, msg *mail.M
return partError(no, err.Error())
}
files <- f.Name()
- return f.Close()
+ if err = f.Close(); err != nil {
+ return partError(no, err.Error())
+ }
+ return nil
}
return parse(msg, saver)
}
M list.go +2 -2
@@ 12,7 12,7 @@ import (
var sixMonthPast = time.Now().Add(-6 * 30 * 24 * time.Hour)
var oneDayAhead = time.Now().Add(24 * time.Hour)
-func List(mbox Mailbox, dst io.Writer, folder string, pick Matcher) error {
+func List(mbox Mailbox, dst io.Writer, folder string, pick *Sequence) error {
msgs, err := mbox.ReadFolder(folder)
if err != nil && msgs == nil {
// don't leave now, show as much as we can
@@ 26,7 26,7 @@ func List(mbox Mailbox, dst io.Writer, f
fType = defaultFolderType
}
for _, msg := range msgs {
- if !pick.Matches(msg) {
+ if !pick.Matches(msg.Id()) {
continue
}
header := msg.Header()
M list_test.go +1 -1
@@ 14,7 14,7 @@ func BenchmarkList(b *testing.B) {
panic(err)
}
mbox := NewMHMailbox(mh.NewMailbox())
- msgs := new(AlwaysMatcher)
+ msgs := NewAlwaysMatcher()
b.StartTimer()
for i := 0; i < b.N; i++ {
_ = List(mbox, dst, "inbox", msgs)
M parse.go +2 -2
@@ 18,7 18,6 @@ type part struct {
Body io.Reader
}
-// todo: ine line obly? merge with parsePart?
// todo: use buffer
func parse(msg *mail.Message, proc func(part, int) error) error {
_, err := parsePart(part{textproto.MIMEHeader(msg.Header), msg.Body}, proc, 1)
@@ 52,7 51,7 @@ func parsePart(p part, proc func(part, i
// it's save to apply this decoder to non-mime emails
func mimeDecoder(p part) (io.Reader, error) {
- var out io.Reader = p.Body
+ var out io.Reader
switch enc := p.Header.Get("Content-Transfer-Encoding"); enc {
case "quoted-printable":
// this can only trigger if p is a mail.Message.
@@ 65,6 64,7 @@ func mimeDecoder(p part) (io.Reader, err
out = base64.NewDecoder(base64.StdEncoding, out)
default:
// "7bit", "8bit", "binary" and none-mime emails: nothing to do
+ out = p.Body
}
// decode charset
ct := p.Header.Get("Content-Type")
M sequence.go +16 -21
@@ 7,31 7,27 @@ import (
"strings"
)
-type Matcher interface {
- Matches(Message) bool
-}
-
-type sequence struct {
+type Sequence struct {
section [][2]int64
exact []int64
}
-func (s *sequence) Matches(m Message) bool {
+func (s Sequence) Matches(n int64) bool {
for _, match := range s.exact {
- if match == m.Id() {
+ if match == n {
return true
}
}
for _, match := range s.section {
- if match[0] <= m.Id() && m.Id() <= match[1] {
+ if match[0] <= n && n <= match[1] {
return true
}
}
return false
}
-func ParseSequence(input string) (Matcher, error) {
- var seq sequence
+func ParseSequence(input string) (*Sequence, error) {
+ var seq Sequence
f := strings.Split(input, ",")
for i := range f {
// first, try number
@@ 58,11 54,17 @@ func ParseSequence(input string) (Matche
return &seq, nil
}
-type regexp struct {
+func NewAlwaysMatcher() *Sequence {
+ var s Sequence
+ s.section = append(s.section, [2]int64{0, 1<<63 - 1})
+ return &s
+}
+
+type Regexp struct {
r *rgxp.Regexp
}
-func (s regexp) Matches(m Message) bool {
+func (s Regexp) Matches(m Message) bool {
for key := range m.Header() {
if s.r.MatchString(key + ": " + m.Header().Get(key)) {
return true
@@ 71,17 73,10 @@ func (s regexp) Matches(m Message) bool
return false
}
-func ParseRegexp(s string) (Matcher, error) {
+func ParseRegexp(s string) (*Regexp, error) {
r, err := rgxp.Compile(s)
if err != nil {
return nil, err
}
- return regexp{r}, nil
+ return &Regexp{r}, nil
}
-
-// AlwaysMatcher is a Matcher that always matches.
-type AlwaysMatcher struct{}
-
-func (AlwaysMatcher) Matches(m Message) bool {
- return true
-}
M sequence_test.go +2 -7
@@ 1,10 1,6 @@
package mailbox
-import (
- "testing"
-
- mh "bitbucket.org/telesto/mailbox/mh"
-)
+import "testing"
var testsSequence = []struct {
seq string
@@ 41,8 37,7 @@ func TestSequence(t *testing.T) {
i, err, tc.parseErr)
}
if err == nil {
- m := &mhMessage{&mh.Message{Id: tc.number}}
- got := s.Matches(m)
+ got := s.Matches(tc.number)
if got != tc.want {
t.Errorf("%d: wrong matching, found '%t', expected %t",
i, got, tc.want)