feat(fls): write the e-mail programs of a .fls, loaded by Java as the original

topologyWriter.ts writes the e-mail server's domain and bean accounts with
their mailboxes, and the e-mail client's three folders and address book.
The client's account is no bean (FILIUS 2.14 has no kontoListe property):
it lives in /konten.txt and is written with the files.

A Java error is not copied: older files keep recipients as strings, which
Java puts into its typed lists unchecked, and its e-mail window fails on
them. The writer writes the AddressEntry Java's own AddressEntry(String)
makes of each; a null recipient is left out. The Java oracle now reports
that reading next to each such string, and our addressEntry matches it on
all 9 in the corpus. The test names the departure (RECIPIENTS_AS_STRINGS)
and checks that it touches man-in-the-middle.fls alone.

Checked by Java against Java: every corpus file, read and written again,
loads with the same e-mail programs as the original, up to that departure.
The synthetic topology adds an e-mail server and client with an account, a
mailbox, three folders, an address book and recipients of every form. 15
mutation probes, each loaded by Java, were all caught. The writer now
writes everything the reader reads of Java's view.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-09-30 08:44:34 +00:00
co-authored by Claude Opus 5.5
parent ccec734143
commit 34d3788cd2
9 changed files with 1083 additions and 58 deletions
+2 -2
View File
@@ -49,8 +49,8 @@ Swift-Pfade relativ zu `filius-ipad/ios/FiliusPad/TopologyEditor/` (Stand
| `src/javaEmail.ts` | Java `EmailServer` (Konten-Bean, `kontenLaden`/`stringZuListeBenutzerkonten`), `EmailAnwendung` (Ordner, Adressbuch, `laden`), `EmailKonto`, `Email`, `AddressEntry`, `EmailUtils` | neu nach Java: E-Mail-Beans über ihre Setter, `/mailserver/konten.txt` und `/konten.txt` im Format von Javas Lesern, ohne ihre Fehler (leere Felder zählen, eine kurze Zeile fällt allein weg, Nachrichten mit leerem Text oder Betreff bleiben, `;` im Betreff bleibt, CRLF, beim Client die letzte vollständige Zeile); Empfänger älterer Dateien als Zeichenketten; gegen Java auf dem Korpus und an 43 Fällen geprüft (13 benannte Java-Fehler) |
| `src/javaBeansWriter.ts` | — | neu: Schreiber für das `XMLDecoder`-Format, Gegenstück zu `javabeans.ts`; ausdrücklich typisierte Eingabe, geteilte Objekte über `id`/`idref`, was XML nicht fassen kann (und CR) als `<char code>`; von Java selbst geprüft (`BeansDump`) |
| `test/javaBeansWriter.test.ts`, `test/beans/` | — | neu: 11 Dateien des Schreibers, von Javas `XMLDecoder` gelesen und beschrieben; Erwartungen von Hand |
| `src/topologyWriter.ts` | Java `SzenarioVerwaltung.netzwerkSpeichern`, Konstruktoren von `NetzwerkInterface`, `Port`, `GUIKabelItem` und der Systemsoftware | neu nach Java: `konfiguration.xml` aus Javas Sicht — Geräte, Schnittstellen (vom Konstruktor angelegte über Getter, weitere per `add`), Ports über Getter-Verweise, Kabel samt Zeichen-Enden (`kabelpanel`), Doku-Elemente; Systemsoftware über ihre Setter: SSID, Lernzeit, RIP, manuelle Routen, DHCP-Client und -Server, statische NAT, Modem, Router-Firewall (über das `konfig`-Plug-in des Webservers, wie XMLEncoder sie erreicht); Dateisysteme (an die Wurzel des Konstruktors angehängt wie bei XMLEncoder, beim Router hinter dessen Vorlagen); installierte Programme nach den Dateien (Webserver, Tauschbörse und E-Mail-Server legen ihre Ordner nur an, wo sie fehlen; der DNS-Server liest `/dns/hosts` beim Installieren), je unter ihrem Schlüssel mit der Systemsoftware wie `installApp`, samt Einstellungen und persönlicher Firewall; Kopf „Filius version: 2.14.0 (mdg-filius)“ |
| `test/topologyWriter.test.ts`, `test/written.java.json` | — | neu: alle 23 Korpus-Dateien gelesen und neu geschrieben, von Java geladen — Topologie, Systemsoftware, Dateisysteme und Programme (ohne E-Mail-Konten, -Nachrichten und Adressbuch) wie beim Original (Java gegen Java); dazu eine künstliche Topologie mit dem, was der Korpus nicht hat (u. a. eingeschaltete Router-Firewall mit Regeln jedes Protokolls, alle Firewall-Schalter abseits der Vorgabe, Modem mit eigenem Port und Ziel, verschachtelter Dateibaum mit umbenannter Wurzel, namenlosem Ordner, Datei ohne Typ und Inhalt mit CR/CRLF und Zeichen jenseits der BMP, Heimrouter mit eigener Wurzel, jedes Filius-Programm mit Einstellungen abseits der Vorgabe samt persönlicher Firewall, ein von Java angelegter Ordner `/peer2peer`) |
| `src/topologyWriter.ts` | Java `SzenarioVerwaltung.netzwerkSpeichern`, Konstruktoren von `NetzwerkInterface`, `Port`, `GUIKabelItem` und der Systemsoftware | neu nach Java: `konfiguration.xml` aus Javas Sicht — Geräte, Schnittstellen (vom Konstruktor angelegte über Getter, weitere per `add`), Ports über Getter-Verweise, Kabel samt Zeichen-Enden (`kabelpanel`), Doku-Elemente; Systemsoftware über ihre Setter: SSID, Lernzeit, RIP, manuelle Routen, DHCP-Client und -Server, statische NAT, Modem, Router-Firewall (über das `konfig`-Plug-in des Webservers, wie XMLEncoder sie erreicht); Dateisysteme (an die Wurzel des Konstruktors angehängt wie bei XMLEncoder, beim Router hinter dessen Vorlagen); installierte Programme nach den Dateien (Webserver, Tauschbörse und E-Mail-Server legen ihre Ordner nur an, wo sie fehlen; der DNS-Server liest `/dns/hosts` beim Installieren), je unter ihrem Schlüssel mit der Systemsoftware wie `installApp`, samt Einstellungen und persönlicher Firewall; E-Mail: Domain und Bean-Konten des Servers samt Postfächern, Ordner und Adressbuch des Clients (sein Konto steht in `/konten.txt`, einer Datei); Javas Fehler nicht übernommen: ein Empfänger, den eine ältere Datei als Zeichenkette hält, wird als der `AddressEntry` geschrieben, den Javas `AddressEntry(String)` daraus macht (Java legt die Zeichenkette ungeprüft in die typisierte Liste, sein E-Mail-Fenster scheitert daran), ein `null`-Empfänger fällt weg; Kopf „Filius version: 2.14.0 (mdg-filius)“ |
| `test/topologyWriter.test.ts`, `test/written.java.json` | — | neu: alle 23 Korpus-Dateien gelesen und neu geschrieben, von Java geladen — Topologie, Systemsoftware, Dateisysteme und Programme samt E-Mail wie beim Original (bis auf die benannte Abweichung bei Empfängern als Zeichenkette, nur in `man-in-the-middle.fls`) (Java gegen Java); dazu eine künstliche Topologie mit dem, was der Korpus nicht hat (u. a. eingeschaltete Router-Firewall mit Regeln jedes Protokolls, alle Firewall-Schalter abseits der Vorgabe, Modem mit eigenem Port und Ziel, verschachtelter Dateibaum mit umbenannter Wurzel, namenlosem Ordner, Datei ohne Typ und Inhalt mit CR/CRLF und Zeichen jenseits der BMP, Heimrouter mit eigener Wurzel, jedes Filius-Programm mit Einstellungen abseits der Vorgabe samt persönlicher Firewall, von Java angelegte Ordner `/peer2peer` und `/mailserver`, E-Mail-Server und -Client mit Konto, Postfach, drei Ordnern, Adressbuch und Empfängern aller Formen) |
| `src/importEmail.ts` | `Persistence/TopologyProjectStore.swift` (`registerJavaEmailConfigurations`, `assignedJavaEmailMessages`) | übertragen, Eingabe ist Javas Sicht: Server-Konten aus `/mailserver/konten.txt`, ohne Datei aus der Bean-Liste (Java verlöre sie); Client-Konto aus `/konten.txt`, ohne Datei aus der älteren `kontoListe` (Filius 2.14 liest sie nicht mehr); Konten und Nachrichten bleiben, wo Swift verwirft, was seine Prüfung nicht besteht; Vor- und Nachname getrennt; Empfangszeit nur aus der Datei (Swift nummeriert); gegen Swifts Modell geprüft |
| `test/importEmail.test.ts`, `test/email-*.swift.json` | `State/TopologyEmail.swift` (`decodeJavaServer`, `decodeJavaClient`) als Vergleich | neu: dieselben 43 Kontodateien mit Swifts Leser; wie Swift bis auf benannte Fälle, in denen Swift prüft und die ganze Datei verwirft, wo Java liest |
| `src/javaFileSystem.ts`, `src/javaString.ts` | Java `Dateisystem.holeDatei`, `String.trim`/`split`/`equalsIgnoreCase` | neu nach Java; die Groß-/Kleinschreibung gegenüber ASCII am JDK über die ganze BMP gemessen |
+36
View File
@@ -11791,8 +11791,12 @@
"empfaenger": [
[
"string",
"rechner3@senior.de",
[
null,
"rechner3@senior.de"
]
]
],
"cc": [],
"bcc": [],
@@ -11811,8 +11815,12 @@
"empfaenger": [
[
"string",
"alice@senior.de",
[
null,
"alice@senior.de"
]
]
],
"cc": [],
"bcc": [],
@@ -11853,8 +11861,12 @@
"empfaenger": [
[
"string",
"Bob@filius.de",
[
null,
"Bob@filius.de"
]
]
],
"cc": [],
"bcc": [],
@@ -11873,8 +11885,12 @@
"empfaenger": [
[
"string",
"bob@filius.de",
[
null,
"bob@filius.de"
]
]
],
"cc": [],
"bcc": [],
@@ -11893,8 +11909,12 @@
"empfaenger": [
[
"string",
"bob@filius.de",
[
null,
"bob@filius.de"
]
]
],
"cc": [],
"bcc": [],
@@ -11913,8 +11933,12 @@
"empfaenger": [
[
"string",
"bob@filius.de",
[
null,
"bob@filius.de"
]
]
],
"cc": [],
"bcc": [],
@@ -12144,8 +12168,12 @@
"empfaenger": [
[
"string",
"bob@filius.de",
[
null,
"bob@filius.de"
]
]
],
"cc": [],
"bcc": [],
@@ -12166,8 +12194,12 @@
"empfaenger": [
[
"string",
"rechner3@senior.de",
[
null,
"rechner3@senior.de"
]
]
],
"cc": [],
"bcc": [],
@@ -12186,8 +12218,12 @@
"empfaenger": [
[
"string",
"alice@senior.de",
[
null,
"alice@senior.de"
]
]
],
"cc": [],
"bcc": [],
+99 -4
View File
@@ -19,8 +19,15 @@
// the web server, the peer-to-peer application and the e-mail server make
// their directories only where the files lack them, and the DNS server reads
// /dns/hosts when it is installed. Each is put under its key and given the
// system software, as installApp does. E-mail accounts, messages and address
// books are a later layer.
// system software, as installApp does.
//
// E-mail: the server's domain and bean accounts with their mailboxes, the
// client's three folders and address book. The client's account is no bean
// (FILIUS 2.14 has no kontoListe property): it lives in /konten.txt, a file.
// Java's errors are not copied: a recipient an older file keeps as a string
// is written as the AddressEntry Java's own AddressEntry(String) makes of it
// — Java puts the string into the typed list unchecked, and its e-mail
// window fails on it; a null recipient is left out.
//
// Checked by Java: every corpus file, read and written again, loads in Java
// FILIUS to the same topology and system software (topologyWriter.test.ts,
@@ -38,14 +45,20 @@ import {
type BeanValue,
short,
} from './javaBeansWriter.js';
import { addressEntry, type JavaAddressEntry, type JavaContact, type JavaEmail, type JavaEmailAccount, type JavaRecipient } from './javaEmail.js';
import type { FlsApplication, FlsFileTree, FlsFirewall, FlsSystemSoftware } from './systemSoftware.js';
import type { FlsDocumentationItem, FlsInterface, FlsLink, FlsNode, FlsNodeClass } from './topology.js';
/** The version line of the files this writer makes: the format of FILIUS 2.14. */
export const WRITTEN_VERSION_LINE = 'Filius version: 2.14.0 (mdg-filius)';
/** An installed application; e-mail accounts, messages and address books are a later layer. */
export type ApplicationToWrite = Omit<FlsApplication, 'source'>;
/**
* An installed application with its settings. The e-mail accounts Java reads
* from files (/mailserver/konten.txt, /konten.txt) are written with the
* files; an older file's kontoListe, which FILIUS 2.14 does not read, is not
* written.
*/
export type ApplicationToWrite = Omit<FlsApplication, 'source' | 'fileAccounts' | 'fileAccount' | 'legacyAccounts'>;
/** The system software's settings, files and applications. */
export type SystemToWrite = Omit<FlsSystemSoftware, 'applications'> & {
@@ -282,9 +295,91 @@ function applicationStatements(application: ApplicationToWrite, system: BeanRefe
statements.push({ set: 'maxTeilnehmerZahl', value: int(application.maxPeers) });
}
if (application.firewall !== undefined) statements.push(...firewallStatements(application.firewall));
if (application.mailDomain !== undefined) statements.push({ set: 'mailDomain', value: application.mailDomain });
if (application.beanAccounts !== undefined) {
statements.push({ set: 'listeBenutzerkonten', value: listOf(application.beanAccounts.map(emailAccount)) });
}
if (application.received !== undefined) statements.push({ set: 'empfangeneNachrichten', value: emails(application.received) });
if (application.sent !== undefined) statements.push({ set: 'gesendeteNachrichten', value: emails(application.sent) });
if (application.drafts !== undefined) statements.push({ set: 'erstellteNachrichten', value: emails(application.drafts) });
if (application.addressBook !== undefined) {
statements.push({
set: 'adressbuch',
value: object(
'java.util.Vector',
application.addressBook.map((entry) => ({ call: 'add', args: [contact(entry)] })),
),
});
}
return statements;
}
const EMAIL_PACKAGE = 'filius.software.email';
function emailAccount(account: JavaEmailAccount): BeanObject {
return object(`${EMAIL_PACKAGE}.EmailKonto`, [
{ set: 'benutzername', value: account.username },
{ set: 'passwort', value: account.password },
{ set: 'nachname', value: account.lastName },
{ set: 'vorname', value: account.firstName },
{ set: 'emailAdresse', value: account.emailAddress },
{ set: 'pop3server', value: account.pop3Server },
{ set: 'pop3port', value: account.pop3Port },
{ set: 'smtpserver', value: account.smtpServer },
{ set: 'smtpport', value: account.smtpPort },
{ set: 'nachrichten', value: emails(account.messages) },
]);
}
function emails(messages: readonly JavaEmail[]): BeanObject {
return listOf(
messages.map((message) =>
object(`${EMAIL_PACKAGE}.Email`, [
{ set: 'absender', value: address(message.sender) },
{ set: 'empfaenger', value: recipients(message.to) },
{ set: 'cc', value: recipients(message.cc) },
{ set: 'bcc', value: recipients(message.bcc) },
{ set: 'betreff', value: message.subject },
{ set: 'text', value: message.text },
{ set: 'dateReceived', value: message.dateReceived },
{ set: 'neu', value: message.isNew },
{ set: 'delete', value: message.isDeleted },
{ set: 'versendet', value: message.isSent },
]),
),
);
}
/** A list of AddressEntry: a string read as Java's AddressEntry(String) reads it, null left out. */
function recipients(entries: readonly JavaRecipient[]): BeanObject {
return object(
'java.util.ArrayList',
entries.flatMap((entry) =>
entry === null ? [] : [{ call: 'add', args: [address(typeof entry === 'string' ? addressEntry(entry) : entry)] }],
),
);
}
function address(entry: JavaAddressEntry): BeanObject {
const statements: BeanStatement[] = [];
if (entry.name !== null) statements.push({ set: 'name', value: entry.name });
if (entry.mailAddress !== null) statements.push({ set: 'mailAddress', value: entry.mailAddress });
return object(`${EMAIL_PACKAGE}.AddressEntry`, statements);
}
function contact(entry: JavaContact): BeanObject {
return object(`${EMAIL_PACKAGE}.Kontakt`, [
{ set: 'name', value: entry.name },
{ set: 'vorname', value: entry.firstName },
{ set: 'strasse', value: entry.street },
{ set: 'hausnr', value: int(entry.houseNumber) },
{ set: 'plz', value: int(entry.postalCode) },
{ set: 'wohnort', value: entry.city },
{ set: 'email', value: entry.email },
{ set: 'telefon', value: entry.phone },
]);
}
/** A LinkedList of String arrays: routes, static NAT. */
function rows(table: readonly (readonly (string | null)[])[]): BeanObject {
return listOf(table.map((row) => ({ kind: 'array', componentClass: 'java.lang.String', items: [...row] })));
+8 -3
View File
@@ -1,7 +1,7 @@
// The e-mail beans under Java's property names, as FlsOracle.java and
// EmailFileCases.java write them.
import type { JavaEmail, JavaEmailAccount, JavaRecipient } from '../src/index.js';
import { addressEntry, type JavaEmail, type JavaEmailAccount, type JavaRecipient } from '../src/index.js';
export function javaEmailAccount(account: JavaEmailAccount) {
return {
@@ -19,8 +19,13 @@ export function javaEmailAccount(account: JavaEmailAccount) {
}
export function javaEmail(email: JavaEmail) {
const recipient = (entry: JavaRecipient) =>
entry === null ? null : typeof entry === 'string' ? ['string', entry] : [entry.name, entry.mailAddress];
// A string with how AddressEntry(String) reads it.
const recipient = (entry: JavaRecipient) => {
if (entry === null) return null;
if (typeof entry !== 'string') return [entry.name, entry.mailAddress];
const parsed = addressEntry(entry);
return ['string', entry, [parsed.name, parsed.mailAddress]];
};
return {
absender: [email.sender.name, email.sender.mailAddress],
empfaenger: email.to.map(recipient),
+140 -11
View File
@@ -1,8 +1,9 @@
// Every corpus file, read and written again: Java FILIUS loads the written
// file (tools/java-oracle, written.java.json) to the same topology as the
// original (corpus.java.json) — devices, names, positions, interfaces,
// system software, files and applications (without e-mail accounts,
// messages and address books), cables and documentation. Java against Java: no mapping of this package stands
// system software, files, applications with their e-mail accounts,
// messages and address books, cables and documentation — up to one Java
// error the writer does not copy (RECIPIENTS_AS_STRINGS). Java against Java: no mapping of this package stands
// between the two.
//
// UPDATE_WRITTEN=1 writes the files to test/written/ (not checked in); the
@@ -15,6 +16,7 @@ import { dirname, join, relative } from 'node:path';
import { fileURLToPath } from 'node:url';
import { describe, expect, it } from 'vitest';
import { decodeJavaBeans, readFlsArchive, readTopology, writeFlsArchive } from '../src/index.js';
import type { JavaEmail } from '../src/javaEmail.js';
import { writeTopologyXml, type TopologyToWrite } from '../src/topologyWriter.js';
const here = dirname(fileURLToPath(import.meta.url));
@@ -44,13 +46,26 @@ const original = JSON.parse(readFileSync(join(corpusRoot, 'corpus.java.json'), '
const written = JSON.parse(readFileSync(join(here, 'written.java.json'), 'utf8')) as Record<string, JavaFile>;
/**
* The system software without what a later layer writes: the e-mail
* programs' domain, accounts, messages and address book.
* The Java error the writer does not copy: older files keep e-mail
* recipients as strings, which Java puts into its typed lists unchecked (its
* e-mail window then fails on them). The writer writes the AddressEntry
* Java's own AddressEntry(String) makes of each — the oracle reports it
* next to the string — and leaves a null recipient out.
*/
function systemOf(system: Record<string, unknown>) {
if (system.applications === undefined) return system;
const applications = (system.applications as Record<string, unknown>[]).map(({ mailDomain: _domain, beanAccounts: _accounts, received: _received, sent: _sent, drafts: _drafts, addressBook: _book, ...rest }) => rest);
return { ...system, applications };
const RECIPIENTS_AS_STRINGS = ['java-examples/man-in-the-middle.fls'];
/** Java's view of the original as the writer means it: each recipient as Java reads its string, none null. */
function withRecipientsRead(value: unknown, key = ''): unknown {
if (Array.isArray(value)) {
if (key === 'empfaenger' || key === 'cc' || key === 'bcc') {
return value.filter((entry) => entry !== null).map((entry) => (entry[0] === 'string' ? entry[2] : entry));
}
return value.map((item) => withRecipientsRead(item));
}
if (value !== null && typeof value === 'object') {
return Object.fromEntries(Object.entries(value).map(([name, item]) => [name, withRecipientsRead(item, name)]));
}
return value;
}
/**
@@ -67,7 +82,7 @@ function topologyOf(view: JavaFile) {
useIpAsName: node.useIpAsName,
useMacAsName: node.useMacAsName,
ports: node.ports,
system: systemOf(node.system),
system: node.system,
})),
cables: view.cables,
documentation: view.documentation,
@@ -88,10 +103,52 @@ describe('the topology written again, as Java loads it', () => {
expect(java?.sha256, 'written.java.json is not about this output: UPDATE_WRITTEN=1, then npm run oracle:java').toBe(
createHash('sha256').update(archive).digest('hex'),
);
expect(topologyOf(java!)).toEqual(topologyOf(original[name]!));
expect(topologyOf(java!)).toEqual(topologyOf(withRecipientsRead(original[name]!) as JavaFile));
});
}
it('departs from Java only where it keeps recipients as strings', () => {
const changed = flsFiles(corpusRoot)
.map((file) => relative(corpusRoot, file))
.filter((name) => JSON.stringify(withRecipientsRead(original[name])) !== JSON.stringify(original[name]));
expect(changed).toEqual(RECIPIENTS_AS_STRINGS);
});
});
/**
* An e-mail with a sender without address, recipients as entries, as the
* string an older file keeps (read as AddressEntry(String) reads it) and
* null (left out), a text with CR, and a date.
*/
const SYNTHETIC_MAIL: JavaEmail = {
sender: { name: 'Anna', mailAddress: null },
to: [{ name: null, mailAddress: 'ben@schule.de' }, 'Carla <carla@schule.de>', null],
cc: [{ name: 'Dora', mailAddress: 'dora@schule.de' }],
bcc: ['eva@schule.de'],
subject: 'Hallo',
text: 'Zeile 1\r\nZeile 2',
dateReceived: '1727690000000',
isNew: true,
isDeleted: true,
isSent: false,
};
/** SYNTHETIC_MAIL as the oracle describes it after Java loaded it. */
function javaMail(changes: Record<string, unknown> = {}) {
return {
absender: ['Anna', null],
empfaenger: [[null, 'ben@schule.de'], ['Carla', 'carla@schule.de']],
cc: [['Dora', 'dora@schule.de']],
bcc: [[null, 'eva@schule.de']],
betreff: 'Hallo',
text: 'Zeile 1\r\nZeile 2',
dateReceived: '1727690000000',
neu: true,
delete: true,
versendet: false,
...changes,
};
}
/** Text a file's content may hold: markup, CR and CRLF, a tab, beyond the BMP. */
const FILE_CONTENT = '<p>a & b</p>\r\nline\rend\ttab Grüße 😀\n';
@@ -178,6 +235,45 @@ const SYNTHETIC: TopologyToWrite = {
{ key: 'filius.software.lokal.FileExplorer', javaClass: 'filius.software.lokal.FileExplorer' },
{ key: 'filius.software.lokal.ImageViewer', javaClass: 'filius.software.lokal.ImageViewer' },
{ key: 'filius.software.www.WebBrowser', javaClass: 'filius.software.www.WebBrowser' },
{
key: 'filius.software.email.EmailServer',
javaClass: 'filius.software.email.EmailServer',
isActive: true,
mailDomain: 'schule.de',
beanAccounts: [
{
username: 'anna',
password: 'geheim',
lastName: 'Muster',
firstName: '',
emailAddress: 'anna@schule.de',
pop3Server: null,
pop3Port: null,
smtpServer: null,
smtpPort: null,
messages: [SYNTHETIC_MAIL],
},
],
},
{
key: 'filius.software.email.EmailAnwendung',
javaClass: 'filius.software.email.EmailAnwendung',
received: [SYNTHETIC_MAIL],
sent: [{ ...SYNTHETIC_MAIL, isSent: true, isNew: false }],
drafts: [{ ...SYNTHETIC_MAIL, subject: null, text: null, dateReceived: null, to: [] }],
addressBook: [
{
name: 'Muster',
firstName: 'Anna',
street: null,
houseNumber: 12,
postalCode: 20095,
city: 'Hamburg',
email: 'anna@schule.de',
phone: null,
},
],
},
],
},
},
@@ -341,8 +437,9 @@ describe('a topology beyond the corpus, as Java loads it', () => {
javaFile('untyped', null, null),
{ directory: 'webserver', children: [javaFile('index.html', 'html', '<p>own</p>')] },
{ directory: 'dns', children: [javaFile('hosts', null, 'a.de. A 3600 10.0.0.1\n')] },
// Made by the peer-to-peer application, whose directory the files lack.
// Made by the peer-to-peer application and the e-mail server, whose directories the files lack.
{ directory: 'peer2peer', children: [] },
{ directory: 'mailserver', children: [] },
],
},
// In the order of Java's key.
@@ -351,6 +448,38 @@ describe('a topology beyond the corpus, as Java loads it', () => {
{ key: 'filius.software.clientserver.ServerBaustein', class: 'filius.software.clientserver.ServerBaustein', aktiv: true, port: 7777 },
{ key: 'filius.software.dateiaustausch.PeerToPeerAnwendung', class: 'filius.software.dateiaustausch.PeerToPeerAnwendung', maxTeilnehmerZahl: 7 },
{ key: 'filius.software.dns.DNSServer', class: 'filius.software.dns.DNSServer', aktiv: true, port: 5353, recursiveResolutionEnabled: true },
{
key: 'filius.software.email.EmailAnwendung',
class: 'filius.software.email.EmailAnwendung',
received: [javaMail()],
sent: [javaMail({ versendet: true, neu: false })],
drafts: [javaMail({ betreff: null, text: null, dateReceived: null, empfaenger: [] })],
addressBook: [['Muster', 'Anna', null, 12, 20095, 'Hamburg', 'anna@schule.de', null]],
// No /konten.txt.
fileAccount: null,
},
{
key: 'filius.software.email.EmailServer',
class: 'filius.software.email.EmailServer',
aktiv: true,
mailDomain: 'schule.de',
beanAccounts: [
{
benutzername: 'anna',
passwort: 'geheim',
nachname: 'Muster',
vorname: '',
emailAdresse: 'anna@schule.de',
pop3server: null,
pop3port: null,
smtpserver: null,
smtpport: null,
nachrichten: [javaMail()],
},
],
// No /mailserver/konten.txt.
fileAccounts: null,
},
{
key: 'filius.software.firewall.Firewall',
class: 'filius.software.firewall.Firewall',
+781 -26
View File
@@ -2771,8 +2771,33 @@
"key": "filius.software.email.EmailServer",
"class": "filius.software.email.EmailServer",
"aktiv": true,
"mailDomain": "filius.de",
"beanAccounts": [],
"mailDomain": "gmx.com",
"beanAccounts": [
{
"benutzername": "herbert",
"passwort": "herbert1234",
"nachname": "Nachname",
"vorname": "Vorname",
"emailAdresse": null,
"pop3server": null,
"pop3port": null,
"smtpserver": null,
"smtpport": null,
"nachrichten": []
},
{
"benutzername": "george",
"passwort": "george1234",
"nachname": "Nachname",
"vorname": "Vorname",
"emailAdresse": null,
"pop3server": null,
"pop3port": null,
"smtpserver": null,
"smtpport": null,
"nachrichten": []
}
],
"fileAccounts": [
{
"benutzername": "herbert",
@@ -2859,8 +2884,21 @@
"key": "filius.software.email.EmailServer",
"class": "filius.software.email.EmailServer",
"aktiv": true,
"mailDomain": "filius.de",
"beanAccounts": [],
"mailDomain": "webmail.com",
"beanAccounts": [
{
"benutzername": "frimp",
"passwort": "frimp1234",
"nachname": "Nachname",
"vorname": "Vorname",
"emailAdresse": null,
"pop3server": null,
"pop3port": null,
"smtpserver": null,
"smtpport": null,
"nachrichten": []
}
],
"fileAccounts": [
{
"benutzername": "frimp",
@@ -4406,7 +4444,7 @@
]
}
],
"sha256": "80bd96325313dee3d357a3e4698c1bca23e793f4a0e4d1a6d6ae8980ef1f2f78"
"sha256": "f46da844fb935e67ebfc332820994f771564939a98734f5d9ba63873c9789706"
},
"java-examples/Internet_Komplett_mit_eMail_Webserver_Intranet_Portforwarding_Firewall_DHCP_DE.fls": {
"success": true,
@@ -4452,7 +4490,68 @@
"key": "filius.software.email.EmailAnwendung",
"class": "filius.software.email.EmailAnwendung",
"received": [],
"sent": [],
"sent": [
{
"absender": [
"Herbert Schmidt",
"herbert@gmx.de"
],
"empfaenger": [
[
null,
"frimp@webmail.de"
]
],
"cc": [],
"bcc": [],
"betreff": "Hallo Frimp!",
"text": "Huhu! \n\nHi Frimp!\n\nDein \nHerbert",
"dateReceived": "",
"neu": true,
"delete": false,
"versendet": false
},
{
"absender": [
"Herbert Schmidt",
"herbert@gmx.de"
],
"empfaenger": [
[
null,
"frimp@webmail.de"
]
],
"cc": [],
"bcc": [],
"betreff": "RE: Hallo Herbert!",
"text": "Hallo Frimp!\n\nFrimp Müller <frimp@webmail.de> schrieb:\n> Huhu! \n> \n> Hi Herbert!\n> \n> Dein \n> Frimp\n> ",
"dateReceived": "",
"neu": true,
"delete": false,
"versendet": false
},
{
"absender": [
"Herbert Schmidt",
"herbert@gmx.de"
],
"empfaenger": [
[
"Frimp Mueller",
"frimp@webmail.de"
]
],
"cc": [],
"bcc": [],
"betreff": "RE: RE: RE: Hallo Herbert!",
"text": "jetzt?!\n\nFrimp Mueller <frimp@webmail.de> schrieb:\n> Hi Herbert Again!\n> \n> Herbert Schmidt <herbert@gmx.de> schrieb:\n> > Hallo Frimp!\n> > \n> > Frimp Müller <frimp@webmail.de> schrieb:\n> > > Huhu! \n> > > \n> > > Hi Herbert!\n> > > \n> > > Dein \n> > > Frimp\n> > >\n> >\n> ",
"dateReceived": "",
"neu": true,
"delete": false,
"versendet": false
}
],
"drafts": [],
"addressBook": [],
"fileAccount": {
@@ -4571,7 +4670,68 @@
"key": "filius.software.email.EmailAnwendung",
"class": "filius.software.email.EmailAnwendung",
"received": [],
"sent": [],
"sent": [
{
"absender": [
"Frimp Müller",
"frimp@webmail.de"
],
"empfaenger": [
[
null,
"herbert@gmx.de"
]
],
"cc": [],
"bcc": [],
"betreff": "Hallo Herbert!",
"text": "Huhu! \n\nHi Herbert!\n\nDein \nFrimp",
"dateReceived": "",
"neu": true,
"delete": false,
"versendet": false
},
{
"absender": [
"Frimp Müller",
"frimp@webmail.de"
],
"empfaenger": [
[
"Herbert Schmidt",
"herbert@gmx.de"
]
],
"cc": [],
"bcc": [],
"betreff": "RE: RE: Hallo Herbert!",
"text": "funktioniert es jetzt?!\n\nHerbert Schmidt <herbert@gmx.de> schrieb:\n> Hallo Frimp!\n> \n> Frimp Müller <frimp@webmail.de> schrieb:\n> > Huhu! \n> > \n> > Hi Herbert!\n> > \n> > Dein \n> > Frimp\n> >\n> ",
"dateReceived": "",
"neu": true,
"delete": false,
"versendet": false
},
{
"absender": [
"Frimp Mueller",
"frimp@webmail.de"
],
"empfaenger": [
[
"Herbert Schmidt",
"herbert@gmx.de"
]
],
"cc": [],
"bcc": [],
"betreff": "RE: RE: Hallo Herbert!",
"text": "Hi Herbert Again!\n\nHerbert Schmidt <herbert@gmx.de> schrieb:\n> Hallo Frimp!\n> \n> Frimp Müller <frimp@webmail.de> schrieb:\n> > Huhu! \n> > \n> > Hi Herbert!\n> > \n> > Dein \n> > Frimp\n> >\n> ",
"dateReceived": "",
"neu": true,
"delete": false,
"versendet": false
}
],
"drafts": [],
"addressBook": [],
"fileAccount": {
@@ -5319,8 +5479,33 @@
"key": "filius.software.email.EmailServer",
"class": "filius.software.email.EmailServer",
"aktiv": true,
"mailDomain": "filius.de",
"beanAccounts": [],
"mailDomain": "gmx.de",
"beanAccounts": [
{
"benutzername": "herbert",
"passwort": "herbert1234",
"nachname": "Nachname",
"vorname": "Vorname",
"emailAdresse": null,
"pop3server": null,
"pop3port": null,
"smtpserver": null,
"smtpport": null,
"nachrichten": []
},
{
"benutzername": "george",
"passwort": "george1234",
"nachname": "Nachname",
"vorname": "Vorname",
"emailAdresse": null,
"pop3server": null,
"pop3port": null,
"smtpserver": null,
"smtpport": null,
"nachrichten": []
}
],
"fileAccounts": [
{
"benutzername": "herbert",
@@ -5407,8 +5592,21 @@
"key": "filius.software.email.EmailServer",
"class": "filius.software.email.EmailServer",
"aktiv": true,
"mailDomain": "filius.de",
"beanAccounts": [],
"mailDomain": "webmail.de",
"beanAccounts": [
{
"benutzername": "frimp",
"passwort": "frimp1234",
"nachname": "Nachname",
"vorname": "Vorname",
"emailAdresse": null,
"pop3server": null,
"pop3port": null,
"smtpserver": null,
"smtpport": null,
"nachrichten": []
}
],
"fileAccounts": [
{
"benutzername": "frimp",
@@ -6907,7 +7105,7 @@
]
}
],
"sha256": "f9d437533b63a6af9f25a130978e6f9bbe6f86c4dd6c3836c51e7aaa7482c559"
"sha256": "fb90133ed91aebfe934b73c37e71b970d4cce7eb25c531dc8b11a82a0bd77b6f"
},
"java-examples/Public_and_Private_Networks_2_EN.fls": {
"success": true,
@@ -10218,7 +10416,32 @@
"class": "filius.software.email.EmailServer",
"aktiv": true,
"mailDomain": "filius.de",
"beanAccounts": [],
"beanAccounts": [
{
"benutzername": "rechner1",
"passwort": "rechner1",
"nachname": "Nachname",
"vorname": "Vorname",
"emailAdresse": null,
"pop3server": null,
"pop3port": null,
"smtpserver": null,
"smtpport": null,
"nachrichten": []
},
{
"benutzername": "rechner2",
"passwort": "rechner2",
"nachname": "Nachname",
"vorname": "Vorname",
"emailAdresse": null,
"pop3server": null,
"pop3port": null,
"smtpserver": null,
"smtpport": null,
"nachrichten": []
}
],
"fileAccounts": [
{
"benutzername": "rechner1",
@@ -10305,8 +10528,33 @@
"key": "filius.software.email.EmailServer",
"class": "filius.software.email.EmailServer",
"aktiv": true,
"mailDomain": "filius.de",
"beanAccounts": [],
"mailDomain": "senior.de",
"beanAccounts": [
{
"benutzername": "rechner3",
"passwort": "rechner3",
"nachname": "Nachname",
"vorname": "Vorname",
"emailAdresse": null,
"pop3server": null,
"pop3port": null,
"smtpserver": null,
"smtpport": null,
"nachrichten": []
},
{
"benutzername": "rechner4",
"passwort": "rechner4",
"nachname": "Nachname",
"vorname": "Vorname",
"emailAdresse": null,
"pop3server": null,
"pop3port": null,
"smtpserver": null,
"smtpport": null,
"nachrichten": []
}
],
"fileAccounts": [
{
"benutzername": "rechner3",
@@ -10487,7 +10735,7 @@
}
],
"documentation": [],
"sha256": "12ff44b32e2b3af3c05578d6020c56fbbfb753db8ef7ac26dd98b2dbefa41eeb"
"sha256": "f4dff6029b345b51838c518820d3a16a61dbf4e844b1e943dd61929fc67861c3"
},
"java-examples/internetwork_komplett.fls": {
"success": true,
@@ -11546,8 +11794,190 @@
{
"key": "filius.software.email.EmailAnwendung",
"class": "filius.software.email.EmailAnwendung",
"received": [],
"sent": [],
"received": [
{
"absender": [
"Rechner 1",
"rechner1@filius.de"
],
"empfaenger": [
[
null,
"rechner3@senior.de"
]
],
"cc": [],
"bcc": [],
"betreff": "test",
"text": "test",
"dateReceived": "",
"neu": true,
"delete": false,
"versendet": false
},
{
"absender": [
"Bob 1",
"bob@filius.de"
],
"empfaenger": [
[
null,
"alice@senior.de"
]
],
"cc": [],
"bcc": [],
"betreff": "test3",
"text": "",
"dateReceived": "",
"neu": true,
"delete": false,
"versendet": false
},
{
"absender": [
"Bob 1",
"bob@filius.de"
],
"empfaenger": [
[
null,
"alice@senior.de"
]
],
"cc": [],
"bcc": [],
"betreff": "test bl",
"text": "test bl\n",
"dateReceived": "",
"neu": true,
"delete": false,
"versendet": false
}
],
"sent": [
{
"absender": [
"Alice 3",
"alice@senior.de"
],
"empfaenger": [
[
null,
"Bob@filius.de"
]
],
"cc": [],
"bcc": [],
"betreff": "Beste Grüße",
"text": "Hallo Bob,\n\nschön von dir zu hören.\n\nGruß\nAlice",
"dateReceived": "",
"neu": true,
"delete": false,
"versendet": false
},
{
"absender": [
"Alice 3",
"alice@senior.de"
],
"empfaenger": [
[
null,
"bob@filius.de"
]
],
"cc": [],
"bcc": [],
"betreff": "test",
"text": "test",
"dateReceived": "",
"neu": true,
"delete": false,
"versendet": false
},
{
"absender": [
"Alice 3",
"alice@senior.de"
],
"empfaenger": [
[
null,
"bob@filius.de"
]
],
"cc": [],
"bcc": [],
"betreff": "RE: test3",
"text": "\n\nBob 1 schrieb:\n> ",
"dateReceived": "",
"neu": true,
"delete": false,
"versendet": false
},
{
"absender": [
"Alice 3",
"alice@senior.de"
],
"empfaenger": [
[
null,
"bob@filius.de"
]
],
"cc": [],
"bcc": [],
"betreff": "RE: test3",
"text": "\n\nBob 1 schrieb:\n> ",
"dateReceived": "",
"neu": true,
"delete": false,
"versendet": false
},
{
"absender": [
"Alice 3",
"alice@senior.de"
],
"empfaenger": [
[
"Bob 1",
"bob@filius.de"
]
],
"cc": [],
"bcc": [],
"betreff": "RE: test bl",
"text": "huhu bob!\n\nBob 1 <bob@filius.de> schrieb:\n> test bl\n> ",
"dateReceived": "",
"neu": true,
"delete": false,
"versendet": false
},
{
"absender": [
"Alice 3",
"alice@senior.de"
],
"empfaenger": [
[
null,
"bob@filius.de"
]
],
"cc": [],
"bcc": [],
"betreff": "Hi Bob!",
"text": "Hi BoB!",
"dateReceived": "",
"neu": true,
"delete": false,
"versendet": false
}
],
"drafts": [],
"addressBook": [],
"fileAccount": {
@@ -11656,7 +12086,7 @@
"key": "filius.software.email.EmailServer",
"class": "filius.software.email.EmailServer",
"aktiv": true,
"mailDomain": "filius.de",
"mailDomain": "eve.de",
"beanAccounts": [],
"fileAccounts": []
},
@@ -11717,8 +12147,90 @@
{
"key": "filius.software.email.EmailAnwendung",
"class": "filius.software.email.EmailAnwendung",
"received": [],
"sent": [],
"received": [
{
"absender": [
"Alice 3",
"alice@senior.de"
],
"empfaenger": [
[
null,
"bob@filius.de"
]
],
"cc": [],
"bcc": [],
"betreff": "RE: test3",
"text": "Bob 1 schrieb:\n>",
"dateReceived": "",
"neu": true,
"delete": false,
"versendet": false
}
],
"sent": [
{
"absender": [
"Rechner 1",
"rechner1@filius.de"
],
"empfaenger": [
[
null,
"rechner3@senior.de"
]
],
"cc": [],
"bcc": [],
"betreff": "test",
"text": "test",
"dateReceived": "",
"neu": true,
"delete": false,
"versendet": false
},
{
"absender": [
"Bob 1",
"bob@filius.de"
],
"empfaenger": [
[
null,
"alice@senior.de"
]
],
"cc": [],
"bcc": [],
"betreff": "test3",
"text": "",
"dateReceived": "",
"neu": true,
"delete": false,
"versendet": false
},
{
"absender": [
"Bob 1",
"bob@filius.de"
],
"empfaenger": [
[
null,
"alice@senior.de"
]
],
"cc": [],
"bcc": [],
"betreff": "test bl",
"text": "test bl",
"dateReceived": "",
"neu": true,
"delete": false,
"versendet": false
}
],
"drafts": [],
"addressBook": [],
"fileAccount": {
@@ -11905,7 +12417,61 @@
"class": "filius.software.email.EmailServer",
"aktiv": true,
"mailDomain": "filius.de",
"beanAccounts": [],
"beanAccounts": [
{
"benutzername": "bob",
"passwort": "bob",
"nachname": "Nachname",
"vorname": "Vorname",
"emailAdresse": null,
"pop3server": null,
"pop3port": null,
"smtpserver": null,
"smtpport": null,
"nachrichten": [
{
"absender": [
"Alice 3",
"alice@senior.de"
],
"empfaenger": [
[
"Bob 1",
"bob@filius.de"
]
],
"cc": [],
"bcc": [],
"betreff": "RE: test bl",
"text": "huhu bob!\n\nBob 1 <bob@filius.de> schrieb:\n> test bl\n>\n",
"dateReceived": "",
"neu": true,
"delete": false,
"versendet": false
},
{
"absender": [
"Alice 3",
"alice@senior.de"
],
"empfaenger": [
[
null,
"bob@filius.de"
]
],
"cc": [],
"bcc": [],
"betreff": "Hi Bob!",
"text": "Hi BoB!\n",
"dateReceived": "",
"neu": true,
"delete": false,
"versendet": false
}
]
}
],
"fileAccounts": [
{
"benutzername": "bob",
@@ -12021,8 +12587,21 @@
"key": "filius.software.email.EmailServer",
"class": "filius.software.email.EmailServer",
"aktiv": true,
"mailDomain": "filius.de",
"beanAccounts": [],
"mailDomain": "senior.de",
"beanAccounts": [
{
"benutzername": "alice",
"passwort": "alice",
"nachname": "Nachname",
"vorname": "Vorname",
"emailAdresse": null,
"pop3server": null,
"pop3port": null,
"smtpserver": null,
"smtpport": null,
"nachrichten": []
}
],
"fileAccounts": [
{
"benutzername": "alice",
@@ -12217,7 +12796,7 @@
"font": null
}
],
"sha256": "f0449fcd25c2883580a8148b7e3aa2fd7318da423ae70f28326725a1f8737c5b"
"sha256": "f34f202638d8723ab709a39933495ef5028c2ba1b7dd41a7952c7af3c68f1102"
},
"java-examples/modem_beispiel.fls": {
"success": true,
@@ -17632,6 +18211,10 @@
{
"directory": "peer2peer",
"children": []
},
{
"directory": "mailserver",
"children": []
}
]
},
@@ -17660,6 +18243,178 @@
"port": 5353,
"recursiveResolutionEnabled": true
},
{
"key": "filius.software.email.EmailAnwendung",
"class": "filius.software.email.EmailAnwendung",
"received": [
{
"absender": [
"Anna",
null
],
"empfaenger": [
[
null,
"ben@schule.de"
],
[
"Carla",
"carla@schule.de"
]
],
"cc": [
[
"Dora",
"dora@schule.de"
]
],
"bcc": [
[
null,
"eva@schule.de"
]
],
"betreff": "Hallo",
"text": "Zeile 1\r\nZeile 2",
"dateReceived": "1727690000000",
"neu": true,
"delete": true,
"versendet": false
}
],
"sent": [
{
"absender": [
"Anna",
null
],
"empfaenger": [
[
null,
"ben@schule.de"
],
[
"Carla",
"carla@schule.de"
]
],
"cc": [
[
"Dora",
"dora@schule.de"
]
],
"bcc": [
[
null,
"eva@schule.de"
]
],
"betreff": "Hallo",
"text": "Zeile 1\r\nZeile 2",
"dateReceived": "1727690000000",
"neu": false,
"delete": true,
"versendet": true
}
],
"drafts": [
{
"absender": [
"Anna",
null
],
"empfaenger": [],
"cc": [
[
"Dora",
"dora@schule.de"
]
],
"bcc": [
[
null,
"eva@schule.de"
]
],
"betreff": null,
"text": null,
"dateReceived": null,
"neu": true,
"delete": true,
"versendet": false
}
],
"addressBook": [
[
"Muster",
"Anna",
null,
12,
20095,
"Hamburg",
"anna@schule.de",
null
]
],
"fileAccount": null
},
{
"key": "filius.software.email.EmailServer",
"class": "filius.software.email.EmailServer",
"aktiv": true,
"mailDomain": "schule.de",
"beanAccounts": [
{
"benutzername": "anna",
"passwort": "geheim",
"nachname": "Muster",
"vorname": "",
"emailAdresse": "anna@schule.de",
"pop3server": null,
"pop3port": null,
"smtpserver": null,
"smtpport": null,
"nachrichten": [
{
"absender": [
"Anna",
null
],
"empfaenger": [
[
null,
"ben@schule.de"
],
[
"Carla",
"carla@schule.de"
]
],
"cc": [
[
"Dora",
"dora@schule.de"
]
],
"bcc": [
[
null,
"eva@schule.de"
]
],
"betreff": "Hallo",
"text": "Zeile 1\r\nZeile 2",
"dateReceived": "1727690000000",
"neu": true,
"delete": true,
"versendet": false
}
]
}
],
"fileAccounts": null
},
{
"key": "filius.software.firewall.Firewall",
"class": "filius.software.firewall.Firewall",
@@ -17996,6 +18751,6 @@
"font": null
}
],
"sha256": "6d94879ad946a92c723e194ba5895eced6971e92438cad6991229062afa0cd1c"
"sha256": "e959ee2a763b90112bd773b8a31f2a27e9ce7bf01c07d2429b3d1426da471475"
}
}
+3
View File
@@ -56,6 +56,9 @@ packages/fls/::gesendete
packages/fls/::erstellte
packages/fls/::konten
packages/fls/::laden
# The directory Java FILIUS's EmailServer keeps its accounts in
# (/mailserver/konten.txt).
packages/fls/::mailserver
# Property names of Java FILIUS's Datei (dateiTyp, dateiInhalt) and Kontakt
# (hausnr), as Java's XMLDecoder and the Java oracle name them.
packages/fls/::datei
+1 -1
View File
@@ -41,7 +41,7 @@ virtuellen Bildschirm statt „headless".
die installierten Programme eines Rechners mit ihren Einstellungen (die
persönliche Firewall samt Regeln) (Klassen, die Filius
nicht mitbringt — eigene Anwendungen im Archiv unter `projekt/anwendungen`
— fehlen, weil das Werkzeug nur `konfiguration.xml` lädt); E-Mail: Konten des Servers aus der Bean-Liste und aus `/mailserver/konten.txt` (`kontenLaden`), Ordner und Adressbuch des Clients und sein Konto aus `/konten.txt` (`laden`); Kabel (Enden als Gerät/Schnittstelle),
— fehlen, weil das Werkzeug nur `konfiguration.xml` lädt); E-Mail: Konten des Servers aus der Bean-Liste und aus `/mailserver/konten.txt` (`kontenLaden`), Ordner und Adressbuch des Clients und sein Konto aus `/konten.txt` (`laden`); ein Empfänger, den eine ältere Datei als Zeichenkette hält, samt dem, was Javas `AddressEntry(String)` daraus macht; Kabel (Enden als Gerät/Schnittstelle),
Doku-Elemente.
## Getter-Standardwerte
+4 -2
View File
@@ -440,13 +440,15 @@ public class FlsOracle {
/**
* Older files keep recipients as strings: the list is typed, but the
* decoder does not check, so an element may be a String.
* decoder does not check, so an element may be a String. With it, how
* Java's own AddressEntry(String) reads it.
*/
static List<Object> addresses(List<AddressEntry> entries) {
List<Object> result = new ArrayList<>();
for (Object entry : entries) {
if (entry == null) result.add(null);
else result.add(entry instanceof AddressEntry address ? address(address) : Arrays.asList("string", entry.toString()));
else result.add(entry instanceof AddressEntry address ? address(address)
: Arrays.asList("string", entry.toString(), address(new AddressEntry(entry.toString()))));
}
return result;
}