001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.cocoon.acting;
018:
019: import org.apache.avalon.framework.configuration.Configurable;
020: import org.apache.avalon.framework.configuration.Configuration;
021: import org.apache.avalon.framework.configuration.ConfigurationException;
022: import org.apache.avalon.framework.parameters.Parameters;
023: import org.apache.avalon.framework.service.ServiceException;
024: import org.apache.avalon.framework.thread.ThreadSafe;
025:
026: import org.apache.cocoon.environment.ObjectModelHelper;
027: import org.apache.cocoon.environment.Redirector;
028: import org.apache.cocoon.environment.Request;
029: import org.apache.cocoon.environment.SourceResolver;
030: import org.apache.cocoon.mail.MailSender;
031:
032: import org.apache.commons.lang.StringUtils;
033:
034: import java.util.HashMap;
035: import java.util.Map;
036:
037: import javax.mail.MessagingException;
038: import javax.mail.internet.AddressException;
039:
040: /**
041: * The Sendmail action class sends email. Action supports following
042: * parameters:
043: *
044: * <dl>
045: * <dt>smtp-host</dt>
046: * <dd>The smtp server to send the mail through. If not specified,
047: * default from cocoon.xconf will be used.</dd>
048: * <dt>smtp-user</dt>
049: * <dd>The smtp user. If smtp-user and smtp-host not specified,
050: * default from cocoon.xconf will be used.</dd>
051: * <dt>smtp-password</dt>
052: * <dd>The smtp user's password. If smtp-user and smtp-host not
053: * specified, default from cocoon.xconf will be used.</dd>
054: * <dt>from</dt>
055: * <dd>the email address the mail appears to be from</dd>
056: * <dt>to</dt>
057: * <dd>the email address(es) the mail it sent to. This can
058: * be multiple addresses separated with commas.</dd>
059: * <dt>replyTo</dt>
060: * <dd>the email address(es) replies should be sent to. This can
061: * be multiple addresses separated with commas.</dd>
062: * <dt>cc</dt>
063: * <dd>an email address(es) of someone, who should receive a
064: * carbon copy. This can also be a list of multiple addresses
065: * separated by commas.</dd>
066: * <dt>bcc</dt>
067: * <dd>an email address(es) of someone, who should receive a black
068: * carbon copy. This can also be a list of multiple addresses
069: * separated by commas.</dd>
070: * <dt>subject</dt>
071: * <dd>the subject line of the email</dd>
072: * <dt>src</dt>
073: * <dd>A url specifying the source of the text body of the email</dd>
074: * <dt>srcMimeType</dt>
075: * <dd>The optional Mime Type of the source of the text body of the email
076: * if you specified src</dd>
077: * <dt>body</dt>
078: * <dd>the text body of the email, if src is specified, body will be ignored</dd>
079: * <dt>charset</dt>
080: * <dd>the character set, which should be used the encode the body text.
081: * This parameter is only used, if no attachements are send.</dd>
082: * <dt>attachments</dt>
083: * <dd>One or more attachments, separated by whitespace, which should be
084: * attached to the email message. If the argument contains a ':', it is
085: * assumed, that the argument describes a
086: * <code>org.apache.excalibur.source.Source</code> object. Otherwise, it
087: * is assumed, that the argument describes a request parameter of an
088: * uploaded file, which Cocoon has internally turned into a
089: * {@link org.apache.cocoon.servlet.multipart.Part}
090: * object.</dd>
091: * </dl>
092: *
093: * <p>
094: * Minimally, <code>from</code>, <code>to</code>, <code>body</code> parameters
095: * should be specified. Rest of parameters are optional.</p>
096: *
097: * <p>
098: * The class loads all of these parameters from the sitemap, except the
099: * attachements, which may come from file upload request parameters.
100: * Note it's strongly recommended that the to, cc and bcc addresses be
101: * specified by the sitemap, not the request, to prevent possible abuse of the
102: * SendmailAction as a spam source.</p>
103: *
104: * <p>
105: * One or two parameters are returned to the sitemap depending on the outcome
106: * of sending the message: <code>status</code> and <code>message</code>.</p>
107: *
108: * <p>
109: * If the email message could be successfully delivered only the parameter
110: * <code>status</code> with the value <code>success</code> is returned.</p>
111: *
112: * <p>
113: * If there was a problem sending the message, <code>status</code> can have
114: * the value <code>user-error</code> and the <code>message</code>
115: * parameter is set to an explainatory text. This usually indicates problems with
116: * one or more email addresses. Other problems lead to a value of
117: * <code>server-error</code> for <code>status</code> and
118: * <code>message</code> contains a corresponding message.</p>
119: *
120: * @author <a href="mailto:frank.ridderbusch@gmx.de">Frank Ridderbusch</a>
121: * @author <a href="mailto:haul@apache.org">Christian Haul</a>
122: * @author <a href="mailto:balld@apache.org">Donald Ball</a>
123: * @author <a href="mailto:andrzej@chaeron.com">Andrzej Taramina</a>
124: * @since 2.1
125: * @version CVS $Id: Sendmail.java 469258 2006-10-30 20:21:40Z vgritsenko $
126: */
127: public class Sendmail extends ServiceableAction implements ThreadSafe,
128: Configurable {
129:
130: private static final String STATUS = "status";
131: private static final String MESSAGE = "message";
132:
133: /** Request-Attribute that holds status data*/
134: public static final String REQUEST_ATTRIBUTE = "org.apache.cocoon.acting.Sendmail";
135:
136: private String smtpHost;
137: private String smtpUser;
138: private String smtpPassword;
139:
140: public void configure(Configuration conf)
141: throws ConfigurationException {
142: if (getLogger().isDebugEnabled()) {
143: getLogger().debug("configure");
144: }
145:
146: // FIXME Remove support of old "smtphost" attribute.
147: smtpHost = conf.getChild("smtp-host").getValue(
148: conf.getAttribute("smtphost", null));
149: smtpUser = conf.getChild("smtp-user").getValue(null);
150: smtpPassword = conf.getChild("smtp-password").getValue(null);
151:
152: if (getLogger().isDebugEnabled()) {
153: if (smtpHost != null)
154: getLogger().debug(
155: "Using " + smtpHost + " as the smtp server");
156: if (smtpUser != null)
157: getLogger().debug(
158: "Using " + smtpUser + " as the smtp user");
159: }
160: }
161:
162: public Map act(Redirector redirector, SourceResolver resolver,
163: Map objectModel, String source, Parameters parameters)
164: throws Exception {
165: boolean success = false;
166: Map status = null;
167:
168: MailSender mms = null;
169: try {
170: Request request = ObjectModelHelper.getRequest(objectModel);
171:
172: // FIXME Remove support of old smtphost parameter
173: String smtpHost = parameters.getParameter("smtp-host",
174: parameters.getParameter("smtphost", this .smtpHost));
175: String smtpUser = parameters.getParameter("smtp-user",
176: this .smtpUser);
177: String smtpPassword = parameters.getParameter(
178: "smtp-password", this .smtpPassword);
179:
180: // Empty parameter means absent parameter
181: if ("".equals(smtpHost)) {
182: smtpHost = this .smtpHost;
183: }
184: if ("".equals(smtpUser)) {
185: smtpUser = this .smtpUser;
186: }
187: if ("".equals(smtpPassword)) {
188: smtpPassword = this .smtpPassword;
189: }
190:
191: mms = (MailSender) this .manager.lookup(MailSender.ROLE);
192:
193: // Initialize non-default session if host or user specified.
194: if (smtpHost != null || smtpUser != null) {
195: mms.setSmtpHost(smtpHost, smtpUser, smtpPassword);
196: }
197:
198: if (parameters.isParameter("from")) {
199: mms.setFrom(parameters.getParameter("from", null));
200: }
201: if (parameters.isParameter("to")) {
202: mms.setTo(parameters.getParameter("to", null));
203: }
204: if (parameters.isParameter("replyTo")) {
205: mms
206: .setReplyTo(parameters.getParameter("replyTo",
207: null));
208: }
209: if (parameters.isParameter("cc")) {
210: mms.setCc(parameters.getParameter("cc", null));
211: }
212: if (parameters.isParameter("bcc")) {
213: mms.setBcc(parameters.getParameter("bcc", null));
214: }
215: if (parameters.isParameter("subject")) {
216: mms
217: .setSubject(parameters.getParameter("subject",
218: null));
219: }
220:
221: String bodyURL = parameters.getParameter("src", "");
222: String body = parameters.getParameter("body", "");
223: if (bodyURL.length() > 0) {
224: String type = null;
225: if (parameters.isParameter("srcMimeType")) {
226: type = parameters.getParameter("srcMimeType", null);
227: }
228: mms.setBodyURL(bodyURL, type);
229: } else if (body.length() > 0) {
230: String type = null;
231: String charset = parameters.getParameter("charset", "");
232: if (charset.length() > 0) {
233: type = "text/plain; charset=" + charset;
234: }
235: mms.setBody(body, type);
236: }
237:
238: if (parameters.isParameter("attachments")) {
239: String fileName[] = StringUtils.split(parameters
240: .getParameter("attachments"));
241: for (int i = 0; i < fileName.length; i++) {
242: String srcName = fileName[i];
243:
244: if (srcName.indexOf(":") == -1) {
245: Object obj = request.get(srcName);
246: mms.addAttachment(obj);
247: if (getLogger().isDebugEnabled()) {
248: getLogger().debug(
249: "request-attachment: " + obj);
250: }
251: } else {
252: mms.addAttachmentURL(srcName);
253: if (getLogger().isDebugEnabled()) {
254: getLogger().debug(
255: "sitemap-attachment: " + srcName);
256: }
257: }
258: }
259: }
260:
261: mms.send();
262:
263: success = true;
264: status = new HashMap(3);
265: status.put(Sendmail.STATUS, "success");
266:
267: } catch (AddressException e) {
268: getLogger().warn("AddressException: ", e);
269:
270: status = new HashMap(3);
271: status.put(Sendmail.STATUS, "user-error");
272: status.put(Sendmail.MESSAGE, e.getMessage());
273:
274: } catch (MessagingException e) {
275: getLogger().warn(
276: "MessagingException: "
277: + "An error occured while sending email.",
278: e);
279:
280: status = new HashMap(3);
281: status.put(Sendmail.STATUS, "server-error");
282: status.put(Sendmail.MESSAGE,
283: "An error occured while sending email: "
284: + e.getMessage());
285:
286: } catch (ServiceException e) {
287: getLogger()
288: .error(
289: "ServiceException: "
290: + "An error occured while initializing.",
291: e);
292:
293: status = new HashMap(3);
294: status.put(Sendmail.STATUS, "server-error");
295: status.put(Sendmail.MESSAGE,
296: "An exception was thrown while sending email: "
297: + e.getMessage());
298:
299: } catch (Exception e) {
300: getLogger().error(
301: "An exception was thrown while sending email.", e);
302:
303: status = new HashMap(3);
304: status.put(Sendmail.STATUS, "server-error");
305: status.put(Sendmail.MESSAGE,
306: "An exception was thrown while sending email.");
307:
308: } finally {
309: ObjectModelHelper.getRequest(objectModel).setAttribute(
310: Sendmail.REQUEST_ATTRIBUTE, status);
311: this.manager.release(mms);
312: }
313:
314: return success ? status : null;
315: }
316: }
|