franta-hg@0: package cz.frantovo.postak; franta-hg@0: franta-hg@0: import java.io.File; franta-hg@0: import java.util.ArrayList; franta-hg@0: import java.util.Collection; franta-hg@0: import java.util.Properties; franta-hg@0: import java.util.logging.Level; franta-hg@0: import java.util.logging.Logger; franta-hg@0: import java.util.regex.Pattern; franta-hg@0: import javax.mail.Address; franta-hg@0: import javax.mail.Authenticator; franta-hg@0: import javax.mail.MessagingException; franta-hg@0: import javax.mail.PasswordAuthentication; franta-hg@0: import javax.mail.Session; franta-hg@0: import javax.mail.Transport; franta-hg@0: import javax.mail.internet.MimeMessage; franta-hg@0: franta-hg@0: /** franta-hg@0: * Odešle hromadnou zprávu pomocí SMTP. franta-hg@0: * franta-hg@0: * @author fiki franta-hg@0: */ franta-hg@0: public class Postak { franta-hg@0: franta-hg@11: private static final Logger log = Logger.getLogger(Postak.class.getName()); franta-hg@0: /** Regulární výraz pro správnou e-mailovou adresu */ franta-hg@0: private static String REGULARNI_EMAIL = "^[_a-zA-Z0-9\\.\\-]+@[_a-zA-Z0-9\\.\\-]+\\.[a-zA-Z]{2,4}$"; franta-hg@0: franta-hg@0: private Nastaveni nastaveni; franta-hg@0: franta-hg@0: public Postak(Nastaveni nastaveni) { franta-hg@0: this.nastaveni = nastaveni; franta-hg@0: } franta-hg@0: franta-hg@0: public void setNastaveni(Nastaveni nastaveni) { franta-hg@0: this.nastaveni = nastaveni; franta-hg@0: } franta-hg@0: franta-hg@0: /** franta-hg@0: * Nízkoúrovňová odesílací metoda, která už nekontroluje limit příjemců. franta-hg@0: * Pokud se nevejdou do limitu SMTP serveru, vyhazuje výjimku. franta-hg@0: * franta-hg@0: * TODO: lepší to bude nestaické - nastavení si vyžádat v konstruktoru franta-hg@0: */ franta-hg@0: private void odesliSMTP(HromadnaZprava zprava) throws MessagingException { franta-hg@0: franta-hg@0: if (zkontrolujZpravu(zprava) && zkontrolujNastaveni(nastaveni)) { franta-hg@0: franta-hg@0: /** Inicializace SMTP */ franta-hg@0: Properties smtpVlastnosti = System.getProperties(); franta-hg@0: smtpVlastnosti.put("mail.smtp.host", nastaveni.getPostovniServer()); franta-hg@0: smtpVlastnosti.put("mail.smtp.port", String.valueOf(nastaveni.getPostovniPort())); franta-hg@0: franta-hg@0: if (nastaveni.getPostovniPort() == 465) { franta-hg@0: if (new File(nastaveni.getCestaKCertifikatum()).exists()) { franta-hg@0: System.setProperty("javax.net.ssl.trustStore", nastaveni.getCestaKCertifikatum()); franta-hg@11: log.log(Level.INFO, "Používám vlastní důvěryhodné certifikáty: {0}", nastaveni.getCestaKCertifikatum()); franta-hg@0: } franta-hg@0: /** TODO: neřídit se číslem portu, ale přidat příznak pro šifrování */ franta-hg@0: smtpVlastnosti.put("mail.smtp.starttls.enable", "true"); franta-hg@0: smtpVlastnosti.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory"); franta-hg@0: smtpVlastnosti.put("mail.smtp.socketFactory.port", String.valueOf(nastaveni.getPostovniPort())); franta-hg@0: smtpVlastnosti.put("mail.smtp.socketFactory.fallback", "false"); franta-hg@0: /** franta-hg@0: * NAHRÁNÍ CERTIFIKÁTU: franta-hg@0: * 1) stáhneme si certifikát (---BEGIN CERTIFICATE---) a uložíme do vse_ca.cer franta-hg@0: * 2) keytool -importcert -file vse_ca.cer -keystore DuveryhodneCertifikaty.keystore -storepass "changeit" franta-hg@0: * Pokud daný soubor existuje, program ho používá, pokud ne, používá certifikáty uložené v systému (Javovské). franta-hg@0: */ franta-hg@0: } franta-hg@0: franta-hg@0: PostakuvHeslovnik heslovnik = new PostakuvHeslovnik(); franta-hg@0: if (nastaveni.getPostovniJmeno() != null && nastaveni.getPostovniJmeno().length() > 0) { franta-hg@0: heslovnik.setJmenoHeslo(nastaveni.getPostovniJmeno(), nastaveni.getPostovniHeslo()); franta-hg@0: smtpVlastnosti.put("mail.smtp.auth", "true"); franta-hg@0: log.log(Level.FINEST, "Používám pro SMTP jméno a heslo"); franta-hg@0: } franta-hg@0: franta-hg@0: Session smtpRelace = Session.getInstance(smtpVlastnosti, heslovnik); franta-hg@0: franta-hg@0: smtpRelace.setDebug(true); franta-hg@0: smtpRelace.setDebugOut(System.out); franta-hg@0: franta-hg@0: /** Sestavení zprávy */ franta-hg@0: MimeMessage mimeZprava = new MimeMessage(smtpRelace); franta-hg@0: mimeZprava.setFrom(zprava.getOdesilatel()); franta-hg@0: if (zprava.getOdpovedetKomu() != null) { franta-hg@0: Address[] odpovedetKomu = {zprava.getOdpovedetKomu()}; franta-hg@0: mimeZprava.setReplyTo(odpovedetKomu); franta-hg@0: } franta-hg@0: naplnPrijemce(mimeZprava, zprava); franta-hg@0: mimeZprava.setSubject(zprava.getPredmet()); franta-hg@11: mimeZprava.setHeader("User-Agent", "https://frantovo.cz/projekty/SuperPostak/"); franta-hg@11: mimeZprava.setHeader("Precedence", "bulk"); franta-hg@0: if (zprava.isFormatHTML()) { franta-hg@0: mimeZprava.setText(zprava.getText(), "UTF-8", "html"); franta-hg@0: } else { franta-hg@0: mimeZprava.setText(zprava.getText(), "UTF-8"); franta-hg@0: } franta-hg@0: franta-hg@0: /** Vlastní odeslání */ franta-hg@0: Transport.send(mimeZprava); franta-hg@0: franta-hg@0: } else { franta-hg@0: MessagingException e = new MessagingException("Zpráva nebo nastavení jsou nevyhovující"); franta-hg@0: log.log(Level.SEVERE, null, e); franta-hg@0: throw e; franta-hg@0: } franta-hg@0: franta-hg@0: } franta-hg@0: franta-hg@0: /** franta-hg@0: * Nastaví zprávě (MimeMessage) všechny příjemce, které najde ve zprávě a nastavení. franta-hg@0: * Respektuje typy příjemců: komu, kopie, skrytá kopie. franta-hg@0: */ franta-hg@0: private static void naplnPrijemce(MimeMessage mimeZprava, HromadnaZprava zprava) throws MessagingException { franta-hg@0: /** franta-hg@0: * Příjemci se budou definovat pouze ve zprávě. franta-hg@0: * Z nastavení se brát nebudou (výchozí příjemci už ve zprávě budou). franta-hg@0: */ franta-hg@0: ArrayList prijemci = zprava.getPrijemci(); franta-hg@0: for (InternetAddressKomu komu : prijemci) { franta-hg@0: if (zkontrolujAdresu(komu)) { franta-hg@0: mimeZprava.addRecipient(komu.getTyp(), komu); franta-hg@0: } franta-hg@0: } franta-hg@0: } franta-hg@0: franta-hg@0: /** Vypíše do logu seznam příjemců */ franta-hg@0: public static void vypisPrijemce(Collection prijemci) { franta-hg@0: for (InternetAddressKomu p : prijemci) { franta-hg@0: log.log(Level.INFO, p.toString()); franta-hg@0: } franta-hg@0: } franta-hg@0: franta-hg@0: /** Veřejná odesílací metoda. franta-hg@0: * Postará se o rozdělení zpráv na dílčí (které se vejdou do limitu příjemců) franta-hg@0: */ franta-hg@0: public void odesli(HromadnaZprava zprava) throws MessagingException { franta-hg@0: Collection zpravy = zprava.getDilciZpravy(nastaveni.getLimitZprav()); franta-hg@0: franta-hg@0: for (HromadnaZprava dilciZprava : zpravy) { franta-hg@0: odesliSMTP(dilciZprava); franta-hg@0: } franta-hg@0: } franta-hg@0: franta-hg@0: private static boolean zkontrolujAdresu(InternetAddressKomu a) { franta-hg@0: if (a.getTyp() == null) { franta-hg@11: log.log(Level.WARNING, "Neplatná adresa (typ): {0}", a.getAddress()); franta-hg@0: return false; franta-hg@0: } franta-hg@0: franta-hg@0: if (a.getAddress() == null || a.getAddress().length() < 1) { franta-hg@11: log.log(Level.WARNING, "Neplatná adresa (address): {0}", a.getPersonal()); franta-hg@0: return false; franta-hg@0: } franta-hg@0: franta-hg@0: if (!zkontrolujAdresu(a.getAddress())) { franta-hg@11: log.log(Level.WARNING, "Adresa nevyhovuje regulárnímu výrazu: {0}", a.getAddress()); franta-hg@0: return false; franta-hg@0: } franta-hg@0: franta-hg@0: return true; franta-hg@0: } franta-hg@0: franta-hg@0: /** Zkontroluje e-mailovou adresu pomocí regulárního výrazu. */ franta-hg@0: public static boolean zkontrolujAdresu(String adresa) { franta-hg@0: return adresa != null && Pattern.matches(REGULARNI_EMAIL, adresa); franta-hg@0: } franta-hg@0: franta-hg@0: /** @return Vrací true, pokud je zpráva v pořádku */ franta-hg@0: private static boolean zkontrolujZpravu(HromadnaZprava z) { franta-hg@0: franta-hg@0: if (z.getPrijemci() == null) { franta-hg@0: log.log(Level.WARNING, "getPrijemci() == null"); franta-hg@0: return false; franta-hg@0: } franta-hg@0: franta-hg@0: if (z.getPrijemci().size() < 1) { franta-hg@0: log.log(Level.WARNING, "getPrijemci().size() < 1"); franta-hg@0: return false; franta-hg@0: } franta-hg@0: franta-hg@0: if (z.getOdesilatel() == null) { franta-hg@0: log.log(Level.WARNING, "getOdesilatel() == null"); franta-hg@0: return false; franta-hg@0: } franta-hg@0: franta-hg@0: if (z.getPredmet() == null) { franta-hg@0: log.log(Level.WARNING, "getPredmet() == null"); franta-hg@0: return false; franta-hg@0: } franta-hg@0: franta-hg@0: return true; franta-hg@0: } franta-hg@0: franta-hg@0: private static boolean zkontrolujNastaveni(Nastaveni n) { franta-hg@0: franta-hg@0: if (n.getPostovniServer() == null || n.getPostovniServer().length() < 1) { franta-hg@0: return false; franta-hg@0: } franta-hg@0: franta-hg@0: return true; franta-hg@0: } franta-hg@0: franta-hg@0: /** Slouží k uložení jména a hesla pro SMTP */ franta-hg@0: private static class PostakuvHeslovnik extends Authenticator { franta-hg@0: franta-hg@0: private String jmeno = "user"; franta-hg@0: private char[] heslo = "luser".toCharArray(); franta-hg@0: franta-hg@0: @Override franta-hg@0: public PasswordAuthentication getPasswordAuthentication() { franta-hg@0: return new PasswordAuthentication(jmeno, String.valueOf(heslo)); franta-hg@0: } franta-hg@0: franta-hg@0: public void setJmenoHeslo(String jmeno, char[] heslo) { franta-hg@0: this.jmeno = jmeno; franta-hg@0: this.heslo = heslo; franta-hg@0: } franta-hg@0: } franta-hg@0: }