james-server-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From b...@apache.org
Subject svn commit: r572819 - in /james/mime4j/trunk/src: main/java/org/apache/james/mime4j/ main/java/org/apache/james/mime4j/util/ test/java/org/apache/james/mime4j/
Date Tue, 04 Sep 2007 21:57:00 GMT
Author: bago
Date: Tue Sep  4 14:56:58 2007
New Revision: 572819

URL: http://svn.apache.org/viewvc?rev=572819&view=rev
Log:
Let BodyDescriptor be an interface and move current behavior to DefaultBodyDescriptor (MIME4J-22)
- [JW#2] Let BodyDescriptor provide full blown access to the headers
- Patch submitted by Jochen Wiedmann

Added:
    james/mime4j/trunk/src/main/java/org/apache/james/mime4j/DefaultBodyDescriptor.java  
(with props)
    james/mime4j/trunk/src/main/java/org/apache/james/mime4j/util/MimeUtil.java   (with props)
Modified:
    james/mime4j/trunk/src/main/java/org/apache/james/mime4j/BodyDescriptor.java
    james/mime4j/trunk/src/main/java/org/apache/james/mime4j/MimeTokenStream.java
    james/mime4j/trunk/src/main/java/org/apache/james/mime4j/SimpleContentHandler.java
    james/mime4j/trunk/src/test/java/org/apache/james/mime4j/BodyDescriptorTest.java

Modified: james/mime4j/trunk/src/main/java/org/apache/james/mime4j/BodyDescriptor.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/src/main/java/org/apache/james/mime4j/BodyDescriptor.java?rev=572819&r1=572818&r2=572819&view=diff
==============================================================================
--- james/mime4j/trunk/src/main/java/org/apache/james/mime4j/BodyDescriptor.java (original)
+++ james/mime4j/trunk/src/main/java/org/apache/james/mime4j/BodyDescriptor.java Tue Sep 
4 14:56:58 2007
@@ -19,12 +19,8 @@
 
 package org.apache.james.mime4j;
 
-import java.util.HashMap;
 import java.util.Map;
 
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
 /**
  * Encapsulates the values of the MIME-specific header fields 
  * (which starts with <code>Content-</code>). 
@@ -32,379 +28,53 @@
  * 
  * @version $Id: BodyDescriptor.java,v 1.4 2005/02/11 10:08:37 ntherning Exp $
  */
-public class BodyDescriptor {
-    private static Log log = LogFactory.getLog(BodyDescriptor.class);
-    
-    private String mimeType = "text/plain";
-    private String boundary = null;
-    private String charset = "us-ascii";
-    private String transferEncoding = "7bit";
-    private Map parameters = new HashMap();
-    private boolean contentTypeSet = false;
-    private boolean contentTransferEncSet = false;
-    
+public interface BodyDescriptor {
     /**
-     * Creates a new root <code>BodyDescriptor</code> instance.
+     * Returns the body descriptors boundary.
+     * @return Boundary string, if known, or null. The latter may be the
+     *   case, in particular, if the body is no multipart entity.
      */
-    public BodyDescriptor() {
-        this(null);
-    }
+    String getBoundary();
 
     /**
-     * Creates a new <code>BodyDescriptor</code> instance.
-     * 
-     * @param parent the descriptor of the parent or <code>null</code> if this
-     *        is the root descriptor.
-     */
-    public BodyDescriptor(BodyDescriptor parent) {
-        if (parent != null && parent.isMimeType("multipart/digest")) {
-            mimeType = "message/rfc822";
-        } else {
-            mimeType = "text/plain";
-        }
-    }
-    
-    /**
-     * Should be called for each <code>Content-</code> header field of 
-     * a MIME message or part.
-     * 
-     * @param name the field name.
-     * @param value the field value.
+     * Adds a field to the body descriptor.
+     * @param pFieldName The fields name.
+     * @param pFieldValue The unparsed fields value.
      */
-    public void addField(String name, String value) {
-        
-        name = name.trim().toLowerCase();
-        
-        if (name.equals("content-transfer-encoding") && !contentTransferEncSet) {
-            contentTransferEncSet = true;
-            
-            value = value.trim().toLowerCase();
-            if (value.length() > 0) {
-                transferEncoding = value;
-            }
-            
-        } else if (name.equals("content-type") && !contentTypeSet) {
-            contentTypeSet = true;
-            
-            value = value.trim();
-            
-            /*
-             * Unfold Content-Type value
-             */
-            StringBuffer sb = new StringBuffer();
-            for (int i = 0; i < value.length(); i++) {
-                char c = value.charAt(i);
-                if (c == '\r' || c == '\n') {
-                    continue;
-                }
-                sb.append(c);
-            }
-            
-            Map params = getHeaderParams(sb.toString());
-            
-            String main = (String) params.get("");
-            if (main != null) {
-                main = main.toLowerCase().trim();
-                int index = main.indexOf('/');
-                boolean valid = false;
-                if (index != -1) {
-                    String type = main.substring(0, index).trim();
-                    String subtype = main.substring(index + 1).trim();
-                    if (type.length() > 0 && subtype.length() > 0) {
-                        main = type + "/" + subtype;
-                        valid = true;
-                    }
-                }
-                
-                if (!valid) {
-                    main = null;
-                }
-            }
-            String b = (String) params.get("boundary");
-            
-            if (main != null 
-                    && ((main.startsWith("multipart/") && b != null) 
-                            || !main.startsWith("multipart/"))) {
-                
-                mimeType = main;
-            }
-            
-            if (isMultipart()) {
-                boundary = b;
-            }
-            
-            String c = (String) params.get("charset");
-            if (c != null) {
-                c = c.trim();
-                if (c.length() > 0) {
-                    charset = c.toLowerCase();
-                }
-            }
-            
-            /*
-             * Add all other parameters to parameters.
-             */
-            parameters.putAll(params);
-            parameters.remove("");
-            parameters.remove("boundary");
-            parameters.remove("charset");
-        }
-    }
-    
-    private Map getHeaderParams(String headerValue) {
-        Map result = new HashMap();
-
-        // split main value and parameters
-        String main;
-        String rest;
-        if (headerValue.indexOf(";") == -1) {
-            main = headerValue;
-            rest = null;
-        } else {
-            main = headerValue.substring(0, headerValue.indexOf(";"));
-            rest = headerValue.substring(main.length() + 1);
-        }
-
-        result.put("", main);
-        if (rest != null) {
-            char[] chars = rest.toCharArray();
-            StringBuffer paramName = new StringBuffer();
-            StringBuffer paramValue = new StringBuffer();
-
-            final byte READY_FOR_NAME = 0;
-            final byte IN_NAME = 1;
-            final byte READY_FOR_VALUE = 2;
-            final byte IN_VALUE = 3;
-            final byte IN_QUOTED_VALUE = 4;
-            final byte VALUE_DONE = 5;
-            final byte ERROR = 99;
-
-            byte state = READY_FOR_NAME;
-            boolean escaped = false;
-            for (int i = 0; i < chars.length; i++) {
-                char c = chars[i];
-
-                switch (state) {
-                    case ERROR:
-                        if (c == ';')
-                            state = READY_FOR_NAME;
-                        break;
-
-                    case READY_FOR_NAME:
-                        if (c == '=') {
-                            log.error("Expected header param name, got '='");
-                            state = ERROR;
-                            break;
-                        }
-
-                        paramName = new StringBuffer();
-                        paramValue = new StringBuffer();
-
-                        state = IN_NAME;
-                        // fall-through
-
-                    case IN_NAME:
-                        if (c == '=') {
-                            if (paramName.length() == 0)
-                                state = ERROR;
-                            else
-                                state = READY_FOR_VALUE;
-                            break;
-                        }
-
-                        // not '='... just add to name
-                        paramName.append(c);
-                        break;
-
-                    case READY_FOR_VALUE:
-                        boolean fallThrough = false;
-                        switch (c) {
-                            case ' ':
-                            case '\t':
-                                break;  // ignore spaces, especially before '"'
-
-                            case '"':
-                                state = IN_QUOTED_VALUE;
-                                break;
-
-                            default:
-                                state = IN_VALUE;
-                                fallThrough = true;
-                                break;
-                        }
-                        if (!fallThrough)
-                            break;
-
-                        // fall-through
-
-                    case IN_VALUE:
-                        fallThrough = false;
-                        switch (c) {
-                            case ';':
-                            case ' ':
-                            case '\t':
-                                result.put(
-                                   paramName.toString().trim().toLowerCase(),
-                                   paramValue.toString().trim());
-                                state = VALUE_DONE;
-                                fallThrough = true;
-                                break;
-                            default:
-                                paramValue.append(c);
-                                break;
-                        }
-                        if (!fallThrough)
-                            break;
-
-                    case VALUE_DONE:
-                        switch (c) {
-                            case ';':
-                                state = READY_FOR_NAME;
-                                break;
+    void addField(String pFieldName, String pFieldValue);
 
-                            case ' ':
-                            case '\t':
-                                break;
-
-                            default:
-                                state = ERROR;
-                                break;
-                        }
-                        break;
-                        
-                    case IN_QUOTED_VALUE:
-                        switch (c) {
-                            case '"':
-                                if (!escaped) {
-                                    // don't trim quoted strings; the spaces could be intentional.
-                                    result.put(
-                                            paramName.toString().trim().toLowerCase(),
-                                            paramValue.toString());
-                                    state = VALUE_DONE;
-                                } else {
-                                    escaped = false;
-                                    paramValue.append(c);                               
    
-                                }
-                                break;
-                                
-                            case '\\':
-                                if (escaped) {
-                                    paramValue.append('\\');
-                                }
-                                escaped = !escaped;
-                                break;
-
-                            default:
-                                if (escaped) {
-                                    paramValue.append('\\');
-                                }
-                                escaped = false;
-                                paramValue.append(c);
-                                break;
-                        }
-                        break;
-
-                }
-            }
-
-            // done looping.  check if anything is left over.
-            if (state == IN_VALUE) {
-                result.put(
-                        paramName.toString().trim().toLowerCase(),
-                        paramValue.toString().trim());
-            }
-        }
-
-        return result;
-    }
-    
-
-    public boolean isMimeType(String mimeType) {
-        return this.mimeType.equals(mimeType.toLowerCase());
-    }
-    
-    /**
-     * Return true if the BodyDescriptor belongs to a message 
-     * 
-     * @return
-     */
-    public boolean isMessage() {
-        return mimeType.equals("message/rfc822");
-    }
-    
-    /**
-     * Retrun true if the BodyDescripotro belogns to a multipart
-     * 
-     * @return
-     */
-    public boolean isMultipart() {
-        return mimeType.startsWith("multipart/");
-    }
-    
-    /**
-     * Return the MimeType 
-     * 
-     * @return mimeType
-     */
-    public String getMimeType() {
-        return mimeType;
-    }
-    
-    /**
-     * Return the boundary
-     * 
-     * @return boundary
-     */
-    public String getBoundary() {
-        return boundary;
-    }
-    
     /**
-     * Return the charset
-     * 
-     * @return charset
+     * Returns the body descriptors MIME type.
+     * @return The MIME type, which has been parsed from the
+     *   content-type definition. Must not be null, but
+     *   "text/plain", if no content-type was specified.
      */
-    public String getCharset() {
-        return charset;
-    }
-    
+    String getMimeType();
+
     /**
-     * Return all parameters for the BodyDescriptor
-     * 
-     * @return parameters
+     * The body descriptors character set.
+     * @return Character set, which has been parsed from the
+     *   content-type definition. Must not be null, but "US-ASCII",
+     *   if no content-type was specified.
      */
-    public Map getParameters() {
-        return parameters;
-    }
-    
+    String getCharset();
+
     /**
-     * Return the TransferEncoding
-     * 
-     * @return transferEncoding
+     * Returns the body descriptors transfer encoding.
+     * @return The transfer encoding. Must not be null, but "7bit",
+     *   if no transfer-encoding was specified.
      */
-    public String getTransferEncoding() {
-        return transferEncoding;
-    }
-    
+    String getTransferEncoding();
+
     /**
-     * Return true if it's base64 encoded
-     * 
-     * @return
-     * 
+     * Returns the map of parameters of the content-type header.
      */
-    public boolean isBase64Encoded() {
-        return "base64".equals(transferEncoding);
-    }
-    
+    Map getParameters();
+
     /**
-     * Return true if it's quoted-printable
-     * @return
+     * Returns the body descriptors content-length.
+     * @return Content length, if known, or -1, to indicate the absence of a
+     *   content-length header.
      */
-    public boolean isQuotedPrintableEncoded() {
-        return "quoted-printable".equals(transferEncoding);
-    }
-    
-    public String toString() {
-        return mimeType;
-    }
+    long getContentLength();
 }

Added: james/mime4j/trunk/src/main/java/org/apache/james/mime4j/DefaultBodyDescriptor.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/src/main/java/org/apache/james/mime4j/DefaultBodyDescriptor.java?rev=572819&view=auto
==============================================================================
--- james/mime4j/trunk/src/main/java/org/apache/james/mime4j/DefaultBodyDescriptor.java (added)
+++ james/mime4j/trunk/src/main/java/org/apache/james/mime4j/DefaultBodyDescriptor.java Tue
Sep  4 14:56:58 2007
@@ -0,0 +1,213 @@
+/*
+ * 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.mime4j;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.james.mime4j.util.MimeUtil;
+
+/**
+ * Encapsulates the values of the MIME-specific header fields 
+ * (which starts with <code>Content-</code>). 
+ *
+ * 
+ * @version $Id: BodyDescriptor.java,v 1.4 2005/02/11 10:08:37 ntherning Exp $
+ */
+public class DefaultBodyDescriptor implements BodyDescriptor {
+    private static Log log = LogFactory.getLog(DefaultBodyDescriptor.class);
+    
+    private String mimeType = "text/plain";
+    private String boundary = null;
+    private String charset = "us-ascii";
+    private String transferEncoding = "7bit";
+    private Map parameters = new HashMap();
+    private boolean contentTypeSet;
+    private boolean contentTransferEncSet;
+    private long contentLength = -1;
+    
+    /**
+     * Creates a new root <code>BodyDescriptor</code> instance.
+     */
+    public DefaultBodyDescriptor() {
+        this(null);
+    }
+
+    /**
+     * Creates a new <code>BodyDescriptor</code> instance.
+     * 
+     * @param parent the descriptor of the parent or <code>null</code> if this
+     *        is the root descriptor.
+     */
+    public DefaultBodyDescriptor(BodyDescriptor parent) {
+        if (parent != null && MimeUtil.isSameMimeType("multipart/digest", parent.getMimeType()))
{
+            mimeType = "message/rfc822";
+        } else {
+            mimeType = "text/plain";
+        }
+    }
+    
+    /**
+     * Should be called for each <code>Content-</code> header field of 
+     * a MIME message or part.
+     * 
+     * @param name the field name.
+     * @param value the field value.
+     */
+    public void addField(String name, String value) {
+        
+        name = name.trim().toLowerCase();
+        
+        if (name.equals("content-transfer-encoding") && !contentTransferEncSet) {
+            contentTransferEncSet = true;
+            
+            value = value.trim().toLowerCase();
+            if (value.length() > 0) {
+                transferEncoding = value;
+            }
+            
+        } else if (name.equals("content-length")  &&  contentLength != -1) {
+            try {
+                contentLength = Long.parseLong(value.trim());
+            } catch (NumberFormatException e) {
+                log.error("Invalid content-length: " + value);
+            }
+        } else if (name.equals("content-type") && !contentTypeSet) {
+            contentTypeSet = true;
+            
+            value = value.trim();
+            
+            /*
+             * Unfold Content-Type value
+             */
+            StringBuffer sb = new StringBuffer();
+            for (int i = 0; i < value.length(); i++) {
+                char c = value.charAt(i);
+                if (c == '\r' || c == '\n') {
+                    continue;
+                }
+                sb.append(c);
+            }
+            
+            Map params = MimeUtil.getHeaderParams(sb.toString());
+            
+            String main = (String) params.get("");
+            if (main != null) {
+                main = main.toLowerCase().trim();
+                int index = main.indexOf('/');
+                boolean valid = false;
+                if (index != -1) {
+                    String type = main.substring(0, index).trim();
+                    String subtype = main.substring(index + 1).trim();
+                    if (type.length() > 0 && subtype.length() > 0) {
+                        main = type + "/" + subtype;
+                        valid = true;
+                    }
+                }
+                
+                if (!valid) {
+                    main = null;
+                }
+            }
+            String b = (String) params.get("boundary");
+            
+            if (main != null 
+                    && ((main.startsWith("multipart/") && b != null) 
+                            || !main.startsWith("multipart/"))) {
+                
+                mimeType = main;
+            }
+            
+            if (MimeUtil.isMultipart(mimeType)) {
+                boundary = b;
+            }
+            
+            String c = (String) params.get("charset");
+            if (c != null) {
+                c = c.trim();
+                if (c.length() > 0) {
+                    charset = c.toLowerCase();
+                }
+            }
+            
+            /*
+             * Add all other parameters to parameters.
+             */
+            parameters.putAll(params);
+            parameters.remove("");
+            parameters.remove("boundary");
+            parameters.remove("charset");
+        }
+    }
+
+    /**
+     * Return the MimeType 
+     * 
+     * @return mimeType
+     */
+    public String getMimeType() {
+        return mimeType;
+    }
+    
+    /**
+     * Return the boundary
+     * 
+     * @return boundary
+     */
+    public String getBoundary() {
+        return boundary;
+    }
+    
+    /**
+     * Return the charset
+     * 
+     * @return charset
+     */
+    public String getCharset() {
+        return charset;
+    }
+    
+    /**
+     * Return all parameters for the BodyDescriptor
+     * 
+     * @return parameters
+     */
+    public Map getParameters() {
+        return parameters;
+    }
+    
+    /**
+     * Return the TransferEncoding
+     * 
+     * @return transferEncoding
+     */
+    public String getTransferEncoding() {
+        return transferEncoding;
+    }
+    
+    public String toString() {
+        return mimeType;
+    }
+
+    public long getContentLength() {
+        return contentLength;
+    }
+}

Propchange: james/mime4j/trunk/src/main/java/org/apache/james/mime4j/DefaultBodyDescriptor.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: james/mime4j/trunk/src/main/java/org/apache/james/mime4j/MimeTokenStream.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/src/main/java/org/apache/james/mime4j/MimeTokenStream.java?rev=572819&r1=572818&r2=572819&view=diff
==============================================================================
--- james/mime4j/trunk/src/main/java/org/apache/james/mime4j/MimeTokenStream.java (original)
+++ james/mime4j/trunk/src/main/java/org/apache/james/mime4j/MimeTokenStream.java Tue Sep
 4 14:56:58 2007
@@ -27,6 +27,7 @@
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+import org.apache.james.mime4j.util.MimeUtil;
 
 
 /**
@@ -249,14 +250,16 @@
                     setParsingFieldState();
                     break;
                 case T_END_HEADER:
-                    if (body.isMultipart()) {
+                    final String mimeType = body.getMimeType();
+                    if (MimeUtil.isMultipart(mimeType)) {
                         state = T_START_MULTIPART;
-                    } else if (body.isMessage()) {
+                    } else if (MimeUtil.isMessage(mimeType)) {
                         Cursor nextCursor = cursor;
-                        if (body.isBase64Encoded()) {
+                        final String transferEncoding = body.getTransferEncoding();
+                        if (MimeUtil.isBase64Encoding(transferEncoding)) {
                             log.debug("base64 encoded message/rfc822 detected");
                             nextCursor = cursor.decodeBase64();
-                        } else if (body.isQuotedPrintableEncoded()) {
+                        } else if (MimeUtil.isQuotedPrintableEncoded(transferEncoding)) {
                             log.debug("quoted-printable encoded message/rfc822 detected");
                             nextCursor = cursor.decodeQuotedPrintable();
                         }
@@ -294,7 +297,7 @@
         }
 
         private void initHeaderParsing() throws IOException {
-            body = new BodyDescriptor(parent);
+            body = newBodyDescriptor(parent);
             startLineNumber = lineNumber = cursor.getLineNumber();
 
             int curr = 0;
@@ -561,5 +564,14 @@
         }
         state = T_END_OF_STREAM;
         return state;
+    }
+
+    /**
+     * Creates a new instance of {@link BodyDescriptor}. Subclasses may override
+     * this in order to create body descriptors, that provide more specific
+     * information.
+     */
+    protected BodyDescriptor newBodyDescriptor(BodyDescriptor pParent) {
+        return new DefaultBodyDescriptor(pParent);
     }
 }

Modified: james/mime4j/trunk/src/main/java/org/apache/james/mime4j/SimpleContentHandler.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/src/main/java/org/apache/james/mime4j/SimpleContentHandler.java?rev=572819&r1=572818&r2=572819&view=diff
==============================================================================
--- james/mime4j/trunk/src/main/java/org/apache/james/mime4j/SimpleContentHandler.java (original)
+++ james/mime4j/trunk/src/main/java/org/apache/james/mime4j/SimpleContentHandler.java Tue
Sep  4 14:56:58 2007
@@ -23,6 +23,7 @@
 import org.apache.james.mime4j.decoder.QuotedPrintableInputStream;
 import org.apache.james.mime4j.field.Field;
 import org.apache.james.mime4j.message.Header;
+import org.apache.james.mime4j.util.MimeUtil;
 
 import java.io.InputStream;
 import java.io.IOException;
@@ -87,10 +88,10 @@
      * @see org.apache.james.mime4j.AbstractContentHandler#body(org.apache.james.mime4j.BodyDescriptor,
java.io.InputStream)
      */
     public final void body(BodyDescriptor bd, InputStream is) throws IOException {
-        if (bd.isBase64Encoded()) {
+        if (MimeUtil.isBase64Encoding(bd.getTransferEncoding())) {
             bodyDecoded(bd, new Base64InputStream(is));
         }
-        else if (bd.isQuotedPrintableEncoded()) {
+        else if (MimeUtil.isQuotedPrintableEncoded(bd.getTransferEncoding())) {
             bodyDecoded(bd, new QuotedPrintableInputStream(is));
         }
         else {

Added: james/mime4j/trunk/src/main/java/org/apache/james/mime4j/util/MimeUtil.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/src/main/java/org/apache/james/mime4j/util/MimeUtil.java?rev=572819&view=auto
==============================================================================
--- james/mime4j/trunk/src/main/java/org/apache/james/mime4j/util/MimeUtil.java (added)
+++ james/mime4j/trunk/src/main/java/org/apache/james/mime4j/util/MimeUtil.java Tue Sep  4
14:56:58 2007
@@ -0,0 +1,229 @@
+package org.apache.james.mime4j.util;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+
+/**
+ * A utility class, which provides some MIME related application logic,
+ * depending on abstract objects like the {@link BodyDescriptor}.
+ */
+public class MimeUtil {
+    private static final Log log = LogFactory.getLog(MimeUtil.class);
+
+    /**
+     * Returns, whether the given two MIME types are identical.
+     */
+    public static boolean isSameMimeType(String pType1, String pType2) {
+        return pType1 != null  &&  pType2 != null  &&  pType1.equalsIgnoreCase(pType2);
+    }
+
+    /**
+     * Returns true, if the given MIME type is that of a message. 
+     */
+    public static boolean isMessage(String pMimeType) {
+        return pMimeType != null  &&  pMimeType.equalsIgnoreCase("message/rfc822");
+    }
+
+    /**
+     * Return true, if the given MIME type indicates a multipart entity.
+     */
+    public static boolean isMultipart(String pMimeType) {
+        return pMimeType != null  &&  pMimeType.toLowerCase().startsWith("multipart/");
+    }
+
+    /**
+     * Returns, whether the given transfer-encoding is "base64".
+     */
+    public static boolean isBase64Encoding(String pTransferEncoding) {
+        return "base64".equalsIgnoreCase(pTransferEncoding);
+    }
+
+    /**
+     * Returns, whether the given transfer-encoding is "quoted-printable".
+     */
+    public static boolean isQuotedPrintableEncoded(String pTransferEncoding) {
+        return "quoted-printable".equals(pTransferEncoding);
+    }
+
+    /**
+     * Parses a complex field value into a map of key/value pairs. You may
+     * use this, for example, to parse a definition like
+     * <pre>
+     *   text/plain; charset=UTF-8; boundary=foobar
+     * </pre>
+     * The above example would return a map with the keys "", "charset",
+     * and "boundary", and the values "text/plain", "UTF-8", and "foobar".
+     * @param pValue The field value to parse.
+     * @return The result map; use the key "" to retrieve the first value.
+     */
+    public static Map getHeaderParams(String pValue) {
+        Map result = new HashMap();
+
+        // split main value and parameters
+        String main;
+        String rest;
+        if (pValue.indexOf(";") == -1) {
+            main = pValue;
+            rest = null;
+        } else {
+            main = pValue.substring(0, pValue.indexOf(";"));
+            rest = pValue.substring(main.length() + 1);
+        }
+
+        result.put("", main);
+        if (rest != null) {
+            char[] chars = rest.toCharArray();
+            StringBuffer paramName = new StringBuffer();
+            StringBuffer paramValue = new StringBuffer();
+
+            final byte READY_FOR_NAME = 0;
+            final byte IN_NAME = 1;
+            final byte READY_FOR_VALUE = 2;
+            final byte IN_VALUE = 3;
+            final byte IN_QUOTED_VALUE = 4;
+            final byte VALUE_DONE = 5;
+            final byte ERROR = 99;
+
+            byte state = READY_FOR_NAME;
+            boolean escaped = false;
+            for (int i = 0; i < chars.length; i++) {
+                char c = chars[i];
+
+                switch (state) {
+                    case ERROR:
+                        if (c == ';')
+                            state = READY_FOR_NAME;
+                        break;
+
+                    case READY_FOR_NAME:
+                        if (c == '=') {
+                            log.error("Expected header param name, got '='");
+                            state = ERROR;
+                            break;
+                        }
+
+                        paramName = new StringBuffer();
+                        paramValue = new StringBuffer();
+
+                        state = IN_NAME;
+                        // fall-through
+
+                    case IN_NAME:
+                        if (c == '=') {
+                            if (paramName.length() == 0)
+                                state = ERROR;
+                            else
+                                state = READY_FOR_VALUE;
+                            break;
+                        }
+
+                        // not '='... just add to name
+                        paramName.append(c);
+                        break;
+
+                    case READY_FOR_VALUE:
+                        boolean fallThrough = false;
+                        switch (c) {
+                            case ' ':
+                            case '\t':
+                                break;  // ignore spaces, especially before '"'
+
+                            case '"':
+                                state = IN_QUOTED_VALUE;
+                                break;
+
+                            default:
+                                state = IN_VALUE;
+                                fallThrough = true;
+                                break;
+                        }
+                        if (!fallThrough)
+                            break;
+
+                        // fall-through
+
+                    case IN_VALUE:
+                        fallThrough = false;
+                        switch (c) {
+                            case ';':
+                            case ' ':
+                            case '\t':
+                                result.put(
+                                   paramName.toString().trim().toLowerCase(),
+                                   paramValue.toString().trim());
+                                state = VALUE_DONE;
+                                fallThrough = true;
+                                break;
+                            default:
+                                paramValue.append(c);
+                                break;
+                        }
+                        if (!fallThrough)
+                            break;
+
+                    case VALUE_DONE:
+                        switch (c) {
+                            case ';':
+                                state = READY_FOR_NAME;
+                                break;
+
+                            case ' ':
+                            case '\t':
+                                break;
+
+                            default:
+                                state = ERROR;
+                                break;
+                        }
+                        break;
+                        
+                    case IN_QUOTED_VALUE:
+                        switch (c) {
+                            case '"':
+                                if (!escaped) {
+                                    // don't trim quoted strings; the spaces could be intentional.
+                                    result.put(
+                                            paramName.toString().trim().toLowerCase(),
+                                            paramValue.toString());
+                                    state = VALUE_DONE;
+                                } else {
+                                    escaped = false;
+                                    paramValue.append(c);                               
    
+                                }
+                                break;
+                                
+                            case '\\':
+                                if (escaped) {
+                                    paramValue.append('\\');
+                                }
+                                escaped = !escaped;
+                                break;
+
+                            default:
+                                if (escaped) {
+                                    paramValue.append('\\');
+                                }
+                                escaped = false;
+                                paramValue.append(c);
+                                break;
+                        }
+                        break;
+
+                }
+            }
+
+            // done looping.  check if anything is left over.
+            if (state == IN_VALUE) {
+                result.put(
+                        paramName.toString().trim().toLowerCase(),
+                        paramValue.toString().trim());
+            }
+        }
+
+        return result;
+    }
+}

Propchange: james/mime4j/trunk/src/main/java/org/apache/james/mime4j/util/MimeUtil.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: james/mime4j/trunk/src/test/java/org/apache/james/mime4j/BodyDescriptorTest.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/src/test/java/org/apache/james/mime4j/BodyDescriptorTest.java?rev=572819&r1=572818&r2=572819&view=diff
==============================================================================
--- james/mime4j/trunk/src/test/java/org/apache/james/mime4j/BodyDescriptorTest.java (original)
+++ james/mime4j/trunk/src/test/java/org/apache/james/mime4j/BodyDescriptorTest.java Tue Sep
 4 14:56:58 2007
@@ -34,7 +34,7 @@
     public void testGetParameters() {
         BodyDescriptor bd = null;
         
-        bd = new BodyDescriptor();
+        bd = new DefaultBodyDescriptor();
         bd.addField("Content-Type ", "text/plain; charset=ISO-8859-1; "
                 + "boundary=foo; param1=value1; param2=value2; param3=value3");
         assertEquals(3, bd.getParameters().size());
@@ -42,7 +42,7 @@
         assertEquals("value2", (String) bd.getParameters().get("param2"));
         assertEquals("value3", (String) bd.getParameters().get("param3"));
         
-        bd = new BodyDescriptor();
+        bd = new DefaultBodyDescriptor();
         bd.addField("Content-Type ", "text/plain; param1=value1; param2=value2;"
                      + " param3=value3");
         assertEquals(3, bd.getParameters().size());
@@ -50,7 +50,7 @@
         assertEquals("value2", (String) bd.getParameters().get("param2"));
         assertEquals("value3", (String) bd.getParameters().get("param3"));
         
-        bd = new BodyDescriptor();
+        bd = new DefaultBodyDescriptor();
         bd.addField("Content-Type ", "text/plain; "
                 + "param1= \" value with\tspaces \" ; "
                 + "param2=\"\\\"value4 with escaped \\\" \\\"\";");
@@ -62,7 +62,7 @@
          * Make sure escaped characters (except ") are still escaped.
          * The parameter value should be \n\"
          */
-        bd = new BodyDescriptor();
+        bd = new DefaultBodyDescriptor();
         bd.addField("Content-Type ", "text/plain; param=\"\\n\\\\\\\"\"");
         assertEquals(1, bd.getParameters().size());
         assertEquals("\\n\\\"", (String) bd.getParameters().get("param"));
@@ -74,7 +74,7 @@
         /*
          * Make sure that only the first Content-Type header added is used.
          */
-        bd = new BodyDescriptor();
+        bd = new DefaultBodyDescriptor();
         bd.addField("Content-Type ", "text/plain; charset=ISO-8859-1");
         assertEquals("text/plain", bd.getMimeType());
         assertEquals("iso-8859-1", bd.getCharset());
@@ -86,30 +86,30 @@
     public void testGetMimeType() {
         BodyDescriptor bd = null;
         
-        bd = new BodyDescriptor();
+        bd = new DefaultBodyDescriptor();
         bd.addField("Content-Type ", "text/PLAIN");
         assertEquals("text/plain", bd.getMimeType());
         
-        bd = new BodyDescriptor();
+        bd = new DefaultBodyDescriptor();
         bd.addField("Content-Type ", "text/PLAIN;");
         assertEquals("text/plain", bd.getMimeType());
         
-        bd = new BodyDescriptor();
+        bd = new DefaultBodyDescriptor();
         bd.addField("content-type", "   TeXt / html   ");
         assertEquals("text/html", bd.getMimeType());
         
-        bd = new BodyDescriptor();
+        bd = new DefaultBodyDescriptor();
         bd.addField("CONTENT-TYPE", "   x-app/yada ;  param = yada");
         assertEquals("x-app/yada", bd.getMimeType());
         
-        bd = new BodyDescriptor();
+        bd = new DefaultBodyDescriptor();
         bd.addField("CONTENT-TYPE", "   yada");
         assertEquals("text/plain", bd.getMimeType());
         
         /*
          * Make sure that only the first Content-Type header added is used.
          */
-        bd = new BodyDescriptor();
+        bd = new DefaultBodyDescriptor();
         bd.addField("Content-Type ", "text/plain");
         assertEquals("text/plain", bd.getMimeType());
         bd.addField("Content-Type ", "text/html");
@@ -121,18 +121,18 @@
         BodyDescriptor child = null;
         BodyDescriptor parent = null;
         
-        parent = new BodyDescriptor();
+        parent = new DefaultBodyDescriptor();
         parent.addField("Content-Type", "mutlipart/alternative; boundary=foo");
         
-        child = new BodyDescriptor(parent);
+        child = new DefaultBodyDescriptor(parent);
         assertEquals("text/plain", child.getMimeType());
         child.addField("Content-Type", " child/type");
         assertEquals("child/type", child.getMimeType());
         
-        parent = new BodyDescriptor();
+        parent = new DefaultBodyDescriptor();
         parent.addField("Content-Type", "multipart/digest; boundary=foo");
         
-        child = new BodyDescriptor(parent);
+        child = new DefaultBodyDescriptor(parent);
         assertEquals("message/rfc822", child.getMimeType());
         child.addField("Content-Type", " child/type");
         assertEquals("child/type", child.getMimeType());
@@ -145,12 +145,12 @@
         /*
          * Test charset.
          */
-        bd = new BodyDescriptor();
+        bd = new DefaultBodyDescriptor();
         assertEquals("us-ascii", bd.getCharset());
         bd.addField("Content-Type ", "some/type; charset=ISO-8859-1");
         assertEquals("iso-8859-1", bd.getCharset());
         
-        bd = new BodyDescriptor();
+        bd = new DefaultBodyDescriptor();
         assertEquals("us-ascii", bd.getCharset());
         bd.addField("Content-Type ", "some/type");
         assertEquals("us-ascii", bd.getCharset());
@@ -158,27 +158,27 @@
         /*
          * Test boundary.
          */
-        bd = new BodyDescriptor();
+        bd = new DefaultBodyDescriptor();
         bd.addField("Content-Type", "text/html; boundary=yada yada");
         assertNull(bd.getBoundary());
 
-        bd = new BodyDescriptor();
+        bd = new DefaultBodyDescriptor();
         bd.addField("Content-Type", "multipart/yada; boundary=yada");
         assertEquals("yada", bd.getBoundary());
 
         /*
          * Test some weird parameters.
          */
-        bd = new BodyDescriptor();
+        bd = new DefaultBodyDescriptor();
         bd.addField("Content-Type", "multipart/yada; boundary=yada yada");
         assertEquals("yada", bd.getBoundary());
         
-        bd = new BodyDescriptor();
+        bd = new DefaultBodyDescriptor();
         bd.addField("Content-Type", "multipart/yada; boUNdarY= ya:*da; \tcharset\t =  big5");
         assertEquals("ya:*da", bd.getBoundary());
         assertEquals("big5", bd.getCharset());
         
-        bd = new BodyDescriptor();
+        bd = new DefaultBodyDescriptor();
         bd.addField("Content-Type", "multipart/yada; boUNdarY= \"ya \\\"\\\"\tda \\\"\";
"
                             + "\tcharset\t =  \"\\\"hepp\\\"  =us\t-ascii\"");
         assertEquals("ya \"\"\tda \"", bd.getBoundary());



---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


Mime
View raw message