mirror of
https://github.com/mjl-/mox.git
synced 2024-12-26 16:33:47 +03:00
68 lines
1.9 KiB
Go
68 lines
1.9 KiB
Go
|
package smtpserver
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"crypto/sha256"
|
||
|
"fmt"
|
||
|
"io"
|
||
|
"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(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 = 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(func(tx *bstore.Tx) error {
|
||
|
mbq := bstore.QueryTx[store.Mailbox](tx)
|
||
|
mbq.FilterNonzero(store.Mailbox{Name: rejectsMailbox})
|
||
|
mb, err := mbq.Get()
|
||
|
if err == bstore.ErrAbsent {
|
||
|
return nil
|
||
|
}
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("looking for rejects mailbox: %w", err)
|
||
|
}
|
||
|
|
||
|
q := bstore.QueryTx[store.Message](tx)
|
||
|
q.FilterNonzero(store.Message{MailboxID: mb.ID})
|
||
|
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
|
||
|
}
|