feat(editor): F4.6e the e-mail program and e-mail server on a computer's desktop
The oracle MailWindowRun uses Java's e-mail windows as a person does and answers their dialogs. The core sets and saves the program's account, deletes a mail, checks a form as Java's window does, and gives the server its domain, new and removed accounts and the window's own line; the room sends both programs' views and takes their actions; the editor has both windows. Better than Java: a name field for a new account, a user name the server has is refused, deleting hits the folder shown, a new domain goes into the accounts file at once. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -19,8 +19,9 @@
|
||||
// Java's do (TerminalWindow, BrowserWindow).
|
||||
//
|
||||
// A program's window may show more than its lines (plan §7.3): the browser's
|
||||
// page, the web server's button and table go to the clients as a view,
|
||||
// whole, when they change.
|
||||
// page, the web server's button and table, the e-mail program's account and
|
||||
// folders, the e-mail server's domain and accounts go to the clients as a
|
||||
// view, whole, when they change.
|
||||
//
|
||||
// While the simulation runs, the document's programs are watched: a program
|
||||
// installed or removed on the desktop (Java's software installation) is
|
||||
@@ -29,6 +30,7 @@
|
||||
|
||||
import * as Y from 'yjs';
|
||||
import {
|
||||
accountOfForm,
|
||||
DEFAULT_SPEED_PERCENT,
|
||||
NetworkRuntimeEngine,
|
||||
captureRows,
|
||||
@@ -53,6 +55,8 @@ import {
|
||||
type NodeSettings,
|
||||
type SimMode,
|
||||
type Topic,
|
||||
type EmailClientView,
|
||||
type EmailServerView,
|
||||
type TraceFrame,
|
||||
type WebServerView,
|
||||
} from '@mdg-filius/protocol';
|
||||
@@ -324,6 +328,68 @@ export class SimulationRoom {
|
||||
return this.actInBrowser(input);
|
||||
case 'webServer':
|
||||
return this.actInWebServer(input);
|
||||
case 'emailClient':
|
||||
return this.actInEmailClient(input);
|
||||
case 'emailServer':
|
||||
return this.actInEmailServer(input);
|
||||
default:
|
||||
return 'unknownAction';
|
||||
}
|
||||
}
|
||||
|
||||
/** The account dialog (setAccount), the compose window (send), fetching and deleting a mail of a folder. */
|
||||
private actInEmailClient(input: Extract<ClientMessage, { kind: 'input' }>): ErrorCode | undefined {
|
||||
const client = this.engine.emailClient(input.node);
|
||||
if (client === undefined) return 'unknownApp';
|
||||
const { args } = input;
|
||||
const text = (...names: string[]) => names.every((name) => typeof args[name] === 'string');
|
||||
switch (input.action) {
|
||||
case 'setAccount': {
|
||||
if (!text('name', 'email', 'pop3Host', 'pop3Port', 'smtpHost', 'smtpPort', 'username', 'password')) return 'badArgs';
|
||||
const account = accountOfForm(args as unknown as Parameters<typeof accountOfForm>[0]);
|
||||
if (account === undefined) return 'badArgs';
|
||||
client.setAccount(account);
|
||||
return undefined;
|
||||
}
|
||||
case 'send':
|
||||
if (!text('to', 'cc', 'bcc', 'subject', 'text')) return 'badArgs';
|
||||
return client.send(args as unknown as Parameters<typeof client.send>[0]) === undefined ? undefined : 'badArgs';
|
||||
case 'fetch':
|
||||
// Without an account Java's button does nothing.
|
||||
client.fetch();
|
||||
return undefined;
|
||||
case 'removeMail':
|
||||
if ((args.folder !== 'inbox' && args.folder !== 'sent') || !Number.isInteger(args.index)) return 'badArgs';
|
||||
client.removeMail(args.folder, args.index as number);
|
||||
return undefined;
|
||||
default:
|
||||
return 'unknownAction';
|
||||
}
|
||||
}
|
||||
|
||||
/** The start button, the domain (only while the server is off, as Java's field), a new account and the removal of one. */
|
||||
private actInEmailServer(input: Extract<ClientMessage, { kind: 'input' }>): ErrorCode | undefined {
|
||||
const server = this.engine.emailServer(input.node);
|
||||
if (server === undefined) return 'unknownApp';
|
||||
const { args } = input;
|
||||
switch (input.action) {
|
||||
case 'setActive':
|
||||
if (typeof args.active !== 'boolean') return 'badArgs';
|
||||
server.setActive(args.active, true);
|
||||
return undefined;
|
||||
case 'setDomain':
|
||||
if (typeof args.domain !== 'string') return 'badArgs';
|
||||
return !server.isActive && server.setDomain(args.domain) ? undefined : 'badArgs';
|
||||
case 'addAccount': {
|
||||
const { username, password, firstName, lastName } = args;
|
||||
if (typeof username !== 'string' || typeof password !== 'string' || typeof firstName !== 'string' || typeof lastName !== 'string') return 'badArgs';
|
||||
// The window's checks: a user name and a password, the name without white space (musterKeineLeerzeichen).
|
||||
if (username === '' || password === '' || /[ \t\n\v\f\r]/.test(username)) return 'badArgs';
|
||||
return server.addAccount({ username, password, firstName, lastName }) ? undefined : 'badArgs';
|
||||
}
|
||||
case 'removeAccount':
|
||||
if (typeof args.username !== 'string') return 'badArgs';
|
||||
return server.removeAccount(args.username) ? undefined : 'badArgs';
|
||||
default:
|
||||
return 'unknownAction';
|
||||
}
|
||||
@@ -401,6 +467,22 @@ export class SimulationRoom {
|
||||
const view: WebServerView = { active: server.isActive, useVirtualHosts: server.useVirtualHosts, virtualHosts: server.virtualHostTable.map(([host, folder]) => [host, folder] as const) };
|
||||
return view;
|
||||
}
|
||||
case 'emailClient': {
|
||||
const client = this.engine.emailClient(node);
|
||||
if (client === undefined) return null;
|
||||
const view: EmailClientView = { account: client.account, inbox: client.inbox.map((entry) => entry.mail), sent: client.sent.map((entry) => entry.mail) };
|
||||
return view;
|
||||
}
|
||||
case 'emailServer': {
|
||||
const server = this.engine.emailServer(node);
|
||||
if (server === undefined) return null;
|
||||
const view: EmailServerView = {
|
||||
active: server.isActive,
|
||||
domain: server.domain,
|
||||
accounts: server.state.accounts.map((account) => ({ username: account.username, mails: account.mailbox.length })),
|
||||
};
|
||||
return view;
|
||||
}
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user