1   /*
2    * Created by IntelliJ IDEA.
3    * User: owen
4    * Date: Nov 22, 2002
5    * Time: 3:50:23 PM
6    * CVS Revision: $Revision: 1.34 $
7    * Last CVS Commit: $Date: 2006/10/20 05:51:09 $
8    * Author of last CVS Commit: $Author: cmiller $
9    * To change this template use Options | File Templates.
10   */
11  package com.atlassian.mail.server.impl;
12  
13  import alt.javax.mail.Session;
14  import alt.javax.mail.SessionImpl;
15  import alt.javax.mail.internet.MimeMessage;
16  import alt.javax.mail.internet.MimeMessageImpl;
17  import com.atlassian.mail.Email;
18  import com.atlassian.mail.MailException;
19  import com.atlassian.mail.MailFactory;
20  import com.atlassian.mail.config.PropertiesLoader;
21  import com.atlassian.mail.server.AbstractMailServer;
22  import com.atlassian.mail.server.MailServerManager;
23  import com.atlassian.mail.server.SMTPMailServer;
24  import com.atlassian.mail.server.impl.util.MessageCreator;
25  import com.opensymphony.util.TextUtils;
26  import org.apache.commons.lang.builder.ToStringBuilder;
27  import org.apache.log4j.Category;
28  
29  import javax.mail.Authenticator;
30  import javax.mail.MessagingException;
31  import javax.mail.PasswordAuthentication;
32  import javax.naming.Context;
33  import javax.naming.InitialContext;
34  import javax.naming.NamingException;
35  import java.io.PrintStream;
36  import java.io.UnsupportedEncodingException;
37  import java.util.Properties;
38  
39  public class SMTPMailServerImpl extends AbstractMailServer implements SMTPMailServer
40  {
41      private static final Category log = Category.getInstance(SMTPMailServerImpl.class);
42  
43      private boolean isSessionServer;
44      private String defaultFrom;
45      private String prefix;
46      private String jndiLocation;
47      private String smtpPort = DEFAULT_SMTP_PORT;
48      private boolean removePrecedence;
49      private boolean debug;
50  
51      private transient PrintStream debugStream;
52      private transient Session session;
53  
54      public SMTPMailServerImpl()
55      {
56      }
57  
58      public SMTPMailServerImpl(Long id, String name, String description, String from, String prefix, boolean isSession, String location, String username, String password)
59      {
60          this(id, name, description, from, prefix, isSession, location, username, password, SMTPMailServer.DEFAULT_SMTP_PORT);
61      }
62  
63      public SMTPMailServerImpl(Long id, String name, String description, String from, String prefix, boolean isSession, String location, String username, String password, String smtpPort)
64      {
65          this(id, name, description, from, prefix, isSession, false, location, username, password, smtpPort);
66      }
67  
68      public SMTPMailServerImpl(Long id, String name, String description, String from, String prefix, boolean isSession, boolean removePrecedence, String location, String username, String password, String smtpPort)
69      {
70          super(id, name, description, location, username, password);
71          setDefaultFrom(from);
72          setPrefix(prefix);
73          setSessionServer(isSession);
74          setSmtpPort(smtpPort);
75          setRemovePrecedence(removePrecedence);
76  
77          if (isSession)
78          {
79              setJndiLocation(location);
80              setHostname(null);
81          }
82      }
83  
84      public String getJndiLocation()
85      {
86          return jndiLocation;
87      }
88  
89      public void setJndiLocation(String jndiLocation)
90      {
91          this.jndiLocation = jndiLocation;
92          propertyChanged();
93      }
94  
95      protected Authenticator getAuthenticator()
96      {
97          return new MyAuthenticator();
98      }
99  
100     /**
101      * get the mail session
102      */
103     public Session getSession() throws NamingException, MailException
104     {
105         if (session == null)
106 
107         {
108             if (isSessionServer())
109             {
110                 Object jndiSession = getJndiSession();
111                 if (jndiSession instanceof javax.mail.Session)
112                 {
113                     session = new SessionImpl((javax.mail.Session) jndiSession);
114                 }
115                 else
116                 {
117                     log.error("Mail server at location [" + getJndiLocation() + "] is not of required type javax.mail.Session, or is in different classloader. " +
118                             "It is of type '" + (jndiSession != null ? jndiSession.getClass().getName() : null) + "' in classloader '"+jndiSession.getClass().getClassLoader()+"' instead");
119                     throw new IllegalArgumentException("Mail server at location [" + getJndiLocation() + "] is not of required type javax.mail.Session. ");
120                 }
121             }
122             else
123             {
124                 Properties props = new Properties();
125                 props.put("mail.smtp.host", getHostname());
126                 props.put("mail.smtp.port", getSmtpPort());
127                 props.put("mail.transport.protocol", "smtp");
128                 props.put("mail.debug", ""+debug);
129 //                props.put("mail.removePrecedence", removePrecedence);
130                 if (Boolean.getBoolean("mail.debug"))
131                 {
132                     props.put("mail.debug", "true");
133                 }
134                 Authenticator auth = null;
135                 if (TextUtils.stringSet(getUsername()))
136                 {
137                     props.put("mail.smtp.auth", "true");
138                     auth = getAuthenticator();
139                 }
140                 props.putAll(PropertiesLoader.ATLASSIAN_MAIL_PROPERTIES);
141                 session = MailFactory.getServerManager().getSession(props, auth);
142                 if (debugStream != null)
143                 {
144                     try
145                     {
146                     session.getWrappedSession().setDebugOut(debugStream);
147                     } catch (NoSuchMethodError nsme)
148                     {
149                         // JRA-8543
150                         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.");
151                     }
152                 }
153             }
154         }
155         return session;
156     }
157 
158     protected Object getJndiSession() throws NamingException
159     {
160         Context ctx = new InitialContext();
161         Object jndiSession = ctx.lookup(getJndiLocation());
162         return jndiSession;
163     }
164 
165     public void send(Email email) throws MailException
166     {
167         try
168         {
169             Session thisSession = getSession();
170 
171             MimeMessage message = new MimeMessageImpl(thisSession);
172             MessageCreator messageCreator = new MessageCreator();
173 
174             messageCreator.updateMimeMessage(email, getDefaultFrom(), prefix, message);
175 
176             // Send the message
177             thisSession.getTransport("smtp").send(message);
178 
179             // Message-Id is set by the MTA (I think) so is only accessible after sending
180             if (message.getHeader("Message-Id") != null && message.getHeader("Message-Id").length > 0)
181             {
182                 email.setMessageId(message.getHeader("Message-Id")[0]);
183             }
184         }
185         catch (NamingException e)
186         {
187             throw new MailException(e);
188         }
189         catch (MessagingException e)
190         {
191             throw new MailException(e);
192         }
193         catch (UnsupportedEncodingException e)
194         {
195             log.debug("Error setting the 'from' address with an email and the user's fullname");
196             e.printStackTrace();
197         }
198     }
199 
200 
201     /**
202      * Send a message - but don't throw exceptions, just log the errors
203      */
204     public void quietSend(Email email) throws MailException
205     {
206         try
207         {
208             send(email);
209         }
210         catch (Exception e)
211         {
212             log.error("Error sending mail. to:" + email.getTo() + ", cc:" + email.getCc() + ", bcc:" + email.getBcc() + ", subject:" + email.getSubject() + ", body:" + email.getBody() + ", mimeType:" + email.getMimeType() + ", encoding:" + email.getEncoding() + ", multipart:" + email.getMultipart() + ", error:" + e, e);
213         }
214     }
215 
216     public String getType()
217     {
218         return MailServerManager.SERVER_TYPES[1];
219     }
220 
221     public String getDefaultFrom()
222     {
223         return defaultFrom;
224     }
225 
226     public void setDefaultFrom(String defaultFrom)
227     {
228         this.defaultFrom = defaultFrom;
229         propertyChanged();
230     }
231 
232     public String getPrefix()
233     {
234         return prefix;
235     }
236 
237     public void setPrefix(String prefix)
238     {
239         this.prefix = prefix;
240     }
241 
242     public boolean isRemovePrecedence()
243     {
244         return removePrecedence;
245     }
246 
247     public void setRemovePrecedence(boolean precedence)
248     {
249         this.removePrecedence = precedence;
250         propertyChanged();
251     }
252 
253     public String getSmtpPort()
254     {
255         return smtpPort;
256     }
257 
258     public void setSmtpPort(String smtpPort)
259     {
260         this.smtpPort = smtpPort;
261         propertyChanged();
262     }
263 
264     public void setDebug(boolean debug) {
265         this.debug = debug;
266         propertyChanged();
267     }
268 
269     public void setDebugStream(PrintStream debugStream) {
270         this.debugStream = debugStream;
271         propertyChanged();
272     }
273 
274 
275     public boolean getDebug() {
276         return this.debug;
277     }
278 
279     public PrintStream getDebugStream() {
280         return this.debugStream;
281     }
282 
283     public boolean isSessionServer()
284     {
285         return isSessionServer;
286     }
287 
288     public void setSessionServer(boolean sessionServer)
289     {
290         isSessionServer = sessionServer;
291         propertyChanged();
292     }
293 
294     private class MyAuthenticator extends Authenticator
295     {
296         public PasswordAuthentication getPasswordAuthentication()
297         {
298             return new PasswordAuthentication(getUsername(), getPassword());
299         }
300     }
301 
302     ///CLOVER:OFF
303     public boolean equals(Object o)
304     {
305         if (this == o)
306         {
307             return true;
308         }
309         if (!(o instanceof SMTPMailServerImpl))
310         {
311             return false;
312         }
313         if (!super.equals(o))
314         {
315             return false;
316         }
317 
318         final SMTPMailServerImpl smtpMailServer = (SMTPMailServerImpl) o;
319 
320         if (isSessionServer != smtpMailServer.isSessionServer)
321         {
322             return false;
323         }
324         if (defaultFrom != null ? !defaultFrom.equals(smtpMailServer.defaultFrom) : smtpMailServer.defaultFrom != null)
325         {
326             return false;
327         }
328         if (prefix != null ? !prefix.equals(smtpMailServer.prefix) : smtpMailServer.prefix != null)
329         {
330             return false;
331         }
332         if (smtpPort != null ? !smtpPort.equals(smtpMailServer.smtpPort) : smtpMailServer.smtpPort != null)
333         {
334             return false;
335         }
336         if (removePrecedence !=  smtpMailServer.removePrecedence)
337         {
338             return false;
339         }
340 
341         return true;
342     }
343 
344     public int hashCode()
345     {
346         int result = super.hashCode();
347         result = 29 * result + (isSessionServer ? 1 : 0);
348         result = 29 * result + (defaultFrom != null ? defaultFrom.hashCode() : 0);
349         result = 29 * result + (prefix != null ? prefix.hashCode() : 0);
350         result = 29 * result + (smtpPort != null ? smtpPort.hashCode() : 0);
351         result = 29 * result + (removePrecedence ? 1 : 0);
352         return result;
353     }
354 
355     public String toString()
356     {
357        return new ToStringBuilder(this).append("id", getId()).append("name", getName()).append("description", getDescription()).append("server name", getHostname()).append("username", getUsername()).append("password", getPassword()).append("isSessionServer", isSessionServer).append("defaultFrom", defaultFrom).append("prefix", prefix).append("smtpPort", smtpPort).toString();
358     }
359 
360     /**
361      * Discard the cached session when a property of the server changes.
362      */
363     protected void propertyChanged()
364     {
365         super.propertyChanged();
366         session = null;
367     }
368 }