package dslab.mailbox; import dslab.Email; import dslab.Message; import dslab.exception.MalformedInputException; import dslab.exception.UnknownRecipientException; import java.io.*; import java.net.Socket; import java.net.SocketException; import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedList; import java.util.concurrent.ConcurrentHashMap; import java.util.logging.Logger; public class DMTPConnection implements Runnable { Logger logger = Logger.getLogger(DMTPConnection.class.getName()); private final Socket socket; private PrintWriter out; private BufferedReader in; private Message msg = new Message(); private final String domain; private final ConcurrentHashMap> messageStorage; private final ConcurrentHashMap userStorage; public DMTPConnection(Socket connection, ConcurrentHashMap> messageStorage, ConcurrentHashMap userStorage, String domain) { this.socket = connection; this.messageStorage = messageStorage; this.userStorage = userStorage; this.domain = domain; } @Override public void run() { logger.finer("Preparing for DMTP communication in " + this.toString()); try { this.out = new PrintWriter(socket.getOutputStream(), true); this.in = new BufferedReader(new InputStreamReader(socket.getInputStream())); out.println("ok DMTP"); String userInput; try { if (!("begin".equals(in.readLine()))) { out.println("error protocol error"); shutdown(); } } catch (SocketException e) { // Thrown if socket has already been closed by shutdown() method logger.finer("Received interrupt. Exiting " + this.toString()); shutdown(); } out.println("ok"); while (!Thread.currentThread().isInterrupted() && (userInput = in.readLine()) != null) { if ("quit".equals(userInput)) { out.println("ok bye"); shutdown(); } else if ("send".equals(userInput)) { try { storeMessage(); out.println("ok"); } catch (UnknownRecipientException e) { out.println(e.getMessage()); } } else if ("to".equals(userInput.split("\\s+")[0])) { msg.setTo(new ArrayList<>()); String[] emailAddresses = userInput.split("\\s+")[1].split(","); logger.info("Split EMail addresses: " + Arrays.toString(emailAddresses)); int count = 0; try { for (String emailAddress : emailAddresses) { logger.info("Current email address in msg.getTo(): " + emailAddress); Email add = new Email(emailAddress); if (this.domain.equals(add.getDomain())) { logger.info("Address " + emailAddress + " belongs to this domain " + this.domain); if (!this.userStorage.containsKey(add.getUsername())) { logger.info("Our userStorage in domain " + this.domain + " does not contain user " + add.getUsername()); out.println("error unknown recipient " + add.toString()); } else { logger.info("Address " + add.toString() + " belongs to this domain and user exists. Adding address to msg.To() field"); msg.addTo(add); count++; } } } out.println("ok " + count); } catch (MalformedInputException e) { out.println(e.getMessage()); } } else if ("from".equals(userInput.split("\\s+")[0])) { try { Email from = new Email(userInput.split("\\s+")[1]); this.msg.setFrom(from); out.println("ok"); } catch (MalformedInputException mie) { out.println(mie.getMessage()); } } else if ("subject".equals(userInput.split("\\s+")[0])) { String subject = ""; if (userInput.split("\\s+").length > 1) subject = userInput.split("\\s+", 2)[1]; msg.setSubject(subject); out.println("ok"); } else if ("data".equals(userInput.split("\\s+")[0])) { String data = userInput.split("\\s+", 2)[1]; msg.setData(data); out.println("ok"); } else { out.println("error protocol error"); shutdown(); } } } catch (InterruptedIOException ioe) { logger.info("Received interrupt from parent. Shutting down..."); shutdown(); } catch (IOException e) { logger.severe("Failed to get IO-Stream"); e.printStackTrace(); shutdown(); } } private synchronized void storeMessage() throws UnknownRecipientException { logger.info("Storing message " + msg.toString()); this.msg.setId(MailboxServer.id++); String errorUnknownRecipient = ""; for (Email recipient : this.msg.getTo()) { if (this.messageStorage.containsKey(recipient)) { this.messageStorage.get(recipient).add(this.msg); } else { if (errorUnknownRecipient.isBlank()) errorUnknownRecipient = "error unknown recipient " + recipient.getUsername(); } } if (!errorUnknownRecipient.isBlank()) throw new UnknownRecipientException(errorUnknownRecipient); this.msg = new Message(); } public void shutdown() { logger.info("Shutting down client connection " + this.toString()); try { if (socket != null) socket.close(); in.close(); out.close(); } catch (IOException e) { logger.severe("Error closing socket and/or IO-streams"); e.printStackTrace(); } Thread.currentThread().interrupt(); } }