email-0.1: WashUtils/RFC2047.hs
-- © 2003 Peter Thiemann
module WashUtils.RFC2047 where
-- decoding of header fields
import qualified Data.ByteString as Bs
import qualified Data.ByteString.Char8 as BsChar8
import Data.Char
import qualified Data.Encoding as DataEnc
import Data.Encoding.ASCII (ASCII(..))
import Data.Encoding (encodeStrictByteString)
import Data.List
import qualified WashUtils.Base64 as Base64
import qualified WashUtils.QuotedPrintable as QuotedPrintable
import qualified WashUtils.Base64 as Base64
import WashUtils.Hex
import Text.ParserCombinators.Parsec
lineString =
do initial <- many (noneOf "\n\r=")
rest <- option "" (do xs <- try encoded_words <|> string "="
ys <- lineString
return (xs ++ ys))
return (initial ++ rest)
especials = "()<>@,;:\\\"/[]?.="
tokenchar = "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~" \\ especials
p_token = many1 (oneOf tokenchar)
p_encoded_text = many1 $ oneOf "!\"#$%&'()*+,-./0123456789:;<=>@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
allchar = "\NUL\SOH\STX\ETX\EOT\ENQ\ACK\a\b\t\n\v\f\r\SO\SI\DLE\DC1\DC2\DC3\DC4\NAK\SYN\ETB\CAN\EM\SUB\ESC\FS\GS\RS\US !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\DEL"
-- supress linear white space between adjacent encoded_word
encoded_words =
do ew <- encoded_word
ws <- many space
option (ew++ws) (encoded_words >>= \ews -> return (ew++ews))
encoded_word =
do string "=?"
charset <- p_token
char '?'
encoding <- p_token
char '?'
encoded_text <- p_encoded_text
string "?="
return $ decode charset (map toUpper encoding) encoded_text
decodeCharset charset text =
--encodeCharset charset text =
DataEnc.decodeStrictByteString encoding (BsChar8.pack text)
where encoding = DataEnc.encodingFromString (map toUpper charset)
decode charset "B" encoded_text =
decodeCharset charset (Base64.decode' encoded_text)
decode charset "Q" encoded_text =
decodeCharset charset (decode_quoted encoded_text)
decode charset encoding encoded_text =
error ("Unknown encoding: " ++ encoding)
decode_quoted [] = []
decode_quoted ('=':upper:lower:xs) =
chr (16 * hexDigitVal upper + hexDigitVal lower) : decode_quoted xs
--decode_quoted ('_':xs) = ' ' : decode_quoted xs
decode_quoted (x:xs) =
x : decode_quoted xs
-- --------------------------------------------------------------------
-- RFC 2047: encoding of header fields
encodeCharset :: String -> String -> [Char]
encodeCharset charset text =
BsChar8.unpack (DataEnc.encodeStrictByteString encoder text)
where encoder = DataEnc.encodingFromString charset
encodeWord :: String -> [Char]
encodeWord w =
"=?" ++ charset ++ "?" ++ encoding ++ "?" ++ encoded ++ "?="
where encoding = "B"
charset = "UTF-8"
--encoded = QuotedPrintable.encode' converted
encoded = Base64.encode' converted
converted = encodeCharset charset w
encodeValue :: [Char] -> [Char]
encodeValue v =
case span (not . flip elem "()<>@.!,?") v of
([], []) -> []
(word, []) -> maybeEncode word
(word, x:rest) -> maybeEncode word ++ x : encodeValue rest
maybeEncode :: [Char] -> [Char]
maybeEncode word | all p word = word
| otherwise = encodeWord word
where p x = x /= '?' && let ox = ord x in ox >= 33 && ox <= 126
encodeAscii = encodeStrictByteString ASCII
encodeCharsetBS :: String -> String -> Bs.ByteString
encodeCharsetBS x = encodeAscii . encodeCharset x
encodeWordBS :: String -> Bs.ByteString
encodeWordBS = encodeAscii . encodeWord
encodeValueBS :: [Char] -> Bs.ByteString
encodeValueBS = encodeAscii . encodeValue
maybeEncodeBS :: [Char] -> Bs.ByteString
maybeEncodeBS = encodeAscii . maybeEncode