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[i] = null;
165 } else {
166 messages[i] = new 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 (0 < 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 }
|