# HG changeset patch # User telesto # Date 1462562433 -7200 # Fri May 06 21:20:33 2016 +0200 # Node ID 2f7365b74469d95a5c04789fc9e512b5dd6a7bef # Parent ee3884916764a8a4bf268b93a1886869b7c71b3d fix attach diff --git a/cmd/mb/main.go b/cmd/mb/main.go --- a/cmd/mb/main.go +++ b/cmd/mb/main.go @@ -195,17 +195,24 @@ os.Stdout.WriteString(name + "\n") } case "attach": + // todo: 1..n files if len(os.Args) < 4 { err = missingParams break } var src io.ReadCloser = os.Stdin - if len(os.Args) > 2 { + if len(os.Args) > 3 { if src, err = openMsg(mbox, os.Args[2]); err != nil { break } } err = mb.Attach(mbox, os.Stdout, src, os.Args[3]) + if err1 := src.Close(); err == nil { + err = err1 + } + case "detach": + // todo. + os.Stdout.WriteString("todo!\n") case "reply": // is a reply-all var src io.ReadCloser = os.Stdin if len(os.Args) > 2 { @@ -222,11 +229,9 @@ if name, err = mb.Reply(mbox, msg); len(name) > 0 { os.Stdout.WriteString(name + "\n") } - if err != nil { - src.Close() - break + if err1 := src.Close(); err == nil { + err = err1 } - err = src.Close() case "forward": var src io.ReadCloser = os.Stdin if len(os.Args) > 2 { @@ -243,11 +248,9 @@ if name, err = mb.Forward(mbox, msg); len(name) > 0 { os.Stdout.WriteString(name + "\n") } - if err != nil { - src.Close() - break + if err1 := src.Close(); err == nil { + err = err1 } - err = src.Close() case "edit": // todo: implement this err = errors.New(cmd + ": not implemented") @@ -266,6 +269,9 @@ if err = mb.Send(msg); err != nil { // todo: move msg from draft to sent } + if err1 := src.Close(); err == nil { + err = err1 + } case "mv": // todo: defaultfolder if len(os.Args) < 4 { @@ -304,7 +310,7 @@ if msgId, err = mb.Store(mbox, os.Stdin, folder); len(msgId) != 0 { os.Stdout.WriteString(path.Join(folder, msgId) + "\n") } - case "pack": + case "pack": // rename to sort, as we gonna sort by date if len(os.Args) < 3 { err = missingParams break diff --git a/command.go b/command.go --- a/command.go +++ b/command.go @@ -139,7 +139,7 @@ _, err = io.Copy(dst, transform.NewReader(in, t)) return err } - if _, err = fmt.Fprintf(dst, "[MIME Part %d: %s]\n", strconv.Itoa(no), p.Header.Get("Content-Type")); err != nil { + if _, err = fmt.Fprintf(dst, "[MIME Part %d: %s]\n", 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 diff --git a/edit.go b/edit.go --- a/edit.go +++ b/edit.go @@ -156,8 +156,10 @@ h := textproto.MIMEHeader(msg.Header) h.Set("Date", time.Now().Format("Mon, 2 Jan 2006 15:04:05 -0700")) + // todo: not utf-8, we use quoted printable! h.Set("Content-Type", "text/plain; charset=utf-8") h.Set("Content-Transfer-Encoding", "quoted-printable") + h.Set("Mime-Version", "1.0") if err := writeHeader(buf, h); err != nil { return fmt.Errorf("writing msg header: %s", err) } @@ -249,13 +251,14 @@ // todo: multipart if len(b) == 0 { // non mime msg + h := msg.Header if _, err := fmt.Fprintf(dst, "From: %s\nTo: %s\nSubject: Re: %s\nCc: %s\nBcc: \n\n"+ "\nOn %s, %s wrote\n\n\n", - sender, parseAddressList(msg.Header.Get("From")), - dec.safeDecodeHeader(msg.Header.Get("Subject")), - parseAddressList(msg.Header.Get("Cc")), - dec.safeDecodeHeader(msg.Header.Get("Date")), - parseAddressList(msg.Header.Get("From"))); err != nil { + sender, parseAddressList(h.Get("From")), + dec.safeDecodeHeader(h.Get("Subject")), + parseAddressList(h.Get("Cc")), + dec.safeDecodeHeader(h.Get("Date")), + parseAddressList(h.Get("From"))); err != nil { return err } if err := parse(msg, newPlainTextPrinter(dst, "eMessage{true})); err != nil { @@ -287,8 +290,9 @@ return s } -func readIntoMimeMessage(src io.Reader) (*mail.Message, error) { - tp := textproto.NewReader(bufio.NewReader(src)) +func readIntoMultipartMessage(src io.Reader) (*mail.Message, error) { + buf := bufio.NewReader(src) + tp := textproto.NewReader(buf) hdr, err := tp.ReadMIMEHeader() if err != nil { @@ -299,13 +303,14 @@ return nil, errors.New("reading mime boundary: " + err.Error()) } if len(b) > 0 { - // we have a mime message + // we have a multipart mime message return mail.ReadMessage(src) } h := md5.New() // h.Write never returns an error io.WriteString(h, strconv.Itoa(time.Now().Nanosecond())) b = fmt.Sprintf("%x", h.Sum(nil)) + var mhdr bytes.Buffer fmt.Fprintf(&mhdr, "\r\n--%s\r\nMIME-Version: 1.0\r\n"+ "Content-Type: %s\r\n"+ @@ -313,10 +318,10 @@ "Content-Disposition: inline\r\n\r\n", 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("Content-Transfer-Encoding", "7bit") 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, buf)}, nil } func boundary(hdr textproto.MIMEHeader) (string, error) { @@ -336,13 +341,13 @@ if err != nil { return err } - msg, err := readIntoMimeMessage(src) + defer att.Close() + msg, err := readIntoMultipartMessage(src) if err != nil { return err } buf := bufio.NewWriter(dst) defer buf.Flush() - if err = writeHeader(buf, msg.Header); err != nil { return fmt.Errorf("writing msg header: %s", err) } @@ -362,6 +367,7 @@ encoder = base64.NewEncoder(base64.StdEncoding, newLineWriter(buf, 76)) encoding = "base64" } + defer encoder.Close() hEnc := mime.QEncoding filename = hEnc.Encode("utf-8", path.Base(filename)) b, err := boundary(textproto.MIMEHeader(msg.Header)) @@ -383,7 +389,10 @@ if _, err = fmt.Fprintf(buf, "\r\n\r\n--%s\r\n", b); err != nil { return err } - return buf.Flush() + if err = buf.Flush(); err != nil { + return err + } + return att.Close() } type lineWriter struct { @@ -420,6 +429,7 @@ return n, err } +// use \n, as \r\n causes troubles when sending emails func writeHeader(dst io.Writer, h map[string][]string) error { enc := mime.QEncoding var b bytes.Buffer