Return-Path:
Delivered-To: apmail-james-mime4j-dev-archive@minotaur.apache.org
Received: (qmail 40732 invoked from network); 3 Jan 2010 21:54:10 -0000
Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.3)
by minotaur.apache.org with SMTP; 3 Jan 2010 21:54:10 -0000
Received: (qmail 88753 invoked by uid 500); 3 Jan 2010 21:54:10 -0000
Delivered-To: apmail-james-mime4j-dev-archive@james.apache.org
Received: (qmail 88720 invoked by uid 500); 3 Jan 2010 21:54:09 -0000
Mailing-List: contact mime4j-dev-help@james.apache.org; run by ezmlm
Precedence: bulk
List-Help:
List-Unsubscribe:
List-Post:
List-Id:
Reply-To: mime4j-dev@james.apache.org
Delivered-To: mailing list mime4j-dev@james.apache.org
Received: (qmail 88710 invoked by uid 99); 3 Jan 2010 21:54:09 -0000
Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136)
by apache.org (qpsmtpd/0.29) with ESMTP; Sun, 03 Jan 2010 21:54:09 +0000
X-ASF-Spam-Status: No, hits=-2000.0 required=10.0
tests=ALL_TRUSTED
X-Spam-Check-By: apache.org
Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4)
by apache.org (qpsmtpd/0.29) with ESMTP; Sun, 03 Jan 2010 21:54:04 +0000
Received: by eris.apache.org (Postfix, from userid 65534)
id 8167F23889EB; Sun, 3 Jan 2010 21:53:44 +0000 (UTC)
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Subject: svn commit: r895488 - in
/james/mime4j/branches/cycleclean/core/src/main/java/org/apache/james/mime4j:
parser/impl/DefaultBodyDescriptor.java
parser/impl/MaximalBodyDescriptor.java util/MimeUtil.java
Date: Sun, 03 Jan 2010 21:53:43 -0000
To: mime4j-dev@james.apache.org
From: bago@apache.org
X-Mailer: svnmailer-1.0.8
Message-Id: <20100103215344.8167F23889EB@eris.apache.org>
Author: bago
Date: Sun Jan 3 21:53:42 2010
New Revision: 895488
URL: http://svn.apache.org/viewvc?rev=895488&view=rev
Log:
MimeUtil.getHeaderParams moved temporarily to DefaultFieldParser that was the only client of that method (this helps organizing code. but I think that the entry points for field parsing still needs improvement) (MIME4J-157)
Modified:
james/mime4j/branches/cycleclean/core/src/main/java/org/apache/james/mime4j/parser/impl/DefaultBodyDescriptor.java
james/mime4j/branches/cycleclean/core/src/main/java/org/apache/james/mime4j/parser/impl/MaximalBodyDescriptor.java
james/mime4j/branches/cycleclean/core/src/main/java/org/apache/james/mime4j/util/MimeUtil.java
Modified: james/mime4j/branches/cycleclean/core/src/main/java/org/apache/james/mime4j/parser/impl/DefaultBodyDescriptor.java
URL: http://svn.apache.org/viewvc/james/mime4j/branches/cycleclean/core/src/main/java/org/apache/james/mime4j/parser/impl/DefaultBodyDescriptor.java?rev=895488&r1=895487&r2=895488&view=diff
==============================================================================
--- james/mime4j/branches/cycleclean/core/src/main/java/org/apache/james/mime4j/parser/impl/DefaultBodyDescriptor.java (original)
+++ james/mime4j/branches/cycleclean/core/src/main/java/org/apache/james/mime4j/parser/impl/DefaultBodyDescriptor.java Sun Jan 3 21:53:42 2010
@@ -126,7 +126,7 @@
private void parseContentType(String value) {
contentTypeSet = true;
- Map params = MimeUtil.getHeaderParams(value);
+ Map params = DefaultBodyDescriptor.getHeaderParams(value);
String main = params.get("");
String type = null;
@@ -246,4 +246,185 @@
public String getSubType() {
return subType;
}
+
+ /**
+ * Parses a complex field value into a map of key/value pairs. You may
+ * use this, for example, to parse a definition like
+ *
+ * text/plain; charset=UTF-8; boundary=foobar
+ *
+ * The above example would return a map with the keys "", "charset",
+ * and "boundary", and the values "text/plain", "UTF-8", and "foobar".
+ *
+ * Header value will be unfolded and excess white space trimmed.
+ *
+ * @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) {
+ pValue = pValue.trim();
+
+ 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();
+ StringBuilder paramName = new StringBuilder(64);
+ StringBuilder paramValue = new StringBuilder(64);
+
+ 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 (char c : chars) {
+ 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.setLength(0);
+ paramValue.setLength(0);
+
+ 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;
+ }
}
Modified: james/mime4j/branches/cycleclean/core/src/main/java/org/apache/james/mime4j/parser/impl/MaximalBodyDescriptor.java
URL: http://svn.apache.org/viewvc/james/mime4j/branches/cycleclean/core/src/main/java/org/apache/james/mime4j/parser/impl/MaximalBodyDescriptor.java?rev=895488&r1=895487&r2=895488&view=diff
==============================================================================
--- james/mime4j/branches/cycleclean/core/src/main/java/org/apache/james/mime4j/parser/impl/MaximalBodyDescriptor.java (original)
+++ james/mime4j/branches/cycleclean/core/src/main/java/org/apache/james/mime4j/parser/impl/MaximalBodyDescriptor.java Sun Jan 3 21:53:42 2010
@@ -175,7 +175,7 @@
private void parseContentDisposition(final String value) {
isContentDispositionSet = true;
- contentDispositionParameters = MimeUtil.getHeaderParams(value);
+ contentDispositionParameters = DefaultBodyDescriptor.getHeaderParams(value);
contentDispositionType = contentDispositionParameters.get("");
final String contentDispositionModificationDate
Modified: james/mime4j/branches/cycleclean/core/src/main/java/org/apache/james/mime4j/util/MimeUtil.java
URL: http://svn.apache.org/viewvc/james/mime4j/branches/cycleclean/core/src/main/java/org/apache/james/mime4j/util/MimeUtil.java?rev=895488&r1=895487&r2=895488&view=diff
==============================================================================
--- james/mime4j/branches/cycleclean/core/src/main/java/org/apache/james/mime4j/util/MimeUtil.java (original)
+++ james/mime4j/branches/cycleclean/core/src/main/java/org/apache/james/mime4j/util/MimeUtil.java Sun Jan 3 21:53:42 2010
@@ -24,20 +24,14 @@
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.GregorianCalendar;
-import java.util.HashMap;
import java.util.Locale;
-import java.util.Map;
import java.util.Random;
import java.util.TimeZone;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
/**
* A utility class, which provides some MIME related application logic.
*/
public final class MimeUtil {
- private static final Log log = LogFactory.getLog(MimeUtil.class);
/**
* The quoted-printable
encoding.
@@ -159,193 +153,21 @@
}
/**
- * Parses a complex field value into a map of key/value pairs. You may
- * use this, for example, to parse a definition like
- *
- * text/plain; charset=UTF-8; boundary=foobar
- *
- * The above example would return a map with the keys "", "charset",
- * and "boundary", and the values "text/plain", "UTF-8", and "foobar".
- *
- * Header value will be unfolded and excess white space trimmed.
- *
- * @param pValue The field value to parse.
- * @return The result map; use the key "" to retrieve the first value.
- */
- @SuppressWarnings("fallthrough")
- public static Map getHeaderParams(String pValue) {
- pValue = pValue.trim();
-
- 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();
- StringBuilder paramName = new StringBuilder(64);
- StringBuilder paramValue = new StringBuilder(64);
-
- 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 (char c : chars) {
- 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.setLength(0);
- paramValue.setLength(0);
-
- 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;
- }
-
- /**
* Creates a new unique message boundary string that can be used as boundary
* parameter for the Content-Type header field of a message.
*
* @return a new unique message boundary string.
*/
+ /* TODO - From rfc2045:
+ * Since the hyphen character ("-") may be represented as itself in the
+ * Quoted-Printable encoding, care must be taken, when encapsulating a
+ * quoted-printable encoded body inside one or more multipart entities,
+ * to ensure that the boundary delimiter does not appear anywhere in the
+ * encoded body. (A good strategy is to choose a boundary that includes
+ * a character sequence such as "=_" which can never appear in a
+ * quoted-printable body. See the definition of multipart messages in
+ * RFC 2046.)
+ */
public static String createUniqueBoundary() {
StringBuilder sb = new StringBuilder();
sb.append("-=Part.");