Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

net/textproto: can`t be used for rfc3030 (SMTP extensions for Large and Binary MIME Messages) #44265

Open
norguhtar opened this issue Feb 15, 2021 · 5 comments
Labels
NeedsInvestigation

Comments

@norguhtar
Copy link

@norguhtar norguhtar commented Feb 15, 2021

What version of Go are you using (go version)?

go version go1.15.7 linux/amd64

Does this issue reproduce with the latest release?

Yes

What operating system and processor architecture are you using (go env)?

go env Output
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/root/.cache/go-build"
GOENV="/root/.config/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GOMODCACHE="/root/go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/root/go"
GOPRIVATE=""
GOPROXY="direct"
GOROOT="/usr/lib/golang"
GOSUMDB="off"
GOTMPDIR=""
GOTOOLDIR="/usr/lib/golang/pkg/tool/linux_amd64"
GCCGO="gccgo"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build209411982=/tmp/go-build -gno-record-gcc-switches"

What did you do?

I try implement email client with support rfc3030, and got problem with writer.
Now net/textproto return me only DotWriter but rfc3030 don`t use dot (.) in close command.

What did you expect to see?

Got other writerCloser from net/textproto like DotWriter can be used for implement rfc3030

What did you see instead?

Only DotWriter. This writeCloser not compatible with rfc3030. When email sended like described in rfc3030 DATA command and dot not used for this process

@seankhliao seankhliao changed the title net/textproto can`t be used for rfc3030 net/textproto: can`t be used for rfc3030 (SMTP extensions for Large and Binary MIME Messages) Feb 15, 2021
@seankhliao seankhliao added the NeedsInvestigation label Feb 15, 2021
@ianlancetaylor
Copy link
Contributor

@ianlancetaylor ianlancetaylor commented Feb 15, 2021

What would have to change to make this work?

@norguhtar
Copy link
Author

@norguhtar norguhtar commented Feb 16, 2021

For example we can add bdatWriter

@@ -13,8 +13,9 @@
 // A Writer implements convenience methods for writing
 // requests or responses to a text protocol network connection.
 type Writer struct {
-       W   *bufio.Writer
-       dot *dotWriter
+       W    *bufio.Writer
+       dot  *dotWriter
+       bdat *bdatWriter
 }
 
 // NewWriter returns a new Writer writing to w.
@@ -46,6 +47,11 @@
        return w.dot
 }
 
+func (w *Writer) BdatWriter() io.WriteCloser {
+       w.bdat = &bdatWriter{w: w}
+       return w.bdat
+}
+
 func (w *Writer) closeDot() {
        if w.dot != nil {
                w.dot.Close() // sets w.dot = nil
@@ -57,6 +63,10 @@
        state int
 }
 
+type bdatWriter struct {
+       w *Writer
+}
+
 const (
        wstateBegin     = iota // initial state; must be zero
        wstateBeginLine        // beginning of line
@@ -117,3 +127,26 @@
        }
        return bw.Flush()
 }
+
+func (r *bdatWriter) Write(b []byte) (n int, err error) {
+       bw := r.w.W
+       bLen := len(b)
+       if bLen > 0 {
+               bdatHeader := fmt.Sprintf("BDAT %d \r\n", bLen)
+               bw.Write([]byte(bdatHeader))
+               n, err = bw.Write(b)
+               if err == nil {
+                       err = bw.Flush()
+               }
+       }
+       return
+}
+
+func (r *bdatWriter) Close() error {
+       bw := r.w.W
+       _, err := bw.Write([]byte("BDAT 0 LAST\r\n"))
+       if err != nil {
+               return err
+       }
+       return bw.Flush()
+}

Or just create RawWriter

@@ -13,8 +13,9 @@
 // A Writer implements convenience methods for writing
 // requests or responses to a text protocol network connection.
 type Writer struct {
-       W   *bufio.Writer
-       dot *dotWriter
+       W    *bufio.Writer
+       dot  *dotWriter
+       raw *rawWriter
 }
 
 // NewWriter returns a new Writer writing to w.
@@ -46,6 +47,11 @@
        return w.dot
 }
 
+func (w *Writer) RawWriter() io.WriteCloser {
+       w.raw = &RawWriter{w: w}
+       return w.raw
+}
+
 func (w *Writer) closeDot() {
        if w.dot != nil {
                w.dot.Close() // sets w.dot = nil
@@ -57,6 +63,10 @@
        state int
 }
 
+type rawWriter struct {
+       w *Writer
+}
+
 const (
        wstateBegin     = iota // initial state; must be zero
        wstateBeginLine        // beginning of line
@@ -117,3 +127,26 @@
        }
        return bw.Flush()
 }
+
+func (r *rawWriter) Write(b []byte) (n int, err error) {
+       bw := r.w.W
+       n, err = bw.Write(b)
+       if err == nil {
+           bw.Flush()
+       }
+       return
+}
+
+func (r *bdatWriter) Close() error {
+       bw := r.w.W
+       return bw.Flush()
+}

And then create an external interface for transmission using the BDAT command.

I tried the first option, it worked as it should. But there is no control over how the result is sent. I think the second option is more general and useful

@ianlancetaylor
Copy link
Contributor

@ianlancetaylor ianlancetaylor commented Feb 16, 2021

OK, this sounds like we need new API, which should go through the proposal process (https://golang.org/s/proposal).

@norguhtar
Copy link
Author

@norguhtar norguhtar commented Feb 17, 2021

Ok. I need create new issue?

@ianlancetaylor
Copy link
Contributor

@ianlancetaylor ianlancetaylor commented Feb 17, 2021

Creating a new issue will be simpler. Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
NeedsInvestigation
Projects
None yet
Development

No branches or pull requests

3 participants