MailEngine.java
001 /*
002  * This class is part of DocWhatsUp, a bug profiling and -reporting lib.
003  
004  * Copyright (C)
005  
006  * This library is free software; you can redistribute it and/or modify it
007  * under the terms of the GNU General Public License as published by the
008  * Free Software Foundation; either version 2 of the License, or (at your
009  * option) any later version.
010  
011  * This program is distributed in the hope that it will be useful, but
012  * WITHOUT ANY WARRANTY; without even the implied warranty of
013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
014  * Public License for more details.
015  *  
016  * You should have received a copy of the GNU General Public License along
017  * with this program; if not, write to the Free Software Foundation, Inc.,
018  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019  
020  * EXTENSION:
021  * Linking DocWhatsUp statically or dynamically with other modules is making a
022  * combined work based on DocWhatsUp.  Thus, the terms and conditions of the 
023  * GNU General Public License cover the whole combination.
024  *
025  * As a special exception, the copyright holder of DocWhatsUp give you
026  * permission to link DocWhatsUp with independent modules that communicate with
027  * DocWhatsUp solely through the DocWhatsUp.java interface, regardless of the 
028  * license terms of these independent modules, and to copy and distribute the
029  * resulting combined work under terms of your choice, provided that
030  * every copy of the combined work is accompanied by a complete copy of
031  * the source code of DocWhatsUp (the version of DocWhatsUp used to produce the
032  * combined work), being distributed under the terms of the GNU General
033  * Public License plus this exception.  An independent module is a module
034  * which is not derived from or based on DocWhatsUp.
035 
036  * Note that people who make modified versions of DocWhatsUp are not obligated
037  * to grant this special exception for their modified versions; it is
038  * their choice whether to do so.  The GNU General Public License gives
039  * permission to release a modified version without this exception; this
040  * exception also makes it possible to release a modified version which
041  * carries forward this exception.
042  
043  * Author: Philipp Bartsch; codeshaker@gmx.net
044  */
045 
046 package org.shaker.dwu;
047 
048 import java.awt.Component;
049 import java.awt.Cursor;
050 import java.util.Date;
051 
052 import javax.mail.AuthenticationFailedException;
053 import javax.mail.Message;
054 import javax.mail.MessagingException;
055 import javax.mail.PasswordAuthentication;
056 import javax.mail.Session;
057 import javax.mail.Transport;
058 import javax.mail.internet.InternetAddress;
059 
060 import com.sun.mail.smtp.SMTPMessage;
061 
062 /**
063  * This pure static class provides methods to submit BugProfiles
064  * and to check addresses and ports.
065  *
066  @author <A HREF="mailto:codeshaker@gmx.net">
067  *            Philipp Bartsch (codeshaker@gmx.net)</A>
068  *            <A HREF="../../../../gpl.txt">GPL License</A>
069  */
070 public final class MailEngine {
071     
072     /**a local reference to DWU`s properties*/
073     private final static Settings SETTINGS  = DocWhatsUp.SETTINGS;        
074     
075     /**
076      * Invisible constructor. This class is a factory, so it`s not meant to be
077      * instantiated.
078      */
079     private MailEngine () {}
080     
081     /**
082      * Submits an array of BugProfiles and returns a success description.
083      *
084      @param  parent     a parental Component
085      @param  profiles the array of BugProfiles
086      @return             a string, that contains an error description in
087      *                    case of a failed submission or nothing, if successful
088      */
089     static String submit (final Component      parent,
090                           final BugProfile[]  profiles) {
091         try {
092             if (profiles == null
093                 || profiles.length == 0)
094                 throw new NullPointerException("No queued BugProfile found");
095                             
096             final Session session = Session.getDefaultInstance(SETTINGS,
097                                                                null)
098             if (SETTINGS.hasPOPServer())
099                 performPOPAuth(session);
100                                             
101             final Message[] messages = getMessageArray(session,
102                                                        profiles);
103             if (parent != null)
104                 parent.setCursor(new Cursor (Cursor.WAIT_CURSOR));
105                 submitMsgs(messages,
106                               profiles);
107                 if (SETTINGS.hasMaintainer() && ToolBox.existsLogFile())
108                     submitMaintenanceMessage(session);
109             if (parent != null)
110                 parent.setCursor(new Cursor (Cursor.DEFAULT_CURSOR));
111             return "";       
112         catch (AuthenticationFailedException afe) {
113             if (parent != null)
114                 parent.setCursor(new Cursor (Cursor.DEFAULT_CURSOR));
115             return afe.getMessage();
116         catch (MessagingException me) {
117             if (parent != null)
118                 parent.setCursor(new Cursor (Cursor.DEFAULT_CURSOR));
119             return me.getMessage();    
120         catch (Exception e) {
121             if (parent != null)
122                 parent.setCursor(new Cursor (Cursor.DEFAULT_CURSOR));
123             ToolBox.logException(e);
124             return (e.getMessage() == null
125                     "Internal Error!"
126                     : e.getMessage());    
127         finally {
128             GUIFactory.killProgressWindow();
129         }
130     }
131     
132     /**
133      * This method performs a POP-Authentification based on the settings in
134      * dwuProps (POP server, POP port, username, password).
135      
136      @param session                 the current mailing session
137      @throws MessagingException   on POP-Auth connection errors
138      */
139     private static final void performPOPAuth (final Session session
140                                               throws MessagingException {                
141         session.getStore("pop3").connect(SETTINGS.getPOPServer(),
142                                          SETTINGS.getPOPPort(),
143                                          SETTINGS.getUser(),
144                                          SETTINGS.getPassword());
145     }
146     
147     /**
148      * Returns a Message array that encapsulates the BugProfile queue.
149      
150      @param  session                 the current mailing session
151      @param  profs                the BugProfiles queue stored in an array
152      @return Message[]            an array of messages
153      @throws MessagingException   thrown on message creation errors
154      */
155     private static final Message[] getMessageArray (final Session      session,
156                                                      final BugProfile[] profs
157                                                     throws MessagingException {
158         final Message[]         messages = new Message[profs.length];
159         final InternetAddress    sender     = SETTINGS.getSender();
160                 
161         // create a message (mail object) for each bugprofile
162         for (int i = 0; i < profs.length; i++) {
163             if (profs[i].getRecipient() == null) {        
164                 messages[inull;
165             else {
166                 messages[inew SMTPMessage(session);
167                 messages[i].setContent(profs[i].getMailBody(),
168                                           profs[i].getMimeType());
169                 messages[i].setFrom(sender);
170                 messages[i].setRecipient(Message.RecipientType.TO, 
171                                          profs[i].getRecipient());
172                 if (SETTINGS.hasCoRecipient()) {
173                     final InternetAddress[] ccAdds = SETTINGS.getCoRecipients();
174                     for (int j = ccAdds.length - 1; j>=0; j--)                
175                         messages[i].addRecipient(Message.RecipientType.TO,
176                                                  ccAdds[j]);
177                 }
178                 messages[i].setSubject(profs[i].getSubjectLine());
179             }            
180         }        
181         return messages;                                                 
182     }
183     
184     /**
185      * This method sends a maintenance mail, that contains the error.log text.
186      
187      @param session the current mailing session
188      */
189     private static final void submitMaintenanceMessage (final Session session
190                                                      throws MessagingException {
191         final BugProfile         mBug;
192         mBug = DocWhatsUp.createBugProfile("Maintenance Message on " +
193                                            new Date(System.currentTimeMillis()),
194                                            "Maintenance");
195         mBug.setProperty("format",
196                          "html");
197         mBug.setProperty("Logfile Body",
198                          ToolBox.getLogText());
199         final Message message = new SMTPMessage(session);
200         message.setFrom(SETTINGS.getSender());
201         if (SETTINGS.hasMaintainer()) { 
202             // maintainer addresses
203             final InternetAddress[] mntAdds    = SETTINGS.getMaintainers();
204             for (int i = mntAdds.length-1; i>=0; i--)
205                 message.addRecipient(Message.RecipientType.TO,
206                                      mntAdds[i]);
207         }
208         message.setContent(mBug.getMailBody(),
209                            mBug.getMimeType());
210         // ;P    
211         message.setSubject("Hi Philipp! " + mBug.getProperty(BugMail.MESSAGE));
212                                          
213         GUIFactory.showProgressWindow(1);
214         Transport.send(message);   
215         mBug.killPhysically();
216         ToolBox.killLogFile();
217         GUIFactory.PROGRESSKIT.increase();
218     }
219         
220     /**
221      * Sends an array of messages.
222      
223      @param messages                the messages
224      @param profiles                the underlying profiles
225      @throws MessagingException    in case of an submission error
226      */
227     private static final void submitMsgs (final Message[]    messages,
228                                           final BugProfile[] profiles
229                                           throws MessagingException {
230         GUIFactory.showProgressWindow(messages.length);
231         for (int i = messages.length-1; i >= 0; i--) {                                
232             // is null if no recipient specified and no "alt" available
233             if (messages[i!= null) {
234                 Transport.send(messages[i]);   
235                 SETTINGS.registerSubmission(profiles[i].getHashSig());                
236             }
237             profiles[i].killPhysically();
238             GUIFactory.PROGRESSKIT.increase();            
239         }        
240     }
241     
242     
243     /**
244      * Returns true, if the given address string is a valid mail address.<br>
245      * TODO Weak implementation yet, has to be improved!
246      *
247      @param  address the address string
248      @return         boolean flag
249      */
250     static boolean validateMail (final String address) {
251         try {
252             new InternetAddress(address).validate();    
253             return true;
254         catch (Exception e) {
255             return false;        
256         }    
257     }
258     
259     /**
260      * Returns true, if the given address string is a valid server
261      * address.<b>
262      * TODO Weak implementation yet, has to be improved!
263      *
264      @param  address the address
265      @return boolean flag
266      */
267     static boolean validateServer (final String address) {
268         return address.indexOf("."> -1;
269     }
270     
271     /**
272      * Returns true, if the given address string is a port
273      *
274      @param portString    the port
275      @return              boolean flag
276      */
277     static boolean validatePort (final String portString) {
278         try {
279             final int port = Integer.parseInt(portString);
280             return (< port && port < 65537);                
281         catch (NumberFormatException nfe) {
282             // the griven number is not an integer
283             // so its not a valid port.
284             return false;    
285         }
286     }
287     
288     /** 
289      * An Authenticator. Necessary for POP Auth.
290      
291      @author <a href="mailto:codeshaker@gmx.net">
292       *            Philipp Bartsch (codeshaker@gmx.net)</a>
293       */
294     final class DWUAuthenticator extends javax.mail.Authenticator {
295     
296         /**Username*/
297         private final String user;
298         /**Password*/
299         private final String pass;
300     
301         /**
302          * Creates an Authenticator object.
303          @param user username
304          @param pass password
305          */
306         public DWUAuthenticator (final String user,
307                                  final String pass) {
308             this.user = user;
309             this.pass = pass;
310         }
311     
312         /**
313          * Returns the needed Authenticator.
314          @return PasswordAuthentication a specialized Authenticator
315          */
316         public PasswordAuthentication getPassAuth () {
317             return new PasswordAuthentication(user, 
318                                               pass);    
319         }        
320     }
321 }