// Runs a story of FILIUS' e-mail server (EmailServer with its SMTPServer and // POP3Server) on a core scenario's network in Java FILIUS and records what // really happens: every frame each card saw, every line the server wrote // into its window, every line of the generic client that talks to it, and // the server's accounts at the end (each message as Email.toString, whether // it is new, whether it is marked for deletion). // // EmailRun // // The stories use mail-lan (client on 192.168.0.20, e-mail server on .30, // domain filius.de). The server's accounts come from /mailserver/konten.txt // as below (anna with two messages, from bob and from carla; bob without), // switched on. // FILIUS' generic client (ClientBaustein) on .20 sends the commands as they // are, one message each, after a pause for the answer. // smtp to anna, then QUIT // smtpErrors commands out of order, then a mail to a recipient the // domain does not know (a notice goes to the local sender) // pop3 log in, STAT, LIST, RETR and DELE both messages, QUIT; // again: log in, STAT, QUIT // pop3Errors unknown user, PASS before USER, wrong password, NOOP before // and after log-in, USER after log-in // Java's errors in these dialogues are measured without a network // (MailCases), so the stories keep to what Java does right. import filius.software.clientserver.ClientBaustein; import filius.software.email.Email; import filius.software.email.EmailKonto; import filius.software.email.EmailServer; import filius.software.system.Datei; import filius.software.system.Dateisystem; import java.util.ArrayList; import java.util.List; public class EmailRun { static final String CLIENT = "00000000-0000-0000-0000-000000000201"; static final String SERVER = "00000000-0000-0000-0000-000000000203"; /** The server's accounts before the run, in EmailServer's file format. */ static final String ACCOUNTS = "anna;filius.de;geheim;Muster;Anna;#Bob Beispiel $$$$$Hallo Anna$Erste Zeile|Zweite Zeile" + "#Carla $Anna Muster ,$$$$Termin$Morgen um 10?\n" + "bob;filius.de;passwort;Beispiel;Bob;\n"; static ScenarioNetwork network; static ClientBaustein client; static final List events = new ArrayList<>(); static synchronized void event(String who, String what) { events.add(new Object[] { System.currentTimeMillis() - network.start, who, what }); } static void sleepUntil(long milliseconds) throws InterruptedException { long rest = network.start + milliseconds - System.currentTimeMillis(); if (rest > 0) Thread.sleep(rest); } static long at; static void connect(int port) throws InterruptedException { sleepUntil(at); client.setZielIPAdresse("192.168.0.30"); client.setZielPort(port); event("client", "call verbinden " + port); client.verbinden(); at += 2500; } /** Each command after the answer to the one before. */ static void send(String... messages) throws InterruptedException { for (String message : messages) { sleepUntil(at); event("client", "call senden " + message); client.senden(message); at += 1500; } } public static void main(String[] args) throws Exception { network = ScenarioNetwork.read(args[0]); String story = args[1]; long end = Long.parseLong(args[2]); network.system(SERVER).installApp("filius.software.email.EmailServer", false); EmailServer server = (EmailServer) network.system(SERVER).holeSoftware("filius.software.email.EmailServer"); Dateisystem files = network.system(SERVER).getDateisystem(); files.speicherDatei("/mailserver", new Datei("konten.txt", "txt", ACCOUNTS)); server.setMailDomain("filius.de"); server.setAktiv(true); server.hinzuBeobachter((observable, data) -> event("server", String.valueOf(data))); network.system(CLIENT).installApp("filius.software.clientserver.ClientBaustein", false); client = (ClientBaustein) network.system(CLIENT).holeSoftware("filius.software.clientserver.ClientBaustein"); client.hinzuBeobachter((observable, data) -> event("client", String.valueOf(data))); network.start(); at = 500; switch (story) { case "smtp": connect(25); send("HELO 192.168.0.20", "MAIL FROM: ", "RCPT TO:", "DATA", "From: Bob Beispiel \nTo: \nSubject: Gruß\n\nHallo Anna,\nwie geht's?\r\n.\r\n", "QUIT"); break; case "smtpErrors": connect(25); send("NOOP", "EHLO", "DATA", "MAIL FROM: bob@filius.de", "RCPT TO:", "DATA", "MAIL FROM:", "RCPT TO: anna", "NOOP", "DATA", "From: \nTo: \nSubject: Wer?\n\nIst da jemand?\n.\n", "QUIT"); break; case "pop3": connect(110); send("USER anna", "PASS geheim", "STAT", "LIST", "RETR 0", "RETR 1", "DELE 0", "DELE 1", "QUIT"); at += 1000; connect(110); send("USER anna", "PASS geheim", "STAT", "QUIT"); break; case "pop3Errors": connect(110); send("NOOP", "USER niemand", "PASS x", "USER anna", "PASS falsch", "PASS geheim", "NOOP", "USER bob", "QUIT"); break; default: throw new IllegalArgumentException("unknown story " + story); } sleepUntil(Math.max(end, at + 3000)); ScenarioNetwork.Json out = new ScenarioNetwork.Json(); out.open('{'); network.writeFrames(out); synchronized (EmailRun.class) { out.key("events").open('['); for (Object[] each : events) out.open('[').number((Long) each[0]).string((String) each[1]).string((String) each[2]).close(']'); out.close(']'); } out.key("accounts").open('['); for (EmailKonto account : server.getListeBenutzerkonten()) { out.open('[').string(account.getBenutzername()); for (Email email : account.getNachrichten()) { out.open('[').string(email.toString()).string(String.valueOf(email.getNeu())).string(String.valueOf(email.getDelete())).close(']'); } out.close(']'); } out.close(']'); out.key("file").string(files.holeDatei("/mailserver/konten.txt").getDateiInhalt()); out.close('}'); network.stop(); ScenarioNetwork.write(args[3], out); System.exit(0); } }