diff --git a/imap.go b/imap.go index 7b433571..eb69dff1 100644 --- a/imap.go +++ b/imap.go @@ -68,6 +68,7 @@ const ( MailboxAttrSent MailboxAttr = "\\Sent" MailboxAttrTrash MailboxAttr = "\\Trash" MailboxAttrImportant MailboxAttr = "\\Important" // RFC 8457 + MailboxAttrTemplates MailboxAttr = "\\Templates" ) // Flag is a message flag. diff --git a/imapclient/client.go b/imapclient/client.go index d02c86f7..0698da8a 100644 --- a/imapclient/client.go +++ b/imapclient/client.go @@ -138,7 +138,7 @@ type Client struct { dec *imapwire.Decoder encMutex sync.Mutex - greetingCh chan struct{} + greetingCh chan string greetingRecv bool greetingErr error @@ -177,7 +177,7 @@ func New(conn net.Conn, options *Options) *Client { br: br, bw: bw, dec: imapwire.NewDecoder(br, imapwire.ConnSideClient), - greetingCh: make(chan struct{}), + greetingCh: make(chan string, 1), decCh: make(chan struct{}), state: imap.ConnStateNone, enabled: make(imap.CapSet), @@ -295,7 +295,7 @@ func (c *Client) setState(state imap.ConnState) { // and block until it's received. If the capabilities cannot be fetched, nil is // returned. func (c *Client) Caps() imap.CapSet { - if err := c.WaitGreeting(); err != nil { + if _, err := c.WaitGreeting(); err != nil { return nil } @@ -905,6 +905,7 @@ func (c *Client) readResponseData(typ string) error { if c.greetingErr == nil && code != "CAPABILITY" { c.setCaps(nil) // request initial capabilities } + c.greetingCh <- text close(c.greetingCh) } case "CAPABILITY": @@ -982,16 +983,16 @@ func (c *Client) readResponseData(typ string) error { return nil } -// WaitGreeting waits for the server's initial greeting. -func (c *Client) WaitGreeting() error { +// WaitGreeting waits for the server's initial greeting and its text. +func (c *Client) WaitGreeting() (string, error) { select { - case <-c.greetingCh: - return c.greetingErr + case greetingText := <-c.greetingCh: + return greetingText, c.greetingErr case <-c.decCh: if c.decErr != nil { - return fmt.Errorf("got error before greeting: %v", c.decErr) + return "", fmt.Errorf("got error before greeting: %v", c.decErr) } - return fmt.Errorf("connection closed before greeting") + return "", fmt.Errorf("connection closed before greeting") } } diff --git a/imapclient/client_test.go b/imapclient/client_test.go index 9e5c206f..1fa34707 100644 --- a/imapclient/client_test.go +++ b/imapclient/client_test.go @@ -204,6 +204,22 @@ func (sw *swapWriter) Swap(w io.Writer) { sw.mutex.Unlock() } +func TestWaitGreeting(t *testing.T) { + client, server := newClientServerPair(t, imap.ConnStateAuthenticated) + defer client.Close() + defer server.Close() + + greetingText, err := client.WaitGreeting() + if err != nil { + t.Errorf("WaitGreeting() = %v", err) + } + + // imapmemserver or dovecot PREAUTH greetings + if greetingText != "IMAP server ready" && greetingText != "Logged in as test-user" { + t.Errorf("Unexpected greeting text = %s", greetingText) + } +} + func TestLogin(t *testing.T) { client, server := newClientServerPair(t, imap.ConnStateNotAuthenticated) defer client.Close() @@ -271,7 +287,7 @@ func TestWaitGreeting_eof(t *testing.T) { t.Fatalf("serverConn.Close() = %v", err) } - if err := client.WaitGreeting(); err == nil { + if _, err := client.WaitGreeting(); err == nil { t.Fatalf("WaitGreeting() should fail") } } diff --git a/internal/internal.go b/internal/internal.go index 624b1e48..ed2c7e5c 100644 --- a/internal/internal.go +++ b/internal/internal.go @@ -136,6 +136,7 @@ func canonInit() { imap.MailboxAttrSent, imap.MailboxAttrTrash, imap.MailboxAttrImportant, + imap.MailboxAttrTemplates, } canonFlag = make(map[string]imap.Flag)