Index: src/test/java/org/apache/james/mime4j/io/LineDelimiterTest.java
===================================================================
--- src/test/java/org/apache/james/mime4j/io/LineDelimiterTest.java	(revision 0)
+++ src/test/java/org/apache/james/mime4j/io/LineDelimiterTest.java	(revision 0)
@@ -0,0 +1,65 @@
+/****************************************************************
+ * 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.io;
+
+import org.apache.james.mime4j.MimeException;
+import org.apache.james.mime4j.MimeMode;
+import org.apache.james.mime4j.io.LineDelimiterStrategy;
+
+import junit.framework.TestCase;
+
+public class LineDelimiterTest extends TestCase {
+
+    public void testLaxStrategy() throws Exception {
+        LineDelimiterStrategy lds = new LineDelimiterStrategy(MimeMode.LENIENT);
+        assertEquals(2, lds.testDelimiter('\r', '\n'));
+        assertEquals(1, lds.testDelimiter('a', '\n'));
+        assertEquals(0, lds.testDelimiter('\n', 'a'));
+        assertEquals(0, lds.testDelimiter('\r', 'a'));
+        assertEquals(0, lds.testDelimiter('a', '\r'));
+        assertEquals(1, lds.testDelimiter((char) -1, '\n'));
+    }
+
+    public void testStrictStrategy() throws Exception {
+        LineDelimiterStrategy lds = new LineDelimiterStrategy(MimeMode.STRICT);
+        assertEquals(2, lds.testDelimiter('\r', '\n'));
+        try {
+            lds.testDelimiter('a', '\n');
+            fail("MimeException should have been thrown");
+        } catch (MimeException ex) {
+            // ignore
+        }
+        assertEquals(0, lds.testDelimiter('\n', 'a'));
+        try {
+            lds.testDelimiter('\r', 'a');
+            fail("MimeException should have been thrown");
+        } catch (MimeException ex) {
+            // ignore
+        }
+        assertEquals(0, lds.testDelimiter('a', '\r'));
+        try {
+            lds.testDelimiter((char) -1, '\n');
+            fail("MimeException should have been thrown");
+        } catch (MimeException ex) {
+            // ignore
+        }
+    }
+
+}
Index: src/test/java/org/apache/james/mime4j/io/MimeBoundaryInputStreamTest.java
===================================================================
--- src/test/java/org/apache/james/mime4j/io/MimeBoundaryInputStreamTest.java	(revision 728635)
+++ src/test/java/org/apache/james/mime4j/io/MimeBoundaryInputStreamTest.java	(working copy)
@@ -24,6 +24,8 @@
 import java.io.IOException;
 import java.io.InputStream;
 
+import org.apache.james.mime4j.MimeIOException;
+import org.apache.james.mime4j.MimeMode;
 import org.apache.james.mime4j.io.BufferedLineReaderInputStream;
 import org.apache.james.mime4j.io.LineReaderInputStream;
 import org.apache.james.mime4j.io.MimeBoundaryInputStream;
@@ -78,6 +80,68 @@
         assertTrue(mime2.isLastPart());
     }
     
+    public void testStrictLineDelimiterReading() throws IOException {
+        String text = "Line 1\r\nLine 2\r\n--boundary\r\n" +
+                "Line 3\r\nLine 4\r\n--boundary--\r\n";
+        
+        ByteArrayInputStream bis = new ByteArrayInputStream(text.getBytes("US-ASCII"));
+        
+        BufferedLineReaderInputStream buffer = new BufferedLineReaderInputStream(bis, 4096); 
+        
+        MimeBoundaryInputStream mime1 = new MimeBoundaryInputStream(buffer, "boundary");
+        assertEquals("Line 1\r\nLine 2", read(mime1, 5));
+        
+        assertFalse(mime1.isLastPart());
+        
+        MimeBoundaryInputStream mime2 = new MimeBoundaryInputStream(buffer, "boundary");
+        assertEquals("Line 3\r\nLine 4", read(mime2, 5));
+
+        assertTrue(mime2.isLastPart());
+    }
+    
+    public void testStrictLineDelimiterReadingException1() throws IOException {
+        String text = "Line 1\r\nLine 2\n--boundary--\n";
+        ByteArrayInputStream bis = new ByteArrayInputStream(text.getBytes("US-ASCII"));
+        BufferedLineReaderInputStream buffer = new BufferedLineReaderInputStream(bis, 4096); 
+        try {
+            MimeBoundaryInputStream mime = new MimeBoundaryInputStream(buffer, "boundary", 
+                    new LineDelimiterStrategy(MimeMode.STRICT));
+            read(mime, 5);
+            fail("MimeIOException should have been thrown");
+        } catch (MimeIOException ex) {
+            // ignore
+        }
+    }
+    
+    public void testStrictLineDelimiterReadingException2() throws IOException {
+        String text = "Line 1\r\nLine 2\r\n--boundary--\n";
+        ByteArrayInputStream bis = new ByteArrayInputStream(text.getBytes("US-ASCII"));
+        BufferedLineReaderInputStream buffer = new BufferedLineReaderInputStream(bis, 4096); 
+        try {
+            MimeBoundaryInputStream mime = new MimeBoundaryInputStream(buffer, "boundary", 
+                    new LineDelimiterStrategy(MimeMode.STRICT));
+            read(mime, 5);
+            fail("MimeIOException should have been thrown");
+        } catch (MimeIOException ex) {
+            // ignore
+        }
+    }
+    
+    public void testStrictLineDelimiterExceptionReading3() throws IOException {
+        String text = "Line 1\r\nLine 2\r\n--boundary\n" +
+                "Line 3\r\nLine 4\r\n--boundary--\r\n";
+        ByteArrayInputStream bis = new ByteArrayInputStream(text.getBytes("US-ASCII"));
+        BufferedLineReaderInputStream buffer = new BufferedLineReaderInputStream(bis, 4096); 
+        try {
+            MimeBoundaryInputStream mime = new MimeBoundaryInputStream(buffer, "boundary", 
+                    new LineDelimiterStrategy(MimeMode.STRICT));
+            read(mime, 5);
+            fail("MimeIOException should have been thrown");
+        } catch (MimeIOException ex) {
+            // ignore
+        }
+    }
+    
     public void testBasicReadingSmallBuffer1() throws IOException {
         String text = "yadayadayadayadayadayadayadayadayadayadayadayadayadayadayadayada\r\n--boundary\r\n" +
                 "blahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblah\r\n--boundary--";
Index: src/test/java/org/apache/james/mime4j/io/BufferedLineReaderInputStreamTest.java
===================================================================
--- src/test/java/org/apache/james/mime4j/io/BufferedLineReaderInputStreamTest.java	(revision 728635)
+++ src/test/java/org/apache/james/mime4j/io/BufferedLineReaderInputStreamTest.java	(working copy)
@@ -19,6 +19,8 @@
 
 package org.apache.james.mime4j.io;
 
+import org.apache.james.mime4j.MimeIOException;
+import org.apache.james.mime4j.MimeMode;
 import org.apache.james.mime4j.io.BufferedLineReaderInputStream;
 import org.apache.james.mime4j.io.LineReaderInputStream;
 import org.apache.james.mime4j.io.MaxLineLimitException;
@@ -163,4 +165,38 @@
         }
     }
 
+    public void testReadStrictModeLoneLF() throws Exception {
+        
+        String teststr = "1234567890\n";
+        byte[] raw = teststr.getBytes("US-ASCII");
+        
+        LineReaderInputStream instream = new BufferedLineReaderInputStream(
+                new ByteArrayInputStream(raw), 1024, 13, 
+                new LineDelimiterStrategy(MimeMode.STRICT)); 
+        ByteArrayBuffer linebuf = new ByteArrayBuffer(8); 
+        linebuf.clear();
+        try {
+            instream.readLine(linebuf);
+            fail("MimeIOException should have been thrown");
+        } catch (MimeIOException ex) {
+        }
+    }
+    
+    public void testReadStrictModeLoneCR() throws Exception {
+        
+        String teststr = "12345\r67890\r\n";
+        byte[] raw = teststr.getBytes("US-ASCII");
+        
+        LineReaderInputStream instream = new BufferedLineReaderInputStream(
+                new ByteArrayInputStream(raw), 1024, 13, 
+                new LineDelimiterStrategy(MimeMode.STRICT)); 
+        ByteArrayBuffer linebuf = new ByteArrayBuffer(8); 
+        linebuf.clear();
+        try {
+            instream.readLine(linebuf);
+            fail("MimeIOException should have been thrown");
+        } catch (MimeIOException ex) {
+        }
+    }
+    
 }
Index: src/test/java/org/apache/james/mime4j/parser/MimeEntityTest.java
===================================================================
--- src/test/java/org/apache/james/mime4j/parser/MimeEntityTest.java	(revision 728635)
+++ src/test/java/org/apache/james/mime4j/parser/MimeEntityTest.java	(working copy)
@@ -50,12 +50,15 @@
         RootInputStream rootStream = new RootInputStream(instream); 
         BufferedLineReaderInputStream rawstream = new BufferedLineReaderInputStream(rootStream, 12); 
         
+        MimeEntityConfig config = new MimeEntityConfig();
+        
         MimeEntity entity = new MimeEntity(
                 rootStream,
                 rawstream,
                 null,
                 EntityStates.T_START_MESSAGE,
-                EntityStates.T_END_MESSAGE);
+                EntityStates.T_END_MESSAGE,
+                config);
         
         
         assertEquals(EntityStates.T_START_MESSAGE, entity.getState());
@@ -137,12 +140,15 @@
         RootInputStream rootStream = new RootInputStream(instream); 
         BufferedLineReaderInputStream rawstream = new BufferedLineReaderInputStream(rootStream, 24); 
         
+        MimeEntityConfig config = new MimeEntityConfig();
+        
         MimeEntity entity = new MimeEntity(
                 rootStream,
                 rawstream,
                 null,
                 EntityStates.T_START_MESSAGE,
-                EntityStates.T_END_MESSAGE);
+                EntityStates.T_END_MESSAGE,
+                config);
         
         assertEquals(EntityStates.T_START_MESSAGE, entity.getState());
         entity.advance();
@@ -250,12 +256,15 @@
         RootInputStream rootStream = new RootInputStream(instream); 
         BufferedLineReaderInputStream rawstream = new BufferedLineReaderInputStream(rootStream, 24); 
         
+        MimeEntityConfig config = new MimeEntityConfig();
+        
         MimeEntity entity = new MimeEntity(
                 rootStream,
                 rawstream,
                 null,
                 EntityStates.T_START_MESSAGE,
-                EntityStates.T_END_MESSAGE);
+                EntityStates.T_END_MESSAGE,
+                config);
         
         entity.setRecursionMode(RecursionMode.M_RAW);
         
Index: src/main/java/org/apache/james/mime4j/io/RootInputStream.java
===================================================================
--- src/main/java/org/apache/james/mime4j/io/RootInputStream.java	(revision 728635)
+++ src/main/java/org/apache/james/mime4j/io/RootInputStream.java	(working copy)
@@ -31,6 +31,9 @@
  * {@link org.apache.james.mime4j.parser.MimeStreamParser#stop()} method.
  */
 public class RootInputStream extends FilterInputStream {
+
+    private final LineDelimiterStrategy lineStratey;
+    
     private int lineNumber = 1;
     private int prev = -1;
     private boolean truncated = false;
@@ -39,12 +42,27 @@
      * Creates a new <code>RootInputStream</code>.
      * 
      * @param is the stream to read from.
+     * @param lineStratey the line delimiter strategy. 
+     *   May be <code>null</code>.
      */
-    public RootInputStream(InputStream is) {
+    public RootInputStream(InputStream is, LineDelimiterStrategy lineStratey) {
         super(is);
+        if (lineStratey == null) {
+            lineStratey = LineDelimiterStrategy.DEFAULT;
+        }
+        this.lineStratey = lineStratey;
     }
 
     /**
+     * Creates a new <code>RootInputStream</code>.
+     * 
+     * @param is the stream to read from.
+     */
+    public RootInputStream(InputStream is) {
+        this(is, null);
+    }
+
+    /**
      * Gets the current line number starting at 1 
      * (the number of <code>\r\n</code> read so far plus 1).
      * 
@@ -73,12 +91,15 @@
             return -1;
         }
         
-        int b = in.read();
-        if (prev == '\r' && b == '\n') {
-            lineNumber++;
+        int cur = in.read();
+        if (cur != -1) {
+            cur = cur & 0xff;
+            if (lineStratey.testDelimiterIO(prev, cur) > 0) {
+                lineNumber++;
+            }
         }
-        prev = b;
-        return b;
+        prev = cur;
+        return cur;
     }
     
     /**
@@ -92,11 +113,14 @@
         }
         
         int n = in.read(b, off, len);
-        for (int i = off; i < off + n; i++) {
-            if (prev == '\r' && b[i] == '\n') {
-                lineNumber++;
+        if (n != -1) {
+            for (int i = off; i < off + n; i++) {
+                int cur = b[i] & 0xff;
+                if (lineStratey.testDelimiterIO(prev, cur) > 0) {
+                    lineNumber++;
+                }
+                prev = cur;
             }
-            prev = b[i];
         }
         return n;
     }
Index: src/main/java/org/apache/james/mime4j/io/MimeBoundaryInputStream.java
===================================================================
--- src/main/java/org/apache/james/mime4j/io/MimeBoundaryInputStream.java	(revision 728635)
+++ src/main/java/org/apache/james/mime4j/io/MimeBoundaryInputStream.java	(working copy)
@@ -33,6 +33,7 @@
 public class MimeBoundaryInputStream extends LineReaderInputStream {
 
     private final byte[] boundary;
+    private final LineDelimiterStrategy lineStrategy;
     
     private boolean eof;
     private int limit;
@@ -48,14 +49,23 @@
      * 
      * @param inbuffer The underlying stream.
      * @param boundary Boundary string (not including leading hyphens).
+     * @param lineStrategy the line delimiter strategy. 
+     *        May be <code>null</code>.
      * @throws IllegalArgumentException when boundary is too long
+     * @throws IOException in case of an I/O exception.
      */
-    public MimeBoundaryInputStream(BufferedLineReaderInputStream inbuffer, String boundary) 
-            throws IOException {
+    public MimeBoundaryInputStream(
+            BufferedLineReaderInputStream inbuffer, 
+            String boundary,
+            LineDelimiterStrategy lineStrategy) throws IOException {
         super(inbuffer);
         if (inbuffer.capacity() <= boundary.length()) {
             throw new IllegalArgumentException("Boundary is too long");
         }
+        if (lineStrategy == null) {
+            lineStrategy = LineDelimiterStrategy.DEFAULT;
+        }
+        this.lineStrategy = lineStrategy; 
         this.buffer = inbuffer;
         this.eof = false;
         this.limit = -1;
@@ -78,10 +88,22 @@
     }
 
     /**
-     * Closes the underlying stream.
+     * Creates a new MimeBoundaryInputStream.
      * 
-     * @throws IOException on I/O errors.
+     * @param inbuffer The underlying stream.
+     * @param boundary Boundary string (not including leading hyphens).
+     * @throws IllegalArgumentException when boundary is too long
+     * @throws IOException in case of an I/O exception.
      */
+    public MimeBoundaryInputStream(
+            BufferedLineReaderInputStream inbuffer, 
+            String boundary) throws IOException {
+        this(inbuffer, boundary, null);
+    }
+    
+    /**
+     * This method does nothing, It DOES NOT closes the underlying stream.
+     */
     @Override
     public void close() throws IOException {
     }
@@ -203,9 +225,12 @@
         
         
         int i = buffer.indexOf(boundary);
-        // NOTE this currently check only for LF. It doesn't check for canonical CRLF
-        // and neither for isolated CR. This will require updates according to MIME4J-60
-        while (i > 0 && buffer.charAt(i-1) != '\n') {
+        while (i > 0) {
+            int cur = buffer.charAt(i - 1) & 0xff;
+            int prev = (i > 1) ? buffer.charAt(i - 2) & 0xff : -1;
+            if (lineStrategy.testDelimiterIO(prev, cur) > 0) {
+                break;
+            }
             // skip the "fake" boundary (it does not contain LF or CR so we cannot have
             // another boundary starting before this is complete.
             i = i + boundary.length;
@@ -230,17 +255,14 @@
         boundaryLen = boundary.length;
         int len = limit - buffer.pos();
         if (len > 0) {
-            if (buffer.charAt(limit - 1) == '\n') {
-                boundaryLen++;
-                limit--;
+            int cur = buffer.charAt(limit - 1) & 0xff;
+            int prev = (len > 1) ? buffer.charAt(limit - 2) & 0xff : -1;
+            int l = lineStrategy.testDelimiterIO(prev, cur);
+            if (l > 0) {
+                boundaryLen += l;
+                limit -= l;
             }
         }
-        if (len > 1) {
-            if (buffer.charAt(limit - 1) == '\r') {
-                boundaryLen++;
-                limit--;
-            }
-        }
     }
     
     private void skipBoundary() throws IOException {
@@ -249,28 +271,31 @@
             buffer.skip(boundaryLen);
             boolean checkForLastPart = true;
             for (;;) {
-                if (buffer.length() > 1) {
-                    int ch1 = buffer.charAt(buffer.pos());
-                    int ch2 = buffer.charAt(buffer.pos() + 1);
+                int len = buffer.length(); 
+                if (len > 0) {
+                    int ch1 = buffer.charAt(buffer.pos())& 0xff;
+                    int ch2 = len > 1 ? buffer.charAt(buffer.pos() + 1) & 0xff : -1;
                     
-                    if (checkForLastPart) if (ch1 == '-' && ch2 == '-') {
-                        this.lastPart = true;
-                        buffer.skip(2);
-                        checkForLastPart = false;
-                        continue;
+                    if (checkForLastPart) { 
+                        if (ch1 == '-' && ch2 == '-') {
+                            this.lastPart = true;
+                            buffer.skip(2);
+                            checkForLastPart = false;
+                            continue;
+                        }
                     }
-                    
-                    if (ch1 == '\r' && ch2 == '\n') {
-                        buffer.skip(2);
+                    int l = lineStrategy.testDelimiterIO(-1, ch1);
+                    if (l > 0) {
+                        buffer.skip(l);
                         break;
-                    } else if (ch1 == '\n') {
-                        buffer.skip(1);
+                    }
+                    l = lineStrategy.testDelimiterIO(ch1, ch2);
+                    if (l > 0) {
+                        buffer.skip(l);
                         break;
-                    } else {
-                        // ignoring everything in a line starting with a boundary.
-                        buffer.skip(1);
                     }
-                    
+                    // ignoring everything in a line starting with a boundary.
+                    buffer.skip(1);
                 } else {
                     if (eof) {
                         break;
Index: src/main/java/org/apache/james/mime4j/io/BufferedLineReaderInputStream.java
===================================================================
--- src/main/java/org/apache/james/mime4j/io/BufferedLineReaderInputStream.java	(revision 728635)
+++ src/main/java/org/apache/james/mime4j/io/BufferedLineReaderInputStream.java	(working copy)
@@ -36,11 +36,13 @@
     private int buflen;
     
     private final int maxLineLen;
+    private final LineDelimiterStrategy lineStrategy;
     
     public BufferedLineReaderInputStream(
             final InputStream instream, 
             int buffersize,
-            int maxLineLen) {
+            int maxLineLen,
+            LineDelimiterStrategy lineStrategy) {
         super(instream);
         if (instream == null) {
             throw new IllegalArgumentException("Input stream may not be null");
@@ -48,16 +50,27 @@
         if (buffersize <= 0) {
             throw new IllegalArgumentException("Buffer size may not be negative or zero");
         }
+        if (lineStrategy == null) {
+            lineStrategy = LineDelimiterStrategy.DEFAULT;
+        }
         this.buffer = new byte[buffersize];
         this.bufpos = 0;
         this.buflen = 0;
         this.maxLineLen = maxLineLen;
+        this.lineStrategy = lineStrategy;
     }
 
     public BufferedLineReaderInputStream(
             final InputStream instream, 
+            int buffersize,
+            int maxLineLen) {
+        this(instream, buffersize, maxLineLen, null);
+    }
+
+    public BufferedLineReaderInputStream(
+            final InputStream instream, 
             int buffersize) {
-        this(instream, buffersize, -1);
+        this(instream, buffersize, -1, null);
     }
 
     private void expand(int newlen) {
@@ -163,13 +176,18 @@
                     break;
                 }
             }
-            int i = indexOf((byte)'\n');
-            int chunk;
-            if (i != -1) {
-                found = true;
-                chunk = i + 1 - pos();
-            } else {
-                chunk = length();
+            int chunk = length();
+
+            int cur = -1;
+            int prev = -1;
+            for (int i =  this.bufpos; i < this.buflen; i++) {
+                prev = cur;
+                cur = this.buffer[i] & 0xff;
+                if (lineStrategy.testDelimiterIO(prev, cur) > 0) {
+                    found = true;
+                    chunk = i + 1 - pos();
+                    break;
+                }
             }
             if (chunk > 0) {
                 dst.append(buf(), pos(), chunk);
Index: src/main/java/org/apache/james/mime4j/io/LineDelimiterStrategy.java
===================================================================
--- src/main/java/org/apache/james/mime4j/io/LineDelimiterStrategy.java	(revision 0)
+++ src/main/java/org/apache/james/mime4j/io/LineDelimiterStrategy.java	(revision 0)
@@ -0,0 +1,106 @@
+/****************************************************************
+ * 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.io;
+
+import org.apache.james.mime4j.MimeException;
+import org.apache.james.mime4j.MimeIOException;
+import org.apache.james.mime4j.MimeMode;
+import org.apache.james.mime4j.util.MessageUtils;
+
+/**
+ * A strategy to identify line delimiters in data streams. 
+ * 
+ * @version $Id:$
+ */
+public class LineDelimiterStrategy {
+
+    public static final LineDelimiterStrategy DEFAULT = new LineDelimiterStrategy(
+            MimeMode.LENIENT); 
+    
+    private final MimeMode mode;
+    
+    public LineDelimiterStrategy(MimeMode mode) {
+        super();
+        this.mode = mode;
+    }
+    
+    /**
+     * Determines if the current position in the data stream represents
+     * a valid line delimiter.
+     * 
+     * @param prev previous character in the data stream. 
+     *  May be -1 if not available.
+     * @param cur current character in the data stream
+     * 
+     * @return 0 if the current pair of characters does not a valid line 
+     *  delimiter; 1 if only the current character represents a line 
+     *  delimiter; 2 if both character represent a line delimiter. 
+     * 
+     * @throws MimeException if an invalid sequence of characters is
+     *   encountered.
+     */
+    public int testDelimiter(int prev, int cur) throws MimeException {
+        if (this.mode.equals(MimeMode.STRICT)) {
+            if (prev == MessageUtils.CR && cur == MessageUtils.LF) {
+                return 2;
+            }
+            if (prev == MessageUtils.CR) {
+                throw new MimeException("Isolated CR encountered");
+            }
+            if (cur == MessageUtils.LF) {
+                throw new MimeException("Isolated LF encountered");
+            }
+            return 0;
+        } else {
+            if (cur == MessageUtils.LF) {
+                if (prev == MessageUtils.CR) {
+                    return 2;
+                } else {
+                    return 1;
+                }
+            } else {
+                return 0;
+            }
+        }
+    }
+
+    /**
+     * Convenience method that is similar to {@link #testDelimiter(int, int)}
+     * but throws {@link MimeIOException} instead of {@link MimeException}. 
+     * 
+     * @param prev previous character in the data stream. 
+     *  May be -1 if not available.
+     * @param cur current character in the data stream
+     * @return 0 if the current pair of characters does not a valid line 
+     *  delimiter; 1 if only the current character represents a line 
+     *  delimiter; 2 if both character represent a line delimiter. 
+     * 
+     * @throws MimeIOException if an invalid sequence of characters is
+     *   encountered.
+     */
+    public int testDelimiterIO(int prev, int cur) throws MimeIOException {
+        try {
+            return testDelimiter(prev, cur);
+        } catch (MimeException ex) {
+            throw new MimeIOException(ex);
+        }
+    }
+    
+}
Index: src/main/java/org/apache/james/mime4j/parser/AbstractEntity.java
===================================================================
--- src/main/java/org/apache/james/mime4j/parser/AbstractEntity.java	(revision 728635)
+++ src/main/java/org/apache/james/mime4j/parser/AbstractEntity.java	(working copy)
@@ -29,6 +29,7 @@
 import org.apache.james.mime4j.descriptor.DefaultBodyDescriptor;
 import org.apache.james.mime4j.descriptor.MaximalBodyDescriptor;
 import org.apache.james.mime4j.descriptor.MutableBodyDescriptor;
+import org.apache.james.mime4j.io.LineDelimiterStrategy;
 import org.apache.james.mime4j.io.LineReaderInputStream;
 import org.apache.james.mime4j.io.MaxHeaderLimitException;
 import org.apache.james.mime4j.io.MaxLineLimitException;
@@ -48,6 +49,7 @@
     protected final int endState;
     protected final MimeEntityConfig config;
     protected final MutableBodyDescriptor body;
+    protected final LineDelimiterStrategy lineStrategy;
     
     protected int state;
 
@@ -83,12 +85,21 @@
             BodyDescriptor parent,
             int startState, 
             int endState,
+            LineDelimiterStrategy lineStrategy,
             MimeEntityConfig config) {
+        super();
+        if (config == null) {
+            config = new MimeEntityConfig();
+        }
+        if (lineStrategy == null) {
+            lineStrategy = new LineDelimiterStrategy(config.getMimeMode());
+        }
         this.log = LogFactory.getLog(getClass());        
         this.parent = parent;
         this.state = startState;
         this.startState = startState;
         this.endState = endState;
+        this.lineStrategy = lineStrategy;
         this.config = config;
         this.body = newBodyDescriptor(parent);
         this.linebuf = new ByteArrayBuffer(64);
@@ -145,12 +156,14 @@
                 break;
             }
             len = linebuf.length();
-            if (len > 0 && linebuf.byteAt(len - 1) == '\n') {
-                len--;
+            if (len > 0) {
+                int cur = linebuf.byteAt(len - 1) & 0xff;
+                int prev = len > 1 ? linebuf.byteAt(len - 2) & 0xff : -1;
+                int l = lineStrategy.testDelimiter(prev, cur);
+                if (l > 0) {
+                    len -= l;
+                }
             }
-            if (len > 0 && linebuf.byteAt(len - 1) == '\r') {
-                len--;
-            }
             if (len == 0) {
                 // empty line detected 
                 endOfHeader = true;
@@ -293,7 +306,7 @@
      * @throws IOException subclasses may elect to throw this exception
      */
     protected void monitor(Event event) throws MimeException, IOException {
-        if (config.isStrictParsing()) {
+        if (config.isStrict()) {
             throw new MimeParseEventException(event);
         } else {
             warn(event);
Index: src/main/java/org/apache/james/mime4j/parser/MimeEntity.java
===================================================================
--- src/main/java/org/apache/james/mime4j/parser/MimeEntity.java	(revision 728635)
+++ src/main/java/org/apache/james/mime4j/parser/MimeEntity.java	(working copy)
@@ -28,6 +28,7 @@
 import org.apache.james.mime4j.descriptor.BodyDescriptor;
 import org.apache.james.mime4j.io.BufferedLineReaderInputStream;
 import org.apache.james.mime4j.io.LimitedInputStream;
+import org.apache.james.mime4j.io.LineDelimiterStrategy;
 import org.apache.james.mime4j.io.LineReaderInputStream;
 import org.apache.james.mime4j.io.LineReaderInputStreamAdaptor;
 import org.apache.james.mime4j.io.MimeBoundaryInputStream;
@@ -61,8 +62,9 @@
             BodyDescriptor parent, 
             int startState, 
             int endState,
+            LineDelimiterStrategy lineStrategy,
             MimeEntityConfig config) {
-        super(parent, startState, endState, config);
+        super(parent, startState, endState, lineStrategy, config);
         this.rootStream = rootStream;
         this.inbuffer = inbuffer;
         this.dataStream = new LineReaderInputStreamAdaptor(
@@ -76,9 +78,9 @@
             BufferedLineReaderInputStream inbuffer,
             BodyDescriptor parent, 
             int startState, 
-            int endState) {
-        this(rootStream, inbuffer, parent, startState, endState, 
-                new MimeEntityConfig());
+            int endState,
+            MimeEntityConfig config) {
+        this(rootStream, inbuffer, parent, startState, endState, null, config);
     }
 
     public int getRecursionMode() {
@@ -204,11 +206,16 @@
                         new BufferedLineReaderInputStream(
                                 mimeStream, 
                                 bufferSize, 
-                                config.getMaxLineLen()), 
-                        boundary);
+                                config.getMaxLineLen(),
+                                lineStrategy), 
+                        boundary,
+                        lineStrategy);
             } else {
                 inbuffer.ensureCapacity(bufferSize);
-                mimeStream = new MimeBoundaryInputStream(inbuffer, boundary);
+                mimeStream = new MimeBoundaryInputStream(
+                        inbuffer, 
+                        boundary,
+                        lineStrategy);
             }
         } catch (IllegalArgumentException e) {
             // thrown when boundary is too long
@@ -259,10 +266,12 @@
                     new BufferedLineReaderInputStream(
                             instream, 
                             4 * 1024,
-                            config.getMaxLineLen()),
+                            config.getMaxLineLen(),
+                            lineStrategy),
                     body, 
                     EntityStates.T_START_MESSAGE, 
                     EntityStates.T_END_MESSAGE,
+                    lineStrategy,
                     config);
             message.setRecursionMode(recursionMode);
             return message;
@@ -277,13 +286,15 @@
             BufferedLineReaderInputStream stream = new BufferedLineReaderInputStream(
                     mimeStream, 
                     4 * 1024,
-                    config.getMaxLineLen());
+                    config.getMaxLineLen(),
+                    lineStrategy);
             MimeEntity mimeentity = new MimeEntity(
                     rootStream, 
                     stream,
                     body, 
                     EntityStates.T_START_BODYPART, 
                     EntityStates.T_END_BODYPART,
+                    lineStrategy,
                     config);
             mimeentity.setRecursionMode(recursionMode);
             return mimeentity;
Index: src/main/java/org/apache/james/mime4j/parser/MimeTokenStream.java
===================================================================
--- src/main/java/org/apache/james/mime4j/parser/MimeTokenStream.java	(revision 728635)
+++ src/main/java/org/apache/james/mime4j/parser/MimeTokenStream.java	(working copy)
@@ -29,10 +29,12 @@
 import java.util.LinkedList;
 
 import org.apache.james.mime4j.MimeException;
+import org.apache.james.mime4j.MimeMode;
 import org.apache.james.mime4j.decoder.Base64InputStream;
 import org.apache.james.mime4j.decoder.QuotedPrintableInputStream;
 import org.apache.james.mime4j.descriptor.BodyDescriptor;
 import org.apache.james.mime4j.io.BufferedLineReaderInputStream;
+import org.apache.james.mime4j.io.LineDelimiterStrategy;
 import org.apache.james.mime4j.io.RootInputStream;
 import org.apache.james.mime4j.util.MimeUtil;
 
@@ -96,7 +98,7 @@
      */
     public static final MimeTokenStream createStrictValidationStream() {
         MimeEntityConfig config = new MimeEntityConfig();
-        config.setStrictParsing(true);
+        config.setMode(MimeMode.STRICT);
         return new MimeTokenStream(config);
     }
     
@@ -149,12 +151,15 @@
     }
 
     private void doParse(InputStream stream, String contentType) {
+        LineDelimiterStrategy lineStrategy = new LineDelimiterStrategy(
+                config.getMimeMode());
         entities.clear();
-        rootInputStream = new RootInputStream(stream);
+        rootInputStream = new RootInputStream(stream, lineStrategy);
         inbuffer = new BufferedLineReaderInputStream(
                 rootInputStream, 
                 4 * 1024,
-                config.getMaxLineLen());
+                config.getMaxLineLen(),
+                lineStrategy);
         switch (recursionMode) {
         case M_RAW:
             RawEntity rawentity = new RawEntity(inbuffer);
@@ -170,6 +175,7 @@
                     null, 
                     T_START_MESSAGE, 
                     T_END_MESSAGE,
+                    lineStrategy,
                     config);
             mimeentity.setRecursionMode(recursionMode);
             if (contentType != null) {
Index: src/main/java/org/apache/james/mime4j/parser/MimeEntityConfig.java
===================================================================
--- src/main/java/org/apache/james/mime4j/parser/MimeEntityConfig.java	(revision 728635)
+++ src/main/java/org/apache/james/mime4j/parser/MimeEntityConfig.java	(working copy)
@@ -20,6 +20,7 @@
 package org.apache.james.mime4j.parser;
 
 import org.apache.james.mime4j.MimeException;
+import org.apache.james.mime4j.MimeMode;
 import org.apache.james.mime4j.util.CharArrayBuffer;
 
 /**
@@ -28,14 +29,14 @@
 public final class MimeEntityConfig implements Cloneable {
 
     private boolean maximalBodyDescriptor;
-    private boolean strictParsing;
+    private MimeMode mimeMode;
     private int maxLineLen;
     private int maxHeaderCount;
     private long maxContentLen;
     
     public MimeEntityConfig() {
         this.maximalBodyDescriptor = false;
-        this.strictParsing = false;
+        this.mimeMode = MimeMode.LENIENT;
         this.maxLineLen = 1000;
         this.maxHeaderCount = 1000;
         this.maxContentLen = -1;
@@ -52,24 +53,29 @@
     /**
      * Defines whether minor violations of the MIME specification should be 
      * tolerated or should result in a {@link MimeException}. If this parameter
-     * is set to <code>true</code>, a strict interpretation of the MIME 
-     * specification will be enforced, If this parameter is set to <code>false</code>
-     * minor violations will result in a warning in the log.
+     * is set to {@link MimeMode#STRICT}, a strict interpretation of the MIME 
+     * specification will be enforced, If this parameter is set to 
+     * {@link MimeMode#LENIENT} minor violations will result in a warning in 
+     * the log.
      * 
-     * @param strictParsing value of the strict parsing mode
+     * @param mimeMode the parsing mode
      */
-    public void setStrictParsing(boolean strictParsing) {
-        this.strictParsing = strictParsing;
+    public void setMode(final MimeMode mimeMode) {
+        this.mimeMode = mimeMode;
     }
 
+    public MimeMode getMimeMode() {
+        return this.mimeMode;
+    }
+
     /**
      * Returns the value of the strict parsing mode
-     * @see #setStrictParsing(boolean)
+     * @see #setMode(MimeMode)
      * 
      * @return value of the strict parsing mode
      */
-    public boolean isStrictParsing() {
-        return this.strictParsing;
+    public boolean isStrict() {
+        return this.mimeMode.equals(MimeMode.STRICT);
     }
     
     /**
@@ -153,8 +159,8 @@
         CharArrayBuffer buffer = new CharArrayBuffer(128);
         buffer.append("[max body descriptor: ");
         buffer.append(Boolean.toString(this.maximalBodyDescriptor));
-        buffer.append("][strict parsing: ");
-        buffer.append(Boolean.toString(this.strictParsing));
+        buffer.append("][mode: ");
+        buffer.append(this.mimeMode);
         buffer.append("][max header length: ");
         buffer.append(Integer.toString(this.maxLineLen));
         buffer.append("]");
Index: src/main/java/org/apache/james/mime4j/MimeMode.java
===================================================================
--- src/main/java/org/apache/james/mime4j/MimeMode.java	(revision 0)
+++ src/main/java/org/apache/james/mime4j/MimeMode.java	(revision 0)
@@ -0,0 +1,40 @@
+package org.apache.james.mime4j;
+
+public class MimeMode {
+
+    public static final MimeMode STRICT    = new MimeMode(0, "STRICT"); 
+    public static final MimeMode LENIENT   = new MimeMode(1, "LENIENT"); 
+    
+    private final int mode;
+    private final String text;
+    
+    private MimeMode(int mode, final String text) {
+        super();
+        this.mode = mode;
+        this.text = text;
+    }
+
+    @Override
+    public boolean equals(final Object obj) {
+        if (obj == null) return false;
+        if (this == obj) return true;
+        if (obj instanceof MimeMode) {
+            MimeMode that = (MimeMode) obj;
+            return this.mode == that.mode;
+        } else {
+            return false;
+        }
+    }
+
+
+    @Override
+    public int hashCode() {
+        return 17 + 37 * this.mode;
+    }
+
+    @Override
+    public String toString() {
+        return this.text;
+    }
+    
+}
