purebred-email 0.5 → 0.5.1
raw patch · 6 files changed
+58/−16 lines, 6 filesdep −semigroupsdep ~attoparsecdep ~bytestringPVP ok
version bump matches the API change (PVP)
Dependencies removed: semigroups
Dependency ranges changed: attoparsec, bytestring
API changes (from Hackage documentation)
Files
- purebred-email.cabal +4/−5
- src/Data/IMF.hs +30/−1
- src/Data/IMF/Syntax.hs +19/−8
- src/Data/MIME.hs +1/−1
- src/Data/MIME/EncodedWord.hs +2/−0
- tests/Parser.hs +2/−1
purebred-email.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.2 name: purebred-email-version: 0.5+version: 0.5.1 synopsis: types and parser for email messages (including MIME) description: The purebred email library. RFC 5322, MIME, etc.@@ -36,7 +36,7 @@ test-vectors/*.eml tests/golden/*.golden tested-with:- GHC ==8.8.4 || ==8.10.4 || ==9.0.1+ GHC ==8.8.4 || ==8.10.7 || ==9.0.2 || ==9.2.3 || ==9.4.1 homepage: https://github.com/purebred-mua/purebred-email bug-reports: https://github.com/purebred-mua/purebred-email/issues@@ -54,11 +54,10 @@ build-depends: base >= 4.11 && < 5- , attoparsec >= 0.13 && < 0.14- , bytestring >= 0.10 && < 0.11+ , attoparsec >= 0.13 && < 0.15+ , bytestring >= 0.10 && < 0.12 , case-insensitive >= 1.2 && < 1.3 , lens >= 4 && < 6- , semigroups >= 0.16 , text >= 1.2 , time >= 1.9
src/Data/IMF.hs view
@@ -387,7 +387,36 @@ phrase :: CharsetLookup -> Parser T.Text phrase charsets = foldMany1Sep " " $- fmap (decodeEncodedWord charsets) ("=?" *> encodedWord)+ -- RFC 2047 §2: if it is desirable to encode more text than will+ -- fit in an 'encoded-word' of 75 characters, multiple+ -- 'encoded-word's (separated by CRLF SPACE) may be used.+ --+ -- The initial header parsing unfolds the header, so such+ -- "continuation" encoded-words are now separated by SPACE. The+ -- CRLFs have been erased. Naïvely, this seems to make this case+ -- indistinguishable from "consecutive" encoded-words that were+ -- actually separated by SPACE. However, a careful examination of+ -- the grammar shows that encoded-words in a 'phrase' cannot be+ -- separated by whitespace:+ --+ -- @+ -- phrase = 1*( encoded-word / word )+ -- encoded-word = "=?" charset "?" encoding "?" encoded-text "?="+ -- word = atom / quoted-string+ -- atom = [CFWS] 1*atext [CFWS]+ -- quoted-string = [CFWS]+ -- DQUOTE *([FWS] qcontent) [FWS] DQUOTE+ -- [CFWS]+ -- @+ --+ -- The only place whitespace is allowed is within 'atom' and+ -- 'quoted-string'. Therefore two encoded-words separated by+ -- SPACE must be the result of folding a long encoded-word. So+ -- consume as many SPACE separated encoded-words as possible,+ -- decode them, and concatenate the result.+ fmap+ ( foldMap (decodeEncodedWord charsets) )+ ( ("=?" *> encodedWord) `sepBy1` char8 ' ' ) <|> fmap decodeLenient word displayName :: CharsetLookup -> Parser T.Text
src/Data/IMF/Syntax.hs view
@@ -14,7 +14,6 @@ -- You should have received a copy of the GNU Affero General Public License -- along with this program. If not, see <http://www.gnu.org/licenses/>. -{-# LANGUAGE CPP #-} {-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE FunctionalDependencies #-}@@ -77,7 +76,7 @@ ) where import Prelude hiding (takeWhile)-import Control.Applicative ((<|>), Alternative, liftA2, many, optional)+import Control.Applicative ((<|>), Alternative, liftA2, many, optional, some) import Control.Monad (void) import qualified Data.Attoparsec.ByteString as A import qualified Data.Attoparsec.Internal as A@@ -98,11 +97,7 @@ -- | Constraint synonym to handle the Semigroup Monoid Proposal -- transition gracefully.-#if MIN_VERSION_base(4,11,0) type SM a = Monoid a-#else-type SM a = (Semigroup a, Monoid a)-#endif class IsChar a where toChar :: a -> Char@@ -196,8 +191,24 @@ -- | Folding white space (FWS). A run of one or more whitespace -- characters. Returns a single SPACE character. fws :: (Alternative (f s), CharParsing f s a) => (f s) s-fws = ( optional (takeWhile isWsp *> crlf) *> takeWhile1 isWsp )- $> singleton ' '+fws =+ -- obs-FWS is more permissive, so must come first. This means+ -- that the second branch is unused, but keep it anyway for+ -- completeness.+ obsFWS+ <|>+ -- FWS = ([*WSP CRLF] 1*WSP) / obs-FWS+ optional (takeWhile isWsp *> crlf) *> takeWhile1 isWsp $> singleton ' '++-- | Obsolete Folding White Space:+-- https://www.rfc-editor.org/errata/eid1908+--+-- @+-- obs-FWS = 1*([CRLF] WSP)+-- @+--+obsFWS :: (Alternative (f s), CharParsing f s a) => (f s) s+obsFWS = some (optional crlf *> wsp) $> singleton ' ' -- | FWS collapsed to a single SPACE character, or empty string --
src/Data/MIME.hs view
@@ -486,7 +486,7 @@ (\(Message h' b') -> Message h' (Part b')) <$> f (Message h b) Encapsulated msg -> Message h . Encapsulated <$> entities f msg Multipart sub b bs ->- Message h . Multipart sub b <$> sequenceA (entities f <$> bs)+ Message h . Multipart sub b <$> traverse (entities f) bs FailedParse _ _ -> pure (Message h a) -- | Leaf entities with @Content-Disposition: attachment@
src/Data/MIME/EncodedWord.hs view
@@ -56,6 +56,8 @@ import Data.MIME.QuotedPrintable import Data.IMF.Syntax (ci, takeTillString) +{-# ANN module ("HLint: ignore Eta reduce" :: String) #-}+ data EncodedWord = EncodedWord { _encodedWordCharset :: CI.CI B.ByteString , _encodedWordLanguage :: Maybe (CI.CI B.ByteString)
tests/Parser.hs view
@@ -20,7 +20,8 @@ import Data.Either (isLeft) -import Data.Attoparsec.ByteString.Lazy as AL+import Data.Attoparsec.ByteString.Lazy as AL hiding (parseOnly)+import Data.Attoparsec.ByteString (parseOnly) import qualified Data.ByteString as B import qualified Data.ByteString.Char8 as Char8 import qualified Data.ByteString.Lazy as L