Forked the emersion/go-imap v1 project.

This commit is contained in:
2025-05-01 11:58:18 +03:00
commit bcc3f95e8e
107 changed files with 16268 additions and 0 deletions

120
imapserver/append.go Normal file
View File

@@ -0,0 +1,120 @@
package imapserver
import (
"fmt"
"io"
"strings"
"github.com/emersion/go-imap/v2"
"github.com/emersion/go-imap/v2/internal"
"github.com/emersion/go-imap/v2/internal/imapwire"
)
// appendLimit is the maximum size of an APPEND payload.
//
// TODO: make configurable
const appendLimit = 100 * 1024 * 1024 // 100MiB
func (c *Conn) handleAppend(tag string, dec *imapwire.Decoder) error {
var (
mailbox string
options imap.AppendOptions
)
if !dec.ExpectSP() || !dec.ExpectMailbox(&mailbox) || !dec.ExpectSP() {
return dec.Err()
}
hasFlagList, err := dec.List(func() error {
flag, err := internal.ExpectFlag(dec)
if err != nil {
return err
}
options.Flags = append(options.Flags, flag)
return nil
})
if err != nil {
return err
}
if hasFlagList && !dec.ExpectSP() {
return dec.Err()
}
t, err := internal.DecodeDateTime(dec)
if err != nil {
return err
}
if !t.IsZero() && !dec.ExpectSP() {
return dec.Err()
}
options.Time = t
var dataExt string
if !dec.Special('~') && dec.Atom(&dataExt) { // ignore literal8 prefix if any for BINARY
switch strings.ToUpper(dataExt) {
case "UTF8":
// '~' is the literal8 prefix
if !dec.ExpectSP() || !dec.ExpectSpecial('(') || !dec.ExpectSpecial('~') {
return dec.Err()
}
default:
return newClientBugError("Unknown APPEND data extension")
}
}
lit, nonSync, err := dec.ExpectLiteralReader()
if err != nil {
return err
}
if lit.Size() > appendLimit {
return &imap.Error{
Type: imap.StatusResponseTypeNo,
Code: imap.ResponseCodeTooBig,
Text: fmt.Sprintf("Literals are limited to %v bytes for this command", appendLimit),
}
}
if err := c.acceptLiteral(lit.Size(), nonSync); err != nil {
return err
}
c.setReadTimeout(literalReadTimeout)
defer c.setReadTimeout(cmdReadTimeout)
if err := c.checkState(imap.ConnStateAuthenticated); err != nil {
io.Copy(io.Discard, lit)
dec.CRLF()
return err
}
data, appendErr := c.session.Append(mailbox, lit, &options)
if _, discardErr := io.Copy(io.Discard, lit); discardErr != nil {
return err
}
if dataExt != "" && !dec.ExpectSpecial(')') {
return dec.Err()
}
if !dec.ExpectCRLF() {
return err
}
if appendErr != nil {
return appendErr
}
if err := c.poll("APPEND"); err != nil {
return err
}
return c.writeAppendOK(tag, data)
}
func (c *Conn) writeAppendOK(tag string, data *imap.AppendData) error {
enc := newResponseEncoder(c)
defer enc.end()
enc.Atom(tag).SP().Atom("OK").SP()
if data != nil {
enc.Special('[')
enc.Atom("APPENDUID").SP().Number(data.UIDValidity).SP().UID(data.UID)
enc.Special(']').SP()
}
enc.Text("APPEND completed")
return enc.CRLF()
}