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