Skip to content

Commit c7dce92

Browse files
foxcppemersion
authored andcommitted
Merge support for APPENDLIMIT extension
1 parent 8411770 commit c7dce92

File tree

7 files changed

+66
-2
lines changed

7 files changed

+66
-2
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ includes:
134134
* [SPECIAL-USE](https://tools.ietf.org/html/rfc6154)
135135
* [CHILDREN](https://tools.ietf.org/html/rfc3348)
136136
* [UNSELECT](https://tools.ietf.org/html/rfc3691)
137+
* [APPENDLIMIT](https://tools.ietf.org/html/rfc7889)
137138

138139
Support for other extensions is provided via separate packages. See below.
139140

@@ -145,7 +146,6 @@ Commands defined in IMAP extensions are available in other packages. See [the
145146
wiki](https://github.com/emersion/go-imap/wiki/Using-extensions#using-client-extensions)
146147
to learn how to use them.
147148

148-
* [APPENDLIMIT](https://github.com/emersion/go-imap-appendlimit)
149149
* [COMPRESS](https://github.com/emersion/go-imap-compress)
150150
* [ENABLE](https://github.com/emersion/go-imap-enable)
151151
* [ID](https://github.com/ProtonMail/go-imap-id)

backend/appendlimit.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package backend
2+
3+
import (
4+
"errors"
5+
)
6+
7+
// An error that should be returned by User.CreateMessage when the message size
8+
// is too big.
9+
var ErrTooBig = errors.New("Message size exceeding limit")
10+
11+
// A backend that supports retrieving per-user message size limits.
12+
type AppendLimitBackend interface {
13+
Backend
14+
15+
// Get the fixed maximum message size in octets that the backend will accept
16+
// when creating a new message. If there is no limit, return nil.
17+
CreateMessageLimit() *uint32
18+
}
19+
20+
// A user that supports retrieving per-user message size limits.
21+
type AppendLimitUser interface {
22+
User
23+
24+
// Get the fixed maximum message size in octets that the backend will accept
25+
// when creating a new message. If there is no limit, return nil.
26+
//
27+
// This overrides the global backend limit.
28+
CreateMessageLimit() *uint32
29+
}

imap.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ const (
1717
StatusUidNext StatusItem = "UIDNEXT"
1818
StatusUidValidity StatusItem = "UIDVALIDITY"
1919
StatusUnseen StatusItem = "UNSEEN"
20+
21+
StatusAppendLimit StatusItem = "APPENDLIMIT"
2022
)
2123

2224
// A FetchItem is a message data item that can be fetched.

mailbox.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,10 @@ type MailboxStatus struct {
221221
// Together with a UID, it is a unique identifier for a message.
222222
// Must be greater than or equal to 1.
223223
UidValidity uint32
224+
225+
// Per-mailbox limit of message size. Set only if server supports the
226+
// APPENDLIMIT extension.
227+
AppendLimit uint32
224228
}
225229

226230
// Create a new mailbox status that will contain the specified items.
@@ -263,6 +267,8 @@ func (status *MailboxStatus) Parse(fields []interface{}) error {
263267
status.UidNext, err = ParseNumber(f)
264268
case StatusUidValidity:
265269
status.UidValidity, err = ParseNumber(f)
270+
case StatusAppendLimit:
271+
status.AppendLimit, err = ParseNumber(f)
266272
default:
267273
status.Items[k] = f
268274
}
@@ -290,6 +296,8 @@ func (status *MailboxStatus) Format() []interface{} {
290296
v = status.UidNext
291297
case StatusUidValidity:
292298
v = status.UidValidity
299+
case StatusAppendLimit:
300+
v = status.AppendLimit
293301
}
294302

295303
fields = append(fields, RawString(k), v)

server/cmd_auth.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,13 @@ func (cmd *Append) Handle(conn Conn) error {
253253
}
254254

255255
if err := mbox.CreateMessage(cmd.Flags, cmd.Date, cmd.Message); err != nil {
256+
if err == backend.ErrTooBig {
257+
return ErrStatusResp(&imap.StatusResp{
258+
Type: imap.StatusRespNo,
259+
Code: "TOOBIG",
260+
Info: "Message size exceeding limit",
261+
})
262+
}
256263
return err
257264
}
258265

server/conn.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,24 @@ func (c *conn) Close() error {
165165
func (c *conn) Capabilities() []string {
166166
caps := []string{"IMAP4rev1", "LITERAL+", "SASL-IR", "CHILDREN", "UNSELECT"}
167167

168+
appendLimitSet := false
169+
if c.ctx.State == imap.AuthenticatedState {
170+
if u, ok := c.ctx.User.(backend.AppendLimitUser); ok {
171+
if limit := u.CreateMessageLimit(); limit != nil {
172+
caps = append(caps, fmt.Sprintf("APPENDLIMIT=%v", *limit))
173+
appendLimitSet = true
174+
}
175+
}
176+
} else if be, ok := c.Server().Backend.(backend.AppendLimitBackend); ok {
177+
if limit := be.CreateMessageLimit(); limit != nil {
178+
caps = append(caps, fmt.Sprintf("APPENDLIMIT=%v", *limit))
179+
appendLimitSet = true
180+
}
181+
}
182+
if !appendLimitSet {
183+
caps = append(caps, "APPENDLIMIT")
184+
}
185+
168186
if c.ctx.State == imap.NotAuthenticatedState {
169187
if !c.IsTLS() && c.s.TLSConfig != nil {
170188
caps = append(caps, "STARTTLS")

server/server_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import (
1010
)
1111

1212
// Extnesions that are always advertised by go-imap server.
13-
const builtinExtensions = "LITERAL+ SASL-IR CHILDREN UNSELECT"
13+
const builtinExtensions = "LITERAL+ SASL-IR CHILDREN UNSELECT APPENDLIMIT"
1414

1515
func testServer(t *testing.T) (s *server.Server, conn net.Conn) {
1616
bkd := memory.New()

0 commit comments

Comments
 (0)