java/Postak/src/cz/frantovo/postak/Postak.java
author František Kučera <franta-hg@frantovo.cz>
Sat, 28 Feb 2009 18:06:12 +0100
changeset 4 dfb345ef9452
parent 0 e76872ad5226
child 5 bea5d9e11d37
permissions -rw-r--r--
Drobnosti a serializace
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@0
    25
    private static 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@0
    57
                    log.log(Level.INFO, "Používám vlastní důvěryhodné certifikáty: " + 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@0
    93
            mimeZprava.setHeader("User-Agent", "http://frantovo.cz/projekty/SuperPostak/");
franta-hg@0
    94
            if (zprava.isFormatHTML()) {
franta-hg@0
    95
                mimeZprava.setText(zprava.getText(), "UTF-8", "html");
franta-hg@0
    96
            } else {
franta-hg@0
    97
                mimeZprava.setText(zprava.getText(), "UTF-8");
franta-hg@0
    98
            }
franta-hg@0
    99
franta-hg@0
   100
            /** Vlastní odeslání */
franta-hg@0
   101
            Transport.send(mimeZprava);
franta-hg@0
   102
franta-hg@0
   103
        } else {
franta-hg@0
   104
            MessagingException e = new MessagingException("Zpráva nebo nastavení jsou nevyhovující");
franta-hg@0
   105
            log.log(Level.SEVERE, null, e);
franta-hg@0
   106
            throw e;
franta-hg@0
   107
        }
franta-hg@0
   108
franta-hg@0
   109
    }
franta-hg@0
   110
franta-hg@0
   111
    /**
franta-hg@0
   112
     * Nastaví zprávě (MimeMessage) všechny příjemce, které najde ve zprávě a nastavení.
franta-hg@0
   113
     * Respektuje typy příjemců: komu, kopie, skrytá kopie.    
franta-hg@0
   114
     */
franta-hg@0
   115
    private static void naplnPrijemce(MimeMessage mimeZprava, HromadnaZprava zprava) throws MessagingException {
franta-hg@0
   116
        /** 
franta-hg@0
   117
         * Příjemci se budou definovat pouze ve zprávě.
franta-hg@0
   118
         * Z nastavení se brát nebudou (výchozí příjemci už ve zprávě budou).
franta-hg@0
   119
         */
franta-hg@0
   120
        ArrayList<InternetAddressKomu> prijemci = zprava.getPrijemci();
franta-hg@0
   121
        for (InternetAddressKomu komu : prijemci) {
franta-hg@0
   122
            if (zkontrolujAdresu(komu)) {
franta-hg@0
   123
                mimeZprava.addRecipient(komu.getTyp(), komu);
franta-hg@0
   124
            }
franta-hg@0
   125
        }
franta-hg@0
   126
    }
franta-hg@0
   127
franta-hg@0
   128
    /** Vypíše do logu seznam příjemců */
franta-hg@0
   129
    public static void vypisPrijemce(Collection<InternetAddressKomu> prijemci) {
franta-hg@0
   130
        for (InternetAddressKomu p : prijemci) {
franta-hg@0
   131
            log.log(Level.INFO, p.toString());
franta-hg@0
   132
        }
franta-hg@0
   133
    }
franta-hg@0
   134
franta-hg@0
   135
    /** Veřejná odesílací metoda.
franta-hg@0
   136
     * Postará se o rozdělení zpráv na dílčí (které se vejdou do limitu příjemců)
franta-hg@0
   137
     */
franta-hg@0
   138
    public void odesli(HromadnaZprava zprava) throws MessagingException {
franta-hg@0
   139
        Collection<HromadnaZprava> zpravy = zprava.getDilciZpravy(nastaveni.getLimitZprav());
franta-hg@0
   140
franta-hg@0
   141
        for (HromadnaZprava dilciZprava : zpravy) {
franta-hg@0
   142
            odesliSMTP(dilciZprava);
franta-hg@0
   143
        }
franta-hg@0
   144
    }
franta-hg@0
   145
franta-hg@0
   146
    private static boolean zkontrolujAdresu(InternetAddressKomu a) {
franta-hg@0
   147
        if (a.getTyp() == null) {
franta-hg@0
   148
            log.log(Level.WARNING, "Neplatná adresa (typ): " + a.getAddress());
franta-hg@0
   149
            return false;
franta-hg@0
   150
        }
franta-hg@0
   151
franta-hg@0
   152
        if (a.getAddress() == null || a.getAddress().length() < 1) {
franta-hg@0
   153
            log.log(Level.WARNING, "Neplatná adresa (address): " + a.getPersonal());
franta-hg@0
   154
            return false;
franta-hg@0
   155
        }
franta-hg@0
   156
franta-hg@0
   157
        if (!zkontrolujAdresu(a.getAddress())) {
franta-hg@0
   158
            log.log(Level.WARNING, "Adresa nevyhovuje regulárnímu výrazu: " + a.getAddress());
franta-hg@0
   159
            return false;
franta-hg@0
   160
        }
franta-hg@0
   161
franta-hg@0
   162
        return true;
franta-hg@0
   163
    }
franta-hg@0
   164
franta-hg@0
   165
    /** Zkontroluje e-mailovou adresu pomocí regulárního výrazu. */
franta-hg@0
   166
    public static boolean zkontrolujAdresu(String adresa) {
franta-hg@0
   167
        return adresa != null && Pattern.matches(REGULARNI_EMAIL, adresa);
franta-hg@0
   168
    }
franta-hg@0
   169
franta-hg@0
   170
    /** @return  Vrací true, pokud je zpráva v pořádku */
franta-hg@0
   171
    private static boolean zkontrolujZpravu(HromadnaZprava z) {
franta-hg@0
   172
franta-hg@0
   173
        if (z.getPrijemci() == null) {
franta-hg@0
   174
            log.log(Level.WARNING, "getPrijemci() == null");
franta-hg@0
   175
            return false;
franta-hg@0
   176
        }
franta-hg@0
   177
franta-hg@0
   178
        if (z.getPrijemci().size() < 1) {
franta-hg@0
   179
            log.log(Level.WARNING, "getPrijemci().size() < 1");
franta-hg@0
   180
            return false;
franta-hg@0
   181
        }
franta-hg@0
   182
franta-hg@0
   183
        if (z.getOdesilatel() == null) {
franta-hg@0
   184
            log.log(Level.WARNING, "getOdesilatel() == null");
franta-hg@0
   185
            return false;
franta-hg@0
   186
        }
franta-hg@0
   187
franta-hg@0
   188
        if (z.getPredmet() == null) {
franta-hg@0
   189
            log.log(Level.WARNING, "getPredmet() == null");
franta-hg@0
   190
            return false;
franta-hg@0
   191
        }
franta-hg@0
   192
franta-hg@0
   193
        return true;
franta-hg@0
   194
    }
franta-hg@0
   195
franta-hg@0
   196
    private static boolean zkontrolujNastaveni(Nastaveni n) {
franta-hg@0
   197
franta-hg@0
   198
        if (n.getPostovniServer() == null || n.getPostovniServer().length() < 1) {
franta-hg@0
   199
            return false;
franta-hg@0
   200
        }
franta-hg@0
   201
franta-hg@0
   202
        return true;
franta-hg@0
   203
    }
franta-hg@0
   204
franta-hg@0
   205
    /** Slouží k uložení jména a hesla pro SMTP */
franta-hg@0
   206
    private static class PostakuvHeslovnik extends Authenticator {
franta-hg@0
   207
franta-hg@0
   208
        private String jmeno = "user";
franta-hg@0
   209
        private char[] heslo = "luser".toCharArray();
franta-hg@0
   210
franta-hg@0
   211
        @Override
franta-hg@0
   212
        public PasswordAuthentication getPasswordAuthentication() {
franta-hg@0
   213
            return new PasswordAuthentication(jmeno, String.valueOf(heslo));
franta-hg@0
   214
        }
franta-hg@0
   215
franta-hg@0
   216
        public void setJmenoHeslo(String jmeno, char[] heslo) {
franta-hg@0
   217
            this.jmeno = jmeno;
franta-hg@0
   218
            this.heslo = heslo;
franta-hg@0
   219
        }
franta-hg@0
   220
    }
franta-hg@0
   221
}