feat(fls): Java's view of the e-mail programs
The Java view now reads what FILIUS 2.14 keeps for its e-mail programs: the server's domain, switch and bean accounts with their mailboxes, and the accounts of /mailserver/konten.txt, which Java reads at every simulation start and which so win over the bean list; the client's three folders and address book, and its account from /konten.txt (no bean holds it). javaEmail.ts ports the bean setters and both file readers (stringZuListeBenutzerkonten, EmailKonto(String)); javaString.ts Java's trim, split and StringTokenizer; javaFileSystem.ts the file lookup, now shared with the DNS server, with the four non-ASCII units Java's equalsIgnoreCase also takes for an ASCII letter (measured over the BMP). Checked against Java on the corpus (the oracle dumps the e-mail state) and on 43 account files read by EmailServer.kontenLaden and EmailAnwendung.laden (EmailFileCases). Found: older files keep recipients as strings in the typed lists; a getter copy of the sender is filled and set back; one short server line makes Java throw for the whole file; a message with an empty text is lost on reading; a broken last client line empties the account. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -11,7 +11,9 @@
|
||||
// - duplicates stay.
|
||||
|
||||
import type { DnsResourceRecord } from '@mdg-filius/core';
|
||||
import { javaFileContent } from './javaFileSystem.js';
|
||||
import { javaIpCheck, javaParseInt } from './javaIp.js';
|
||||
import { javaTrim } from './javaString.js';
|
||||
import type { FlsFileTree } from './systemSoftware.js';
|
||||
|
||||
/** A record as Java's ResourceRecord holds it (the getters). */
|
||||
@@ -27,51 +29,14 @@ export const DNS_HOSTS_PATH = '/dns/hosts';
|
||||
// EingabenUeberpruefung.musterDomain, including its quirks: labels start with
|
||||
// a letter, labels after the first may hold a backslash, and the empty
|
||||
// string is a valid domain.
|
||||
const JAVA_DOMAIN = /^([a-zA-Z]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z]([a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])?)*)?\.?$/;
|
||||
export const JAVA_DOMAIN = /^([a-zA-Z]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z]([a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])?)*)?\.?$/;
|
||||
// EingabenUeberpruefung.musterIpAdresse.
|
||||
const JAVA_IP_ADDRESS =
|
||||
/^(0*([1-9]?[0-9]?|1[0-9]{1,2}|2[0-4]?[0-9]|25[0-5]))\.((0*(1?[0-9]{1,2}|2[0-4]?[0-9]|25[0-5]))\.){2}(0*(1?[0-9]{1,2}|2[0-4]?[0-9]|25[0-5]))$/;
|
||||
|
||||
/** `String.trim()`: every UTF-16 unit up to U+0020 off both ends. */
|
||||
function javaTrim(text: string): string {
|
||||
return text.replace(/^[\u0000-\u0020]+|[\u0000-\u0020]+$/g, '');
|
||||
}
|
||||
|
||||
/**
|
||||
* The content of /dns/hosts as `Dateisystem.holeDatei` finds it: the first
|
||||
* node in preorder whose path equals it ignoring case, and only if that node
|
||||
* is a file. Undefined when there is none; a file without content reads as
|
||||
* empty (Java would fail on it).
|
||||
*/
|
||||
/** The content of /dns/hosts as Java's DNS server finds it (see javaFileSystem.ts). */
|
||||
export function javaHostsFileContent(root: FlsFileTree | undefined): string | undefined {
|
||||
if (root === undefined) return undefined;
|
||||
const found = firstInPreorder(root, '', (path) => javaEqualsIgnoreCase(path, DNS_HOSTS_PATH));
|
||||
return found?.kind === 'file' ? (found.content ?? '') : undefined;
|
||||
}
|
||||
|
||||
/** Preorder below the root; a node's path is "/" plus each name after the root's. */
|
||||
function firstInPreorder(node: FlsFileTree, path: string, matches: (path: string) => boolean): FlsFileTree | undefined {
|
||||
for (const child of node.children) {
|
||||
const childPath = `${path}/${child.kind === 'other' ? child.className : String(child.name)}`;
|
||||
if (matches(childPath)) return child;
|
||||
const found = firstInPreorder(child, childPath, matches);
|
||||
if (found !== undefined) return found;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* `String.equalsIgnoreCase` against an ASCII path, unit by unit: equal after
|
||||
* Character.toUpperCase, so the long s (U+017F) is an "s". Java also
|
||||
* compares the lower case of both; for the letters of /dns/hosts that adds
|
||||
* no unit (measured over the BMP).
|
||||
*/
|
||||
function javaEqualsIgnoreCase(text: string, asciiPath: string): boolean {
|
||||
if (text.length !== asciiPath.length) return false;
|
||||
for (let index = 0; index < text.length; index++) {
|
||||
if (text[index]!.toUpperCase() !== asciiPath[index]!.toUpperCase()) return false;
|
||||
}
|
||||
return true;
|
||||
return javaFileContent(root, DNS_HOSTS_PATH);
|
||||
}
|
||||
|
||||
/** `DNSServer.leseRecordListe` on the content of /dns/hosts. */
|
||||
|
||||
Reference in New Issue
Block a user