@@ 195,17 195,24 @@ func main() {
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 @@ func main() {
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 @@ func main() {
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 @@ func main() {
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 @@ func main() {
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
@@ 139,7 139,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", 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
@@ 156,8 156,10 @@ func encodeMessage(dst io.Writer, msg *m
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 @@ func fmtReply(dst io.Writer, sender stri
// 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 @@ func parseAddressList(list string) strin
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 @@ func readIntoMimeMessage(src io.Reader)
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 @@ func readIntoMimeMessage(src io.Reader)
"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 @@ func Attach(mbox Mailbox, dst io.Writer,
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 @@ func Attach(mbox Mailbox, dst io.Writer,
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 @@ func Attach(mbox Mailbox, dst io.Writer,
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 @@ func (w *lineWriter) Write(b []byte) (in
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