Answer a send's state only to its caller (issue 1261)

This commit is contained in:
jochen
2026-10-19 21:44:12 +02:00
parent 66aa204f67
commit a9ff48e200
5 changed files with 204 additions and 22 deletions
+23 -10
View File
@@ -1312,19 +1312,30 @@ func tellWaits(store SendStore, tell TellOperator, id string, now time.Time) err
// ---- reading the status -----------------------------------------------------------------------------------------
// ReadSendStatus is where a send asked with mail_send stands, by its ask id: waiting for the operator, sent,
// declined, ended without a choice (expired, refused, cancelled), or not proven. Read from the router's own
// record; when the router's word is a close one that was not decided yet, this is also where a send is first
// decided (and so sent), exactly once (Decide).
func ReadSendStatus(store SendStore, bus AskBus, publish QueuePublish, id string, now time.Time) (map[string]any, error) {
// ReadSendStatus is where a send asked with mail_send stands, answered only to the caller that asked for it
// (novox/hq ADR 0440 §7, issue 1261): an id no send is kept under, or a send whose own caller differs from the
// one asking, answers status "unknown" and nothing else of it — never an error, and never the account,
// recipients or subject of a send that is not the caller's own. The sweep, which settles a send regardless of
// who asked for it, calls readSendStatus directly instead, never through this caller check.
func ReadSendStatus(store SendStore, bus AskBus, publish QueuePublish, id, caller string, now time.Time) (map[string]any, error) {
trimmed := strings.TrimSpace(id)
req, rev, ok, err := getSend(store, trimmed)
if err != nil {
return nil, fmt.Errorf("the send %q cannot be read now (%v); ask again", trimmed, err)
}
if !ok {
return nil, fmt.Errorf("no send %q is kept: the id is the one mail_send gave", trimmed)
if !ok || req.Caller != caller {
return map[string]any{"status": "unknown"}, nil
}
return readSendStatus(store, bus, publish, req, rev, now)
}
// readSendStatus is ReadSendStatus's own reading of one send already fetched (req, rev): waiting for the
// operator, sent, declined, ended without a choice (expired, refused, cancelled), or not proven. Read from the
// router's own record; when the router's word is a close one that was not decided yet, this is also where a
// send is first decided (and so sent), exactly once (Decide). It never checks who is asking: ReadSendStatus
// does that before calling it, and the sweep (which settles a send no matter who asked for it) calls it
// directly.
func readSendStatus(store SendStore, bus AskBus, publish QueuePublish, req SendRequest, rev uint64, now time.Time) (map[string]any, error) {
out := map[string]any{"ask": req.ID, "account": req.Account, "to": req.To, "subject": req.Subject,
"asked": req.At.Format(time.RFC3339)}
if req.Decided != nil {
@@ -1342,7 +1353,7 @@ func ReadSendStatus(store SendStore, bus AskBus, publish QueuePublish, id string
if now.Sub(req.At) > SendAskLasts {
d, _, err := settleSend(store, req, rev, SendDecision{At: now, Outcome: "ended: never heard"})
if err != nil {
return nil, fmt.Errorf("the send %q could not be settled as ended (%v); ask again", trimmed, err)
return nil, fmt.Errorf("the send %q could not be settled as ended (%v); ask again", req.ID, err)
}
reportDecision(out, d, now)
return out, nil
@@ -1448,11 +1459,13 @@ func (b *Bundle) Sweep(now time.Time) {
}
} else {
for _, id := range undecided {
req, _, ok, err := getSend(store, id)
req, rev, ok, err := getSend(store, id)
if err != nil || !ok || req.Decided != nil {
continue
}
if _, err := ReadSendStatus(store, b.askBus(), b.queuePublish(), id, now); err != nil {
// 1261/AC6: the sweep settles a send regardless of who asked for it — readSendStatus directly,
// never ReadSendStatus's caller check.
if _, err := readSendStatus(store, b.askBus(), b.queuePublish(), req, rev, now); err != nil {
if b.Logf != nil {
b.Logf("[mesh-mail] sweeping the send %s: %v", id, err)
}