Where the Swift template departs from Java's filius.software.rip, Java's code rules: a learned route gets 16 hops at the router's next beacon after it expired (RIPTable.check), not when it expires; messages count from any source port; each router draws its pauses from a random of its own (Java: an unseeded Random per router), which the core seeds from the scenario and the router's id (ripSeed), so that the Java oracle can give it the same. A route of hop count 0 to each own network, the first beacon after a second, then every 25.2 to 35.2 s; a message per interface without the routes through it; a new route or a longer one from the same router sends at once; forwarding by the table alone, fewest hops before longest mask. Messages are read with Java's parser (javaIpCheck, javaParseInt, moved from fls to core for it). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
134 lines
5.3 KiB
TypeScript
134 lines
5.3 KiB
TypeScript
// The e-mail programs of a host in the editor model (Swift's
|
|
// registerJavaEmailConfigurations), from Java's view (javaEmail.ts). Java
|
|
// decides what the programs hold; its errors are not copied:
|
|
// - the server's accounts are those of /mailserver/konten.txt, which Java
|
|
// reads at every simulation start; without the file, those of the bean
|
|
// list, which Java would drop there;
|
|
// - the client's account is that of /konten.txt; without it, the first of
|
|
// an older file's kontoListe, which FILIUS 2.14 no longer reads;
|
|
// - a recipient an older file keeps as a string is read as an address.
|
|
// Departures from Swift (named in importProject.test.ts): accounts and
|
|
// messages stay as Java has them, where Swift drops what fails its checks;
|
|
// first and last name stay apart; a port that is no number is the default
|
|
// with a warning (Swift drops the account); a message's date is taken only
|
|
// when the file gives one (Swift numbers a mailbox's messages instead).
|
|
|
|
import {
|
|
DEFAULT_POP3_PORT,
|
|
DEFAULT_SMTP_PORT,
|
|
type EmailAddress,
|
|
type EmailClientAccount,
|
|
type EmailClientConfiguration,
|
|
type EmailContact,
|
|
type EmailMessage,
|
|
type EmailServerConfiguration,
|
|
} from '@mdg-filius/core';
|
|
import { addressEntry, type JavaEmail, type JavaEmailAccount, type JavaRecipient } from './javaEmail.js';
|
|
import { javaParseInt } from '@mdg-filius/core';
|
|
import type { FlsApplication } from './systemSoftware.js';
|
|
|
|
type Warn = (message: string) => void;
|
|
|
|
export function emailClientConfiguration(application: FlsApplication, warn: Warn): EmailClientConfiguration {
|
|
const source = application.fileAccount ?? application.legacyAccounts?.[0] ?? null;
|
|
const numbering = { next: 1 };
|
|
const inbox = emailMessages(application.received ?? [], numbering, undefined, warn);
|
|
const sent = emailMessages(application.sent ?? [], numbering, true, warn);
|
|
const drafts = emailMessages(application.drafts ?? [], numbering, false, warn);
|
|
return {
|
|
account: source === null ? null : clientAccount(source, warn),
|
|
inbox,
|
|
sent,
|
|
drafts,
|
|
addressBook: (application.addressBook ?? []).map(
|
|
(contact): EmailContact => ({
|
|
name: contact.name ?? '',
|
|
firstName: contact.firstName ?? '',
|
|
street: contact.street ?? '',
|
|
houseNumber: contact.houseNumber,
|
|
postalCode: contact.postalCode,
|
|
city: contact.city ?? '',
|
|
email: contact.email ?? '',
|
|
phone: contact.phone ?? '',
|
|
}),
|
|
),
|
|
nextMessageID: numbering.next,
|
|
};
|
|
}
|
|
|
|
export function emailServerConfiguration(application: FlsApplication, warn: Warn): EmailServerConfiguration {
|
|
const accounts = Array.isArray(application.fileAccounts) ? application.fileAccounts : (application.beanAccounts ?? []);
|
|
const numbering = { next: 1 };
|
|
return {
|
|
domain: application.mailDomain ?? 'filius.de',
|
|
pop3Port: DEFAULT_POP3_PORT,
|
|
accounts: accounts.map((account) => ({
|
|
username: account.username ?? '',
|
|
password: account.password ?? '',
|
|
firstName: account.firstName,
|
|
lastName: account.lastName,
|
|
mailbox: emailMessages(account.messages, numbering, undefined, warn),
|
|
})),
|
|
nextMessageID: numbering.next,
|
|
};
|
|
}
|
|
|
|
function clientAccount(account: JavaEmailAccount, warn: Warn): EmailClientAccount {
|
|
return {
|
|
pop3Host: account.pop3Server ?? '',
|
|
pop3Port: port(account.pop3Port, DEFAULT_POP3_PORT, 'POP3', warn),
|
|
smtpHost: account.smtpServer ?? '',
|
|
smtpPort: port(account.smtpPort, DEFAULT_SMTP_PORT, 'SMTP', warn),
|
|
username: account.username ?? '',
|
|
password: account.password ?? '',
|
|
firstName: account.firstName,
|
|
lastName: account.lastName,
|
|
email: account.emailAddress ?? '',
|
|
};
|
|
}
|
|
|
|
/** A port as Java's client reads it (Integer.parseInt); none or no port is the default. */
|
|
function port(text: string | null, fallback: number, protocol: string, warn: Warn): number {
|
|
if (text === null) return fallback;
|
|
const value = javaParseInt(text);
|
|
if (value !== undefined && value >= 0 && value <= 65_535) return value;
|
|
warn(`e-mail client: ${protocol} port '${text}' is not a port, used ${fallback}`);
|
|
return fallback;
|
|
}
|
|
|
|
/** Numbered on from `numbering.next`; `isSent` is the folder's when it has one. */
|
|
function emailMessages(
|
|
messages: readonly JavaEmail[],
|
|
numbering: { next: number },
|
|
isSent: boolean | undefined,
|
|
warn: Warn,
|
|
): EmailMessage[] {
|
|
return messages.map((message) => {
|
|
const received = message.dateReceived !== null && /^[0-9]+$/.test(message.dateReceived) ? Number(message.dateReceived) : undefined;
|
|
return {
|
|
id: numbering.next++,
|
|
from: { name: message.sender.name, mailAddress: message.sender.mailAddress },
|
|
to: recipients(message.to, warn),
|
|
cc: recipients(message.cc, warn),
|
|
bcc: recipients(message.bcc, warn),
|
|
subject: message.subject ?? '',
|
|
body: message.text ?? '',
|
|
...(received === undefined ? {} : { receivedAtMilliseconds: received }),
|
|
isNew: message.isNew,
|
|
isMarkedForDeletion: message.isDeleted,
|
|
isSent: isSent ?? message.isSent,
|
|
};
|
|
});
|
|
}
|
|
|
|
function recipients(entries: readonly JavaRecipient[], warn: Warn): EmailAddress[] {
|
|
return entries.flatMap((entry) => {
|
|
if (entry === null) {
|
|
warn('an e-mail recipient is null, left out');
|
|
return [];
|
|
}
|
|
const address = typeof entry === 'string' ? addressEntry(entry) : entry;
|
|
return [{ name: address.name, mailAddress: address.mailAddress }];
|
|
});
|
|
}
|