Files
go-imap/imapclient/append.go
T
Simon Ser 3a66d70513 imapclient: avoid leaking cmd.Wait method
All commands embed a base struct previously called "cmd". The
"cmd" type exports a Wait method, intended to be used for simple
commands which don't return any additional data. Typical usage:

    type MyCommand {
        cmd
    }

Unfortunately, even if "cmd" is an unexported field, its Wait method
is accessible to other packages. This causes issues for commands
which need to read a bunch of untagged responses before completing.

Fix this by rejiggering the command types. Introduce a baseCommand
type which is embedded in all command types and doesn't export any
method. Add a Command type which exposes a single Wait method for
simple commands.

Closes: https://github.com/emersion/go-imap/issues/641
2024-09-28 15:24:11 +02:00

59 lines
1.3 KiB
Go

package imapclient
import (
"io"
"github.com/emersion/go-imap/v2"
"github.com/emersion/go-imap/v2/internal"
)
// Append sends an APPEND command.
//
// The caller must call AppendCommand.Close.
//
// The options are optional.
func (c *Client) Append(mailbox string, size int64, options *imap.AppendOptions) *AppendCommand {
cmd := &AppendCommand{}
cmd.enc = c.beginCommand("APPEND", cmd)
cmd.enc.SP().Mailbox(mailbox).SP()
if options != nil && len(options.Flags) > 0 {
cmd.enc.List(len(options.Flags), func(i int) {
cmd.enc.Flag(options.Flags[i])
}).SP()
}
if options != nil && !options.Time.IsZero() {
cmd.enc.String(options.Time.Format(internal.DateTimeLayout)).SP()
}
// TODO: literal8 for BINARY
// TODO: UTF8 data ext for UTF8=ACCEPT, with literal8
cmd.wc = cmd.enc.Literal(size)
return cmd
}
// AppendCommand is an APPEND command.
//
// Callers must write the message contents, then call Close.
type AppendCommand struct {
commandBase
enc *commandEncoder
wc io.WriteCloser
data imap.AppendData
}
func (cmd *AppendCommand) Write(b []byte) (int, error) {
return cmd.wc.Write(b)
}
func (cmd *AppendCommand) Close() error {
err := cmd.wc.Close()
if cmd.enc != nil {
cmd.enc.end()
cmd.enc = nil
}
return err
}
func (cmd *AppendCommand) Wait() (*imap.AppendData, error) {
return &cmd.data, cmd.wait()
}