{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
module Data.RFC5322
(
Message(..)
, message
, MessageContext
, BodyHandler(..)
, body
, EqMessage(..)
, Header
, HasHeaders(..)
, header
, headerList
, Headers(..)
, Address(..)
, address
, addressList
, AddrSpec(..)
, Domain(..)
, Mailbox(..)
, mailbox
, mailboxList
, parse
, parsed
, parsePrint
, crlf
, quotedString
, field
, rfc5422DateTimeFormat
, rfc5422DateTimeFormatLax
, buildMessage
, renderMessage
, RenderMessage(..)
, renderRFC5422Date
, buildFields
, buildField
, renderAddressSpec
, renderMailbox
, renderMailboxes
, renderAddress
, renderAddresses
) where
import Control.Applicative
import Data.Foldable (fold)
import Data.List (findIndex, intersperse)
import Data.List.NonEmpty (intersperse)
import Data.Word (Word8)
import GHC.Generics (Generic)
import Control.DeepSeq (NFData)
import Control.Lens
import Control.Lens.Cons.Extras (recons)
import Data.Attoparsec.ByteString as A hiding (parse, take)
import Data.Attoparsec.ByteString.Char8 (char8)
import qualified Data.Attoparsec.ByteString.Lazy as AL
import qualified Data.ByteString as B
import qualified Data.ByteString.Lazy as L
import qualified Data.ByteString.Char8 as Char8
import qualified Data.ByteString.Builder as Builder
import qualified Data.ByteString.Builder.Prim as Prim
import qualified Data.Text as T
import qualified Data.Text.Encoding as T
import Data.Time.Clock (UTCTime)
import Data.Time.Format (defaultTimeLocale, formatTime)
import Data.RFC5322.Internal
( CI, ci, original
, (<<>>), foldMany, foldMany1Sep
, fromChar, isAtext, isQtext, isVchar, isWsp
, optionalCFWS, word, wsp, vchar, optionalFWS, crlf
, domainLiteral, dotAtom, localPart, quotedString
)
import Data.RFC5322.Address.Types
import Data.MIME.Charset
import Data.MIME.EncodedWord (encodedWord, decodeEncodedWord, buildEncodedWord)
import Data.MIME.TransferEncoding (transferEncode)
type = (CI B.ByteString, B.ByteString)
newtype = [Header]
deriving (Headers -> Headers -> Bool
(Headers -> Headers -> Bool)
-> (Headers -> Headers -> Bool) -> Eq Headers
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Headers -> Headers -> Bool
$c/= :: Headers -> Headers -> Bool
== :: Headers -> Headers -> Bool
$c== :: Headers -> Headers -> Bool
Eq, Int -> Headers -> ShowS
[Headers] -> ShowS
Headers -> String
(Int -> Headers -> ShowS)
-> (Headers -> String) -> ([Headers] -> ShowS) -> Show Headers
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Headers] -> ShowS
$cshowList :: [Headers] -> ShowS
show :: Headers -> String
$cshow :: Headers -> String
showsPrec :: Int -> Headers -> ShowS
$cshowsPrec :: Int -> Headers -> ShowS
Show, (forall x. Headers -> Rep Headers x)
-> (forall x. Rep Headers x -> Headers) -> Generic Headers
forall x. Rep Headers x -> Headers
forall x. Headers -> Rep Headers x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep Headers x -> Headers
$cfrom :: forall x. Headers -> Rep Headers x
Generic, Headers -> ()
(Headers -> ()) -> NFData Headers
forall a. (a -> ()) -> NFData a
rnf :: Headers -> ()
$crnf :: Headers -> ()
NFData)
instance Semigroup Headers where
Headers [Header]
a <> :: Headers -> Headers -> Headers
<> Headers [Header]
b = [Header] -> Headers
Headers ([Header]
a [Header] -> [Header] -> [Header]
forall a. Semigroup a => a -> a -> a
<> [Header]
b)
instance Monoid Headers where
mempty :: Headers
mempty = [Header] -> Headers
Headers []
class a where
:: Lens' a Headers
instance HasHeaders Headers where
headers :: (Headers -> f Headers) -> Headers -> f Headers
headers = (Headers -> f Headers) -> Headers -> f Headers
forall a. a -> a
id
type instance Index Headers = CI B.ByteString
type instance IxValue Headers = B.ByteString
instance Ixed Headers where
ix :: Index Headers -> Traversal' Headers (IxValue Headers)
ix = Index Headers
-> (IxValue Headers -> f (IxValue Headers)) -> Headers -> f Headers
forall a. HasHeaders a => CI ByteString -> Traversal' a ByteString
header
hdriso :: Iso' Headers [(CI B.ByteString, B.ByteString)]
hdriso :: p [Header] (f [Header]) -> p Headers (f Headers)
hdriso = (Headers -> [Header])
-> ([Header] -> Headers) -> Iso Headers Headers [Header] [Header]
forall s a b t. (s -> a) -> (b -> t) -> Iso s t a b
iso (\(Headers [Header]
xs) -> [Header]
xs) [Header] -> Headers
Headers
instance At Headers where
at :: Index Headers -> Lens' Headers (Maybe (IxValue Headers))
at Index Headers
k = ([Header] -> f [Header]) -> Headers -> f Headers
Iso Headers Headers [Header] [Header]
hdriso (([Header] -> f [Header]) -> Headers -> f Headers)
-> ((Maybe ByteString -> f (Maybe ByteString))
-> [Header] -> f [Header])
-> (Maybe ByteString -> f (Maybe ByteString))
-> Headers
-> f Headers
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Maybe ByteString -> f (Maybe ByteString))
-> [Header] -> f [Header]
Lens' [Header] (Maybe ByteString)
l
where
l :: Lens' [(CI B.ByteString, B.ByteString)] (Maybe B.ByteString)
l :: (Maybe ByteString -> f (Maybe ByteString))
-> [Header] -> f [Header]
l Maybe ByteString -> f (Maybe ByteString)
f [Header]
kv =
let
i :: Maybe Int
i = (Header -> Bool) -> [Header] -> Maybe Int
forall a. (a -> Bool) -> [a] -> Maybe Int
findIndex ((CI ByteString -> CI ByteString -> Bool
forall a. Eq a => a -> a -> Bool
== CI ByteString
Index Headers
k) (CI ByteString -> Bool)
-> (Header -> CI ByteString) -> Header -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Header -> CI ByteString
forall a b. (a, b) -> a
fst) [Header]
kv
g :: Maybe ByteString -> [Header]
g Maybe ByteString
Nothing = [Header] -> (Int -> [Header]) -> Maybe Int -> [Header]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe [Header]
kv (\Int
j -> Int -> [Header] -> [Header]
forall a. Int -> [a] -> [a]
take Int
j [Header]
kv [Header] -> [Header] -> [Header]
forall a. Semigroup a => a -> a -> a
<> Int -> [Header] -> [Header]
forall a. Int -> [a] -> [a]
drop (Int
j Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) [Header]
kv) Maybe Int
i
g (Just ByteString
v) = [Header] -> (Int -> [Header]) -> Maybe Int -> [Header]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe ((CI ByteString
Index Headers
k,ByteString
v)Header -> [Header] -> [Header]
forall a. a -> [a] -> [a]
:[Header]
kv) (\Int
j -> ASetter [Header] [Header] Header Header
-> Header -> [Header] -> [Header]
forall s t a b. ASetter s t a b -> b -> s -> t
set (Index [Header] -> Traversal' [Header] (IxValue [Header])
forall m. Ixed m => Index m -> Traversal' m (IxValue m)
ix Int
Index [Header]
j) (CI ByteString
Index Headers
k,ByteString
v) [Header]
kv) Maybe Int
i
in
Maybe ByteString -> [Header]
g (Maybe ByteString -> [Header])
-> f (Maybe ByteString) -> f [Header]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe ByteString -> f (Maybe ByteString)
f (CI ByteString -> [Header] -> Maybe ByteString
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup CI ByteString
Index Headers
k [Header]
kv)
header :: HasHeaders a => CI B.ByteString -> Traversal' a B.ByteString
CI ByteString
k = ([Header] -> f [Header]) -> a -> f a
forall a. HasHeaders a => Lens' a [Header]
headerList (([Header] -> f [Header]) -> a -> f a)
-> ((ByteString -> f ByteString) -> [Header] -> f [Header])
-> (ByteString -> f ByteString)
-> a
-> f a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Header -> f Header) -> [Header] -> f [Header]
forall (f :: * -> *) a b.
Traversable f =>
IndexedTraversal Int (f a) (f b) a b
traversed ((Header -> f Header) -> [Header] -> f [Header])
-> ((ByteString -> f ByteString) -> Header -> f Header)
-> (ByteString -> f ByteString)
-> [Header]
-> f [Header]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Header -> Bool) -> Optic' (->) f Header Header
forall (p :: * -> * -> *) (f :: * -> *) a.
(Choice p, Applicative f) =>
(a -> Bool) -> Optic' p f a a
filtered ((CI ByteString
k CI ByteString -> CI ByteString -> Bool
forall a. Eq a => a -> a -> Bool
==) (CI ByteString -> Bool)
-> (Header -> CI ByteString) -> Header -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Header -> CI ByteString
forall a b. (a, b) -> a
fst) Optic' (->) f Header Header
-> ((ByteString -> f ByteString) -> Header -> f Header)
-> (ByteString -> f ByteString)
-> Header
-> f Header
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ByteString -> f ByteString) -> Header -> f Header
forall s t a b. Field2 s t a b => Lens s t a b
_2
data Message s a = Message Headers a
deriving (Int -> Message s a -> ShowS
[Message s a] -> ShowS
Message s a -> String
(Int -> Message s a -> ShowS)
-> (Message s a -> String)
-> ([Message s a] -> ShowS)
-> Show (Message s a)
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
forall s a. Show a => Int -> Message s a -> ShowS
forall s a. Show a => [Message s a] -> ShowS
forall s a. Show a => Message s a -> String
showList :: [Message s a] -> ShowS
$cshowList :: forall s a. Show a => [Message s a] -> ShowS
show :: Message s a -> String
$cshow :: forall s a. Show a => Message s a -> String
showsPrec :: Int -> Message s a -> ShowS
$cshowsPrec :: forall s a. Show a => Int -> Message s a -> ShowS
Show, (forall x. Message s a -> Rep (Message s a) x)
-> (forall x. Rep (Message s a) x -> Message s a)
-> Generic (Message s a)
forall x. Rep (Message s a) x -> Message s a
forall x. Message s a -> Rep (Message s a) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall s a x. Rep (Message s a) x -> Message s a
forall s a x. Message s a -> Rep (Message s a) x
$cto :: forall s a x. Rep (Message s a) x -> Message s a
$cfrom :: forall s a x. Message s a -> Rep (Message s a) x
Generic, Message s a -> ()
(Message s a -> ()) -> NFData (Message s a)
forall a. (a -> ()) -> NFData a
forall s a. NFData a => Message s a -> ()
rnf :: Message s a -> ()
$crnf :: forall s a. NFData a => Message s a -> ()
NFData)
instance HasHeaders (Message s a) where
headers :: (Headers -> f Headers) -> Message s a -> f (Message s a)
headers Headers -> f Headers
f (Message Headers
h a
b) = (Headers -> Message s a) -> f Headers -> f (Message s a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Headers -> a -> Message s a
forall s a. Headers -> a -> Message s a
`Message` a
b) (Headers -> f Headers
f Headers
h)
instance Functor (Message s) where
fmap :: (a -> b) -> Message s a -> Message s b
fmap a -> b
f (Message Headers
h a
a) = Headers -> b -> Message s b
forall s a. Headers -> a -> Message s a
Message Headers
h (a -> b
f a
a)
class EqMessage a where
eqMessage :: Message s a -> Message s a -> Bool
default eqMessage :: (Eq a) => Message s a -> Message s a -> Bool
eqMessage (Message Headers
h1 a
b1) (Message Headers
h2 a
b2) = Headers
h1 Headers -> Headers -> Bool
forall a. Eq a => a -> a -> Bool
== Headers
h2 Bool -> Bool -> Bool
&& a
b1 a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
b2
instance EqMessage a => Eq (Message s a) where
== :: Message s a -> Message s a -> Bool
(==) = Message s a -> Message s a -> Bool
forall a s. EqMessage a => Message s a -> Message s a -> Bool
eqMessage
headerList :: HasHeaders a => Lens' a [(CI B.ByteString, B.ByteString)]
= (Headers -> f Headers) -> a -> f a
forall a. HasHeaders a => Lens' a Headers
headers ((Headers -> f Headers) -> a -> f a)
-> (([Header] -> f [Header]) -> Headers -> f Headers)
-> ([Header] -> f [Header])
-> a
-> f a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([Header] -> f [Header]) -> Headers -> f Headers
forall s t a b. (Coercible s a, Coercible t b) => Iso s t a b
coerced
body :: Lens (Message ctx a) (Message ctx' b) a b
body :: (a -> f b) -> Message ctx a -> f (Message ctx' b)
body a -> f b
f (Message Headers
h a
b) = (b -> Message ctx' b) -> f b -> f (Message ctx' b)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\b
b' -> Headers -> b -> Message ctx' b
forall s a. Headers -> a -> Message s a
Message Headers
h b
b') (a -> f b
f a
b)
{-# ANN body ("HLint: ignore Avoid lambda" :: String) #-}
isSpecial :: Word8 -> Bool
isSpecial :: Word8 -> Bool
isSpecial = String -> Word8 -> Bool
inClass String
"()<>[]:;@\\,.\""
special :: Parser Word8
special :: Parser Word8
special = (Word8 -> Bool) -> Parser Word8
satisfy Word8 -> Bool
isSpecial
rfc5422DateTimeFormat :: String
rfc5422DateTimeFormat :: String
rfc5422DateTimeFormat = String
"%a, %d %b %Y %T %z"
rfc5422DateTimeFormatLax :: String
rfc5422DateTimeFormatLax :: String
rfc5422DateTimeFormatLax = String
"%a, %-d %b %Y %-H:%-M:%-S %z"
renderRFC5422Date :: UTCTime -> B.ByteString
renderRFC5422Date :: UTCTime -> ByteString
renderRFC5422Date = String -> ByteString
Char8.pack (String -> ByteString)
-> (UTCTime -> String) -> UTCTime -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TimeLocale -> String -> UTCTime -> String
forall t. FormatTime t => TimeLocale -> String -> t -> String
formatTime TimeLocale
defaultTimeLocale String
rfc5422DateTimeFormat
buildMailbox :: Mailbox -> Builder.Builder
buildMailbox :: Mailbox -> Builder
buildMailbox (Mailbox Maybe Text
n AddrSpec
a) =
Builder -> (Text -> Builder) -> Maybe Text -> Builder
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Builder
a' (\Text
n' -> Text -> Builder
buildPhrase Text
n' Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
" <" Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
a' Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
">") Maybe Text
n
where
a' :: Builder
a' = AddrSpec -> Builder
buildAddressSpec AddrSpec
a
buildPhrase :: T.Text -> Builder.Builder
buildPhrase :: Text -> Builder
buildPhrase Text
"" = Builder
"\"\""
buildPhrase Text
s =
case Text -> PhraseEscapeRequirement
enc Text
s of
PhraseEscapeRequirement
PhraseAtom -> Text -> Builder
T.encodeUtf8Builder Text
s
PhraseEscapeRequirement
PhraseQuotedString -> Bool -> Builder
qsBuilder Bool
False
PhraseEscapeRequirement
PhraseQuotedStringEscapeSpace -> Bool -> Builder
qsBuilder Bool
True
PhraseEscapeRequirement
PhraseEncodedWord -> EncodedWord -> Builder
buildEncodedWord (EncodedWord -> Builder)
-> (Text -> EncodedWord) -> Text -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TransferDecodedEncodedWord -> EncodedWord
forall a. HasTransferEncoding a => TransferDecoded a -> a
transferEncode (TransferDecodedEncodedWord -> EncodedWord)
-> (Text -> TransferDecodedEncodedWord) -> Text -> EncodedWord
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> TransferDecodedEncodedWord
forall a. HasCharset a => Decoded a -> a
charsetEncode (Text -> Builder) -> Text -> Builder
forall a b. (a -> b) -> a -> b
$ Text
s
where
enc :: Text -> PhraseEscapeRequirement
enc = (Char, PhraseEscapeRequirement) -> PhraseEscapeRequirement
forall a b. (a, b) -> b
snd ((Char, PhraseEscapeRequirement) -> PhraseEscapeRequirement)
-> (Text -> (Char, PhraseEscapeRequirement))
-> Text
-> PhraseEscapeRequirement
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char
-> (Char, PhraseEscapeRequirement)
-> (Char, PhraseEscapeRequirement))
-> (Char, PhraseEscapeRequirement)
-> Text
-> (Char, PhraseEscapeRequirement)
forall a. (Char -> a -> a) -> a -> Text -> a
T.foldr (\Char
c (Char
prev, PhraseEscapeRequirement
req) -> (Char
c, Char -> Char -> PhraseEscapeRequirement
encChar Char
prev Char
c PhraseEscapeRequirement
-> PhraseEscapeRequirement -> PhraseEscapeRequirement
forall a. Semigroup a => a -> a -> a
<> PhraseEscapeRequirement
req)) (Char
'\0', PhraseEscapeRequirement
forall a. Monoid a => a
mempty)
encChar :: Char -> Char -> PhraseEscapeRequirement
encChar Char
prev Char
c
| Char -> Bool
forall c. IsChar c => c -> Bool
isAtext Char
c = PhraseEscapeRequirement
PhraseAtom
| Char -> Bool
forall c. IsChar c => c -> Bool
isQtext Char
c = PhraseEscapeRequirement
PhraseQuotedString
| Char -> Bool
forall c. IsChar c => c -> Bool
isVchar Char
c = PhraseEscapeRequirement
PhraseQuotedString
| Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
' ' =
if Char
prev Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
' '
then PhraseEscapeRequirement
PhraseQuotedStringEscapeSpace
else PhraseEscapeRequirement
PhraseQuotedString
| Bool
otherwise = PhraseEscapeRequirement
PhraseEncodedWord
qsBuilder :: Bool -> Builder
qsBuilder Bool
escSpace = Builder
"\"" Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> BoundedPrim Word8 -> Text -> Builder
T.encodeUtf8BuilderEscaped (Bool -> BoundedPrim Word8
escPrim Bool
escSpace) Text
s Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
"\""
escPrim :: Bool -> BoundedPrim Word8
escPrim Bool
escSpace = (Word8 -> Bool)
-> BoundedPrim Word8 -> BoundedPrim Word8 -> BoundedPrim Word8
forall a.
(a -> Bool) -> BoundedPrim a -> BoundedPrim a -> BoundedPrim a
Prim.condB (\Word8
c -> Word8 -> Bool
forall c. IsChar c => c -> Bool
isQtext Word8
c Bool -> Bool -> Bool
|| Bool -> Bool
not Bool
escSpace Bool -> Bool -> Bool
&& Word8
c Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
32)
(FixedPrim Word8 -> BoundedPrim Word8
forall a. FixedPrim a -> BoundedPrim a
Prim.liftFixedToBounded FixedPrim Word8
Prim.word8)
(FixedPrim Word8 -> BoundedPrim Word8
forall a. FixedPrim a -> BoundedPrim a
Prim.liftFixedToBounded (FixedPrim Word8 -> BoundedPrim Word8)
-> FixedPrim Word8 -> BoundedPrim Word8
forall a b. (a -> b) -> a -> b
$ (Char -> Word8
forall a. IsChar a => Char -> a
fromChar Char
'\\',) (Word8 -> (Word8, Word8))
-> FixedPrim (Word8, Word8) -> FixedPrim Word8
forall (f :: * -> *) b a. Contravariant f => (b -> a) -> f a -> f b
Prim.>$< FixedPrim Word8
Prim.word8 FixedPrim Word8 -> FixedPrim Word8 -> FixedPrim (Word8, Word8)
forall (f :: * -> *) a b. Monoidal f => f a -> f b -> f (a, b)
Prim.>*< FixedPrim Word8
Prim.word8)
data PhraseEscapeRequirement
= PhraseAtom
| PhraseQuotedString
| PhraseQuotedStringEscapeSpace
| PhraseEncodedWord
deriving (PhraseEscapeRequirement -> PhraseEscapeRequirement -> Bool
(PhraseEscapeRequirement -> PhraseEscapeRequirement -> Bool)
-> (PhraseEscapeRequirement -> PhraseEscapeRequirement -> Bool)
-> Eq PhraseEscapeRequirement
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: PhraseEscapeRequirement -> PhraseEscapeRequirement -> Bool
$c/= :: PhraseEscapeRequirement -> PhraseEscapeRequirement -> Bool
== :: PhraseEscapeRequirement -> PhraseEscapeRequirement -> Bool
$c== :: PhraseEscapeRequirement -> PhraseEscapeRequirement -> Bool
Eq, Eq PhraseEscapeRequirement
Eq PhraseEscapeRequirement
-> (PhraseEscapeRequirement -> PhraseEscapeRequirement -> Ordering)
-> (PhraseEscapeRequirement -> PhraseEscapeRequirement -> Bool)
-> (PhraseEscapeRequirement -> PhraseEscapeRequirement -> Bool)
-> (PhraseEscapeRequirement -> PhraseEscapeRequirement -> Bool)
-> (PhraseEscapeRequirement -> PhraseEscapeRequirement -> Bool)
-> (PhraseEscapeRequirement
-> PhraseEscapeRequirement -> PhraseEscapeRequirement)
-> (PhraseEscapeRequirement
-> PhraseEscapeRequirement -> PhraseEscapeRequirement)
-> Ord PhraseEscapeRequirement
PhraseEscapeRequirement -> PhraseEscapeRequirement -> Bool
PhraseEscapeRequirement -> PhraseEscapeRequirement -> Ordering
PhraseEscapeRequirement
-> PhraseEscapeRequirement -> PhraseEscapeRequirement
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: PhraseEscapeRequirement
-> PhraseEscapeRequirement -> PhraseEscapeRequirement
$cmin :: PhraseEscapeRequirement
-> PhraseEscapeRequirement -> PhraseEscapeRequirement
max :: PhraseEscapeRequirement
-> PhraseEscapeRequirement -> PhraseEscapeRequirement
$cmax :: PhraseEscapeRequirement
-> PhraseEscapeRequirement -> PhraseEscapeRequirement
>= :: PhraseEscapeRequirement -> PhraseEscapeRequirement -> Bool
$c>= :: PhraseEscapeRequirement -> PhraseEscapeRequirement -> Bool
> :: PhraseEscapeRequirement -> PhraseEscapeRequirement -> Bool
$c> :: PhraseEscapeRequirement -> PhraseEscapeRequirement -> Bool
<= :: PhraseEscapeRequirement -> PhraseEscapeRequirement -> Bool
$c<= :: PhraseEscapeRequirement -> PhraseEscapeRequirement -> Bool
< :: PhraseEscapeRequirement -> PhraseEscapeRequirement -> Bool
$c< :: PhraseEscapeRequirement -> PhraseEscapeRequirement -> Bool
compare :: PhraseEscapeRequirement -> PhraseEscapeRequirement -> Ordering
$ccompare :: PhraseEscapeRequirement -> PhraseEscapeRequirement -> Ordering
$cp1Ord :: Eq PhraseEscapeRequirement
Ord)
instance Semigroup PhraseEscapeRequirement where
PhraseEscapeRequirement
PhraseEncodedWord <> :: PhraseEscapeRequirement
-> PhraseEscapeRequirement -> PhraseEscapeRequirement
<> PhraseEscapeRequirement
_ =
PhraseEscapeRequirement
PhraseEncodedWord
PhraseEscapeRequirement
l <> PhraseEscapeRequirement
r = PhraseEscapeRequirement
-> PhraseEscapeRequirement -> PhraseEscapeRequirement
forall a. Ord a => a -> a -> a
max PhraseEscapeRequirement
l PhraseEscapeRequirement
r
instance Monoid PhraseEscapeRequirement where
mempty :: PhraseEscapeRequirement
mempty = PhraseEscapeRequirement
PhraseAtom
renderMailboxes :: [Mailbox] -> B.ByteString
renderMailboxes :: [Mailbox] -> ByteString
renderMailboxes = ByteString -> ByteString
L.toStrict (ByteString -> ByteString)
-> ([Mailbox] -> ByteString) -> [Mailbox] -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Builder -> ByteString
Builder.toLazyByteString (Builder -> ByteString)
-> ([Mailbox] -> Builder) -> [Mailbox] -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Mailbox] -> Builder
buildMailboxes
buildMailboxes :: [Mailbox] -> Builder.Builder
buildMailboxes :: [Mailbox] -> Builder
buildMailboxes = [Builder] -> Builder
forall (t :: * -> *) m. (Foldable t, Monoid m) => t m -> m
fold ([Builder] -> Builder)
-> ([Mailbox] -> [Builder]) -> [Mailbox] -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Builder -> [Builder] -> [Builder]
forall a. a -> [a] -> [a]
Data.List.intersperse Builder
", " ([Builder] -> [Builder])
-> ([Mailbox] -> [Builder]) -> [Mailbox] -> [Builder]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Mailbox -> Builder) -> [Mailbox] -> [Builder]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Mailbox -> Builder
buildMailbox
renderMailbox :: Mailbox -> B.ByteString
renderMailbox :: Mailbox -> ByteString
renderMailbox = ByteString -> ByteString
L.toStrict (ByteString -> ByteString)
-> (Mailbox -> ByteString) -> Mailbox -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Builder -> ByteString
Builder.toLazyByteString (Builder -> ByteString)
-> (Mailbox -> Builder) -> Mailbox -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Mailbox -> Builder
buildMailbox
mailbox :: CharsetLookup -> Parser Mailbox
mailbox :: CharsetLookup -> Parser Mailbox
mailbox CharsetLookup
charsets =
Maybe Text -> AddrSpec -> Mailbox
Mailbox (Maybe Text -> AddrSpec -> Mailbox)
-> Parser ByteString (Maybe Text)
-> Parser ByteString (AddrSpec -> Mailbox)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser ByteString Text -> Parser ByteString (Maybe Text)
forall (f :: * -> *) a. Alternative f => f a -> f (Maybe a)
optional (CharsetLookup -> Parser ByteString Text
displayName CharsetLookup
charsets) Parser ByteString (AddrSpec -> Mailbox)
-> Parser ByteString AddrSpec -> Parser Mailbox
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Parser ByteString AddrSpec
angleAddr
Parser Mailbox -> Parser Mailbox -> Parser Mailbox
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Maybe Text -> AddrSpec -> Mailbox
Mailbox Maybe Text
forall a. Maybe a
Nothing (AddrSpec -> Mailbox)
-> Parser ByteString AddrSpec -> Parser Mailbox
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser ByteString AddrSpec
addressSpec
phrase :: CharsetLookup -> Parser T.Text
phrase :: CharsetLookup -> Parser ByteString Text
phrase CharsetLookup
charsets = Text -> Parser ByteString Text -> Parser ByteString Text
forall m (f :: * -> *).
(Semigroup m, Alternative f) =>
m -> f m -> f m
foldMany1Sep Text
" " (Parser ByteString Text -> Parser ByteString Text)
-> Parser ByteString Text -> Parser ByteString Text
forall a b. (a -> b) -> a -> b
$
(EncodedWord -> Text)
-> Parser ByteString EncodedWord -> Parser ByteString Text
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (CharsetLookup -> EncodedWord -> Text
decodeEncodedWord CharsetLookup
charsets) (Parser ByteString ByteString
"=?" Parser ByteString ByteString
-> Parser ByteString EncodedWord -> Parser ByteString EncodedWord
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> Parser ByteString EncodedWord
encodedWord)
Parser ByteString Text
-> Parser ByteString Text -> Parser ByteString Text
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> (ByteString -> Text)
-> Parser ByteString ByteString -> Parser ByteString Text
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ByteString -> Text
decodeLenient Parser ByteString ByteString
forall (f :: * -> * -> *) s a.
(Alternative (f s), CharParsing f s a, SM s) =>
f s s
word
displayName :: CharsetLookup -> Parser T.Text
displayName :: CharsetLookup -> Parser ByteString Text
displayName = CharsetLookup -> Parser ByteString Text
phrase
angleAddr :: Parser AddrSpec
angleAddr :: Parser ByteString AddrSpec
angleAddr = Parser ByteString ByteString
forall (f :: * -> * -> *) s a.
(Alternative (f s), CharParsing f s a, SM s) =>
f s s
optionalCFWS Parser ByteString ByteString -> Parser Word8 -> Parser Word8
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*>
Char -> Parser Word8
char8 Char
'<' Parser Word8
-> Parser ByteString AddrSpec -> Parser ByteString AddrSpec
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> Parser ByteString AddrSpec
addressSpec Parser ByteString AddrSpec
-> Parser Word8 -> Parser ByteString AddrSpec
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* Char -> Parser Word8
char8 Char
'>'
Parser ByteString AddrSpec
-> Parser ByteString ByteString -> Parser ByteString AddrSpec
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* Parser ByteString ByteString
forall (f :: * -> * -> *) s a.
(Alternative (f s), CharParsing f s a, SM s) =>
f s s
optionalCFWS
buildAddressSpec :: AddrSpec -> Builder.Builder
buildAddressSpec :: AddrSpec -> Builder
buildAddressSpec (AddrSpec ByteString
lp (DomainDotAtom NonEmpty ByteString
b))
| ByteString
" " ByteString -> ByteString -> Bool
`B.isInfixOf` ByteString
lp = Builder
"\"" Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
buildLP Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
"\"" Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
rest
| Bool
otherwise = Builder
buildLP Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
rest
where
buildLP :: Builder
buildLP = ByteString -> Builder
Builder.byteString ByteString
lp
rest :: Builder
rest = Builder
"@" Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> (ByteString -> Builder) -> NonEmpty ByteString -> Builder
forall (t :: * -> *) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
foldMap ByteString -> Builder
Builder.byteString (ByteString -> NonEmpty ByteString -> NonEmpty ByteString
forall a. a -> NonEmpty a -> NonEmpty a
Data.List.NonEmpty.intersperse ByteString
"." NonEmpty ByteString
b)
buildAddressSpec (AddrSpec ByteString
lp (DomainLiteral ByteString
b)) =
(ByteString -> Builder) -> [ByteString] -> Builder
forall (t :: * -> *) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
foldMap ByteString -> Builder
Builder.byteString [ByteString
lp, ByteString
"@", ByteString
b]
renderAddressSpec :: AddrSpec -> B.ByteString
renderAddressSpec :: AddrSpec -> ByteString
renderAddressSpec = ByteString -> ByteString
L.toStrict (ByteString -> ByteString)
-> (AddrSpec -> ByteString) -> AddrSpec -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Builder -> ByteString
Builder.toLazyByteString (Builder -> ByteString)
-> (AddrSpec -> Builder) -> AddrSpec -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. AddrSpec -> Builder
buildAddressSpec
addressSpec :: Parser AddrSpec
addressSpec :: Parser ByteString AddrSpec
addressSpec = ByteString -> Domain -> AddrSpec
AddrSpec (ByteString -> Domain -> AddrSpec)
-> Parser ByteString ByteString
-> Parser ByteString (Domain -> AddrSpec)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser ByteString ByteString
forall (f :: * -> * -> *) s a.
(Alternative (f s), CharParsing f s a, SM s) =>
f s s
localPart Parser ByteString (Domain -> AddrSpec)
-> Parser ByteString Domain -> Parser ByteString AddrSpec
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (Char -> Parser Word8
char8 Char
'@' Parser Word8
-> Parser ByteString Domain -> Parser ByteString Domain
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> Parser ByteString Domain
domain)
isDtext :: Word8 -> Bool
isDtext :: Word8 -> Bool
isDtext Word8
c = (Word8
c Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
>= Word8
33 Bool -> Bool -> Bool
&& Word8
c Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
90) Bool -> Bool -> Bool
|| (Word8
c Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
>= Word8
94 Bool -> Bool -> Bool
&& Word8
c Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
126)
domain :: Parser Domain
domain :: Parser ByteString Domain
domain = (NonEmpty ByteString -> Domain
DomainDotAtom (NonEmpty ByteString -> Domain)
-> Parser ByteString (NonEmpty ByteString)
-> Parser ByteString Domain
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser ByteString (NonEmpty ByteString)
forall (f :: * -> * -> *) s a.
(Alternative (f s), CharParsing f s a, SM s) =>
f s (NonEmpty s)
dotAtom)
Parser ByteString Domain
-> Parser ByteString Domain -> Parser ByteString Domain
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> (ByteString -> Domain
DomainLiteral (ByteString -> Domain)
-> Parser ByteString ByteString -> Parser ByteString Domain
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser ByteString ByteString
forall (f :: * -> * -> *) s a.
(Alternative (f s), CharParsing f s a, SM s) =>
f s s
domainLiteral)
mailboxList :: CharsetLookup -> Parser [Mailbox]
mailboxList :: CharsetLookup -> Parser [Mailbox]
mailboxList CharsetLookup
charsets = CharsetLookup -> Parser Mailbox
mailbox CharsetLookup
charsets Parser Mailbox -> Parser Word8 -> Parser [Mailbox]
forall (f :: * -> *) a s. Alternative f => f a -> f s -> f [a]
`sepBy` Char -> Parser Word8
char8 Char
','
renderAddresses :: [Address] -> B.ByteString
renderAddresses :: [Address] -> ByteString
renderAddresses [Address]
xs = ByteString -> [ByteString] -> ByteString
B.intercalate ByteString
", " ([ByteString] -> ByteString) -> [ByteString] -> ByteString
forall a b. (a -> b) -> a -> b
$ Address -> ByteString
renderAddress (Address -> ByteString) -> [Address] -> [ByteString]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Address]
xs
renderAddress :: Address -> B.ByteString
renderAddress :: Address -> ByteString
renderAddress (Single Mailbox
m) = Mailbox -> ByteString
renderMailbox Mailbox
m
renderAddress (Group Text
name [Mailbox]
xs) = Text -> ByteString
T.encodeUtf8 Text
name ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
":" ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> [Mailbox] -> ByteString
renderMailboxes [Mailbox]
xs ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
";"
addressList :: CharsetLookup -> Parser [Address]
addressList :: CharsetLookup -> Parser [Address]
addressList CharsetLookup
charsets = CharsetLookup -> Parser Address
address CharsetLookup
charsets Parser Address -> Parser Word8 -> Parser [Address]
forall (f :: * -> *) a s. Alternative f => f a -> f s -> f [a]
`sepBy` Char -> Parser Word8
char8 Char
','
group :: CharsetLookup -> Parser Address
group :: CharsetLookup -> Parser Address
group CharsetLookup
charsets =
Text -> [Mailbox] -> Address
Group (Text -> [Mailbox] -> Address)
-> Parser ByteString Text
-> Parser ByteString ([Mailbox] -> Address)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> CharsetLookup -> Parser ByteString Text
displayName CharsetLookup
charsets Parser ByteString ([Mailbox] -> Address)
-> Parser Word8 -> Parser ByteString ([Mailbox] -> Address)
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* Char -> Parser Word8
char8 Char
':'
Parser ByteString ([Mailbox] -> Address)
-> Parser [Mailbox] -> Parser Address
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> CharsetLookup -> Parser [Mailbox]
mailboxList CharsetLookup
charsets Parser Address -> Parser Word8 -> Parser Address
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* Char -> Parser Word8
char8 Char
';' Parser Address -> Parser ByteString ByteString -> Parser Address
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* Parser ByteString ByteString
forall (f :: * -> * -> *) s a.
(Alternative (f s), CharParsing f s a, SM s) =>
f s s
optionalCFWS
address :: CharsetLookup -> Parser Address
address :: CharsetLookup -> Parser Address
address CharsetLookup
charsets =
CharsetLookup -> Parser Address
group CharsetLookup
charsets Parser Address -> Parser Address -> Parser Address
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Mailbox -> Address
Single (Mailbox -> Address) -> Parser Mailbox -> Parser Address
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> CharsetLookup -> Parser Mailbox
mailbox CharsetLookup
charsets
data BodyHandler a
= RequiredBody (Parser a)
| OptionalBody (Parser a, a)
| NoBody a
message :: (Headers -> BodyHandler a) -> Parser (Message (MessageContext a) a)
message :: (Headers -> BodyHandler a) -> Parser (Message (MessageContext a) a)
message Headers -> BodyHandler a
f = Parser Headers
fields Parser Headers
-> (Headers -> Parser (Message (MessageContext a) a))
-> Parser (Message (MessageContext a) a)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \Headers
hdrs -> Headers -> a -> Message (MessageContext a) a
forall s a. Headers -> a -> Message s a
Message Headers
hdrs (a -> Message (MessageContext a) a)
-> Parser ByteString a -> Parser (Message (MessageContext a) a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> case Headers -> BodyHandler a
f Headers
hdrs of
RequiredBody Parser ByteString a
b -> Parser ByteString ()
forall (f :: * -> * -> *) s a.
(Alternative (f s), CharParsing f s a) =>
f s ()
crlf Parser ByteString () -> Parser ByteString a -> Parser ByteString a
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> Parser ByteString a
b
OptionalBody (Parser ByteString a
b, a
a) -> Parser ByteString () -> Parser ByteString (Maybe ())
forall (f :: * -> *) a. Alternative f => f a -> f (Maybe a)
optional Parser ByteString ()
forall (f :: * -> * -> *) s a.
(Alternative (f s), CharParsing f s a) =>
f s ()
crlf Parser ByteString (Maybe ())
-> (Maybe () -> Parser ByteString a) -> Parser ByteString a
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Parser ByteString a
-> (() -> Parser ByteString a) -> Maybe () -> Parser ByteString a
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (a -> Parser ByteString a
forall (f :: * -> *) a. Applicative f => a -> f a
pure a
a) (Parser ByteString a -> () -> Parser ByteString a
forall a b. a -> b -> a
const Parser ByteString a
b)
NoBody a
b -> a -> Parser ByteString a
forall (f :: * -> *) a. Applicative f => a -> f a
pure a
b
type family MessageContext a
fields :: Parser Headers
fields :: Parser Headers
fields = [Header] -> Headers
Headers ([Header] -> Headers)
-> Parser ByteString [Header] -> Parser Headers
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser ByteString Header -> Parser ByteString [Header]
forall (f :: * -> *) a. Alternative f => f a -> f [a]
many Parser ByteString Header
field
class RenderMessage a where
buildBody :: Headers -> a -> Maybe Builder.Builder
:: Headers -> Headers
tweakHeaders = Headers -> Headers
forall a. a -> a
id
buildMessage :: forall ctx a. (RenderMessage a) => Message ctx a -> Builder.Builder
buildMessage :: Message ctx a -> Builder
buildMessage (Message Headers
h a
b) =
Headers -> Builder
buildFields (Headers -> Headers
forall a. RenderMessage a => Headers -> Headers
tweakHeaders @a Headers
h)
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder -> (Builder -> Builder) -> Maybe Builder -> Builder
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Builder
forall a. Monoid a => a
mempty (Builder
"\r\n" Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>) (Headers -> a -> Maybe Builder
forall a. RenderMessage a => Headers -> a -> Maybe Builder
buildBody Headers
h a
b)
renderMessage :: (RenderMessage a) => Message ctx a -> L.ByteString
renderMessage :: Message ctx a -> ByteString
renderMessage = Builder -> ByteString
Builder.toLazyByteString (Builder -> ByteString)
-> (Message ctx a -> Builder) -> Message ctx a -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Message ctx a -> Builder
forall ctx a. RenderMessage a => Message ctx a -> Builder
buildMessage
buildFields :: Headers -> Builder.Builder
buildFields :: Headers -> Builder
buildFields = Getting Builder Headers Header
-> (Header -> Builder) -> Headers -> Builder
forall r s a. Getting r s a -> (a -> r) -> s -> r
foldMapOf (([Header] -> Const Builder [Header])
-> Headers -> Const Builder Headers
Iso Headers Headers [Header] [Header]
hdriso (([Header] -> Const Builder [Header])
-> Headers -> Const Builder Headers)
-> ((Header -> Const Builder Header)
-> [Header] -> Const Builder [Header])
-> Getting Builder Headers Header
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Header -> Const Builder Header)
-> [Header] -> Const Builder [Header]
forall (f :: * -> *) a b.
Traversable f =>
IndexedTraversal Int (f a) (f b) a b
traversed) Header -> Builder
buildField
buildField :: (CI B.ByteString, B.ByteString) -> Builder.Builder
buildField :: Header -> Builder
buildField (CI ByteString
k,ByteString
v) =
let key :: ByteString
key = CI ByteString -> ByteString
forall s. CI s -> s
original CI ByteString
k
in
ByteString -> Builder
Builder.byteString ByteString
key
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
":"
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> ByteString -> Int -> Builder
foldUnstructured ByteString
v (ByteString -> Int
B.length ByteString
key Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1)
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
"\r\n"
foldUnstructured :: B.ByteString -> Int -> Builder.Builder
foldUnstructured :: ByteString -> Int -> Builder
foldUnstructured ByteString
s Int
i = case ByteString -> [ByteString]
Char8.words ByteString
s of
[] -> Builder
forall a. Monoid a => a
mempty
(ByteString
h:[ByteString]
t) ->
Builder
" " Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> ByteString -> Builder
Builder.byteString ByteString
h Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> [ByteString] -> Int -> Builder
go [ByteString]
t (Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ ByteString -> Int
B.length ByteString
h)
where
limit :: Int
limit = Int
76
go :: [ByteString] -> Int -> Builder
go [] Int
_ = Builder
forall a. Monoid a => a
mempty
go (ByteString
chunk:[ByteString]
chunks) Int
col
| Int
col Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ ByteString -> Int
B.length ByteString
chunk Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
limit =
Builder
" " Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> ByteString -> Builder
Builder.byteString ByteString
chunk Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> [ByteString] -> Int -> Builder
go [ByteString]
chunks (Int
col Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ ByteString -> Int
B.length ByteString
chunk)
| Int
col Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
1 =
Builder
" " Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> ByteString -> Builder
Builder.byteString ByteString
chunk Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
"\r\n" Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> [ByteString] -> Int -> Builder
go [ByteString]
chunks Int
0
| Bool
otherwise = Builder
"\r\n" Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> [ByteString] -> Int -> Builder
go (ByteString
chunkByteString -> [ByteString] -> [ByteString]
forall a. a -> [a] -> [a]
:[ByteString]
chunks) Int
0
isFtext :: Word8 -> Bool
isFtext :: Word8 -> Bool
isFtext Word8
c = (Word8
c Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
>= Word8
33 Bool -> Bool -> Bool
&& Word8
c Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
57) Bool -> Bool -> Bool
|| (Word8
c Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
>= Word8
59 Bool -> Bool -> Bool
&& Word8
c Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
126)
field :: Parser (CI B.ByteString, B.ByteString)
field :: Parser ByteString Header
field = (,)
(CI ByteString -> ByteString -> Header)
-> Parser ByteString (CI ByteString)
-> Parser ByteString (ByteString -> Header)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser ByteString ByteString -> Parser ByteString (CI ByteString)
forall s. FoldCase s => Parser s -> Parser (CI s)
ci ((Word8 -> Bool) -> Parser ByteString ByteString
takeWhile1 Word8 -> Bool
isFtext)
Parser ByteString (ByteString -> Header)
-> Parser Word8 -> Parser ByteString (ByteString -> Header)
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* Char -> Parser Word8
char8 Char
':' Parser ByteString (ByteString -> Header)
-> Parser ByteString [Word8]
-> Parser ByteString (ByteString -> Header)
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* Parser Word8 -> Parser ByteString [Word8]
forall (f :: * -> *) a. Alternative f => f a -> f [a]
many Parser Word8
forall (f :: * -> * -> *) s a. CharParsing f s a => f s a
wsp
Parser ByteString (ByteString -> Header)
-> Parser ByteString ByteString -> Parser ByteString Header
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Parser ByteString ByteString
unstructured Parser ByteString Header
-> Parser ByteString () -> Parser ByteString Header
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* Parser ByteString ()
forall (f :: * -> * -> *) s a.
(Alternative (f s), CharParsing f s a) =>
f s ()
crlf
unstructured :: Parser B.ByteString
unstructured :: Parser ByteString ByteString
unstructured =
Parser ByteString ByteString -> Parser ByteString ByteString
forall m (f :: * -> *). (Monoid m, Alternative f) => f m -> f m
foldMany (Parser ByteString ByteString
forall (f :: * -> * -> *) s a.
(Alternative (f s), CharParsing f s a, SM s) =>
f s s
optionalFWS Parser ByteString ByteString
-> Parser ByteString ByteString -> Parser ByteString ByteString
forall m (f :: * -> *).
(Semigroup m, Applicative f) =>
f m -> f m -> f m
<<>> (Word8 -> ByteString
B.singleton (Word8 -> ByteString)
-> Parser Word8 -> Parser ByteString ByteString
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser Word8
forall (f :: * -> * -> *) s a. CharParsing f s a => f s a
vchar))
Parser ByteString ByteString
-> Parser ByteString ByteString -> Parser ByteString ByteString
forall m (f :: * -> *).
(Semigroup m, Applicative f) =>
f m -> f m -> f m
<<>> (Word8 -> Bool) -> Parser ByteString ByteString
A.takeWhile Word8 -> Bool
forall c. IsChar c => c -> Bool
isWsp
parsed :: (Cons s s Word8 Word8) => Parser a -> Fold s a
parsed :: Parser a -> Fold s a
parsed Parser a
p = (s -> Either String a) -> Optic' (->) f s (Either String a)
forall (p :: * -> * -> *) (f :: * -> *) s a.
(Profunctor p, Contravariant f) =>
(s -> a) -> Optic' p f s a
to (Parser a -> s -> Either String a
forall s a.
Cons s s Word8 Word8 =>
Parser a -> s -> Either String a
parse Parser a
p) Optic' (->) f s (Either String a)
-> ((a -> f a) -> Either String a -> f (Either String a))
-> (a -> f a)
-> s
-> f s
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> f a) -> Either String a -> f (Either String a)
forall (f :: * -> *) a. Foldable f => IndexedFold Int (f a) a
folded
{-# INLINE parsed #-}
parsePrint :: Parser a -> (a -> B.ByteString) -> Prism' B.ByteString a
parsePrint :: Parser a -> (a -> ByteString) -> Prism' ByteString a
parsePrint Parser a
fwd a -> ByteString
rev = (a -> ByteString) -> (ByteString -> Maybe a) -> Prism' ByteString a
forall b s a. (b -> s) -> (s -> Maybe a) -> Prism s s a b
prism' a -> ByteString
rev (Result a -> Maybe a
forall r. Result r -> Maybe r
AL.maybeResult (Result a -> Maybe a)
-> (ByteString -> Result a) -> ByteString -> Maybe a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Parser a -> ByteString -> Result a
forall a. Parser a -> ByteString -> Result a
AL.parse Parser a
fwd (ByteString -> Result a)
-> (ByteString -> ByteString) -> ByteString -> Result a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Getting ByteString ByteString ByteString
-> ByteString -> ByteString
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting ByteString ByteString ByteString
forall s1 a s2.
(Cons s1 s1 a a, Cons s2 s2 a a, AsEmpty s2) =>
Getter s1 s2
recons)
parse :: (Cons s s Word8 Word8) => Parser a -> s -> Either String a
parse :: Parser a -> s -> Either String a
parse Parser a
p = Result a -> Either String a
forall r. Result r -> Either String r
AL.eitherResult (Result a -> Either String a)
-> (s -> Result a) -> s -> Either String a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Parser a -> ByteString -> Result a
forall a. Parser a -> ByteString -> Result a
AL.parse Parser a
p (ByteString -> Result a) -> (s -> ByteString) -> s -> Result a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Getting ByteString s ByteString -> s -> ByteString
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting ByteString s ByteString
forall s1 a s2.
(Cons s1 s1 a a, Cons s2 s2 a a, AsEmpty s2) =>
Getter s1 s2
recons
{-# INLINE parse #-}