Vollständiger POP3-Server von Grund auf implementiert, analog zum bestehenden IMAP-Server (ING-01): TCP-Listener mit einer Goroutine pro Verbindung, CRLF/Byte-Stuffing-sichere Response-Writer, Zustandsmaschine (Authorization/Transaction/Update), Kommandos USER, PASS, STAT, LIST, RETR, DELE, QUIT. Zentrale Designentscheidungen: - USER antwortet immer +OK (RFC-konform), Prüfung erst bei PASS - Fehlgeschlagene Anmeldung liefert für unbekannten Benutzer und falsches Passwort denselben generischen Text (keine Informationspreisgabe, Akzeptanzkriterium 3) - DELE markiert Nachrichten nur sitzungslokal; store.Delete wird strukturell ausschließlich in QUIT (Transaction -> Update) aufgerufen, wodurch ein Verbindungsabbruch ohne QUIT nichts endgültig löscht (Pflichtprüfung 3) Alle drei Pflichtprüfungen mit echten Nachweisen durchgeführt: Zustandsübergangs-Tests gegen realen TCP-Server, manuelle Session mit Python-Standardbibliothek poplib (echtes Transkript im Prüfprotokoll), automatisierter Test für DELE-ohne-QUIT. Zusätzlich: 20 parallele reale Sessions (Akzeptanzkriterium 1), vollständiger RETR+DELE+QUIT-Zyklus (Akzeptanzkriterium 2). go build/go vet/golangci-lint clean, gesamtes Mail-Modul (~24 Pakete) regressionsfrei getestet. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HhgFcLS8tYMhDJpP74C6AQ
39 lines
1.7 KiB
Go
39 lines
1.7 KiB
Go
// Package pop3 implementiert ING-02: den POP3-Server (RFC 1939) mit den
|
|
// Zuständen Authorization/Transaction/Update und den Kernbefehlen
|
|
// USER/PASS/STAT/LIST/RETR/DELE/QUIT. Bewusste Neuimplementierung nach
|
|
// NEXARCH-Techstack, kein 1:1-Übernehmen von archivmail — gleiche
|
|
// Konvention wie mail/internal/imap (ING-01): eigene, schmale
|
|
// Authenticator/MailboxStore-Schnittstellen statt geteilter Typen über
|
|
// Paketgrenzen hinweg, CRLF-sichere Antworten (response.go).
|
|
package pop3
|
|
|
|
import "context"
|
|
|
|
// Authenticator prüft Zugangsdaten für PASS.
|
|
type Authenticator interface {
|
|
Authenticate(ctx context.Context, username, password string) (ok bool, err error)
|
|
}
|
|
|
|
// Message ist eine Nachricht im Postfach (nur Nummer/Größe für STAT/
|
|
// LIST — Inhalt kommt separat über MailboxStore.Retrieve, damit LIST
|
|
// nicht unnötig alle Nachrichteninhalte laden muss).
|
|
type Message struct {
|
|
Number int
|
|
Size int64
|
|
}
|
|
|
|
// MailboxStore liefert Postfachzustand für STAT/LIST/RETR/DELE.
|
|
type MailboxStore interface {
|
|
// List liefert alle (noch nicht gelöschten) Nachrichten des Postfachs
|
|
// username.
|
|
List(ctx context.Context, username string) ([]Message, error)
|
|
// Retrieve liefert den vollständigen Inhalt einer Nachricht
|
|
// (Akzeptanzkriterium 2: RETR liefert vollständige Nachrichten).
|
|
Retrieve(ctx context.Context, username string, number int) ([]byte, error)
|
|
// Delete löscht die angegebenen Nachrichtennummern ENDGÜLTIG — wird
|
|
// AUSSCHLIESSLICH im Update-Zustand nach einem regulären QUIT
|
|
// aufgerufen (Akzeptanzkriterium 2/Pflichtprüfung 3: DELE markiert
|
|
// nur innerhalb der Sitzung, committet wird erst hier).
|
|
Delete(ctx context.Context, username string, numbers []int) error
|
|
}
|