From 511030563589e79a25d761192c405f30f81e1c75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80=20?= =?UTF-8?q?=D0=9C=D0=B5=D0=BB=D0=B5=D0=BD=D1=82=D1=8C=D0=B5=D0=B2?= Date: Sat, 6 Dec 2025 20:58:12 +0300 Subject: [PATCH] Add recent flag MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Александр Мелентьев --- imap.go | 1 + imapclient/client.go | 9 +++++++++ imapclient/connection_test.go | 37 +++++++++++++++++++++++++++++++++++ imapclient/example_test.go | 31 +++++++++++++++++++++++++++++ 4 files changed, 78 insertions(+) create mode 100644 imapclient/connection_test.go diff --git a/imap.go b/imap.go index 7b433571..39f90cbc 100644 --- a/imap.go +++ b/imap.go @@ -82,6 +82,7 @@ const ( FlagFlagged Flag = "\\Flagged" FlagDeleted Flag = "\\Deleted" FlagDraft Flag = "\\Draft" + FlagRecent Flag = "\\Recent" // This flag was in use in IMAP4rev1 and is now deprecated. // Widely used flags FlagForwarded Flag = "$Forwarded" diff --git a/imapclient/client.go b/imapclient/client.go index d3b12711..4933d2fa 100644 --- a/imapclient/client.go +++ b/imapclient/client.go @@ -385,6 +385,15 @@ func (c *Client) Mailbox() *SelectedMailbox { return c.mailbox } +// Closed returns a channel that is closed when the connection is closed. +// +// This channel cannot be used to reliably determine whether a connection is healthy. If +// the underlying connection times out, the channel will be closed eventually, but not +// immediately. To check whether the connection is healthy, send a command (such as Noop). +func (c *Client) Closed() <-chan struct{} { + return c.decCh +} + // Close immediately closes the connection. func (c *Client) Close() error { c.mutex.Lock() diff --git a/imapclient/connection_test.go b/imapclient/connection_test.go new file mode 100644 index 00000000..a15e338e --- /dev/null +++ b/imapclient/connection_test.go @@ -0,0 +1,37 @@ +package imapclient_test + +import ( + "testing" + "time" + + "github.com/emersion/go-imap/v2" +) + +// TestClient_Closed tests that the Closed() channel is closed when the +// connection is explicitly closed via Close(). +func TestClient_Closed(t *testing.T) { + client, server := newClientServerPair(t, imap.ConnStateAuthenticated) + defer server.Close() + + closedCh := client.Closed() + if closedCh == nil { + t.Fatal("Closed() returned nil channel") + } + + select { + case <-closedCh: + t.Fatal("Closed() channel closed before calling Close()") + default: // Expected + } + + if err := client.Close(); err != nil { + t.Fatalf("Close() = %v", err) + } + + select { + case <-closedCh: + t.Log("Closed() channel properly closed after Close()") + case <-time.After(2 * time.Second): + t.Fatal("Closed() channel not closed after Close()") + } +} diff --git a/imapclient/example_test.go b/imapclient/example_test.go index 86435e7e..6765d929 100644 --- a/imapclient/example_test.go +++ b/imapclient/example_test.go @@ -378,3 +378,34 @@ func ExampleClient_Authenticate_oauth() { log.Fatalf("authentication failed: %v", err) } } + +func ExampleClient_Closed() { + c, err := imapclient.DialTLS("mail.example.org:993", nil) + if err != nil { + log.Fatalf("failed to dial IMAP server: %v", err) + } + + selected := false + + go func(c *imapclient.Client) { + if err := c.Login("root", "asdf").Wait(); err != nil { + log.Fatalf("failed to login: %v", err) + } + + if _, err := c.Select("INBOX", nil).Wait(); err != nil { + log.Fatalf("failed to select INBOX: %v", err) + } + + selected = true + + c.Close() + }(c) + + // This channel shall be closed when the connection is closed. + <-c.Closed() + log.Println("Connection has been closed") + + if !selected { + log.Fatalf("Connection was closed before selecting mailbox") + } +}