Java tutorial
/**************************************************************** * Licensed to the Apache Software Foundation (ASF) under one * * or more contributor license agreements. See the NOTICE file * * distributed with this work for additional information * * regarding copyright ownership. The ASF licenses this file * * to you under the Apache License, Version 2.0 (the * * "License"); you may not use this file except in compliance * * with the License. You may obtain a copy of the License at * * * * http://www.apache.org/licenses/LICENSE-2.0 * * * * Unless required by applicable law or agreed to in writing, * * software distributed under the License is distributed on an * * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * * KIND, either express or implied. See the License for the * * specific language governing permissions and limitations * * under the License. * ****************************************************************/ package org.apache.james.transport.mailets; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.Collection; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.regex.Pattern; import javax.mail.Message; import javax.mail.MessagingException; import javax.mail.Multipart; import javax.mail.Part; import javax.mail.internet.MimeMessage; import javax.mail.internet.MimeUtility; import org.apache.commons.io.FileUtils; import org.apache.mailet.Mail; import org.apache.mailet.MailetException; import org.apache.mailet.base.GenericMailet; /** * <p> * Remove attachments from a Message. Supports simple removal, storing to file, * or storing to mail attributes. * </p> * <p> * Configuration: * </p> * <p> * * <pre> * <mailet match="All" class="StripAttachment" > * <pattern >.*\.xls </pattern> <!-- The regular expression that must be matched -- > * <!-- notpattern >.*\.xls </notpattern--> <!-- The regular expression that must be matched -- > * <directory >c:\temp\james_attach </directory> <!-- The directory to save to -- > * <remove >all </remove> <!-- either "no", "matched", "all" -- > * <!-- attribute>my.attribute.name</attribute --> * </mailet > * </pre> * * </p> */ public class StripAttachment extends GenericMailet { public static final String PATTERN_PARAMETER_NAME = "pattern"; public static final String NOTPATTERN_PARAMETER_NAME = "notpattern"; public static final String ATTRIBUTE_PARAMETER_NAME = "attribute"; public static final String DIRECTORY_PARAMETER_NAME = "directory"; // Either "no", "matched", "all" public static final String REMOVE_ATTACHMENT_PARAMETER_NAME = "remove"; // Either "true", "false" public static final String DECODE_FILENAME_PARAMETER_NAME = "decodeFilename"; public static final String REPLACE_FILENAME_PATTERN_PARAMETER_NAME = "replaceFilenamePattern"; public static final String REMOVE_NONE = "no"; public static final String REMOVE_ALL = "all"; public static final String REMOVE_MATCHED = "matched"; public static final String REMOVED_ATTACHMENTS_ATTRIBUTE_KEY = "org.apache.james.mailet.standard.mailets.StripAttachment.removed"; public static final String SAVED_ATTACHMENTS_ATTRIBUTE_KEY = "org.apache.james.mailet.standard.mailets.StripAttachment.saved"; private String removeAttachments = null; private String directoryName = null; private String attributeName = null; private Pattern regExPattern = null; private Pattern notregExPattern = null; private boolean decodeFilename = false; private List<ReplacingPattern> filenameReplacingPatterns = null; private static boolean getBooleanParameter(String v, boolean def) { return def ? !(v != null && (v.equalsIgnoreCase("false") || v.equalsIgnoreCase("no"))) : v != null && (v.equalsIgnoreCase("true") || v.equalsIgnoreCase("yes")); } /** * Checks if the mandatory parameters are present, creates the directory to * save the files ni (if not present). * * @throws MailetException */ public void init() throws MailetException { String patternString = getInitParameter(PATTERN_PARAMETER_NAME); String notpatternString = getInitParameter(NOTPATTERN_PARAMETER_NAME); if (patternString == null && notpatternString == null) { throw new MailetException("No value for " + PATTERN_PARAMETER_NAME + " parameter was provided."); } directoryName = getInitParameter(DIRECTORY_PARAMETER_NAME); attributeName = getInitParameter(ATTRIBUTE_PARAMETER_NAME); removeAttachments = getInitParameter(REMOVE_ATTACHMENT_PARAMETER_NAME, REMOVE_NONE).toLowerCase(); if (!REMOVE_MATCHED.equals(removeAttachments) && !REMOVE_ALL.equals(removeAttachments)) { removeAttachments = REMOVE_NONE; } try { // if (patternString != null) regExPattern = new // Perl5Compiler().compile(patternString); if (patternString != null) regExPattern = Pattern.compile(patternString); } catch (Exception e) { throw new MailetException("Could not compile regex [" + patternString + "]."); } try { // if (notpatternString != null) notregExPattern = new // Perl5Compiler().compile(notpatternString); if (notpatternString != null) notregExPattern = Pattern.compile(notpatternString); } catch (Exception e) { throw new MailetException("Could not compile regex [" + notpatternString + "]."); } if (directoryName != null) { try { FileUtils.forceMkdir(new File(directoryName)); } catch (Exception e) { throw new MailetException("Could not create directory [" + directoryName + "].", e); } } decodeFilename = getBooleanParameter(getInitParameter(DECODE_FILENAME_PARAMETER_NAME), decodeFilename); if (getInitParameter(REPLACE_FILENAME_PATTERN_PARAMETER_NAME) != null) { filenameReplacingPatterns = new PatternExtractor() .getPatternsFromString(getInitParameter(REPLACE_FILENAME_PATTERN_PARAMETER_NAME)); } String toLog = String.format("StripAttachment is initialised with regex pattern [%s / %s]", patternString, notpatternString); if (directoryName != null) { toLog += String.format(" and will save to directory [%s]", directoryName); } if (attributeName != null) { toLog += String.format(" and will store attachments to attribute [%s]", attributeName); } log(toLog); } /** * Service the mail: scan it for attchemnts matching the pattern, store the * content of a matchin attachment in the given directory. * * @param mail * The mail to service * @throws MailetException * Thrown when an error situation is encountered. */ public void service(Mail mail) throws MailetException { MimeMessage message; try { message = mail.getMessage(); } catch (MessagingException e) { throw new MailetException("Could not retrieve message from Mail object", e); } // All MIME messages with an attachment are multipart, so we do nothing // if it is not mutlipart try { if (message.isMimeType("multipart/*")) { analyseMultipartPartMessage(message, mail); } } catch (MessagingException e) { throw new MailetException("Could not retrieve contenttype of message.", e); } catch (Exception e) { throw new MailetException("Could not analyse message.", e); } } /** * returns a String describing this mailet. * * @return A desciption of this mailet */ public String getMailetInfo() { return "StripAttachment"; } /** * Checks every part in this part (if it is a Multipart) for having a * filename that matches the pattern. If the name matches, the content of * the part is stored (using its name) in te given diretcory. * * Note: this method is recursive. * * @param part * The part to analyse. * @param mail * @return * @throws Exception */ private boolean analyseMultipartPartMessage(Part part, Mail mail) throws Exception { if (part.isMimeType("multipart/*")) { try { Multipart multipart = (Multipart) part.getContent(); boolean atLeastOneRemoved = false; int numParts = multipart.getCount(); for (int i = 0; i < numParts; i++) { Part p = multipart.getBodyPart(i); if (p.isMimeType("multipart/*")) { atLeastOneRemoved |= analyseMultipartPartMessage(p, mail); } else { boolean removed = checkMessageRemoved(p, mail); if (removed) { multipart.removeBodyPart(i); atLeastOneRemoved = true; i--; numParts--; } } } if (atLeastOneRemoved) { part.setContent(multipart); if (part instanceof Message) { ((Message) part).saveChanges(); } } return atLeastOneRemoved; } catch (Exception e) { log("Could not analyse part.", e); } } return false; } private boolean checkMessageRemoved(Part part, Mail mail) throws MessagingException, Exception { String fileName; fileName = part.getFileName(); // filename or name of part can be null, so we have to be careful boolean ret = false; if (fileName != null) { if (decodeFilename) fileName = MimeUtility.decodeText(fileName); if (filenameReplacingPatterns != null) fileName = new ContentReplacer(false, this).applyPatterns(filenameReplacingPatterns, fileName); if (fileNameMatches(fileName)) { if (directoryName != null) { String filename = saveAttachmentToFile(part, fileName); if (filename != null) { @SuppressWarnings("unchecked") Collection<String> c = (Collection<String>) mail .getAttribute(SAVED_ATTACHMENTS_ATTRIBUTE_KEY); if (c == null) { c = new ArrayList<String>(); mail.setAttribute(SAVED_ATTACHMENTS_ATTRIBUTE_KEY, (ArrayList<String>) c); } c.add(filename); } } if (attributeName != null) { @SuppressWarnings("unchecked") Map<String, byte[]> m = (Map<String, byte[]>) mail.getAttribute(attributeName); if (m == null) { m = new LinkedHashMap<String, byte[]>(); mail.setAttribute(attributeName, (LinkedHashMap<String, byte[]>) m); } ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); OutputStream os = new BufferedOutputStream(byteArrayOutputStream); part.writeTo(os); m.put(fileName, byteArrayOutputStream.toByteArray()); } if (removeAttachments.equals(REMOVE_MATCHED)) { ret = true; } } if (!ret) { ret = removeAttachments.equals(REMOVE_ALL); } if (ret) { @SuppressWarnings("unchecked") Collection<String> c = (Collection<String>) mail.getAttribute(REMOVED_ATTACHMENTS_ATTRIBUTE_KEY); if (c == null) { c = new ArrayList<String>(); mail.setAttribute(REMOVED_ATTACHMENTS_ATTRIBUTE_KEY, (ArrayList<String>) c); } c.add(fileName); } } return ret; } /** * Checks if the given name matches the pattern. * * @param name * The name to check for a match. * @return True if a match is found, false otherwise. */ private boolean fileNameMatches(String name) { boolean result = true; if (regExPattern != null) result = regExPattern.matcher(name).matches(); if (result && notregExPattern != null) result = !notregExPattern.matcher(name).matches(); String log = "attachment " + name + " "; if (!result) log += "does not match"; else log += "matches"; log(log); return result; } /** * Saves the content of the part to a file in the given directoy, using the * name of the part. If a file with that name already exists, it will * * @param part * The MIME part to save. * @return * @throws Exception */ private String saveAttachmentToFile(Part part, String fileName) throws Exception { BufferedOutputStream os = null; InputStream is = null; File f = null; try { if (fileName == null) fileName = part.getFileName(); int pos = -1; if (fileName != null) { pos = fileName.lastIndexOf("."); } String prefix = pos > 0 ? (fileName.substring(0, pos)) : fileName; String suffix = pos > 0 ? (fileName.substring(pos)) : ".bin"; while (prefix.length() < 3) prefix += "_"; if (suffix.length() == 0) suffix = ".bin"; f = File.createTempFile(prefix, suffix, new File(directoryName)); log("saving content of " + f.getName() + "..."); os = new BufferedOutputStream(new FileOutputStream(f)); is = part.getInputStream(); if (!(is instanceof BufferedInputStream)) { is = new BufferedInputStream(is); } int c; while ((c = is.read()) != -1) { os.write(c); } return f.getName(); } catch (Exception e) { log("Error while saving contents of [" + (f != null ? f.getName() : (part != null ? part.getFileName() : "NULL")) + "].", e); throw e; } finally { is.close(); os.close(); } } }