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