Repository navigation
Expand file tree
/
Copy pathrejects.go
More file actions
70 lines (62 loc) · 2.09 KB
/
Copy pathrejects.go
File metadata and controls
70 lines (62 loc) · 2.09 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
package smtpserver
import (
"bytes"
"context"
"crypto/sha256"
"fmt"
"io"
"log/slog"
"os"
"github.com/mjl-/bstore"
"github.com/mjl-/mox/message"
"github.com/mjl-/mox/mlog"
"github.com/mjl-/mox/moxio"
"github.com/mjl-/mox/store"
)
// rejectPresent returns whether the message is already present in the rejects mailbox.
func rejectPresent(log mlog.Log, acc *store.Account, rejectsMailbox string, m *store.Message, f *os.File) (present bool, msgID string, hash []byte, rerr error) {
if p, err := message.Parse(log.Logger, false, store.FileMsgReader(m.MsgPrefix, f)); err != nil {
log.Infox("parsing reject message for message-id", err)
} else if header, err := p.Header(); err != nil {
log.Infox("parsing reject message header for message-id", err)
} else {
msgID, _, err = message.MessageIDCanonical(header.Get("Message-Id"))
if err != nil {
log.Debugx("parsing message-id for reject", err, slog.String("messageid", header.Get("Message-Id")))
}
}
// We must not read MsgPrefix, it will likely change for subsequent deliveries.
h := sha256.New()
if _, err := io.Copy(h, &moxio.AtReader{R: f}); err != nil {
log.Infox("copying reject message to hash", err)
} else {
hash = h.Sum(nil)
}
if msgID == "" && len(hash) == 0 {
return false, "", nil, fmt.Errorf("no message-id or hash for determining reject message presence")
}
var exists bool
var err error
acc.WithRLock(func() {
err = acc.DB.Read(context.TODO(), func(tx *bstore.Tx) error {
mb, err := acc.MailboxFind(tx, rejectsMailbox)
if err != nil {
return fmt.Errorf("looking for rejects mailbox: %w", err)
} else if mb == nil {
return nil
}
q := bstore.QueryTx[store.Message](tx)
q.FilterNonzero(store.Message{MailboxID: mb.ID})
q.FilterEqual("Expunged", false)
q.FilterFn(func(m store.Message) bool {
return msgID != "" && m.MessageID == msgID || len(hash) > 0 && bytes.Equal(m.MessageHash, hash)
})
exists, err = q.Exists()
return err
})
})
if err != nil {
return false, "", nil, fmt.Errorf("querying for presence of reject message: %w", err)
}
return exists, msgID, hash, nil
}