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