001: /*
002: * Copyright (c) JForum Team
003: * All rights reserved.
004: *
005: * Redistribution and use in source and binary forms,
006: * with or without modification, are permitted provided
007: * that the following conditions are met:
008: *
009: * 1) Redistributions of source code must retain the above
010: * copyright notice, this list of conditions and the
011: * following disclaimer.
012: * 2) Redistributions in binary form must reproduce the
013: * above copyright notice, this list of conditions and
014: * the following disclaimer in the documentation and/or
015: * other materials provided with the distribution.
016: * 3) Neither the name of "Rafael Steil" nor
017: * the names of its contributors may be used to endorse
018: * or promote products derived from this software without
019: * specific prior written permission.
020: *
021: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT
022: * HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
023: * EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
024: * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
025: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR
026: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
027: * THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
028: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
029: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES
030: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
031: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
032: * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
033: * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
034: * IN CONTRACT, STRICT LIABILITY, OR TORT
035: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
036: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
037: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
038: *
039: * This file creation date: 03/03/2004 - 20:29:45
040: * The JForum Project
041: * http://www.jforum.net
042: */
043: package net.jforum.util.mail;
044:
045: import java.io.StringWriter;
046: import java.util.ArrayList;
047: import java.util.Date;
048: import java.util.Iterator;
049: import java.util.List;
050: import java.util.Properties;
051:
052: import javax.mail.Address;
053: import javax.mail.Message;
054: import javax.mail.MessagingException;
055: import javax.mail.Session;
056: import javax.mail.Transport;
057: import javax.mail.internet.InternetAddress;
058: import javax.mail.internet.MimeMessage;
059:
060: import net.jforum.JForumExecutionContext;
061: import net.jforum.entities.User;
062: import net.jforum.exceptions.MailException;
063: import net.jforum.util.preferences.ConfigKeys;
064: import net.jforum.util.preferences.SystemGlobals;
065:
066: import org.apache.commons.lang.StringUtils;
067: import org.apache.log4j.Logger;
068:
069: import freemarker.template.SimpleHash;
070: import freemarker.template.Template;
071:
072: /**
073: * Dispatch emails to the world.
074: *
075: * @author Rafael Steil
076: * @version $Id: Spammer.java,v 1.36 2007/09/20 16:07:08 rafaelsteil Exp $
077: */
078: public class Spammer {
079: private static final Logger logger = Logger
080: .getLogger(Spammer.class);
081:
082: private static final int MESSAGE_HTML = 0;
083: private static final int MESSAGE_TEXT = 1;
084:
085: private static int messageFormat;
086: private Session session;
087: private String username;
088: private String password;
089:
090: private Properties mailProps = new Properties();
091: private MimeMessage message;
092: private List users = new ArrayList();
093: private String messageId;
094: private String inReplyTo;
095: private boolean needCustomization;
096: private SimpleHash templateParams;
097: private Template template;
098:
099: protected Spammer() throws MailException {
100: boolean ssl = SystemGlobals
101: .getBoolValue(ConfigKeys.MAIL_SMTP_SSL);
102:
103: String hostProperty = this .hostProperty(ssl);
104: String portProperty = this .portProperty(ssl);
105: String authProperty = this .authProperty(ssl);
106: String localhostProperty = this .localhostProperty(ssl);
107:
108: mailProps.put(hostProperty, SystemGlobals
109: .getValue(ConfigKeys.MAIL_SMTP_HOST));
110: mailProps.put(portProperty, SystemGlobals
111: .getValue(ConfigKeys.MAIL_SMTP_PORT));
112:
113: String localhost = SystemGlobals
114: .getValue(ConfigKeys.MAIL_SMTP_LOCALHOST);
115:
116: if (!StringUtils.isEmpty(localhost)) {
117: mailProps.put(localhostProperty, localhost);
118: }
119:
120: mailProps.put("mail.mime.address.strict", "false");
121: mailProps.put("mail.mime.charset", SystemGlobals
122: .getValue(ConfigKeys.MAIL_CHARSET));
123: mailProps.put(authProperty, SystemGlobals
124: .getValue(ConfigKeys.MAIL_SMTP_AUTH));
125:
126: username = SystemGlobals
127: .getValue(ConfigKeys.MAIL_SMTP_USERNAME);
128: password = SystemGlobals
129: .getValue(ConfigKeys.MAIL_SMTP_PASSWORD);
130:
131: messageFormat = SystemGlobals.getValue(
132: ConfigKeys.MAIL_MESSSAGE_FORMAT).equals("html") ? MESSAGE_HTML
133: : MESSAGE_TEXT;
134:
135: this .session = Session.getInstance(mailProps);
136: }
137:
138: public boolean dispatchMessages() {
139: try {
140: int sendDelay = SystemGlobals
141: .getIntValue(ConfigKeys.MAIL_SMTP_DELAY);
142:
143: if (SystemGlobals.getBoolValue(ConfigKeys.MAIL_SMTP_AUTH)) {
144: if (!StringUtils.isEmpty(username)
145: && !StringUtils.isEmpty(password)) {
146: boolean ssl = SystemGlobals
147: .getBoolValue(ConfigKeys.MAIL_SMTP_SSL);
148:
149: Transport transport = this .session
150: .getTransport(ssl ? "smtps" : "smtp");
151:
152: try {
153: String host = SystemGlobals
154: .getValue(ConfigKeys.MAIL_SMTP_HOST);
155: transport.connect(host, username, password);
156:
157: if (transport.isConnected()) {
158: for (Iterator userIter = this .users
159: .iterator(); userIter.hasNext();) {
160: User user = (User) userIter.next();
161:
162: if (this .needCustomization) {
163: this .defineUserMessage(user);
164: }
165:
166: Address address = new InternetAddress(
167: user.getEmail());
168:
169: logger.debug("Sending mail to: "
170: + user.getEmail());
171:
172: this .message.setRecipient(
173: Message.RecipientType.TO,
174: address);
175: transport.sendMessage(this .message,
176: new Address[] { address });
177:
178: if (sendDelay > 0) {
179: try {
180: Thread.sleep(sendDelay);
181: } catch (InterruptedException ie) {
182: logger.error(
183: "Error while Thread.sleep."
184: + ie, ie);
185: }
186: }
187: }
188: }
189: } catch (Exception e) {
190: throw new MailException(e);
191: } finally {
192: try {
193: transport.close();
194: } catch (Exception e) {
195: }
196: }
197: }
198: } else {
199: for (Iterator iter = this .users.iterator(); iter
200: .hasNext();) {
201: User user = (User) iter.next();
202:
203: if (this .needCustomization) {
204: this .defineUserMessage(user);
205: }
206:
207: Address address = new InternetAddress(user
208: .getEmail());
209: logger.debug("Sending mail to: " + user.getEmail());
210: this .message.setRecipient(Message.RecipientType.TO,
211: address);
212: Transport.send(this .message,
213: new Address[] { address });
214:
215: if (sendDelay > 0) {
216: try {
217: Thread.sleep(sendDelay);
218: } catch (InterruptedException ie) {
219: logger.error("Error while Thread.sleep."
220: + ie, ie);
221: }
222: }
223: }
224: }
225: } catch (MessagingException e) {
226: logger.error("Error while dispatching the message." + e, e);
227: }
228:
229: return true;
230: }
231:
232: private void defineUserMessage(User user) {
233: try {
234: this .templateParams.put("user", user);
235:
236: String text = this .processTemplate();
237:
238: this .defineMessageText(text);
239: } catch (Exception e) {
240: throw new MailException(e);
241: }
242: }
243:
244: /**
245: * Prepares the mail message for sending.
246: *
247: * @param subject the subject of the email
248: * @param messageFile the path to the mail message template
249: * @throws MailException
250: */
251: protected void prepareMessage(String subject, String messageFile)
252: throws MailException {
253: if (this .messageId != null) {
254: this .message = new IdentifiableMimeMessage(session);
255: ((IdentifiableMimeMessage) this .message)
256: .setMessageId(this .messageId);
257: } else {
258: this .message = new MimeMessage(session);
259: }
260:
261: this .templateParams.put("forumName", SystemGlobals
262: .getValue(ConfigKeys.FORUM_NAME));
263:
264: try {
265: this .message.setSentDate(new Date());
266: this .message.setFrom(new InternetAddress(SystemGlobals
267: .getValue(ConfigKeys.MAIL_SENDER)));
268: this .message.setSubject(subject, SystemGlobals
269: .getValue(ConfigKeys.MAIL_CHARSET));
270:
271: if (this .inReplyTo != null) {
272: this .message.addHeader("In-Reply-To", this .inReplyTo);
273: }
274:
275: this .createTemplate(messageFile);
276: this .needCustomization = this .isCustomizationNeeded();
277:
278: // If we don't need to customize any part of the message,
279: // then build the generic text right now
280: if (!this .needCustomization) {
281: String text = this .processTemplate();
282: this .defineMessageText(text);
283: }
284: } catch (Exception e) {
285: throw new MailException(e);
286: }
287: }
288:
289: /**
290: * Set the text contents of the email we're sending
291: * @param text the text to set
292: * @throws MessagingException
293: */
294: private void defineMessageText(String text)
295: throws MessagingException {
296: String charset = SystemGlobals
297: .getValue(ConfigKeys.MAIL_CHARSET);
298:
299: if (messageFormat == MESSAGE_HTML) {
300: this .message.setContent(text.replaceAll("\n", "<br />"),
301: "text/html; charset=" + charset);
302: } else {
303: this .message.setText(text);
304: }
305: }
306:
307: /**
308: * Gets the message text to send in the email.
309: *
310: * @param messageFile The optional message file to load the text.
311: * @return The email message text
312: * @throws Exception
313: */
314: protected void createTemplate(String messageFile) throws Exception {
315: String templateEncoding = SystemGlobals
316: .getValue(ConfigKeys.MAIL_TEMPLATE_ENCODING);
317:
318: if (StringUtils.isEmpty(templateEncoding)) {
319: this .template = JForumExecutionContext.templateConfig()
320: .getTemplate(messageFile);
321: } else {
322: this .template = JForumExecutionContext.templateConfig()
323: .getTemplate(messageFile, templateEncoding);
324: }
325: }
326:
327: /**
328: * Merge the template data, creating the final content.
329: * This method should only be called after {@link #createTemplate(String)}
330: * and {@link #setTemplateParams(SimpleHash)}
331: *
332: * @return the generated content
333: * @throws Exception
334: */
335: protected String processTemplate() throws Exception {
336: StringWriter writer = new StringWriter();
337: this .template.process(this .templateParams, writer);
338: return writer.toString();
339: }
340:
341: /**
342: * Set the parameters for the template being processed
343: * @param params the parameters to the template
344: */
345: protected void setTemplateParams(SimpleHash params) {
346: this .templateParams = params;
347: }
348:
349: /**
350: * Check if we have to send customized emails
351: * @return true if there is a need for customized emails
352: */
353: private boolean isCustomizationNeeded() {
354: boolean need = false;
355:
356: for (Iterator iter = this .users.iterator(); iter.hasNext();) {
357: User user = (User) iter.next();
358:
359: if (user.notifyText()) {
360: need = true;
361: break;
362: }
363: }
364:
365: return need;
366: }
367:
368: protected void setMessageId(String messageId) {
369: this .messageId = messageId;
370: }
371:
372: protected void setInReplyTo(String inReplyTo) {
373: this .inReplyTo = inReplyTo;
374: }
375:
376: protected void setUsers(List users) {
377: this .users = users;
378: }
379:
380: private String localhostProperty(boolean ssl) {
381: return ssl ? ConfigKeys.MAIL_SMTP_SSL_LOCALHOST
382: : ConfigKeys.MAIL_SMTP_LOCALHOST;
383: }
384:
385: private String authProperty(boolean ssl) {
386: return ssl ? ConfigKeys.MAIL_SMTP_SSL_AUTH
387: : ConfigKeys.MAIL_SMTP_AUTH;
388: }
389:
390: private String portProperty(boolean ssl) {
391: return ssl ? ConfigKeys.MAIL_SMTP_SSL_PORT
392: : ConfigKeys.MAIL_SMTP_PORT;
393: }
394:
395: private String hostProperty(boolean ssl) {
396: return ssl ? ConfigKeys.MAIL_SMTP_SSL_HOST
397: : ConfigKeys.MAIL_SMTP_HOST;
398: }
399: }
|