# HG changeset patch # User telesto # Date 1462382719 -7200 # Wed May 04 19:25:19 2016 +0200 # Node ID 652afcdc243c36d9c1c3ba6656c634f4705df6de # Parent 7b08a4f3daf9c2a245e7becc7331472112aca4d5 lots of small improvements diff --git a/command.go b/command.go --- a/command.go +++ b/command.go @@ -1,15 +1,15 @@ package mailbox import ( - "bufio" + "bytes" "errors" + "fmt" "io" "io/ioutil" "mime" "mime/multipart" "net/mail" "os" - "path" "strconv" "strings" @@ -60,7 +60,7 @@ } func partError(no int, msg string) error { - return errors.New("part " + strconv.Itoa(no) + ": " + msg) + return errors.New("mime part " + strconv.Itoa(no) + ": " + msg) } func Save(files chan string, msg *mail.Message, number int) error { @@ -76,14 +76,11 @@ if len(filename) == 0 { return partError(no, "no filename") } - basename := path.Base(filename) - if len(basename) == 0 { - return partError(no, "invalid filename '"+filename+"'") - } f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0666) if err != nil { return partError(no, err.Error()) } + defer f.Close() in, err := mimeDecoder(p) if err != nil { return partError(no, err.Error()) @@ -91,12 +88,13 @@ if _, err = io.Copy(f, in); err != nil { return partError(no, err.Error()) } - files <- basename - return nil + files <- f.Name() + return f.Close() } return parse(msg, saver) } +// todo: print something like "inbox/33:1
"? func Parts(parts chan string, msg *mail.Message) error { partsLister := func(p part, no int) error { parts <- p.Header.Get("Content-Type") @@ -122,9 +120,10 @@ func newPlainTextPrinter(dst io.Writer, t transform.Transformer) 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")) if err != nil { - return err + return errors.New("parsing media type: " + err.Error()) } if strings.HasPrefix(mt, "text/plain") { in, err := mimeDecoder(p) @@ -134,8 +133,9 @@ _, err = io.Copy(dst, transform.NewReader(in, t)) return err } - io.WriteString(dst, "[MIME Part "+strconv.Itoa(no)+": ") - io.WriteString(dst, p.Header.Get("Content-Type")+"]\n ") + if _, err = fmt.Fprintf(dst, "[MIME Part %d: %s]\n", strconv.Itoa(no), p.Header.Get("Content-Type")); err != nil { + return err + } // process the stream (by throwing it away), as it is replaced by the string above _, err = io.Copy(ioutil.Discard, p.Body) return err @@ -145,13 +145,13 @@ // if the mail has only one header line without a nl at the end, "mailbox: EOF" // is thrown func View(dst io.Writer, msg *mail.Message) error { - out := bufio.NewWriter(dst) - defer out.Flush() dec := newDecoder() + var b bytes.Buffer for _, key := range viewHeader { - out.WriteString(key + ": " + dec.safeDecodeHeader(msg.Header.Get(key)) + "\n") + b.WriteString(key + ": " + dec.safeDecodeHeader(msg.Header.Get(key)) + "\n") } - // bug: if we dont have a mime msg, this will return "mime: no media type" - // so we should first check if we have a mime msg - return parse(msg, newPlainTextPrinter(out, transform.Nop)) + if _, err := io.Copy(dst, &b); err != nil { + return err + } + return parse(msg, newPlainTextPrinter(dst, transform.Nop)) } diff --git a/edit.go b/edit.go --- a/edit.go +++ b/edit.go @@ -219,8 +219,8 @@ if ct := msg.Header.Get("Content-Type"); len(ct) > 0 { fmt.Fprintf(&b, "Content-Type: %s\n", ct) } - fmt.Fprintf(&b, "\n\n\nBegin forwarded message:\n\n\n"+ - "Date: %s\nFrom: %s\nTo: %s\nCc: %s\nSubject: %s\n\n", dec.safeDecodeHeader(msg.Header.Get("Date")), + b.WriteString("\n\n\nBegin forwarded message:\n\n\n") + fmt.Fprintf(&b, "Date: %s\nFrom: %s\nTo: %s\nCc: %s\nSubject: %s\n\n", dec.safeDecodeHeader(msg.Header.Get("Date")), parseAddressList(msg.Header.Get("From")), parseAddressList(msg.Header.Get("To")), parseAddressList(msg.Header.Get("Cc")), subject) @@ -269,22 +269,22 @@ if len(list) == 0 { return "" } - addrList, err := mail.ParseAddressList(list) if err != nil { return "Error: " + err.Error() } - var b bytes.Buffer + var s string for i := range addrList { if i > 0 { - b.WriteString(", ") + s += ", " } - b.WriteString(addrList[i].Name) - b.WriteString(" <") - b.WriteString(addrList[i].Address) - b.WriteString(">") + sa := addrList[i].Address + if sn := addrList[i].Name; len(sn) > 0 { + sa = sn + " <" + sa + ">" + } + s += sa } - return b.String() + return s } func readIntoMimeMessage(src io.Reader) (*mail.Message, error) { @@ -306,17 +306,17 @@ // h.Write never returns an error io.WriteString(h, strconv.Itoa(time.Now().Nanosecond())) b = fmt.Sprintf("%x", h.Sum(nil)) - - mhdr := strings.NewReader(fmt.Sprintf("\r\n--%s\r\n"+ + var mhdr bytes.Buffer + fmt.Fprintf(&mhdr, "\r\n--%s\r\n"+ "Content-Type: %s\r\n"+ "Content-Transfer-Encoding: %s\r\n"+ "Content-Disposition: inline\r\n\r\n", - b, hdr.Get("Content-Type"), hdr.Get("Content-Transfer-Encoding"))) + b, hdr.Get("Content-Type"), hdr.Get("Content-Transfer-Encoding")) hdr.Del("Content-Transfer-Encoding") hdr.Set("Content-Type", "multipart/mixed; boundary="+b) hdr.Set("Mime-Version", "1.0") - return &mail.Message{mail.Header(hdr), io.MultiReader(mhdr, src)}, nil + return &mail.Message{mail.Header(hdr), io.MultiReader(&mhdr, src)}, nil } func boundary(hdr textproto.MIMEHeader) (string, error) { @@ -342,7 +342,7 @@ } buf := bufio.NewWriter(dst) defer buf.Flush() - // todo: writeHeader uses a buffer by itself + if err = writeHeader(buf, msg.Header); err != nil { return fmt.Errorf("writing msg header: %s", err) } @@ -410,7 +410,7 @@ } for len(b) > w.free { n += write(b[:w.free]) - // don't count the \r\n, these bytes do not come from b + // don't count \r\n, these bytes do not come from b write([]byte("\r\n")) b = b[w.free:] w.free = w.maxwidth