diff --git a/CHANGES.md b/CHANGES.md index 7cee2b0..d93346b 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -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 ``; 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 | diff --git a/corpus/corpus.java.json b/corpus/corpus.java.json index 0a4d3f4..a79057a 100644 --- a/corpus/corpus.java.json +++ b/corpus/corpus.java.json @@ -11791,7 +11791,11 @@ "empfaenger": [ [ "string", - "rechner3@senior.de" + "rechner3@senior.de", + [ + null, + "rechner3@senior.de" + ] ] ], "cc": [], @@ -11811,7 +11815,11 @@ "empfaenger": [ [ "string", - "alice@senior.de" + "alice@senior.de", + [ + null, + "alice@senior.de" + ] ] ], "cc": [], @@ -11853,7 +11861,11 @@ "empfaenger": [ [ "string", - "Bob@filius.de" + "Bob@filius.de", + [ + null, + "Bob@filius.de" + ] ] ], "cc": [], @@ -11873,7 +11885,11 @@ "empfaenger": [ [ "string", - "bob@filius.de" + "bob@filius.de", + [ + null, + "bob@filius.de" + ] ] ], "cc": [], @@ -11893,7 +11909,11 @@ "empfaenger": [ [ "string", - "bob@filius.de" + "bob@filius.de", + [ + null, + "bob@filius.de" + ] ] ], "cc": [], @@ -11913,7 +11933,11 @@ "empfaenger": [ [ "string", - "bob@filius.de" + "bob@filius.de", + [ + null, + "bob@filius.de" + ] ] ], "cc": [], @@ -12144,7 +12168,11 @@ "empfaenger": [ [ "string", - "bob@filius.de" + "bob@filius.de", + [ + null, + "bob@filius.de" + ] ] ], "cc": [], @@ -12166,7 +12194,11 @@ "empfaenger": [ [ "string", - "rechner3@senior.de" + "rechner3@senior.de", + [ + null, + "rechner3@senior.de" + ] ] ], "cc": [], @@ -12186,7 +12218,11 @@ "empfaenger": [ [ "string", - "alice@senior.de" + "alice@senior.de", + [ + null, + "alice@senior.de" + ] ] ], "cc": [], diff --git a/packages/fls/src/topologyWriter.ts b/packages/fls/src/topologyWriter.ts index e88cb0c..814cc40 100644 --- a/packages/fls/src/topologyWriter.ts +++ b/packages/fls/src/topologyWriter.ts @@ -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; +/** + * 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; /** The system software's settings, files and applications. */ export type SystemToWrite = Omit & { @@ -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] }))); diff --git a/packages/fls/test/javaEmailNames.ts b/packages/fls/test/javaEmailNames.ts index 531283a..74731d8 100644 --- a/packages/fls/test/javaEmailNames.ts +++ b/packages/fls/test/javaEmailNames.ts @@ -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), diff --git a/packages/fls/test/topologyWriter.test.ts b/packages/fls/test/topologyWriter.test.ts index 264ced7..8161f91 100644 --- a/packages/fls/test/topologyWriter.test.ts +++ b/packages/fls/test/topologyWriter.test.ts @@ -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; /** - * 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) { - if (system.applications === undefined) return system; - const applications = (system.applications as Record[]).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,11 +103,53 @@ 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 ', 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 = {}) { + 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 = '

a & b

\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', '

own

')] }, { 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', diff --git a/packages/fls/test/written.java.json b/packages/fls/test/written.java.json index dbd773c..84e49b3 100644 --- a/packages/fls/test/written.java.json +++ b/packages/fls/test/written.java.json @@ -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 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 schrieb:\n> Hi Herbert Again!\n> \n> Herbert Schmidt schrieb:\n> > Hallo Frimp!\n> > \n> > Frimp Müller 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 schrieb:\n> Hallo Frimp!\n> \n> Frimp Müller 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 schrieb:\n> Hallo Frimp!\n> \n> Frimp Müller 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 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 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" } } diff --git a/scripts/code_language_allow.txt b/scripts/code_language_allow.txt index bc91a02..292dc92 100644 --- a/scripts/code_language_allow.txt +++ b/scripts/code_language_allow.txt @@ -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 diff --git a/tools/java-oracle/README.md b/tools/java-oracle/README.md index 435fc48..a1a1e6a 100644 --- a/tools/java-oracle/README.md +++ b/tools/java-oracle/README.md @@ -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 diff --git a/tools/java-oracle/src/FlsOracle.java b/tools/java-oracle/src/FlsOracle.java index 22d0688..393552e 100644 --- a/tools/java-oracle/src/FlsOracle.java +++ b/tools/java-oracle/src/FlsOracle.java @@ -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 addresses(List entries) { List 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; }