001: /*
002: * Copyright 2006 Pentaho Corporation. All rights reserved.
003: * This software was developed by Pentaho Corporation and is provided under the terms
004: * of the Mozilla Public License, Version 1.1, or any later version. You may not use
005: * this file except in compliance with the license. If you need a copy of the license,
006: * please go to http://www.mozilla.org/MPL/MPL-1.1.txt. The Original Code is the Pentaho
007: * BI Platform. The Initial Developer is Pentaho Corporation.
008: *
009: * Software distributed under the Mozilla Public License is distributed on an "AS IS"
010: * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. Please refer to
011: * the license for the specific language governing your rights and limitations.
012: *
013: * @created Apr 28, 2005
014: * @author James Dixon
015: */
016:
017: package org.pentaho.plugin.email;
018:
019: import java.io.OutputStream;
020: import java.util.Date;
021: import java.util.Iterator;
022: import java.util.List;
023: import java.util.Properties;
024:
025: import javax.activation.DataHandler;
026: import javax.activation.DataSource;
027: import javax.mail.AuthenticationFailedException;
028: import javax.mail.Authenticator;
029: import javax.mail.Message;
030: import javax.mail.Multipart;
031: import javax.mail.PasswordAuthentication;
032: import javax.mail.SendFailedException;
033: import javax.mail.Session;
034: import javax.mail.Transport;
035: import javax.mail.internet.InternetAddress;
036: import javax.mail.internet.MimeBodyPart;
037: import javax.mail.internet.MimeMessage;
038: import javax.mail.internet.MimeMultipart;
039:
040: import org.apache.commons.logging.Log;
041: import org.apache.commons.logging.LogFactory;
042: import org.dom4j.Document;
043: import org.dom4j.Node;
044: import org.pentaho.actionsequence.dom.IActionInputValueProvider;
045: import org.pentaho.actionsequence.dom.actions.EmailAction;
046: import org.pentaho.actionsequence.dom.actions.EmailAttachment;
047: import org.pentaho.core.system.PentahoSystem;
048: import org.pentaho.messages.Messages;
049: import org.pentaho.messages.util.LocaleHelper;
050: import org.pentaho.plugin.ComponentBase;
051:
052: /**
053: * @author James Dixon
054: *
055: * TODO To change the template for this generated type comment go to Window -
056: * Preferences - Java - Code Style - Code Templates
057: */
058: public class EmailComponent extends ComponentBase {
059:
060: /**
061: *
062: */
063: private static final long serialVersionUID = 1584906077946023715L;
064:
065: private String defaultFrom;
066:
067: private static final String MAILER = "smtpsend"; //$NON-NLS-1$
068:
069: /*
070: private String protocol = null;
071: private String host = null;
072: private String recordDir = null;
073: */
074:
075: public Log getLogger() {
076: return LogFactory.getLog(EmailComponent.class);
077: }
078:
079: protected boolean validateSystemSettings() {
080: // get the settings from the system configuration file
081: String mailhost = PentahoSystem.getSystemSetting(
082: "smtp-email/email_config.xml", "mail.smtp.host", null); //$NON-NLS-1$ //$NON-NLS-2$
083: boolean authenticate = "true".equalsIgnoreCase(PentahoSystem.getSystemSetting("smtp-email/email_config.xml", "mail.smtp.auth", "false")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
084: // don't store these in a class member for secutiry
085: String user = PentahoSystem.getSystemSetting(
086: "smtp-email/email_config.xml", "mail.userid", ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
087: String password = PentahoSystem.getSystemSetting(
088: "smtp-email/email_config.xml", "mail.password", ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
089: defaultFrom = PentahoSystem.getSystemSetting(
090: "smtp-email/email_config.xml", "mail.from.default", ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
091:
092: // Check the email server settings...
093: if (mailhost.equals("") || (user.equals("") && authenticate) || defaultFrom.equals("")) { //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
094: // looks like the email stuff is not configured yet...
095: // see if we can provide feedback to the user...
096:
097: boolean allowParameterUI = feedbackAllowed();
098:
099: if (allowParameterUI) {
100: OutputStream feedbackStream = getFeedbackOutputStream();
101: StringBuffer messageBuffer = new StringBuffer();
102: org.pentaho.core.util.UIUtil
103: .formatErrorMessage(
104: "text/html", Messages.getString("Email.USER_COULD_NOT_SEND_EMAIL"), Messages.getString("Email.USER_SETTINGS_HELP", "~/pentaho-demo/pentaho-solutions/system/smtp-email/email_config.xml"), messageBuffer); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
105: try {
106: feedbackStream
107: .write(messageBuffer.toString().getBytes(
108: LocaleHelper.getSystemEncoding()));
109: } catch (Exception e) {
110: error(
111: Messages
112: .getErrorString("Base.ERROR_0003_INVALID_FEEDBACK_STREAM"), e); //$NON-NLS-1$
113: return false;
114: }
115: return false;
116: } else {
117: // we are not allowed to provide feedback and cannot continue...
118: error(Messages
119: .getErrorString("Email.ERROR_0009_SERVER_SETTINGS_NOT_SET")); //$NON-NLS-1$
120: return false;
121: }
122: }
123: boolean ok = (mailhost != null);
124: if (authenticate) {
125: ok &= (user != null) && (password != null);
126: }
127: ok &= defaultFrom != null;
128: return ok;
129: }
130:
131: public boolean init() {
132: return true;
133: }
134:
135: public boolean validateAction() {
136: boolean result = true;
137: // make sure that we can get a "to" email address
138: if (!(getActionDefinition() instanceof EmailAction)) {
139: error(Messages
140: .getErrorString(
141: "ComponentBase.ERROR_0001_UNKNOWN_ACTION_TYPE", getActionDefinition().getElement().asXML())); //$NON-NLS-1$
142: result = false;
143: } else {
144: EmailAction emailAction = (EmailAction) getActionDefinition();
145:
146: IActionInputValueProvider to = emailAction.getTo();
147: IActionInputValueProvider subject = emailAction
148: .getSubject();
149: IActionInputValueProvider plainMsg = emailAction
150: .getMessagePlain();
151: IActionInputValueProvider htmlMsg = emailAction
152: .getMessageHtml();
153:
154: if (to == IActionInputValueProvider.NULL_INPUT) { //$NON-NLS-1$
155: error(Messages
156: .getErrorString(
157: "Email.ERROR_0001_TO_NOT_DEFINED", getActionName())); //$NON-NLS-1$
158: result = false;
159: } else if (subject == IActionInputValueProvider.NULL_INPUT) { //$NON-NLS-1$
160: error(Messages
161: .getErrorString(
162: "Email.ERROR_0002_SUBJECT_NOT_DEFINED", getActionName())); //$NON-NLS-1$
163: result = false;
164: } else if ((plainMsg == IActionInputValueProvider.NULL_INPUT)
165: && (htmlMsg == IActionInputValueProvider.NULL_INPUT)) { //$NON-NLS-1$ //$NON-NLS-2$
166: error(Messages
167: .getErrorString(
168: "Email.ERROR_0003_BODY_NOT_DEFINED", getActionName())); //$NON-NLS-1$
169: result = false;
170: }
171: }
172:
173: return result;
174:
175: }
176:
177: public boolean executeAction() {
178: EmailAction emailAction = (EmailAction) getActionDefinition();
179:
180: String messagePlain = emailAction.getMessagePlain()
181: .getStringValue();
182: String messageHtml = emailAction.getMessageHtml()
183: .getStringValue();
184: String subject = emailAction.getSubject().getStringValue();
185: String to = emailAction.getTo().getStringValue();
186: String cc = emailAction.getCc().getStringValue();
187: String bcc = emailAction.getBcc().getStringValue();
188: String from = emailAction.getFrom().getStringValue(defaultFrom);
189: if (from.trim().length() == 0) {
190: from = defaultFrom;
191: }
192:
193: /*
194: * if( context.getInputNames().contains( "attach" ) ) { //$NON-NLS-1$
195: * Object attachParameter = context.getInputParameter( "attach"
196: * ).getValue(); //$NON-NLS-1$ // We have a list of attachments, each
197: * element of the list is the name of the parameter containing the
198: * attachment // Use the parameter filename portion as the attachment
199: * name. if ( attachParameter instanceof String ) { String attachName =
200: * context.getInputParameter( "attach-name" ).getStringValue();
201: * //$NON-NLS-1$ AttachStruct attachData = getAttachData( context,
202: * (String)attachParameter, attachName ); if ( attachData != null ) {
203: * attachments.add( attachData ); } } else if ( attachParameter
204: * instanceof List ) { for ( int i = 0; i <
205: * ((List)attachParameter).size(); ++i ) { AttachStruct attachData =
206: * getAttachData( context, ((List)attachParameter).get( i ).toString(),
207: * null ); if ( attachData != null ) { attachments.add( attachData ); } } }
208: * else if ( attachParameter instanceof Map ) { for ( Iterator it =
209: * ((Map)attachParameter).entrySet().iterator(); it.hasNext(); ) {
210: * Map.Entry entry = (Map.Entry)it.next(); AttachStruct attachData =
211: * getAttachData( context, (String)entry.getValue(),
212: * (String)entry.getKey() ); if ( attachData != null ) {
213: * attachments.add( attachData ); } } } }
214: *
215: * int maxSize = Integer.MAX_VALUE; try { maxSize = new Integer(
216: * props.getProperty( "mail.max.attach.size" ) ).intValue(); } catch(
217: * Throwable t ) { //ignore if not set to a valid value }
218: *
219: * if ( totalAttachLength > maxSize ) { // Sort them in order TreeMap tm =
220: * new TreeMap(); for( int idx=0; idx<attachments.size(); idx++ ) { //
221: * tm.put( new Integer( )) } }
222: */
223:
224: if (debug) {
225: debug(Messages.getString("Email.DEBUG_TO_FROM", to, from)); //$NON-NLS-1$
226: debug(Messages.getString("Email.DEBUG_CC_BCC", cc, bcc)); //$NON-NLS-1$
227: debug(Messages.getString("Email.DEBUG_SUBJECT", subject)); //$NON-NLS-1$
228: debug(Messages.getString(
229: "Email.DEBUG_PLAIN_MESSAGE", messagePlain)); //$NON-NLS-1$
230: debug(Messages.getString(
231: "Email.DEBUG_HTML_MESSAGE", messageHtml)); //$NON-NLS-1$
232: }
233:
234: if ((to == null) || (to.trim().length() == 0)) {
235:
236: // Get the output stream that the feedback is going into
237: OutputStream feedbackStream = getFeedbackOutputStream();
238: if (feedbackStream != null) {
239: createFeedbackParameter(
240: "to", Messages.getString("Email.USER_ENTER_EMAIL_ADDRESS"), "", "", true); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
241: setFeedbackMimeType("text/html"); //$NON-NLS-1$
242: return true;
243: } else {
244: return false;
245: }
246: }
247: if (subject == null) {
248: error(Messages.getErrorString(
249: "Email.ERROR_0005_NULL_SUBJECT", getActionName())); //$NON-NLS-1$
250: return false;
251: }
252: if ((messagePlain == null) && (messageHtml == null)) {
253: error(Messages.getErrorString(
254: "Email.ERROR_0006_NULL_BODY", getActionName())); //$NON-NLS-1$
255: return false;
256: }
257:
258: if (getRuntimeContext().isPromptPending()) {
259: return true;
260: }
261:
262: try {
263:
264: Properties props = new Properties();
265:
266: try {
267: Document configDocument = PentahoSystem
268: .getSystemSettings().getSystemSettingsDocument(
269: "smtp-email/email_config.xml"); //$NON-NLS-1$
270: List properties = configDocument
271: .selectNodes("/email-smtp/properties/*"); //$NON-NLS-1$
272: Iterator propertyIterator = properties.iterator();
273: while (propertyIterator.hasNext()) {
274: Node propertyNode = (Node) propertyIterator.next();
275: String propertyName = propertyNode.getName();
276: String propertyValue = propertyNode.getText();
277: props.put(propertyName, propertyValue);
278: }
279: } catch (Exception e) {
280: error(
281: Messages
282: .getString("Email.ERROR_0013_CONFIG_FILE_INVALID"), e); //$NON-NLS-1$
283: return false;
284: }
285:
286: boolean authenticate = "true".equalsIgnoreCase(props.getProperty("mail.smtp.auth")); //$NON-NLS-1$//$NON-NLS-2$
287:
288: // Get a Session object
289:
290: Session session;
291: if (authenticate) {
292: Authenticator authenticator = new EmailAuthenticator();
293: session = Session.getInstance(props, authenticator);
294: } else {
295: session = Session.getInstance(props);
296: }
297:
298: // if debugging is not set in the email config file, match the
299: // component debug setting
300: if (debug && !props.containsKey("mail.debug")) { //$NON-NLS-1$
301: session.setDebug(true);
302: }
303:
304: // construct the message
305: MimeMessage msg = new MimeMessage(session);
306: if (from != null) {
307: msg.setFrom(new InternetAddress(from));
308: } else {
309: // There should be no way to get here
310: error(Messages
311: .getString("Email.ERROR_0012_FROM_NOT_DEFINED")); //$NON-NLS-1$
312: }
313:
314: if ((to != null) && (to.trim().length() > 0)) {
315: msg.setRecipients(Message.RecipientType.TO,
316: InternetAddress.parse(to, false));
317: }
318: if ((cc != null) && (cc.trim().length() > 0)) {
319: msg.setRecipients(Message.RecipientType.CC,
320: InternetAddress.parse(cc, false));
321: }
322: if ((bcc != null) && (bcc.trim().length() > 0)) {
323: msg.setRecipients(Message.RecipientType.BCC,
324: InternetAddress.parse(bcc, false));
325: }
326:
327: if (subject != null) {
328: msg.setSubject(subject);
329: }
330:
331: EmailAttachment[] emailAttachments = emailAction
332: .getAttachments();
333: if ((messagePlain != null) && (messageHtml == null)
334: && (emailAttachments.length == 0)) {
335: msg.setText(messagePlain);
336: } else if (emailAttachments.length == 0) {
337: if (messagePlain != null) {
338: msg.setContent(messagePlain, "text/plain"); //$NON-NLS-1$
339: }
340: if (messageHtml != null) {
341: msg.setContent(messageHtml, "text/html"); //$NON-NLS-1$
342: }
343: } else {
344: // need to create a multi-part message...
345: // create the Multipart and add its parts to it
346: Multipart multipart = new MimeMultipart();
347: // create and fill the first message part
348: if (messageHtml != null) {
349: // create and fill the first message part
350: MimeBodyPart htmlBodyPart = new MimeBodyPart();
351: htmlBodyPart.setContent(messageHtml, "text/html"); //$NON-NLS-1$
352: multipart.addBodyPart(htmlBodyPart);
353: }
354:
355: if (messagePlain != null) {
356: MimeBodyPart textBodyPart = new MimeBodyPart();
357: textBodyPart.setContent(messagePlain, "text/plain"); //$NON-NLS-1$
358: multipart.addBodyPart(textBodyPart);
359: }
360:
361: // add attachements
362: for (int idx = 0; idx < emailAttachments.length; idx++) {
363: DataSource dataSource = emailAttachments[idx]
364: .getContent();
365: String attachmentName = emailAttachments[idx]
366: .getName();
367: if (debug)
368: debug(Messages
369: .getString(
370: "Email.DEBUG_ADDING_ATTACHMENT", attachmentName)); //$NON-NLS-1$
371:
372: // create the second message part
373: MimeBodyPart attachmentBodyPart = new MimeBodyPart();
374:
375: // attach the file to the message
376: attachmentBodyPart.setDataHandler(new DataHandler(
377: dataSource));
378: attachmentBodyPart.setFileName(attachmentName);
379: if (debug)
380: debug(Messages
381: .getString(
382: "Email.DEBUG_ATTACHMENT_SOURCE", dataSource.getName())); //$NON-NLS-1$
383: multipart.addBodyPart(attachmentBodyPart);
384: }
385:
386: // add the Multipart to the message
387: msg.setContent(multipart);
388: }
389:
390: msg.setHeader("X-Mailer", MAILER); //$NON-NLS-1$
391: msg.setSentDate(new Date());
392:
393: Transport.send(msg);
394:
395: if (debug)
396: debug(Messages.getString("Email.DEBUG_EMAIL_SUCCESS")); //$NON-NLS-1$
397: return true;
398: // TODO: persist the content set for a while...
399: } catch (SendFailedException e) {
400: error(Messages.getErrorString(
401: "Email.ERROR_0011_SEND_FAILED", to), e); //$NON-NLS-1$
402: /*
403: Exception ne;
404: MessagingException sfe = e;
405: while ((ne = sfe.getNextException()) != null && ne instanceof MessagingException) {
406: sfe = (MessagingException) ne;
407: error(Messages.getErrorString("Email.ERROR_0011_SEND_FAILED", sfe.toString()), sfe); //$NON-NLS-1$
408: }
409: */
410:
411: } catch (AuthenticationFailedException e) {
412: error(Messages.getString(
413: "Email.ERROR_0014_AUTHENTICATION_FAILED", to), e); //$NON-NLS-1$
414: } catch (Throwable e) {
415: error(Messages.getErrorString(
416: "Email.ERROR_0011_SEND_FAILED", to), e); //$NON-NLS-1$
417: }
418: return false;
419: }
420:
421: public void done() {
422:
423: }
424:
425: private class EmailAuthenticator extends Authenticator {
426:
427: protected PasswordAuthentication getPasswordAuthentication() {
428: String user = PentahoSystem.getSystemSetting(
429: "smtp-email/email_config.xml", "mail.userid", null); //$NON-NLS-1$ //$NON-NLS-2$
430: String password = PentahoSystem
431: .getSystemSetting(
432: "smtp-email/email_config.xml", "mail.password", null); //$NON-NLS-1$ //$NON-NLS-2$
433: return new PasswordAuthentication(user, password);
434: }
435: }
436: }
|