grep msg body
6 files changed, 53 insertions(+), 37 deletions(-)

M command.go
M edit.go
M mailbox.go
M mh.go
M mh/mh.go
M sequence.go
M command.go +8 -3
@@ 116,7 116,12 @@ func ViewPart(dst io.Writer, msg *mail.M
 	return parse(msg, partPrinter)
 }
 
-func newPlainTextPrinter(dst io.Writer, t transform.Transformer) func(part, int) error {
+func anno(w io.Writer, p part, no int) error {
+	_, err := fmt.Fprintf(w, "[MIME Part %d: %s]\n", no, p.Header.Get("Content-Type"))
+	return err
+}
+
+func newPlainTextPrinter(dst io.Writer, t transform.Transformer, anno func(io.Writer, part, int) error) func(part, int) error {
 	return func(p part, no int) error {
 		// todo: if the msg has no content type header, this will return "mime: no media type"
 		mt, _, err := mime.ParseMediaType(p.Header.Get("Content-Type"))

          
@@ 131,7 136,7 @@ func newPlainTextPrinter(dst io.Writer, 
 			_, err = io.Copy(dst, transform.NewReader(in, t))
 			return err
 		}
-		if _, err = fmt.Fprintf(dst, "[MIME Part %d: %s]\n", no, p.Header.Get("Content-Type")); err != nil {
+		if err = anno(dst, p, no); err != nil {
 			return err
 		}
 		// process the stream (by throwing it away), as it is replaced by the string above

          
@@ 151,7 156,7 @@ func View(dst io.Writer, msg *mail.Messa
 	if _, err := io.Copy(dst, &b); err != nil {
 		return err
 	}
-	return parse(msg, newPlainTextPrinter(dst, transform.Nop))
+	return parse(msg, newPlainTextPrinter(dst, transform.Nop, anno))
 }
 
 func Send(msg *mail.Message) error {

          
M edit.go +1 -1
@@ 260,7 260,7 @@ func fmtReply(dst io.Writer, sender stri
 			parseAddressList(h.Get("From"))); err != nil {
 			return err
 		}
-		if err := parse(msg, newPlainTextPrinter(dst, &quoteMessage{true})); err != nil {
+		if err := parse(msg, newPlainTextPrinter(dst, &quoteMessage{true}, anno)); err != nil {
 			return err
 		}
 	}

          
M mailbox.go +1 -0
@@ 8,6 8,7 @@ import (
 type Message interface {
 	Id() int64
 	Header() mail.Header
+	Body() io.Reader
 }
 
 type Mailbox interface {

          
M mh.go +5 -0
@@ 1,6 1,7 @@ 
 package mailbox
 
 import (
+	"io"
 	"net/mail"
 
 	"bitbucket.org/telesto/mailbox/mh"

          
@@ 27,6 28,10 @@ func (mbox mhMessage) Header() mail.Head
 	return mbox.Message.Header
 }
 
+func (mbox mhMessage) Body() io.Reader {
+	return mbox.Message.Body
+}
+
 func (mb mhMailbox) ReadFolder(folder string) ([]Message, error) {
 	mhMsgs, err := mb.Mailbox.ReadFolder(folder)
 	if mhMsgs == nil {

          
M mh/mh.go +6 -4
@@ 28,7 28,7 @@ const (
 
 type Message struct {
 	Id int64
-	mail.Header
+	*mail.Message
 }
 
 type Mailbox struct {

          
@@ 124,7 124,7 @@ func (mbox Mailbox) ReadFolder(folder st
 			mails = append(mails, errMail(list[i].Id, err1))
 			continue
 		}
-		mails = append(mails, &Message{list[i].Id, msg.Header})
+		mails = append(mails, &Message{list[i].Id, msg})
 	}
 	return mails, err
 }

          
@@ 154,8 154,10 @@ func (mh *Mailbox) Append(folder string,
 }
 
 func errMail(id int64, err error) *Message {
-	m := Message{id, make(map[string][]string, 1)}
-	m.Header["Subject"] = []string{"Error: " + err.Error()}
+	h := make(map[string][]string, 1)
+	h["Subject"] = []string{"Error: " + err.Error()}
+	b := strings.NewReader("Error: " + err.Error())
+	m := Message{id, &mail.Message{h, b}}
 	return &m
 }
 

          
M sequence.go +32 -29
@@ 78,43 78,46 @@ func (s Regexp) Matches(m Message) bool 
 	if !s.matchBody {
 		return false
 	}
-	return false
+	return s.r.MatchReader(&readRune{reader: m.Body()})
 }
 
 func ParseRegexp(s string) (*Regexp, error) {
-	ss := strings.Split(s, ":")
-	if len(ss) > 2 {
-		return nil, errors.New("invalid parameter")
+	i := strings.Index(s, ":")
+	keys := "All"
+	regexp := s
+	if i >= 0 {
+		keys = s[:i]
+		regexp = s[i+1:]
+	}
+	if keys == "All" {
+		// match header and body
+		keys = "Header,Body"
 	}
-	var keys string
-	regexp := ss[0]
-	if len(ss) == 2 {
-		keys = ss[0]
-		regexp = ss[1]
+	m := make(map[string]struct{})
+	// todo: don't use closure here
+	hm := func(key string) bool {
+		_, ok := m[key]
+		return ok
+	}
+	var matchBody bool
+	for _, key := range strings.Split(keys, ",") {
+		switch key {
+		case "Body":
+			matchBody = true
+		case "Header":
+			hm = func(string) bool {
+				return true
+			}
+		default:
+			m[key] = struct{}{}
+		}
 	}
 	r, err := rgxp.Compile(regexp)
 	if err != nil {
-		return nil, err
-	}
-	if len(keys) == 0 {
-		// match everything
-		return &Regexp{func(string) bool {
-			return true
-		}, true, r}, nil
+		return nil, errors.New(regexp + ": " + err.Error())
 	}
-	m := make(map[string]struct{})
-	var matchBody bool
-	for _, key := range strings.Split(keys, ",") {
-		m[key] = struct{}{}
-		if key == "body" {
-			matchBody = true
-		}
-	}
-	// todo: don't use closure here
-	return &Regexp{func(key string) bool {
-		_, ok := m[key]
-		return ok
-	}, matchBody, r}, nil
+	// todo: decode
+	return &Regexp{hm, matchBody, r}, nil
 }
 
 // readRune is a structure to enable reading UTF-8 encoded code points