commit 2100aee601b61244789384a4e255e6952fb18c9b Author: jzitnik-dev Date: Thu Oct 16 12:29:15 2025 +0200 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5ff6309 --- /dev/null +++ b/.gitignore @@ -0,0 +1,38 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..aa00ffa --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..039a9d1 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..d13f378 --- /dev/null +++ b/pom.xml @@ -0,0 +1,25 @@ + + + 4.0.0 + + cz.jzitnik + MeitSort + 1.0-SNAPSHOT + + + 22 + 22 + UTF-8 + + + + + com.sun.mail + jakarta.mail + 2.0.1 + + + + \ No newline at end of file diff --git a/src/main/java/cz/jzitnik/GlobalContext.java b/src/main/java/cz/jzitnik/GlobalContext.java new file mode 100644 index 0000000..91f2549 --- /dev/null +++ b/src/main/java/cz/jzitnik/GlobalContext.java @@ -0,0 +1,33 @@ +package cz.jzitnik; + +import cz.jzitnik.utils.mail.MailSender; +import jakarta.mail.Message; + +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; + +public class GlobalContext { + private final BlockingQueue blockingQueue = new LinkedBlockingQueue<>(); + private final MailSender mailSender; + private boolean waitingForMessage = false; + + public GlobalContext(MailSender mailSender) { + this.mailSender = mailSender; + } + + public BlockingQueue getBlockingQueue() { + return blockingQueue; + } + + public boolean isWaitingForMessage() { + return waitingForMessage; + } + + public void setWaitingForMessage(boolean waitingForMessage) { + this.waitingForMessage = waitingForMessage; + } + + public MailSender getMailSender() { + return mailSender; + } +} diff --git a/src/main/java/cz/jzitnik/Main.java b/src/main/java/cz/jzitnik/Main.java new file mode 100644 index 0000000..ebc5af1 --- /dev/null +++ b/src/main/java/cz/jzitnik/Main.java @@ -0,0 +1,56 @@ +package cz.jzitnik; + +import cz.jzitnik.algs.BubbleSort; +import cz.jzitnik.utils.SortingAlgorithm; +import cz.jzitnik.utils.mail.MailContextPool; +import cz.jzitnik.utils.mail.MailSender; +import cz.jzitnik.utils.mail.read.MailReadHandler; +import cz.jzitnik.utils.mail.read.MailReader; +import jakarta.mail.MessagingException; +import jakarta.mail.PasswordAuthentication; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Properties; + +public class Main { + private static MailContextPool getMailContextPool() { + Properties loginProps = new Properties(); + + loginProps.put("mail.smtp.auth", "true"); + loginProps.put("mail.smtp.starttls.enable", "true"); + loginProps.put("mail.smtp.host", "smtppro.zoho.eu"); + loginProps.put("mail.smtp.port", "587"); + + loginProps.put("mail.store.protocol", "imaps"); + loginProps.put("mail.imaps.host", "imappro.zoho.eu"); + loginProps.put("mail.imaps.port", "993"); + loginProps.put("mail.imaps.ssl.enable", "true"); + + return new MailContextPool( + loginProps, + new PasswordAuthentication("klindkubak@zohomail.eu", System.getenv("MEIT_PASSWORD")) + ); + } + + public static void main(String[] args) throws MessagingException, InterruptedException, IOException { + MailContextPool mailContextPool = getMailContextPool(); + + GlobalContext globalContext = new GlobalContext( + new MailSender(mailContextPool) + ); + + MailReader mailReader = new MailReader(mailContextPool, 1000, new MailReadHandler(globalContext)); + Thread thread = new Thread(mailReader); + thread.start(); + + SortingAlgorithm sortingAlgorithm = new BubbleSort(globalContext, "klindkubak@zohomail.eu", "sefljulie@zohomail.eu"); + + int[] arr = {3, 2, 1}; + int[] newArr = sortingAlgorithm.sort(arr); + + System.out.println(Arrays.toString(newArr)); + + System.exit(0); + } +} \ No newline at end of file diff --git a/src/main/java/cz/jzitnik/algs/BubbleSort.java b/src/main/java/cz/jzitnik/algs/BubbleSort.java new file mode 100644 index 0000000..586c4e2 --- /dev/null +++ b/src/main/java/cz/jzitnik/algs/BubbleSort.java @@ -0,0 +1,28 @@ +package cz.jzitnik.algs; + +import cz.jzitnik.GlobalContext; +import cz.jzitnik.utils.SortingAlgorithm; +import jakarta.mail.MessagingException; + +import java.io.IOException; + +public class BubbleSort extends SortingAlgorithm { + public BubbleSort(GlobalContext globalContext, String from, String recipient) { + super(globalContext, from, recipient); + } + + public int[] sort(int[] arr) throws MessagingException, InterruptedException, IOException { + int n = arr.length; + for (int i = 0; i < n - 1; i++) { + for (int j = 0; j < n - 1 - i; j++) { + if (compare(arr[j], arr[j + 1]) == ResponseAnswer.FIRST) { + int temp = arr[j]; + arr[j] = arr[j + 1]; + arr[j + 1] = temp; + } + } + } + + return arr; + } +} diff --git a/src/main/java/cz/jzitnik/utils/SortingAlgorithm.java b/src/main/java/cz/jzitnik/utils/SortingAlgorithm.java new file mode 100644 index 0000000..ef1a7e9 --- /dev/null +++ b/src/main/java/cz/jzitnik/utils/SortingAlgorithm.java @@ -0,0 +1,96 @@ +package cz.jzitnik.utils; + +import cz.jzitnik.GlobalContext; +import cz.jzitnik.utils.mail.MailSender; +import jakarta.mail.BodyPart; +import jakarta.mail.Message; +import jakarta.mail.MessagingException; +import jakarta.mail.Multipart; +import jakarta.mail.internet.InternetAddress; + +import java.awt.geom.RectangularShape; +import java.io.IOException; + +public abstract class SortingAlgorithm { + private final GlobalContext globalContext; + private final String from; + private final String recipient; + + protected enum ResponseAnswer { + FIRST, + SECOND, + SAME, + } + + public SortingAlgorithm(GlobalContext globalContext, String from, String recipient) { + this.globalContext = globalContext; + this.from = from; + this.recipient = recipient; + } + + protected ResponseAnswer compare(int x, int y) throws MessagingException, InterruptedException, IOException { + System.out.println("Sending email"); + MailSender mailSender = globalContext.getMailSender(); + + mailSender.sendMessage( + new InternetAddress(from), + InternetAddress.parse(recipient), + "Porovnání dvou čísel", + "Které číslo je větší? " + x + " nebo " + y + "? Pokud první odpovězte na email s textem PRVNI, pokud druhé tak DRUHE a pokud se rovnají odpovězte ROVNO." + ); + + globalContext.setWaitingForMessage(true); + + System.out.println("Waiting for response"); + + Message answer = globalContext.getBlockingQueue().take(); + globalContext.setWaitingForMessage(false); + + String answ = getTextFromMessage(answer).trim(); + + if (answ.startsWith("PRVNI")) { + return ResponseAnswer.FIRST; + } + + if (answ.startsWith("DRUHE")) { + return ResponseAnswer.SECOND; + } + + if (answ.startsWith("ROVNO")) { + return ResponseAnswer.SAME; + } + + return ResponseAnswer.FIRST; + } + + public abstract int[] sort(int[] arr) throws MessagingException, InterruptedException, IOException; + + + private String getTextFromMessage(Message message) throws MessagingException, IOException { + Object content = message.getContent(); + if (content instanceof String) { + // Plain text email + return (String) content; + } else if (content instanceof Multipart) { + Multipart multipart = (Multipart) content; + return getTextFromMultipart(multipart); + } + return ""; + } + + private String getTextFromMultipart(Multipart multipart) throws MessagingException, IOException { + for (int i = 0; i < multipart.getCount(); i++) { + BodyPart part = multipart.getBodyPart(i); + if (part.isMimeType("text/plain")) { + return (String) part.getContent(); + } else if (part.getContent() instanceof Multipart) { + // Nested multipart + String result = getTextFromMultipart((Multipart) part.getContent()); + if (!result.isEmpty()) { + return result; + } + } + } + return ""; + } +} diff --git a/src/main/java/cz/jzitnik/utils/mail/MailContextPool.java b/src/main/java/cz/jzitnik/utils/mail/MailContextPool.java new file mode 100644 index 0000000..104dd5f --- /dev/null +++ b/src/main/java/cz/jzitnik/utils/mail/MailContextPool.java @@ -0,0 +1,35 @@ +package cz.jzitnik.utils.mail; + +import jakarta.mail.PasswordAuthentication; +import jakarta.mail.Session; + +import java.util.Properties; + +public class MailContextPool { + private final Session session; + private final PasswordAuthentication passwordAuthentication; + private final Properties props; + + public MailContextPool(Properties properties, PasswordAuthentication passwordAuthentication) { + session = Session.getInstance(properties, + new jakarta.mail.Authenticator() { + protected PasswordAuthentication getPasswordAuthentication() { + return passwordAuthentication; + } + }); + this.passwordAuthentication = passwordAuthentication; + props = properties; + } + + public Session getSession() { + return session; + } + + public PasswordAuthentication getPasswordAuthentication() { + return passwordAuthentication; + } + + public Properties getProps() { + return props; + } +} diff --git a/src/main/java/cz/jzitnik/utils/mail/MailSender.java b/src/main/java/cz/jzitnik/utils/mail/MailSender.java new file mode 100644 index 0000000..18676b5 --- /dev/null +++ b/src/main/java/cz/jzitnik/utils/mail/MailSender.java @@ -0,0 +1,22 @@ +package cz.jzitnik.utils.mail; + +import jakarta.mail.Message; +import jakarta.mail.MessagingException; +import jakarta.mail.Transport; +import jakarta.mail.internet.InternetAddress; +import jakarta.mail.internet.MimeMessage; + +public record MailSender(MailContextPool mailContextPool) { + public void sendMessage(InternetAddress from, InternetAddress[] to, String subject, String text) throws MessagingException { + Message message = new MimeMessage(mailContextPool.getSession()); + message.setFrom(from); + message.setRecipients( + Message.RecipientType.TO, + to + ); + message.setSubject(subject); + message.setText(text); + + Transport.send(message); + } +} diff --git a/src/main/java/cz/jzitnik/utils/mail/read/MailReadHandler.java b/src/main/java/cz/jzitnik/utils/mail/read/MailReadHandler.java new file mode 100644 index 0000000..a589fed --- /dev/null +++ b/src/main/java/cz/jzitnik/utils/mail/read/MailReadHandler.java @@ -0,0 +1,25 @@ +package cz.jzitnik.utils.mail.read; + +import cz.jzitnik.GlobalContext; +import jakarta.mail.Message; + +public class MailReadHandler implements MailReader.OnNewEmailListener { + private final GlobalContext globalContext; + + public MailReadHandler(GlobalContext globalContext) { + this.globalContext = globalContext; + } + + @Override + public void onNewEmail(Message message) { + if (!globalContext.isWaitingForMessage()) { + return; + } + + try { + globalContext.getBlockingQueue().put(message); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } +} diff --git a/src/main/java/cz/jzitnik/utils/mail/read/MailReader.java b/src/main/java/cz/jzitnik/utils/mail/read/MailReader.java new file mode 100644 index 0000000..0682b4e --- /dev/null +++ b/src/main/java/cz/jzitnik/utils/mail/read/MailReader.java @@ -0,0 +1,77 @@ +package cz.jzitnik.utils.mail.read; + +import cz.jzitnik.utils.mail.MailContextPool; +import jakarta.mail.*; +import java.util.*; + +public class MailReader implements Runnable { + + private final MailContextPool pool; + private final String username; + private final String password; + private final long checkIntervalMs; + private final OnNewEmailListener listener; + + private int lastMessageCount = 0; + + public interface OnNewEmailListener { + void onNewEmail(Message message); + } + + public MailReader(MailContextPool mailContextPool, long checkIntervalMs, OnNewEmailListener listener) { + this.pool = mailContextPool; + this.username = mailContextPool.getPasswordAuthentication().getUserName(); + this.password = mailContextPool.getPasswordAuthentication().getPassword(); + this.checkIntervalMs = checkIntervalMs; + this.listener = listener; + } + + @Override + public void run() { + while (true) { + Store store = null; + Folder inbox = null; + + try { + store = pool.getSession().getStore("imaps"); + store.connect(pool.getProps().getProperty("mail.imaps.host"), username, password); + + inbox = store.getFolder("INBOX"); + inbox.open(Folder.READ_ONLY); + + System.out.println("[EmailChecker] Connected and monitoring inbox..."); + + while (true) { + Message[] messages = inbox.getMessages(); + int messageCount = messages.length; + + if (messageCount > lastMessageCount) { + for (int i = lastMessageCount; i < messageCount; i++) { + Message newMessage = messages[i]; + listener.onNewEmail(newMessage); + } + lastMessageCount = messageCount; + } + + Thread.sleep(checkIntervalMs); + } + + } catch (Exception e) { + System.err.println("[EmailChecker] Error: " + e.getMessage()); + e.printStackTrace(); + + // Wait before retrying connection + try { + Thread.sleep(30_000); // wait 30 seconds before reconnecting + } catch (InterruptedException ignored) { + } + } finally { + try { + if (inbox != null && inbox.isOpen()) inbox.close(false); + if (store != null && store.isConnected()) store.close(); + } catch (MessagingException ignored) { + } + } + } + } +} \ No newline at end of file