package com.auction; import javax.mail.Authenticator; import javax.mail.Message.RecipientType; import javax.mail.PasswordAuthentication; import javax.mail.Session; import javax.mail.Transport; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeMessage; import java.awt.SystemTray; import java.awt.Toolkit; import java.awt.TrayIcon; import java.awt.TrayIcon.MessageType; import java.util.Date; import java.util.Properties; /** * Service for sending notifications via desktop notifications and/or email. * Supports free notification methods: * 1. Desktop notifications (Windows/Linux/macOS system tray) * 2. Email via Gmail SMTP (free, requires app password) * * Configuration: * - For email: Set notificationEmail to your Gmail address * - Enable 2FA in Gmail and create an App Password * - Use format "smtp:username:appPassword:toEmail" for credentials * - Or use "desktop" for desktop-only notifications */ class NotificationService { private final boolean useDesktop; private final boolean useEmail; private final String smtpUsername; private final String smtpPassword; private final String toEmail; /** * Creates a notification service. * * @param config "desktop" for desktop only, or "smtp:username:password:toEmail" for email * @param unusedParam Kept for compatibility (can pass empty string) */ NotificationService(String config, String unusedParam) { if ("desktop".equalsIgnoreCase(config)) { this.useDesktop = true; this.useEmail = false; this.smtpUsername = null; this.smtpPassword = null; this.toEmail = null; } else if (config.startsWith("smtp:")) { var parts = config.split(":", 4); if (parts.length != 4) { throw new IllegalArgumentException("Email config must be 'smtp:username:password:toEmail'"); } this.useDesktop = true; // Always include desktop this.useEmail = true; this.smtpUsername = parts[1]; this.smtpPassword = parts[2]; this.toEmail = parts[3]; } else { throw new IllegalArgumentException("Config must be 'desktop' or 'smtp:username:password:toEmail'"); } } /** * Sends notification via configured channels. * * @param message The message body * @param title Message title * @param priority Priority level (0=normal, 1=high) */ void sendNotification(String message, String title, int priority) { if (useDesktop) { sendDesktopNotification(title, message, priority); } if (useEmail) { sendEmailNotification(title, message, priority); } } /** * Sends a desktop notification using system tray. * Works on Windows, macOS, and Linux with desktop environments. */ private void sendDesktopNotification(String title, String message, int priority) { try { if (SystemTray.isSupported()) { var tray = SystemTray.getSystemTray(); var image = Toolkit.getDefaultToolkit() .createImage(new byte[0]); // Empty image var trayIcon = new TrayIcon(image, "Troostwijk Scraper"); trayIcon.setImageAutoSize(true); var messageType = priority > 0 ? MessageType.WARNING : MessageType.INFO; tray.add(trayIcon); trayIcon.displayMessage(title, message, messageType); // Remove icon after 2 seconds to avoid clutter Thread.sleep(2000); tray.remove(trayIcon); IO.println("Desktop notification sent: " + title); } else { IO.println("Desktop notifications not supported, logging: " + title + " - " + message); } } catch (Exception e) { System.err.println("Desktop notification failed: " + e.getMessage()); } } /** * Sends email notification via Gmail SMTP (free). * Uses Gmail's SMTP server with app password authentication. */ private void sendEmailNotification(String title, String message, int priority) { try { var props = new Properties(); props.put("mail.smtp.auth", "true"); props.put("mail.smtp.starttls.enable", "true"); props.put("mail.smtp.host", "smtp.gmail.com"); props.put("mail.smtp.port", "587"); props.put("mail.smtp.ssl.trust", "smtp.gmail.com"); var session = Session.getInstance(props, new Authenticator() { protected PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication(smtpUsername, smtpPassword); } }); var msg = new MimeMessage(session); msg.setFrom(new InternetAddress(smtpUsername)); msg.setRecipients(RecipientType.TO, InternetAddress.parse(toEmail)); msg.setSubject("[Troostwijk] " + title); msg.setText(message); msg.setSentDate(new Date()); if (priority > 0) { msg.setHeader("X-Priority", "1"); msg.setHeader("Importance", "High"); } Transport.send(msg); IO.println("Email notification sent: " + title); } catch (Exception e) { System.err.println("Email notification failed: " + e.getMessage()); } } }