Skip to content

Commit

Permalink
Add support for SEARCHRES
Browse files Browse the repository at this point in the history
  • Loading branch information
emersion committed Apr 30, 2023
1 parent b2c1e23 commit 99f2819
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 3 deletions.
2 changes: 1 addition & 1 deletion imapserver/capability.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,11 @@ func (c *Conn) availableCaps() []imap.Cap {
imap.CapEnable,
imap.CapIdle,
}...)
// TODO: implement imap.CapSearchRes
addAvailableCaps(&caps, available, []imap.Cap{
imap.CapNamespace,
imap.CapUIDPlus,
imap.CapESearch,
imap.CapSearchRes,
imap.CapListExtended,
imap.CapListStatus,
imap.CapMove,
Expand Down
5 changes: 5 additions & 0 deletions internal/imapwire/decoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,11 @@ func (dec *Decoder) ExpectMailbox(ptr *string) bool {
}

func (dec *Decoder) ExpectSeqSet(ptr *imap.SeqSet) bool {
if dec.Special('$') {
*ptr = imap.SearchRes()
return true
}

var s string
if !dec.Expect(dec.Func(&s, isSeqSetChar), "sequence-set") {
return false
Expand Down
5 changes: 3 additions & 2 deletions internal/imapwire/encoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,11 +159,12 @@ func (enc *Encoder) Mailbox(name string) *Encoder {
}

func (enc *Encoder) SeqSet(seqSet imap.SeqSet) *Encoder {
if len(seqSet) == 0 {
s := seqSet.String()
if s == "" {
enc.setErr(fmt.Errorf("imapwire: cannot encode empty sequence set"))
return enc
}
return enc.writeString(seqSet.String())
return enc.writeString(s)
}

func (enc *Encoder) Flag(flag imap.Flag) *Encoder {
Expand Down
24 changes: 24 additions & 0 deletions search.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package imap

import (
"reflect"
"time"
)

Expand All @@ -11,6 +12,8 @@ type SearchOptions struct {
ReturnMax bool
ReturnAll bool
ReturnCount bool
// Requires IMAP4rev2 or SEARCHRES
ReturnSave bool
}

// SearchCriteria is a criteria for the SEARCH command.
Expand Down Expand Up @@ -116,3 +119,24 @@ func (data *SearchData) AllNums() []uint32 {
nums, _ := data.All.Nums()
return nums
}

// searchRes is a special empty SeqSet which can be used as a marker. It has
// a non-zero cap so that its data pointer is non-nil and can be compared.
var (
searchRes = make(SeqSet, 0, 1)
searchResAddr = reflect.ValueOf(searchRes).Pointer()
)

// SearchRes returns a special marker which can be used instead of a SeqSet to
// reference the last SEARCH result. On the wire, it's encoded as '$'.
//
// It requires IMAP4rev2 or the SEARCHRES extension.
func SearchRes() SeqSet {
return searchRes
}

// IsSearchRes checks whether a sequence set is a reference to the last SEARCH
// result. See SearchRes.
func IsSearchRes(seqSet SeqSet) bool {
return reflect.ValueOf(seqSet).Pointer() == searchResAddr
}
3 changes: 3 additions & 0 deletions seqset.go
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,9 @@ func (s SeqSet) Nums() (nums []uint32, ok bool) {

// String returns a sorted representation of all contained sequence values.
func (s SeqSet) String() string {
if IsSearchRes(s) {
return "$"
}
if len(s) == 0 {
return ""
}
Expand Down

0 comments on commit 99f2819

Please sign in to comment.