Package org.apache.james.transport.matchers

Source Code of org.apache.james.transport.matchers.AttachmentFileNameIs$Mask

/****************************************************************
* 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.matchers;

import org.apache.mailet.base.GenericMatcher;
import org.apache.mailet.Mail;

import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.Part;
import javax.mail.internet.MimeMessage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.StringTokenizer;
import java.util.Locale;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipEntry;
import java.io.UnsupportedEncodingException;


/**
* <P>Checks if at least one attachment has a file name which matches any
* element of a comma-separated or space-separated list of file name masks.</P>
* <P>Syntax: <CODE>match="AttachmentFileNameIs=[-d] [-z] <I>masks</I>"</CODE></P>
* <P>The match is case insensitive.</P>
* <P>File name masks may start with a wildcard '*'.</P>
* <P>Multiple file name masks can be specified, e.g.: '*.scr,*.bat'.</P>
* <P>If '<CODE>-d</CODE>' is coded, some debug info will be logged.</P>
* <P>If '<CODE>-z</CODE>' is coded, the check will be non-recursively applied
* to the contents of any attached '*.zip' file.</P>
*
* @version CVS $Revision: 940226 $ $Date: 2010-05-02 15:58:29 +0200 (So, 02 Mai 2010) $
* @since 2.2.0
*/
public class AttachmentFileNameIs extends GenericMatcher {
   
    /** Unzip request parameter. */
    protected static final String UNZIP_REQUEST_PARAMETER = "-z";
   
    /** Debug request parameter. */
    protected static final String DEBUG_REQUEST_PARAMETER = "-d";
   
    /** Match string for zip files. */
    protected static final String ZIP_SUFFIX = ".zip";
   
    /**
     * represents a single parsed file name mask.
     */
    private static class Mask {
        /** true if the mask starts with a wildcard asterisk */
        public boolean suffixMatch;
       
        /** file name mask not including the wildcard asterisk */
        public String matchString;
    }
   
    /**
     * Controls certain log messages.
     */
    protected boolean isDebug = false;

    /** contains ParsedMask instances, setup by init */
    private Mask[] masks = null;
   
    /** True if unzip is requested. */
    protected boolean unzipIsRequested;
   

    /*
     * (non-Javadoc)
     * @see org.apache.mailet.base.GenericMatcher#init()
     */
    public void init() throws MessagingException {
        /* sets up fileNameMasks variable by parsing the condition */
       
        StringTokenizer st = new StringTokenizer(getCondition(), ", ", false);
        ArrayList theMasks = new ArrayList(20);
        while (st.hasMoreTokens()) {
            String fileName = st.nextToken();
           
            // check possible parameters at the beginning of the condition
            if (theMasks.size() == 0 && fileName.equalsIgnoreCase(UNZIP_REQUEST_PARAMETER)) {
                unzipIsRequested = true;
                log("zip file analysis requested");
                continue;
            }
            if (theMasks.size() == 0 && fileName.equalsIgnoreCase(DEBUG_REQUEST_PARAMETER)) {
                isDebug = true;
                log("debug requested");
                continue;
            }
            Mask mask = new Mask();
            if (fileName.startsWith("*")) {
                mask.suffixMatch = true;
                mask.matchString = fileName.substring(1);
            } else {
                mask.suffixMatch = false;
                mask.matchString = fileName;
            }
            mask.matchString = cleanFileName(mask.matchString);
            theMasks.add(mask);
        }
        masks = (Mask[])theMasks.toArray(new Mask[0]);
    }

    /**
     * Either every recipient is matching or neither of them.
     * @param mail
     * @throws MessagingException if no matching attachment is found and at least one exception was thrown
     */
    public Collection match(Mail mail) throws MessagingException {
       
        try {
            MimeMessage message = mail.getMessage();
           
            if (matchFound(message)) {
                return mail.getRecipients(); // matching file found
            } else {
                return null; // no matching attachment found
            }
           
        } catch (Exception e) {
            if (isDebug) {
                log("Malformed message", e);
            }
            throw new MessagingException("Malformed message", e);
        }
    }
   
    /**
     * Checks if <I>part</I> matches with at least one of the <CODE>masks</CODE>.
     *
     * @param part
     */
    protected boolean matchFound(Part part) throws Exception {
       
        /*
         * if there is an attachment and no inline text,
         * the content type can be anything
         */
       
        if (part.getContentType() == null ||
            part.getContentType().startsWith("multipart/alternative")) {
            return false;
        }
       
        Object content;
       
        try {
            content = part.getContent();
        } catch (UnsupportedEncodingException uee) {
            // in this case it is not an attachment, so ignore it
            return false;
        }
       
        Exception anException = null;
       
        if (content instanceof Multipart) {
            Multipart multipart = (Multipart) content;
            for (int i = 0; i < multipart.getCount(); i++) {
                try {
                    Part bodyPart = multipart.getBodyPart(i);
                    if (matchFound(bodyPart)) {
                        return true; // matching file found
                    }
                } catch (MessagingException e) {
                    anException = e;
                } // remember any messaging exception and process next bodypart
            }
        } else {
            String fileName = part.getFileName();
            if (fileName != null) {
                fileName = cleanFileName(fileName);
                // check the file name
                if (matchFound(fileName)) {
                    if (isDebug) {
                        log("matched " + fileName);
                    }
                    return true;
                }
                if (unzipIsRequested && fileName.endsWith(ZIP_SUFFIX) && matchFoundInZip(part)){
                    return true;
                }
            }
        }
       
        // if no matching attachment was found and at least one exception was catched rethrow it up
        if (anException != null) {
            throw anException;
        }
       
        return false;
    }

    /**
     * Checks if <I>fileName</I> matches with at least one of the <CODE>masks</CODE>.
     *
     * @param fileName
     */
    protected boolean matchFound(String fileName) {
        for (int j = 0; j < masks.length; j++) {
            boolean fMatch;
            Mask mask = masks[j];
           
            //XXX: file names in mail may contain directory - theoretically
            if (mask.suffixMatch) {
                fMatch = fileName.endsWith(mask.matchString);
            } else {
                fMatch = fileName.equals(mask.matchString);
            }
            if (fMatch) {
                return true; // matching file found
            }
        }
        return false;
    }
   
    /**
     * Checks if <I>part</I> is a zip containing a file that matches with at least one of the <CODE>masks</CODE>.
     *
     *@param part
     */
    protected boolean matchFoundInZip(Part part) throws MessagingException, IOException {
        ZipInputStream zis = new ZipInputStream(part.getInputStream());
       
        try {
            while (true) {
                ZipEntry zipEntry = zis.getNextEntry();
                if (zipEntry == null) {
                    break;
                }
                String fileName = zipEntry.getName();
                if (matchFound(fileName)) {
                    if (isDebug) {
                        log("matched " + part.getFileName() + "(" + fileName + ")");
                    }
                    return true;
                }
            }
            return false;
        } finally {
            zis.close();
        }
    }

    /**
     * Transforms <I>fileName<I> in a trimmed lowercase string usable for matching agains the masks.
     *
     * @param fileName
     */
    protected String cleanFileName(String fileName) {
        return fileName.toLowerCase(Locale.US).trim();
    }
}
TOP

Related Classes of org.apache.james.transport.matchers.AttachmentFileNameIs$Mask

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.