rewrote sequences so i can use it for mime parts
7 files changed, 42 insertions(+), 50 deletions(-)

M cmd/mb/main.go
M command.go
M list.go
M list_test.go
M parse.go
M sequence.go
M sequence_test.go
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)