feat(core): the e-mail server after Java, measured against Java

SMTP on port 25 stores mails for the domain's accounts as Java reads
them anew and tells a local sender of unknown recipients; POP3 on port
110 hands them out. The mailboxes are in the snapshot and go back into
the project. EmailRun plays four stories over the network; MailCases
feeds Java's workers without one (26 cases, de and en). 18 cases name
Java bugs that the core does not take.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-01 18:58:26 +00:00
co-authored by Claude Opus 5.5
parent 8438b42018
commit 015635926f
26 changed files with 45188 additions and 14 deletions
+23 -5
View File
@@ -5,15 +5,17 @@
// Only the cables count: a host's SSID connects nothing at run time, as in
// Java (Swift joins a wireless host to the switch of its SSID; not taken).
// A DNS server runs only when it is switched on (Java: DNSServer.aktiv); an
// echo or web server is there either way, switched on or off (it can be
// echo, web or e-mail server is there either way, switched on or off (it can be
// switched at run time). The programs read the nodes' files (a web server its
// pages).
//
// Back the other way: what the simulation changes that Java keeps in the
// project (its objects are the project's), so a project saved after it holds
// it. That is a router's or home router's firewall, set on its page konfig.
// it. That is a router's or home router's firewall, set on its page konfig,
// and an e-mail server's mailboxes (Java writes them into
// /mailserver/konten.txt at once).
import { portSnapshot, topologySnapshot, type DnsServerConfiguration, type EchoServerSnapshot, type Id, type WebServerSnapshot, type TopologySnapshot } from '@mdg-filius/core';
import { portSnapshot, topologySnapshot, type DnsServerConfiguration, type EchoServerSnapshot, type EmailServerSnapshot, type Id, type WebServerSnapshot, type TopologySnapshot } from '@mdg-filius/core';
import type { ImportedProject } from './importProject.js';
export function projectSnapshot(project: ImportedProject): TopologySnapshot {
@@ -29,6 +31,11 @@ export function projectSnapshot(project: ImportedProject): TopologySnapshot {
for (const [nodeId, configuration] of project.webServerConfigurations) {
webServers.set(nodeId, { ...configuration, isActive: project.activePrograms.get(nodeId)?.has('webServer') === true });
}
const emailServers = new Map<Id, EmailServerSnapshot>();
for (const [nodeId, configuration] of project.emailServerConfigurations) {
if (project.installedPrograms.get(nodeId)?.has('emailServer') !== true) continue;
emailServers.set(nodeId, { domain: configuration.domain, accounts: configuration.accounts, isActive: project.activePrograms.get(nodeId)?.has('emailServer') === true });
}
const webBrowsers = new Set([...project.installedPrograms].filter(([, programs]) => programs.has('webBrowser')).map(([nodeId]) => nodeId));
return topologySnapshot({
nodes: project.graph.nodes.map((node) => ({
@@ -52,11 +59,22 @@ export function projectSnapshot(project: ImportedProject): TopologySnapshot {
simpleClientsByNodeId: project.simpleClientConfigurations,
webServersByNodeId: webServers,
webBrowserNodeIds: webBrowsers,
emailServersByNodeId: emailServers,
fileSystemsByNodeId: project.virtualFileSystems,
});
}
/** The project with what the simulation changed that Java keeps: the firewalls, as the run's snapshot holds them. */
/**
* The project with what the simulation changed that Java keeps, as the run's
* snapshot holds it: the firewalls, and the e-mail servers' mailboxes.
*/
export function projectWithSimulationChanges(project: ImportedProject, snapshot: TopologySnapshot): ImportedProject {
return { ...project, firewallConfigurationsByNodeId: new Map(snapshot.firewallConfigurationsByNodeId) };
const emailServers = new Map(project.emailServerConfigurations);
for (const [nodeId, server] of snapshot.emailServersByNodeId) {
const configuration = emailServers.get(nodeId);
if (configuration === undefined) continue;
const messages = server.accounts.reduce((count, account) => count + account.mailbox.length, 0);
emailServers.set(nodeId, { ...configuration, accounts: server.accounts, nextMessageID: messages + 1 });
}
return { ...project, firewallConfigurationsByNodeId: new Map(snapshot.firewallConfigurationsByNodeId), emailServerConfigurations: emailServers };
}