java/Postak/src/cz/frantovo/postak/Postak.java
changeset 1 699b6c66228b
child 5 bea5d9e11d37
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/java/Postak/src/cz/frantovo/postak/Postak.java	Sat Feb 28 17:52:36 2009 +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 +}