Skip to content

Commit 99f2819

Browse files
committed
Add support for SEARCHRES
1 parent b2c1e23 commit 99f2819

File tree

5 files changed

+36
-3
lines changed

5 files changed

+36
-3
lines changed

imapserver/capability.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,11 +64,11 @@ func (c *Conn) availableCaps() []imap.Cap {
6464
imap.CapEnable,
6565
imap.CapIdle,
6666
}...)
67-
// TODO: implement imap.CapSearchRes
6867
addAvailableCaps(&caps, available, []imap.Cap{
6968
imap.CapNamespace,
7069
imap.CapUIDPlus,
7170
imap.CapESearch,
71+
imap.CapSearchRes,
7272
imap.CapListExtended,
7373
imap.CapListStatus,
7474
imap.CapMove,

internal/imapwire/decoder.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,11 @@ func (dec *Decoder) ExpectMailbox(ptr *string) bool {
461461
}
462462

463463
func (dec *Decoder) ExpectSeqSet(ptr *imap.SeqSet) bool {
464+
if dec.Special('$') {
465+
*ptr = imap.SearchRes()
466+
return true
467+
}
468+
464469
var s string
465470
if !dec.Expect(dec.Func(&s, isSeqSetChar), "sequence-set") {
466471
return false

internal/imapwire/encoder.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,11 +159,12 @@ func (enc *Encoder) Mailbox(name string) *Encoder {
159159
}
160160

161161
func (enc *Encoder) SeqSet(seqSet imap.SeqSet) *Encoder {
162-
if len(seqSet) == 0 {
162+
s := seqSet.String()
163+
if s == "" {
163164
enc.setErr(fmt.Errorf("imapwire: cannot encode empty sequence set"))
164165
return enc
165166
}
166-
return enc.writeString(seqSet.String())
167+
return enc.writeString(s)
167168
}
168169

169170
func (enc *Encoder) Flag(flag imap.Flag) *Encoder {

search.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package imap
22

33
import (
4+
"reflect"
45
"time"
56
)
67

@@ -11,6 +12,8 @@ type SearchOptions struct {
1112
ReturnMax bool
1213
ReturnAll bool
1314
ReturnCount bool
15+
// Requires IMAP4rev2 or SEARCHRES
16+
ReturnSave bool
1417
}
1518

1619
// SearchCriteria is a criteria for the SEARCH command.
@@ -116,3 +119,24 @@ func (data *SearchData) AllNums() []uint32 {
116119
nums, _ := data.All.Nums()
117120
return nums
118121
}
122+
123+
// searchRes is a special empty SeqSet which can be used as a marker. It has
124+
// a non-zero cap so that its data pointer is non-nil and can be compared.
125+
var (
126+
searchRes = make(SeqSet, 0, 1)
127+
searchResAddr = reflect.ValueOf(searchRes).Pointer()
128+
)
129+
130+
// SearchRes returns a special marker which can be used instead of a SeqSet to
131+
// reference the last SEARCH result. On the wire, it's encoded as '$'.
132+
//
133+
// It requires IMAP4rev2 or the SEARCHRES extension.
134+
func SearchRes() SeqSet {
135+
return searchRes
136+
}
137+
138+
// IsSearchRes checks whether a sequence set is a reference to the last SEARCH
139+
// result. See SearchRes.
140+
func IsSearchRes(seqSet SeqSet) bool {
141+
return reflect.ValueOf(seqSet).Pointer() == searchResAddr
142+
}

seqset.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,9 @@ func (s SeqSet) Nums() (nums []uint32, ok bool) {
214214

215215
// String returns a sorted representation of all contained sequence values.
216216
func (s SeqSet) String() string {
217+
if IsSearchRes(s) {
218+
return "$"
219+
}
217220
if len(s) == 0 {
218221
return ""
219222
}

0 commit comments

Comments
 (0)