diff --git a/EOL.hs b/EOL.hs
new file mode 100644
--- /dev/null
+++ b/EOL.hs
@@ -0,0 +1,71 @@
+--------------------------------------------------------------------
+-- |
+-- Module    : EOL
+-- Copyright : (c) Nicolas Pouillard 2008, 2009, 2010, 2011
+-- License   : BSD3
+--
+-- Maintainer: Nicolas Pouillard <nicolas.pouillard@gmail.com>
+-- Stability : provisional
+-- Portability:
+--
+--------------------------------------------------------------------
+
+{-# LANGUAGE PatternGuards, BangPatterns #-}
+module EOL where
+
+import qualified Data.ByteString.Lazy.Char8 as C
+
+-- Make sure all lines are terminated by CRLF.
+
+fixCrlfS :: String -> String
+fixCrlfS ('\r':'\n':xs)   = '\r' : '\n' : fixCrlfS xs
+fixCrlfS ('\n':xs)        = '\r' : '\n' : fixCrlfS xs
+fixCrlfS (x:xs)           = x : fixCrlfS xs
+fixCrlfS []               = []
+
+fixLfS :: String -> String
+fixLfS ('\r':'\n':xs)   = '\n' : fixLfS xs
+fixLfS (x:xs)           = x : fixLfS xs
+fixLfS []               = []
+
+fixCrlfB :: C.ByteString -> C.ByteString
+
+fixCrlfB = C.unlines . map (`C.snoc` '\r') . C.lines
+
+{-
+fixCrlfB = go
+  where go !input = maybe C.empty f $ C.elemIndex '\n' input
+            where f !0   = crlf `C.append` go (C.tail input)
+                  f !off | C.index input (off - 1) == '\r' =
+                                let (a,b) = C.splitAt (off+1) input in a `C.append` go b
+                         | otherwise                       =
+                                let (a,b) = C.splitAt off input in a `C.append` (crlf `C.append` go (C.tail b))
+
+By speed order:
+
+fixCrlfB = go
+  where go input = maybe C.empty f $ C.elemIndex '\n' input
+            where f 0   = crlf `C.append` go (C.tail input)
+                  f off | C.index input (off - 1) == '\r' =
+                           uncurry C.append $ second go $ C.splitAt (off + 1) input
+                        | otherwise =
+                           uncurry C.append $ second (C.append crlf . go . C.tail) $ C.splitAt off input
+
+fixCrlfB = go
+  where go input = maybe C.empty f $ C.elemIndex '\n' input
+            where f 0   = '\r' `C.cons` ('\n' `C.cons` go (C.tail input))
+                  f off | C.index input (off - 1) == '\r' =
+                           uncurry C.append $ second go $ C.splitAt (off + 1) input
+                        | otherwise =
+                           let (a, b) = C.splitAt off input in a `C.append` ('\r' `C.cons` ('\n' `C.cons` go (C.tail b)))
+fixCrlfB = go
+  where go s1 =
+          case C.uncons s1 of
+            Just ('\r', s2) | Just ('\n', rest) <- C.uncons s2 -> '\r' `C.cons` ('\n' `C.cons` go rest)
+            Just ('\n', rest)                                  -> '\r' `C.cons` ('\n' `C.cons` go rest)
+            Just (c, rest)                                     -> c `C.cons` go rest
+            Nothing -> C.empty
+-}
+
+crlf :: C.ByteString
+crlf = C.pack "\r\n"
diff --git a/mbox-tools.cabal b/mbox-tools.cabal
--- a/mbox-tools.cabal
+++ b/mbox-tools.cabal
@@ -1,6 +1,6 @@
 Name:           mbox-tools
 Cabal-Version:  >=1.8
-Version:        0.2.0.3
+Version:        0.2.0.4
 License:        BSD3
 License-File:   LICENSE
 Copyright:      (c) Nicolas Pouillard
@@ -49,25 +49,25 @@
     Build-depends: base(>=3 && <5), bytestring, codec-mbox, parsec, hsemail,
                    pureMD5, fclabels>=1.0, mtl
     main-is: mbox-list.hs
-    Other-modules: Email, FmtComb, EmailFmt
+    Other-modules: EOL, Email, FmtComb, EmailFmt
     ghc-options: -Wall
 executable mbox-pick
     Build-depends: base(>=3 && <5), bytestring, codec-mbox, parsec, hsemail,
                    pureMD5, fclabels, mtl
     main-is: mbox-pick.hs
-    Other-modules: Email, FmtComb, EmailFmt
+    Other-modules: EOL, Email, FmtComb, EmailFmt
     ghc-options: -Wall
 executable mbox-partition
     Build-depends: base(>=3 && <5), bytestring, codec-mbox, parsec, hsemail,
                    pureMD5, fclabels, mtl, containers
     main-is: mbox-partition.hs
-    Other-modules: Email
+    Other-modules: EOL, Email
     ghc-options: -Wall
 executable mbox-grep
     Build-depends: base(>=3 && <5), bytestring, codec-mbox, parsec, hsemail,
                    pureMD5, fclabels, mtl
     main-is: mbox-grep.hs
-    Other-modules: Email
+    Other-modules: EOL, Email
     ghc-options: -Wall
   if flag(use_hutt)
     build-depends: hutt>=0.1
