Skip to content

Commit 465034d

Browse files
authored
imapserver: add support for SPECIAL-USE
1 parent b33055e commit 465034d

File tree

4 files changed

+60
-1
lines changed

4 files changed

+60
-1
lines changed

cmd/imapmemserver/main.go

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,54 @@ func main() {
5454

5555
if username != "" || password != "" {
5656
user := imapmemserver.NewUser(username, password)
57-
user.Create("INBOX", nil)
57+
58+
// Create standard mailboxes with special-use attributes as per RFC 6154
59+
if err := user.Create("INBOX", nil); err != nil {
60+
log.Printf("Failed to create INBOX: %v", err)
61+
}
62+
63+
if err := user.Create("Drafts", &imap.CreateOptions{
64+
SpecialUse: []imap.MailboxAttr{imap.MailboxAttrDrafts},
65+
}); err != nil {
66+
log.Printf("Failed to create Drafts mailbox: %v", err)
67+
}
68+
69+
if err := user.Create("Sent", &imap.CreateOptions{
70+
SpecialUse: []imap.MailboxAttr{imap.MailboxAttrSent},
71+
}); err != nil {
72+
log.Printf("Failed to create Sent mailbox: %v", err)
73+
}
74+
75+
if err := user.Create("Archive", &imap.CreateOptions{
76+
SpecialUse: []imap.MailboxAttr{imap.MailboxAttrArchive},
77+
}); err != nil {
78+
log.Printf("Failed to create Archive mailbox: %v", err)
79+
}
80+
81+
if err := user.Create("Junk", &imap.CreateOptions{
82+
SpecialUse: []imap.MailboxAttr{imap.MailboxAttrJunk},
83+
}); err != nil {
84+
log.Printf("Failed to create Junk mailbox: %v", err)
85+
}
86+
87+
if err := user.Create("Trash", &imap.CreateOptions{
88+
SpecialUse: []imap.MailboxAttr{imap.MailboxAttrTrash},
89+
}); err != nil {
90+
log.Printf("Failed to create Trash mailbox: %v", err)
91+
}
92+
93+
if err := user.Create("Flagged", &imap.CreateOptions{
94+
SpecialUse: []imap.MailboxAttr{imap.MailboxAttrFlagged},
95+
}); err != nil {
96+
log.Printf("Failed to create Flagged mailbox: %v", err)
97+
}
98+
99+
// Subscribe to the most commonly used mailboxes
100+
_ = user.Subscribe("INBOX")
101+
_ = user.Subscribe("Drafts")
102+
_ = user.Subscribe("Sent")
103+
_ = user.Subscribe("Trash")
104+
58105
memServer.AddUser(user)
59106
}
60107

imapserver/capability.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ func (c *Conn) availableCaps() []imap.Cap {
8686
// Capabilities which require backend support and apply to both
8787
// IMAP4rev1 and IMAP4rev2
8888
addAvailableCaps(&caps, available, []imap.Cap{
89+
imap.CapSpecialUse,
8990
imap.CapCreateSpecialUse,
9091
imap.CapLiteralPlus,
9192
imap.CapUnauthenticate,

imapserver/imapmemserver/mailbox.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ type Mailbox struct {
2121
mutex sync.Mutex
2222
name string
2323
subscribed bool
24+
specialUse []imap.MailboxAttr
2425
l []*message
2526
uidNext imap.UID
2627
}
@@ -42,6 +43,9 @@ func (mbox *Mailbox) list(options *imap.ListOptions) *imap.ListData {
4243
if options.SelectSubscribed && !mbox.subscribed {
4344
return nil
4445
}
46+
if options.SelectSpecialUse && len(mbox.specialUse) == 0 {
47+
return nil
48+
}
4549

4650
data := imap.ListData{
4751
Mailbox: mbox.name,
@@ -50,6 +54,9 @@ func (mbox *Mailbox) list(options *imap.ListOptions) *imap.ListData {
5054
if mbox.subscribed {
5155
data.Attrs = append(data.Attrs, imap.MailboxAttrSubscribed)
5256
}
57+
if (options.ReturnSpecialUse || options.SelectSpecialUse) && len(mbox.specialUse) > 0 {
58+
data.Attrs = append(data.Attrs, mbox.specialUse...)
59+
}
5360
if options.ReturnStatus != nil {
5461
data.Status = mbox.statusDataLocked(options.ReturnStatus)
5562
}

imapserver/list.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,8 @@ func readListCmd(dec *imapwire.Decoder) (ref string, patterns []string, options
135135
options.SelectRemote = true
136136
case "RECURSIVEMATCH":
137137
options.SelectRecursiveMatch = true
138+
case "SPECIAL-USE":
139+
options.SelectSpecialUse = true
138140
default:
139141
return newClientBugError("Unknown LIST select option")
140142
}
@@ -229,6 +231,8 @@ func readReturnOption(dec *imapwire.Decoder, options *imap.ListOptions) error {
229231
options.ReturnSubscribed = true
230232
case "CHILDREN":
231233
options.ReturnChildren = true
234+
case "SPECIAL-USE":
235+
options.ReturnSpecialUse = true
232236
case "STATUS":
233237
if !dec.ExpectSP() {
234238
return dec.Err()

0 commit comments

Comments
 (0)