1
2
3
4
5
6
7
8
9
10
11 package com.atlassian.mail.server;
12
13 import com.atlassian.mail.MailException;
14 import com.atlassian.mail.MailFactory;
15 import com.atlassian.mail.MailProtocol;
16 import org.apache.commons.lang.StringUtils;
17 import org.apache.commons.lang.builder.EqualsBuilder;
18 import org.apache.commons.lang.builder.HashCodeBuilder;
19 import org.apache.commons.lang.builder.ToStringBuilder;
20 import org.apache.log4j.Logger;
21
22 import javax.mail.Authenticator;
23 import javax.mail.Session;
24 import java.io.PrintStream;
25 import java.io.Serializable;
26 import java.io.ObjectInputStream;
27 import java.io.IOException;
28 import java.lang.reflect.Field;
29 import java.util.Arrays;
30 import java.util.Properties;
31
32 public abstract class AbstractMailServer implements MailServer, Serializable
33 {
34 protected transient Logger log = Logger.getLogger(this.getClass());
35 private Long id;
36 private String name;
37 private String description;
38 private String hostname;
39 private String username = null;
40 private String password = null;
41 private MailProtocol mailProtocol = null;
42 private String port = null;
43 private long timeout;
44 private boolean debug;
45 private boolean tlsRequired;
46 private transient PrintStream debugStream;
47 private Properties props = new Properties();
48 protected boolean isAuthenticating;
49 private String socksHost;
50 private String socksPort;
51
52 public AbstractMailServer()
53 {
54 }
55
56 public AbstractMailServer(Long id, String name, String description, MailProtocol protocol, String hostName, String port, String username, String password, long timeout, String socksHost, String socksPort)
57 {
58 setId(id);
59 setName(name);
60 setDescription(description);
61 setHostname(hostName);
62 setUsername(username);
63 setPassword(password);
64 setMailProtocol(protocol);
65 setPort(port);
66 setTimeout(timeout);
67 setSocksHost(socksHost);
68 setSocksPort(socksPort);
69
70 this.props = loadSystemProperties(props);
71 }
72
73 private void setInitialProperties()
74 {
75 if (getMailProtocol() != null)
76 {
77 final String protocol = getMailProtocol().getProtocol();
78 props.put("mail."+protocol+".host",""+getHostname());
79 props.put("mail."+protocol+".port", ""+getPort());
80 props.put("mail."+protocol+".timeout",""+getTimeout());
81 props.put("mail.transport.protocol",""+ protocol);
82 if (isTlsRequired())
83 {
84 props.put("mail."+protocol+".starttls.enable","true");
85 }
86 if (StringUtils.isNotBlank(getUsername()))
87 {
88 props.put("mail."+protocol+".auth", "true");
89 isAuthenticating = true;
90 }
91
92 if (StringUtils.isNotBlank(getSocksHost()))
93 {
94 props.put("mail." + protocol + ".socks.host", getSocksHost());
95 }
96
97 if (StringUtils.isNotBlank(getSocksPort()))
98 {
99 props.put("mail." + protocol + ".socks.port", getSocksPort());
100 }
101 }
102 props.put("mail.debug", ""+getDebug());
103 if (Boolean.getBoolean("mail.debug"))
104 {
105 props.put("mail.debug", "true");
106 }
107 }
108
109 protected abstract Authenticator getAuthenticator();
110
111 public Long getId()
112 {
113 return id;
114 }
115
116 public void setId(Long id)
117 {
118 this.id = id;
119 propertyChanged();
120 }
121
122 public String getName()
123 {
124 return name;
125 }
126
127 public void setName(String name)
128 {
129 this.name = name;
130 propertyChanged();
131 }
132
133 public String getDescription()
134 {
135 return description;
136 }
137
138 public void setDescription(String description)
139 {
140 this.description = description;
141 propertyChanged();
142 }
143
144 public String getHostname()
145 {
146 return hostname;
147 }
148
149 public void setHostname(String serverName)
150 {
151 this.hostname = serverName;
152 propertyChanged();
153 }
154
155 public String getUsername()
156 {
157 return username;
158 }
159
160 public void setUsername(String username)
161 {
162 if (StringUtils.isNotBlank(username))
163 this.username = username;
164 else
165 this.username = null;
166 propertyChanged();
167 }
168
169 public String getPassword()
170 {
171 return password;
172 }
173
174 public void setPassword(String password)
175 {
176 if (StringUtils.isNotBlank(password))
177 this.password = password;
178 else
179 this.password = null;
180 propertyChanged();
181 }
182
183 public MailProtocol getMailProtocol()
184 {
185 return mailProtocol;
186 }
187
188 public void setMailProtocol(final MailProtocol protocol)
189 {
190 this.mailProtocol = protocol;
191 propertyChanged();
192 }
193
194 public String getPort()
195 {
196 return port;
197 }
198
199 public void setPort(final String port)
200 {
201 this.port = port;
202 propertyChanged();
203 }
204
205 public long getTimeout()
206 {
207 return timeout;
208 }
209
210 public void setTimeout(long timeout)
211 {
212 this.timeout = timeout;
213 propertyChanged();
214 }
215
216 public String getSocksHost()
217 {
218 return socksHost;
219 }
220
221 public void setSocksHost(String socksHost)
222 {
223 this.socksHost = socksHost;
224 propertyChanged();
225 }
226
227 public String getSocksPort()
228 {
229 return socksPort;
230 }
231
232 public void setSocksPort(String socksPort)
233 {
234 this.socksPort = socksPort;
235 propertyChanged();
236 }
237
238 public boolean isTlsRequired()
239 {
240 return tlsRequired;
241 }
242
243 public void setTlsRequired(final boolean tlsRequired)
244 {
245 this.tlsRequired = tlsRequired;
246 propertyChanged();
247 }
248
249 public Properties getProperties()
250 {
251 return props;
252 }
253
254 public void setProperties(Properties props)
255 {
256 this.props = props;
257 propertyChanged();
258 }
259
260 public void setDebug(boolean debug) {
261 this.debug = debug;
262 propertyChanged();
263 }
264
265 public void setDebugStream(PrintStream debugStream) {
266 this.debugStream = debugStream;
267 propertyChanged();
268 }
269
270
271 public boolean getDebug() {
272 return this.debug;
273 }
274
275 public PrintStream getDebugStream() {
276 return this.debugStream;
277 }
278
279
280 public boolean equals(Object o)
281 {
282 if (this == o) return true;
283 if (!(o instanceof AbstractMailServer)) return false;
284 final AbstractMailServer abstractMailServer = (AbstractMailServer) o;
285 return new EqualsBuilder()
286 .append(id, abstractMailServer.id)
287 .append(name, abstractMailServer.name)
288 .append(description, abstractMailServer.description)
289 .append(hostname, abstractMailServer.hostname)
290 .append(username, abstractMailServer.username)
291 .append(password, abstractMailServer.password)
292 .append(mailProtocol, abstractMailServer.mailProtocol)
293 .append(port, abstractMailServer.port)
294 .append(socksHost, abstractMailServer.socksHost)
295 .append(socksPort, abstractMailServer.socksPort)
296 .isEquals();
297 }
298
299 public int hashCode() {
300 return new HashCodeBuilder()
301 .append(id)
302 .append(name)
303 .append(description)
304 .append(hostname)
305 .append(username)
306 .append(password)
307 .append(mailProtocol)
308 .append(port)
309 .append(socksHost)
310 .append(socksPort)
311 .toHashCode();
312 }
313
314 public String toString()
315 {
316 return new ToStringBuilder(this)
317 .append("id", id)
318 .append("name", name)
319 .append("description", description)
320 .append("server name", hostname)
321 .append("username", username)
322 .append("password", password != null ? "***" : "<unset>")
323 .append("socks host", socksHost)
324 .append("socks port", socksPort)
325 .toString();
326 }
327
328
329
330
331
332 protected void propertyChanged()
333 {
334 setInitialProperties();
335 }
336
337 private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException
338 {
339 ois.defaultReadObject();
340 log = Logger.getLogger(this.getClass());
341 }
342
343
344
345
346
347
348
349
350
351
352 protected synchronized Properties loadSystemProperties(Properties p)
353 {
354 Properties props = new Properties();
355 props.putAll(p);
356 props.putAll(System.getProperties());
357 if (this.props != null)
358 {
359 props.putAll(this.props);
360 }
361 return props;
362 }
363
364 public void setLogger(Logger logger) {
365 this.log = logger;
366 }
367
368
369
370
371
372 protected void getMoreDebugInfoAboutCreatedSession(Session session) {
373 log.debug("Session providers: [" + Arrays.toString(session.getProviders()) + "]");
374 try
375 {
376 final Field addressMapField = Session.class.getDeclaredField("addressMap");
377 final boolean originalAccessibility = addressMapField.isAccessible();
378 addressMapField.setAccessible(true);
379 try
380 {
381 log.debug("Session addressMap: [" + addressMapField.get(session) + "]");
382 }
383 finally
384 {
385 addressMapField.setAccessible(originalAccessibility);
386 }
387
388 }
389 catch (Exception e)
390 {
391 log.debug("Cannot retrieve Session details via reflections: " + e.getMessage(), e);
392 }
393 }
394
395 protected Session getSessionFromServerManager(Properties props, final Authenticator authenticator) throws MailException {
396 log.debug("Getting session");
397 if (getDebug())
398 {
399 log.debug("Debug messages from JavaMail session initialization will not appear in this log." +
400 " These messages are sent to standard out.");
401 }
402 final Session session = MailFactory.getServerManager().getSession(props, authenticator);
403
404 if (log.isDebugEnabled())
405 {
406 getMoreDebugInfoAboutCreatedSession(session);
407 }
408 if (getDebugStream() != null)
409 {
410 try
411 {
412 session.setDebugOut(getDebugStream());
413 }
414 catch (NoSuchMethodError nsme)
415 {
416
417 log.error("Warning: An old (pre-1.3.2) version of the JavaMail library (javamail.jar or mail.jar) bundled with your app server, is in use. Some functions such as IMAPS/POPS/SMTPS will not work. Consider upgrading the app server's javamail jar to the version JIRA provides.");
418 }
419 }
420 return session;
421 }
422
423 }