1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/java/Postak/src/cz/frantovo/postak/Postak.java Sun Nov 23 22:19:20 2008 +0100
1.3 @@ -0,0 +1,221 @@
1.4 +package cz.frantovo.postak;
1.5 +
1.6 +import java.io.File;
1.7 +import java.util.ArrayList;
1.8 +import java.util.Collection;
1.9 +import java.util.Properties;
1.10 +import java.util.logging.Level;
1.11 +import java.util.logging.Logger;
1.12 +import java.util.regex.Pattern;
1.13 +import javax.mail.Address;
1.14 +import javax.mail.Authenticator;
1.15 +import javax.mail.MessagingException;
1.16 +import javax.mail.PasswordAuthentication;
1.17 +import javax.mail.Session;
1.18 +import javax.mail.Transport;
1.19 +import javax.mail.internet.MimeMessage;
1.20 +
1.21 +/**
1.22 + * Odešle hromadnou zprávu pomocí SMTP.
1.23 + *
1.24 + * @author fiki
1.25 + */
1.26 +public class Postak {
1.27 +
1.28 + private static Logger log = Logger.getLogger(Postak.class.getName());
1.29 + /** Regulární výraz pro správnou e-mailovou adresu */
1.30 + private static String REGULARNI_EMAIL = "^[_a-zA-Z0-9\\.\\-]+@[_a-zA-Z0-9\\.\\-]+\\.[a-zA-Z]{2,4}$";
1.31 +
1.32 + private Nastaveni nastaveni;
1.33 +
1.34 + public Postak(Nastaveni nastaveni) {
1.35 + this.nastaveni = nastaveni;
1.36 + }
1.37 +
1.38 + public void setNastaveni(Nastaveni nastaveni) {
1.39 + this.nastaveni = nastaveni;
1.40 + }
1.41 +
1.42 + /**
1.43 + * Nízkoúrovňová odesílací metoda, která už nekontroluje limit příjemců.
1.44 + * Pokud se nevejdou do limitu SMTP serveru, vyhazuje výjimku.
1.45 + *
1.46 + * TODO: lepší to bude nestaické - nastavení si vyžádat v konstruktoru
1.47 + */
1.48 + private void odesliSMTP(HromadnaZprava zprava) throws MessagingException {
1.49 +
1.50 + if (zkontrolujZpravu(zprava) && zkontrolujNastaveni(nastaveni)) {
1.51 +
1.52 + /** Inicializace SMTP */
1.53 + Properties smtpVlastnosti = System.getProperties();
1.54 + smtpVlastnosti.put("mail.smtp.host", nastaveni.getPostovniServer());
1.55 + smtpVlastnosti.put("mail.smtp.port", String.valueOf(nastaveni.getPostovniPort()));
1.56 +
1.57 + if (nastaveni.getPostovniPort() == 465) {
1.58 + if (new File(nastaveni.getCestaKCertifikatum()).exists()) {
1.59 + System.setProperty("javax.net.ssl.trustStore", nastaveni.getCestaKCertifikatum());
1.60 + log.log(Level.INFO, "Používám vlastní důvěryhodné certifikáty: " + nastaveni.getCestaKCertifikatum());
1.61 + }
1.62 + /** TODO: neřídit se číslem portu, ale přidat příznak pro šifrování */
1.63 + smtpVlastnosti.put("mail.smtp.starttls.enable", "true");
1.64 + smtpVlastnosti.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
1.65 + smtpVlastnosti.put("mail.smtp.socketFactory.port", String.valueOf(nastaveni.getPostovniPort()));
1.66 + smtpVlastnosti.put("mail.smtp.socketFactory.fallback", "false");
1.67 + /**
1.68 + * NAHRÁNÍ CERTIFIKÁTU:
1.69 + * 1) stáhneme si certifikát (---BEGIN CERTIFICATE---) a uložíme do vse_ca.cer
1.70 + * 2) keytool -importcert -file vse_ca.cer -keystore DuveryhodneCertifikaty.keystore -storepass "changeit"
1.71 + * Pokud daný soubor existuje, program ho používá, pokud ne, používá certifikáty uložené v systému (Javovské).
1.72 + */
1.73 + }
1.74 +
1.75 + PostakuvHeslovnik heslovnik = new PostakuvHeslovnik();
1.76 + if (nastaveni.getPostovniJmeno() != null && nastaveni.getPostovniJmeno().length() > 0) {
1.77 + heslovnik.setJmenoHeslo(nastaveni.getPostovniJmeno(), nastaveni.getPostovniHeslo());
1.78 + smtpVlastnosti.put("mail.smtp.auth", "true");
1.79 + log.log(Level.FINEST, "Používám pro SMTP jméno a heslo");
1.80 + }
1.81 +
1.82 + Session smtpRelace = Session.getInstance(smtpVlastnosti, heslovnik);
1.83 +
1.84 + smtpRelace.setDebug(true);
1.85 + smtpRelace.setDebugOut(System.out);
1.86 +
1.87 + /** Sestavení zprávy */
1.88 + MimeMessage mimeZprava = new MimeMessage(smtpRelace);
1.89 + mimeZprava.setFrom(zprava.getOdesilatel());
1.90 + if (zprava.getOdpovedetKomu() != null) {
1.91 + Address[] odpovedetKomu = {zprava.getOdpovedetKomu()};
1.92 + mimeZprava.setReplyTo(odpovedetKomu);
1.93 + }
1.94 + naplnPrijemce(mimeZprava, zprava);
1.95 + mimeZprava.setSubject(zprava.getPredmet());
1.96 + mimeZprava.setHeader("User-Agent", "http://frantovo.cz/projekty/SuperPostak/");
1.97 + if (zprava.isFormatHTML()) {
1.98 + mimeZprava.setText(zprava.getText(), "UTF-8", "html");
1.99 + } else {
1.100 + mimeZprava.setText(zprava.getText(), "UTF-8");
1.101 + }
1.102 +
1.103 + /** Vlastní odeslání */
1.104 + Transport.send(mimeZprava);
1.105 +
1.106 + } else {
1.107 + MessagingException e = new MessagingException("Zpráva nebo nastavení jsou nevyhovující");
1.108 + log.log(Level.SEVERE, null, e);
1.109 + throw e;
1.110 + }
1.111 +
1.112 + }
1.113 +
1.114 + /**
1.115 + * Nastaví zprávě (MimeMessage) všechny příjemce, které najde ve zprávě a nastavení.
1.116 + * Respektuje typy příjemců: komu, kopie, skrytá kopie.
1.117 + */
1.118 + private static void naplnPrijemce(MimeMessage mimeZprava, HromadnaZprava zprava) throws MessagingException {
1.119 + /**
1.120 + * Příjemci se budou definovat pouze ve zprávě.
1.121 + * Z nastavení se brát nebudou (výchozí příjemci už ve zprávě budou).
1.122 + */
1.123 + ArrayList<InternetAddressKomu> prijemci = zprava.getPrijemci();
1.124 + for (InternetAddressKomu komu : prijemci) {
1.125 + if (zkontrolujAdresu(komu)) {
1.126 + mimeZprava.addRecipient(komu.getTyp(), komu);
1.127 + }
1.128 + }
1.129 + }
1.130 +
1.131 + /** Vypíše do logu seznam příjemců */
1.132 + public static void vypisPrijemce(Collection<InternetAddressKomu> prijemci) {
1.133 + for (InternetAddressKomu p : prijemci) {
1.134 + log.log(Level.INFO, p.toString());
1.135 + }
1.136 + }
1.137 +
1.138 + /** Veřejná odesílací metoda.
1.139 + * Postará se o rozdělení zpráv na dílčí (které se vejdou do limitu příjemců)
1.140 + */
1.141 + public void odesli(HromadnaZprava zprava) throws MessagingException {
1.142 + Collection<HromadnaZprava> zpravy = zprava.getDilciZpravy(nastaveni.getLimitZprav());
1.143 +
1.144 + for (HromadnaZprava dilciZprava : zpravy) {
1.145 + odesliSMTP(dilciZprava);
1.146 + }
1.147 + }
1.148 +
1.149 + private static boolean zkontrolujAdresu(InternetAddressKomu a) {
1.150 + if (a.getTyp() == null) {
1.151 + log.log(Level.WARNING, "Neplatná adresa (typ): " + a.getAddress());
1.152 + return false;
1.153 + }
1.154 +
1.155 + if (a.getAddress() == null || a.getAddress().length() < 1) {
1.156 + log.log(Level.WARNING, "Neplatná adresa (address): " + a.getPersonal());
1.157 + return false;
1.158 + }
1.159 +
1.160 + if (!zkontrolujAdresu(a.getAddress())) {
1.161 + log.log(Level.WARNING, "Adresa nevyhovuje regulárnímu výrazu: " + a.getAddress());
1.162 + return false;
1.163 + }
1.164 +
1.165 + return true;
1.166 + }
1.167 +
1.168 + /** Zkontroluje e-mailovou adresu pomocí regulárního výrazu. */
1.169 + public static boolean zkontrolujAdresu(String adresa) {
1.170 + return adresa != null && Pattern.matches(REGULARNI_EMAIL, adresa);
1.171 + }
1.172 +
1.173 + /** @return Vrací true, pokud je zpráva v pořádku */
1.174 + private static boolean zkontrolujZpravu(HromadnaZprava z) {
1.175 +
1.176 + if (z.getPrijemci() == null) {
1.177 + log.log(Level.WARNING, "getPrijemci() == null");
1.178 + return false;
1.179 + }
1.180 +
1.181 + if (z.getPrijemci().size() < 1) {
1.182 + log.log(Level.WARNING, "getPrijemci().size() < 1");
1.183 + return false;
1.184 + }
1.185 +
1.186 + if (z.getOdesilatel() == null) {
1.187 + log.log(Level.WARNING, "getOdesilatel() == null");
1.188 + return false;
1.189 + }
1.190 +
1.191 + if (z.getPredmet() == null) {
1.192 + log.log(Level.WARNING, "getPredmet() == null");
1.193 + return false;
1.194 + }
1.195 +
1.196 + return true;
1.197 + }
1.198 +
1.199 + private static boolean zkontrolujNastaveni(Nastaveni n) {
1.200 +
1.201 + if (n.getPostovniServer() == null || n.getPostovniServer().length() < 1) {
1.202 + return false;
1.203 + }
1.204 +
1.205 + return true;
1.206 + }
1.207 +
1.208 + /** Slouží k uložení jména a hesla pro SMTP */
1.209 + private static class PostakuvHeslovnik extends Authenticator {
1.210 +
1.211 + private String jmeno = "user";
1.212 + private char[] heslo = "luser".toCharArray();
1.213 +
1.214 + @Override
1.215 + public PasswordAuthentication getPasswordAuthentication() {
1.216 + return new PasswordAuthentication(jmeno, String.valueOf(heslo));
1.217 + }
1.218 +
1.219 + public void setJmenoHeslo(String jmeno, char[] heslo) {
1.220 + this.jmeno = jmeno;
1.221 + this.heslo = heslo;
1.222 + }
1.223 + }
1.224 +}