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 |
}
|