Skip to content

Commit

Permalink
Merge pull request #1 from creativeprojects/upgrade-gomaildir-0.6.0
Browse files Browse the repository at this point in the history
Upgrade gomaildir 0.6.0
  • Loading branch information
creativeprojects authored Sep 25, 2024
2 parents 71805b1 + 1542665 commit df67055
Show file tree
Hide file tree
Showing 15 changed files with 89 additions and 74 deletions.
28 changes: 28 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
linters:
enable:
- asasalint
- asciicheck
- bidichk
- bodyclose
- contextcheck
- errname
- gocheckcompilerdirectives
- gosec
# - maintidx
- misspell
- nilnil
- noctx
- nolintlint
- predeclared
- reassign
- sloglint
- spancheck
- unconvert
- unparam
- usestdlibvars

linters-settings:
gosec:
excludes:
- G404 # Use of weak random number generator (math/rand instead of crypto/rand)
- G115 # integer overflow conversion
16 changes: 16 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,19 @@ nightly: $(GOBIN)/goreleaser
generate-install:
@echo "[*] $@"
godownloader .godownloader.yml -r creativeprojects/imap -o install.sh

.PHONY: lint
lint:
@echo "[*] $@"
GOOS=darwin golangci-lint run
GOOS=linux golangci-lint run
GOOS=windows golangci-lint run

.PHONY: fix
fix:
@echo "[*] $@"
$(GOCMD) mod tidy
$(GOCMD) fix ./...
GOOS=darwin golangci-lint run --fix
GOOS=linux golangci-lint run --fix
GOOS=windows golangci-lint run --fix
2 changes: 1 addition & 1 deletion cmd/copy.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cmd

import (
"context"
"errors"
"fmt"
"log"
Expand All @@ -13,7 +14,6 @@ import (
"github.com/creativeprojects/imap/term"
"github.com/pterm/pterm"
"github.com/spf13/cobra"
"golang.org/x/net/context"
)

var copyCmd = &cobra.Command{
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ require (
github.com/emersion/go-imap v1.2.1
github.com/emersion/go-imap-compress v0.0.0-20201103190257-14809af1d1b9
github.com/emersion/go-imap-uidplus v0.0.0-20200503180755-e75854c361e9
github.com/emersion/go-maildir v0.5.0
github.com/emersion/go-maildir v0.6.0
github.com/pterm/pterm v0.12.79
github.com/spf13/cobra v1.8.1
github.com/stretchr/testify v1.9.0
Expand Down
6 changes: 2 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ github.com/emersion/go-imap-compress v0.0.0-20201103190257-14809af1d1b9 h1:7dmV1
github.com/emersion/go-imap-compress v0.0.0-20201103190257-14809af1d1b9/go.mod h1:2Ro1PbmiqYiRe5Ct2sGR5hHaKSVHeRpVZwXx8vyYt98=
github.com/emersion/go-imap-uidplus v0.0.0-20200503180755-e75854c361e9 h1:2Kbw3iu7fFeSso6RWIArVNUj1VGG2PvjetnPUW7bnis=
github.com/emersion/go-imap-uidplus v0.0.0-20200503180755-e75854c361e9/go.mod h1:GfiSiw/du0221I3Cf4F0DqX3Bv5Xe580gIIATrQtnJg=
github.com/emersion/go-maildir v0.5.0 h1:RhmSIKAvdSbKCicpe8lrlihjS/xLx0CzWIWJZQQyG4k=
github.com/emersion/go-maildir v0.5.0/go.mod h1:Wpgtt9EOIJWe++WKa+JRvDwv+qIV7MeFdvZu/VbsXN4=
github.com/emersion/go-maildir v0.6.0 h1:MPx2RSS1Xq8j1cNOzfq7YyF+5Leoeif1XqSeuytdET8=
github.com/emersion/go-maildir v0.6.0/go.mod h1:Wpgtt9EOIJWe++WKa+JRvDwv+qIV7MeFdvZu/VbsXN4=
github.com/emersion/go-message v0.15.0/go.mod h1:wQUEfE+38+7EW8p8aZ96ptg6bAb1iwdgej19uXASlE4=
github.com/emersion/go-message v0.18.1 h1:tfTxIoXFSFRwWaZsgnqS1DSZuGpYGzSmCZD8SK3QA2E=
github.com/emersion/go-message v0.18.1/go.mod h1:XpJyL70LwRvq2a8rVbHXikPgKj8+aI0kGdHlg16ibYA=
Expand Down Expand Up @@ -188,8 +188,6 @@ golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U=
golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
Expand Down
4 changes: 2 additions & 2 deletions lib/email_generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func GenerateDateFrom(from time.Time) time.Time {
}

// GenerateFlags generates an random number of message flags
func GenerateFlags(max int) []string {
func GenerateFlags(maxInt int) []string {
available := []string{
imap.SeenFlag,
imap.AnsweredFlag,
Expand All @@ -58,7 +58,7 @@ func GenerateFlags(max int) []string {
imap.RecentFlag,
}
picked := make([]bool, len(available))
count := seededRand.Intn(max)
count := seededRand.Intn(maxInt)
flags := make([]string, count)
for i := 0; i < count; i++ {
for {
Expand Down
6 changes: 3 additions & 3 deletions lib/email_generator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ func TestDateGenerator(t *testing.T) {
}

func TestGenerateFlags(t *testing.T) {
max := 5
maxInt := 5
for i := 0; i < 100000; i++ {
flags := GenerateFlags(max)
flags := GenerateFlags(maxInt)
require.NotNil(t, flags)
require.GreaterOrEqual(t, len(flags), 0)
require.Less(t, len(flags), max)
require.Less(t, len(flags), maxInt)
}
}
7 changes: 1 addition & 6 deletions lib/uid.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
package lib

import (
"math/rand"
"time"
"math/rand/v2"
)

func init() {
rand.Seed(time.Now().UnixMilli())
}

func NewUID() uint32 {
return rand.Uint32()
}
5 changes: 2 additions & 3 deletions limitio/writer.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@ import (
)

type Writer struct {
w io.Writer
limiter *rate.Limiter
limitReader io.Reader
w io.Writer
limiter *rate.Limiter
}

// NewWriter returns a writer that implements io.Writer with rate limiting.
Expand Down
14 changes: 0 additions & 14 deletions storage/backend_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import (
"github.com/creativeprojects/imap/storage/mdir"
"github.com/creativeprojects/imap/storage/mem"
"github.com/creativeprojects/imap/storage/remote"
"github.com/emersion/go-imap"
compress "github.com/emersion/go-imap-compress"
"github.com/emersion/go-imap/backend/memory"
"github.com/emersion/go-imap/server"
Expand All @@ -25,19 +24,6 @@ import (
"golang.org/x/net/nettest"
)

var (
sampleMessage = "From: contact@example.org\r\n" +
"To: contact@example.org\r\n" +
"Subject: A little message, just for you\r\n" +
"Date: Wed, 11 May 2016 14:31:59 +0000\r\n" +
"Message-ID: <0000000@localhost/>\r\n" +
"Content-Type: text/plain\r\n" +
"\r\n" +
"Hi there :)"
sampleMessageDate = time.Date(2020, 10, 20, 12, 11, 0, 0, time.UTC)
sampleMessageFlags = []string{imap.SeenFlag}
)

func TestImapBackend(t *testing.T) {
// Create a memory backend
be := memory.New()
Expand Down
2 changes: 1 addition & 1 deletion storage/copy.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func CopyMessages(ctx context.Context, backendSource, backendDest Backend, mbox
return entries, nil
}

func copyMessage(ctx context.Context, msgSource *mailbox.Message, backendDest Backend, mboxDest mailbox.Info, history *mailbox.History) (*mailbox.MessageID, error) {
func copyMessage(_ context.Context, msgSource *mailbox.Message, backendDest Backend, mboxDest mailbox.Info, history *mailbox.History) (*mailbox.MessageID, error) {
defer msgSource.Body.Close()

if previousEntry := mailbox.FindHistoryEntryFromSourceID(history, msgSource.Uid); previousEntry != nil {
Expand Down
8 changes: 6 additions & 2 deletions storage/local/bolt_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,9 @@ func (s *BoltStore) CreateMailbox(info mailbox.Info) error {
if err != nil {
return err
}
defer tx.Rollback()
defer func() {
_ = tx.Rollback()
}()

// Setup the mailbox bucket.
root, err := tx.CreateBucketIfNotExists([]byte(mailboxBucket))
Expand Down Expand Up @@ -428,7 +430,9 @@ func (s *BoltStore) AddToHistory(info mailbox.Info, actions ...mailbox.HistoryAc
if err != nil {
return err
}
defer tx.Rollback()
defer func() {
_ = tx.Rollback()
}()

// Setup the mailbox bucket.
root, err := tx.CreateBucketIfNotExists([]byte(mailboxBucket))
Expand Down
58 changes: 22 additions & 36 deletions storage/mdir/maildir.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,24 +141,20 @@ func (m *Maildir) SelectMailbox(info mailbox.Info) (*mailbox.Status, error) {
func (m *Maildir) PutMessage(info mailbox.Info, props mailbox.MessageProperties, body io.Reader) (mailbox.MessageID, error) {
name := lib.VerifyDelimiter(info.Name, info.Delimiter, Delimiter)
mbox := maildir.Dir(filepath.Join(m.root, name))
key, copied, err := m.createFromStream(mbox, props.Flags, body)
msg, copied, err := m.createFromStream(mbox, props.Flags, body)
if err != nil {
return mailbox.EmptyMessageID, err
}
if props.Size > 0 && copied != int64(props.Size) {
// delete the message
filename, err := mbox.Filename(key)
if err == nil {
_ = os.Remove(filename)
}
filename := msg.Filename()
_ = os.Remove(filename)
return mailbox.EmptyMessageID, fmt.Errorf("message body size advertised as %d bytes but read %d bytes from buffer", props.Size, copied)
}
m.log.Printf("Message saved: mailbox=%q key=%q size=%d flags=%v date=%q", name, key, copied, props.Flags, props.InternalDate)
m.log.Printf("Message saved: mailbox=%q key=%q size=%d flags=%v date=%q", name, msg, copied, props.Flags, props.InternalDate)

filename, err := mbox.Filename(key)
if err == nil {
_ = os.Chtimes(filename, time.Now(), props.InternalDate)
}
filename := msg.Filename()
_ = os.Chtimes(filename, time.Now(), props.InternalDate)

status, err := m.getMailboxStatus(name)
if err != nil {
Expand All @@ -169,20 +165,20 @@ func (m *Maildir) PutMessage(info mailbox.Info, props mailbox.MessageProperties,
if err != nil {
return mailbox.EmptyMessageID, err
}
return mailbox.NewMessageIDFromString(key), nil
return mailbox.NewMessageIDFromString(msg.Key()), nil
}

func (m *Maildir) createFromStream(mbox maildir.Dir, flags []string, body io.Reader) (string, int64, error) {
key, writer, err := mbox.Create(toFlags(flags))
func (m *Maildir) createFromStream(mbox maildir.Dir, flags []string, body io.Reader) (*maildir.Message, int64, error) {
msg, writer, err := mbox.Create(toFlags(flags))
if err != nil {
return key, 0, err
return msg, 0, err
}
defer writer.Close()
copied, err := io.Copy(writer, body)
if err != nil {
return key, copied, err
return msg, copied, err
}
return key, copied, nil
return msg, copied, nil
}

func (m *Maildir) FetchMessages(ctx context.Context, since time.Time, messages chan *mailbox.Message) error {
Expand All @@ -197,23 +193,17 @@ func (m *Maildir) FetchMessages(ctx context.Context, since time.Time, messages c

name := m.selected
mbox := maildir.Dir(filepath.Join(m.root, name))
keys, err := mbox.Keys()
msgs, err := mbox.Messages()
if err != nil {
return err
}

for _, key := range keys {
for _, msg := range msgs {
if ctx.Err() != nil {
return ctx.Err()
}
flags, err := mbox.Flags(key)
if err != nil {
return fmt.Errorf("cannot read flags for key %q: %w", key, err)
}
filename, err := mbox.Filename(key)
if err != nil {
return fmt.Errorf("cannot find filename for key %q: %w", key, err)
}
flags := msg.Flags()
filename := msg.Filename()
info, err := os.Stat(filename)
if err != nil {
return fmt.Errorf("cannot stat %q: %w", filename, err)
Expand All @@ -222,17 +212,17 @@ func (m *Maildir) FetchMessages(ctx context.Context, since time.Time, messages c
// skip this message
continue
}
file, err := mbox.Open(key)
file, err := msg.Open()
if err != nil {
return fmt.Errorf("cannot open key %q: %w", key, err)
return fmt.Errorf("cannot open key %q: %w", msg, err)
}
messages <- &mailbox.Message{
MessageProperties: mailbox.MessageProperties{
Flags: flagsToStrings(flags),
InternalDate: info.ModTime(),
Size: uint32(info.Size()),
},
Uid: mailbox.NewMessageIDFromString(key),
Uid: mailbox.NewMessageIDFromString(msg.Key()),
Body: file,
}
}
Expand All @@ -248,20 +238,16 @@ func (m *Maildir) LatestDate(ctx context.Context) (time.Time, error) {
}

mbox := maildir.Dir(filepath.Join(m.root, m.selected))
keys, err := mbox.Keys()
msgs, err := mbox.Messages()
if err != nil {
return latest, err
}

for _, key := range keys {
for _, msg := range msgs {
if ctx.Err() != nil {
return latest, ctx.Err()
}
filename, err := mbox.Filename(key)
if err != nil {
// should we keep going after an error?
return latest, fmt.Errorf("cannot find filename for key %q: %w", key, err)
}
filename := msg.Filename()
info, err := os.Stat(filename)
if err != nil {
// should we keep going after an error?
Expand Down
1 change: 1 addition & 0 deletions storage/mem/memory.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ func (m *Backend) LatestDate(ctx context.Context) (time.Time, error) {
return latest, nil
}

//nolint:staticcheck
for uid := mailbox.currentUid; uid >= 0; uid-- {
if msg, found := mailbox.messages[uid]; found {
return msg.date, nil
Expand Down
4 changes: 3 additions & 1 deletion storage/remote/imap.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,9 @@ func NewImap(cfg Config) (*Imap, error) {
if cfg.NoTLS {
imapClient, err = client.Dial(cfg.ServerURL)
} else {
tlsConfig := &tls.Config{}
tlsConfig := &tls.Config{
MinVersion: tls.VersionTLS12,
}
if cfg.SkipTLSVerification {
tlsConfig.InsecureSkipVerify = true
}
Expand Down

0 comments on commit df67055

Please sign in to comment.