java/Postak/src/cz/frantovo/postak/Postak.java
author František Kučera <franta-hg@frantovo.cz>
Tue Nov 29 17:13:30 2011 +0100 (2011-11-29)
changeset 11 c1246cbb7f4c
parent 5 bea5d9e11d37
child 17 9cb46ca7e26c
permissions -rw-r--r--
Zprávy budeme posílat s hlavičkou Precedence: bulk
franta-hg@0
     1
package cz.frantovo.postak;
franta-hg@0
     2
franta-hg@0
     3
import java.io.File;
franta-hg@0
     4
import java.util.ArrayList;
franta-hg@0
     5
import java.util.Collection;
franta-hg@0
     6
import java.util.Properties;
franta-hg@0
     7
import java.util.logging.Level;
franta-hg@0
     8
import java.util.logging.Logger;
franta-hg@0
     9
import java.util.regex.Pattern;
franta-hg@0
    10
import javax.mail.Address;
franta-hg@0
    11
import javax.mail.Authenticator;
franta-hg@0
    12
import javax.mail.MessagingException;
franta-hg@0
    13
import javax.mail.PasswordAuthentication;
franta-hg@0
    14
import javax.mail.Session;
franta-hg@0
    15
import javax.mail.Transport;
franta-hg@0
    16
import javax.mail.internet.MimeMessage;
franta-hg@0
    17
franta-hg@0
    18
/**
franta-hg@0
    19
 * Odešle hromadnou zprávu pomocí SMTP.
franta-hg@0
    20
 * 
franta-hg@0
    21
 * @author fiki
franta-hg@0
    22
 */
franta-hg@0
    23
public class Postak {   
franta-hg@0
    24
    
franta-hg@11
    25
    private static final Logger log = Logger.getLogger(Postak.class.getName());
franta-hg@0
    26
    /** Regulární výraz pro správnou e-mailovou adresu */
franta-hg@0
    27
    private static String REGULARNI_EMAIL = "^[_a-zA-Z0-9\\.\\-]+@[_a-zA-Z0-9\\.\\-]+\\.[a-zA-Z]{2,4}$";
franta-hg@0
    28
    
franta-hg@0
    29
    private Nastaveni nastaveni;
franta-hg@0
    30
franta-hg@0
    31
    public Postak(Nastaveni nastaveni) {
franta-hg@0
    32
        this.nastaveni = nastaveni;
franta-hg@0
    33
    }
franta-hg@0
    34
franta-hg@0
    35
    public void setNastaveni(Nastaveni nastaveni) {
franta-hg@0
    36
        this.nastaveni = nastaveni;
franta-hg@0
    37
    }
franta-hg@0
    38
franta-hg@0
    39
    /** 
franta-hg@0
    40
     * Nízkoúrovňová odesílací metoda, která už nekontroluje limit příjemců.
franta-hg@0
    41
     * Pokud se nevejdou do limitu SMTP serveru, vyhazuje výjimku.
franta-hg@0
    42
     * 
franta-hg@0
    43
     * TODO: lepší to bude nestaické - nastavení si vyžádat v konstruktoru
franta-hg@0
    44
     */
franta-hg@0
    45
    private void odesliSMTP(HromadnaZprava zprava) throws MessagingException {
franta-hg@0
    46
franta-hg@0
    47
        if (zkontrolujZpravu(zprava) && zkontrolujNastaveni(nastaveni)) {
franta-hg@0
    48
franta-hg@0
    49
            /** Inicializace SMTP */
franta-hg@0
    50
            Properties smtpVlastnosti = System.getProperties();
franta-hg@0
    51
            smtpVlastnosti.put("mail.smtp.host", nastaveni.getPostovniServer());
franta-hg@0
    52
            smtpVlastnosti.put("mail.smtp.port", String.valueOf(nastaveni.getPostovniPort()));
franta-hg@0
    53
franta-hg@0
    54
            if (nastaveni.getPostovniPort() == 465) {
franta-hg@0
    55
                if (new File(nastaveni.getCestaKCertifikatum()).exists()) {
franta-hg@0
    56
                    System.setProperty("javax.net.ssl.trustStore", nastaveni.getCestaKCertifikatum());
franta-hg@11
    57
                    log.log(Level.INFO, "Používám vlastní důvěryhodné certifikáty: {0}", nastaveni.getCestaKCertifikatum());
franta-hg@0
    58
                }
franta-hg@0
    59
                /** TODO: neřídit se číslem portu, ale přidat příznak pro šifrování */
franta-hg@0
    60
                smtpVlastnosti.put("mail.smtp.starttls.enable", "true");
franta-hg@0
    61
                smtpVlastnosti.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
franta-hg@0
    62
                smtpVlastnosti.put("mail.smtp.socketFactory.port", String.valueOf(nastaveni.getPostovniPort()));
franta-hg@0
    63
                smtpVlastnosti.put("mail.smtp.socketFactory.fallback", "false");
franta-hg@0
    64
            /**
franta-hg@0
    65
             * NAHRÁNÍ CERTIFIKÁTU:
franta-hg@0
    66
             * 1) stáhneme si certifikát (---BEGIN CERTIFICATE---) a uložíme do vse_ca.cer             
franta-hg@0
    67
             * 2) keytool -importcert -file vse_ca.cer -keystore DuveryhodneCertifikaty.keystore -storepass "changeit"
franta-hg@0
    68
             * Pokud daný soubor existuje, program ho používá, pokud ne, používá certifikáty uložené v systému (Javovské).
franta-hg@0
    69
             */
franta-hg@0
    70
            }
franta-hg@0
    71
franta-hg@0
    72
            PostakuvHeslovnik heslovnik = new PostakuvHeslovnik();
franta-hg@0
    73
            if (nastaveni.getPostovniJmeno() != null && nastaveni.getPostovniJmeno().length() > 0) {
franta-hg@0
    74
                heslovnik.setJmenoHeslo(nastaveni.getPostovniJmeno(), nastaveni.getPostovniHeslo());
franta-hg@0
    75
                smtpVlastnosti.put("mail.smtp.auth", "true");
franta-hg@0
    76
                log.log(Level.FINEST, "Používám pro SMTP jméno a heslo");
franta-hg@0
    77
            }
franta-hg@0
    78
franta-hg@0
    79
            Session smtpRelace = Session.getInstance(smtpVlastnosti, heslovnik);
franta-hg@0
    80
franta-hg@0
    81
            smtpRelace.setDebug(true);
franta-hg@0
    82
            smtpRelace.setDebugOut(System.out);
franta-hg@0
    83
franta-hg@0
    84
            /** Sestavení zprávy */
franta-hg@0
    85
            MimeMessage mimeZprava = new MimeMessage(smtpRelace);
franta-hg@0
    86
            mimeZprava.setFrom(zprava.getOdesilatel());
franta-hg@0
    87
            if (zprava.getOdpovedetKomu() != null) {
franta-hg@0
    88
                Address[] odpovedetKomu = {zprava.getOdpovedetKomu()};
franta-hg@0
    89
                mimeZprava.setReplyTo(odpovedetKomu);
franta-hg@0
    90
            }
franta-hg@0
    91
            naplnPrijemce(mimeZprava, zprava);
franta-hg@0
    92
            mimeZprava.setSubject(zprava.getPredmet());
franta-hg@11
    93
            mimeZprava.setHeader("User-Agent", "https://frantovo.cz/projekty/SuperPostak/");
franta-hg@11
    94
            mimeZprava.setHeader("Precedence", "bulk");
franta-hg@0
    95
            if (zprava.isFormatHTML()) {
franta-hg@0
    96
                mimeZprava.setText(zprava.getText(), "UTF-8", "html");
franta-hg@0
    97
            } else {
franta-hg@0
    98
                mimeZprava.setText(zprava.getText(), "UTF-8");
franta-hg@0
    99
            }
franta-hg@0
   100
franta-hg@0
   101
            /** Vlastní odeslání */
franta-hg@0
   102
            Transport.send(mimeZprava);
franta-hg@0
   103
franta-hg@0
   104
        } else {
franta-hg@0
   105
            MessagingException e = new MessagingException("Zpráva nebo nastavení jsou nevyhovující");
franta-hg@0
   106
            log.log(Level.SEVERE, null, e);
franta-hg@0
   107
            throw e;
franta-hg@0
   108
        }
franta-hg@0
   109
franta-hg@0
   110
    }
franta-hg@0
   111
franta-hg@0
   112
    /**
franta-hg@0
   113
     * Nastaví zprávě (MimeMessage) všechny příjemce, které najde ve zprávě a nastavení.
franta-hg@0
   114
     * Respektuje typy příjemců: komu, kopie, skrytá kopie.    
franta-hg@0
   115
     */
franta-hg@0
   116
    private static void naplnPrijemce(MimeMessage mimeZprava, HromadnaZprava zprava) throws MessagingException {
franta-hg@0
   117
        /** 
franta-hg@0
   118
         * Příjemci se budou definovat pouze ve zprávě.
franta-hg@0
   119
         * Z nastavení se brát nebudou (výchozí příjemci už ve zprávě budou).
franta-hg@0
   120
         */
franta-hg@0
   121
        ArrayList<InternetAddressKomu> prijemci = zprava.getPrijemci();
franta-hg@0
   122
        for (InternetAddressKomu komu : prijemci) {
franta-hg@0
   123
            if (zkontrolujAdresu(komu)) {
franta-hg@0
   124
                mimeZprava.addRecipient(komu.getTyp(), komu);
franta-hg@0
   125
            }
franta-hg@0
   126
        }
franta-hg@0
   127
    }
franta-hg@0
   128
franta-hg@0
   129
    /** Vypíše do logu seznam příjemců */
franta-hg@0
   130
    public static void vypisPrijemce(Collection<InternetAddressKomu> prijemci) {
franta-hg@0
   131
        for (InternetAddressKomu p : prijemci) {
franta-hg@0
   132
            log.log(Level.INFO, p.toString());
franta-hg@0
   133
        }
franta-hg@0
   134
    }
franta-hg@0
   135
franta-hg@0
   136
    /** Veřejná odesílací metoda.
franta-hg@0
   137
     * Postará se o rozdělení zpráv na dílčí (které se vejdou do limitu příjemců)
franta-hg@0
   138
     */
franta-hg@0
   139
    public void odesli(HromadnaZprava zprava) throws MessagingException {
franta-hg@0
   140
        Collection<HromadnaZprava> zpravy = zprava.getDilciZpravy(nastaveni.getLimitZprav());
franta-hg@0
   141
franta-hg@0
   142
        for (HromadnaZprava dilciZprava : zpravy) {
franta-hg@0
   143
            odesliSMTP(dilciZprava);
franta-hg@0
   144
        }
franta-hg@0
   145
    }
franta-hg@0
   146
franta-hg@0
   147
    private static boolean zkontrolujAdresu(InternetAddressKomu a) {
franta-hg@0
   148
        if (a.getTyp() == null) {
franta-hg@11
   149
            log.log(Level.WARNING, "Neplatná adresa (typ): {0}", a.getAddress());
franta-hg@0
   150
            return false;
franta-hg@0
   151
        }
franta-hg@0
   152
franta-hg@0
   153
        if (a.getAddress() == null || a.getAddress().length() < 1) {
franta-hg@11
   154
            log.log(Level.WARNING, "Neplatná adresa (address): {0}", a.getPersonal());
franta-hg@0
   155
            return false;
franta-hg@0
   156
        }
franta-hg@0
   157
franta-hg@0
   158
        if (!zkontrolujAdresu(a.getAddress())) {
franta-hg@11
   159
            log.log(Level.WARNING, "Adresa nevyhovuje regulárnímu výrazu: {0}", a.getAddress());
franta-hg@0
   160
            return false;
franta-hg@0
   161
        }
franta-hg@0
   162
franta-hg@0
   163
        return true;
franta-hg@0
   164
    }
franta-hg@0
   165
franta-hg@0
   166
    /** Zkontroluje e-mailovou adresu pomocí regulárního výrazu. */
franta-hg@0
   167
    public static boolean zkontrolujAdresu(String adresa) {
franta-hg@0
   168
        return adresa != null && Pattern.matches(REGULARNI_EMAIL, adresa);
franta-hg@0
   169
    }
franta-hg@0
   170
franta-hg@0
   171
    /** @return  Vrací true, pokud je zpráva v pořádku */
franta-hg@0
   172
    private static boolean zkontrolujZpravu(HromadnaZprava z) {
franta-hg@0
   173
franta-hg@0
   174
        if (z.getPrijemci() == null) {
franta-hg@0
   175
            log.log(Level.WARNING, "getPrijemci() == null");
franta-hg@0
   176
            return false;
franta-hg@0
   177
        }
franta-hg@0
   178
franta-hg@0
   179
        if (z.getPrijemci().size() < 1) {
franta-hg@0
   180
            log.log(Level.WARNING, "getPrijemci().size() < 1");
franta-hg@0
   181
            return false;
franta-hg@0
   182
        }
franta-hg@0
   183
franta-hg@0
   184
        if (z.getOdesilatel() == null) {
franta-hg@0
   185
            log.log(Level.WARNING, "getOdesilatel() == null");
franta-hg@0
   186
            return false;
franta-hg@0
   187
        }
franta-hg@0
   188
franta-hg@0
   189
        if (z.getPredmet() == null) {
franta-hg@0
   190
            log.log(Level.WARNING, "getPredmet() == null");
franta-hg@0
   191
            return false;
franta-hg@0
   192
        }
franta-hg@0
   193
franta-hg@0
   194
        return true;
franta-hg@0
   195
    }
franta-hg@0
   196
franta-hg@0
   197
    private static boolean zkontrolujNastaveni(Nastaveni n) {
franta-hg@0
   198
franta-hg@0
   199
        if (n.getPostovniServer() == null || n.getPostovniServer().length() < 1) {
franta-hg@0
   200
            return false;
franta-hg@0
   201
        }
franta-hg@0
   202
franta-hg@0
   203
        return true;
franta-hg@0
   204
    }
franta-hg@0
   205
franta-hg@0
   206
    /** Slouží k uložení jména a hesla pro SMTP */
franta-hg@0
   207
    private static class PostakuvHeslovnik extends Authenticator {
franta-hg@0
   208
franta-hg@0
   209
        private String jmeno = "user";
franta-hg@0
   210
        private char[] heslo = "luser".toCharArray();
franta-hg@0
   211
franta-hg@0
   212
        @Override
franta-hg@0
   213
        public PasswordAuthentication getPasswordAuthentication() {
franta-hg@0
   214
            return new PasswordAuthentication(jmeno, String.valueOf(heslo));
franta-hg@0
   215
        }
franta-hg@0
   216
franta-hg@0
   217
        public void setJmenoHeslo(String jmeno, char[] heslo) {
franta-hg@0
   218
            this.jmeno = jmeno;
franta-hg@0
   219
            this.heslo = heslo;
franta-hg@0
   220
        }
franta-hg@0
   221
    }
franta-hg@0
   222
}