@@ -154,16 +154,15 @@ type Client struct {
154154 decCh chan struct {}
155155 decErr error
156156
157- mutex sync.Mutex
158- state imap.ConnState
159- caps imap.CapSet
160- enabled imap.CapSet
161- pendingCapCh chan struct {}
162- mailbox * SelectedMailbox
163- cmdTag uint64
164- pendingCmds []command
165- contReqs []continuationRequest
166- closed bool
157+ mutex sync.Mutex
158+ state imap.ConnState
159+ caps imap.CapSet
160+ enabled imap.CapSet
161+ mailbox * SelectedMailbox
162+ cmdTag uint64
163+ pendingCmds []command
164+ contReqs []continuationRequest
165+ closed bool
167166}
168167
169168// New creates a new IMAP client.
@@ -319,58 +318,35 @@ func (c *Client) Caps() imap.CapSet {
319318
320319 c .mutex .Lock ()
321320 caps := c .caps
322- capCh := c .pendingCapCh
323321 c .mutex .Unlock ()
324322
325323 if caps != nil {
326324 return caps
327325 }
328326
329- if capCh == nil {
330- capCmd := c .Capability ()
331- capCh := make (chan struct {})
332- go func () {
333- capCmd .Wait ()
334- close (capCh )
335- }()
336- c .mutex .Lock ()
337- c .pendingCapCh = capCh
338- c .mutex .Unlock ()
339- }
340-
341- timer := time .NewTimer (respReadTimeout )
342- defer timer .Stop ()
343- select {
344- case <- timer .C :
327+ capCmd := c .Capability ()
328+ caps , err := capCmd .Wait ()
329+ if err != nil {
345330 return nil
346- case <- capCh :
347- // ok
348331 }
349-
350- // TODO: this is racy if caps are reset before we get the reply
351- c .mutex .Lock ()
352- defer c .mutex .Unlock ()
353- return c .caps
332+ return caps
354333}
355334
356335func (c * Client ) setCaps (caps imap.CapSet ) {
357336 // If the capabilities are being reset, request the updated capabilities
358337 // from the server
359- var capCh chan struct {}
360338 if caps == nil {
361- capCh = make (chan struct {})
362-
363339 // We need to send the CAPABILITY command in a separate goroutine:
364340 // setCaps might be called with Client.encMutex locked
365341 go func () {
366342 c .Capability ().Wait ()
367- close (capCh )
368343 }()
369344 }
370345
371346 c .mutex .Lock ()
372347 c .caps = caps
373- c .pendingCapCh = capCh
348+ quotedUTF8 := c .caps .Has (imap .CapIMAP4rev2 ) || c .enabled .Has (imap .CapUTF8Accept )
349+ c .dec .QuotedUTF8 = quotedUTF8
374350 c .mutex .Unlock ()
375351}
376352
@@ -986,6 +962,11 @@ func (c *Client) readResponseData(typ string) error {
986962 return c .handleFetch (num )
987963 case "EXPUNGE" :
988964 return c .handleExpunge (num )
965+ case "VANISHED" :
966+ if ! c .dec .ExpectSP () {
967+ return c .dec .Err ()
968+ }
969+ return c .handleVanished ()
989970 case "SEARCH" :
990971 return c .handleSearch ()
991972 case "ESEARCH" :
@@ -1026,6 +1007,28 @@ func (c *Client) readResponseData(typ string) error {
10261007 return nil
10271008}
10281009
1010+ func (c * Client ) handleVanished () error {
1011+ var data imap.VanishedData
1012+ isParen := c .dec .Special ('(' )
1013+ if isParen {
1014+ var tag string
1015+ if ! c .dec .ExpectAtom (& tag ) || ! c .dec .ExpectSpecial (')' ) {
1016+ return c .dec .Err ()
1017+ }
1018+ data .Earlier = strings .ToUpper (tag ) == "EARLIER"
1019+ }
1020+
1021+ if ! c .dec .ExpectSP () || ! c .dec .ExpectUIDSet (& data .UIDs ) {
1022+ return c .dec .Err ()
1023+ }
1024+
1025+ if handler := c .options .unilateralDataHandler ().Vanished ; handler != nil {
1026+ handler (& data )
1027+ }
1028+
1029+ return nil
1030+ }
1031+
10291032// WaitGreeting waits for the server's initial greeting.
10301033func (c * Client ) WaitGreeting () error {
10311034 select {
@@ -1202,6 +1205,9 @@ type UnilateralDataHandler struct {
12021205 Mailbox func (data * UnilateralDataMailbox )
12031206 Fetch func (msg * FetchMessageData )
12041207
1208+ // requires ENABLE QRESYNC
1209+ Vanished func (data * imap.VanishedData )
1210+
12051211 // Requires ENABLE METADATA or ENABLE SERVER-METADATA.
12061212 Metadata func (mailbox string , entries []string )
12071213
0 commit comments