Mime.hs 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. {-# LANGUAGE OverloadedStrings #-}
  2. module Data.SMTP.Parser.Mime where
  3. import Data.Attoparsec.ByteString.Char8.Extras
  4. import Data.SMTP.Types.Mime
  5. import Text.StringConvert
  6. import Data.Default.Class
  7. import Control.Applicative ((<|>))
  8. import Data.Attoparsec.ByteString.Char8
  9. import qualified Data.Attoparsec.ByteString.Char8 as A
  10. import qualified Data.Char as C
  11. parseContentType :: Parser (ContentType, ContentTypeParameters)
  12. parseContentType = do
  13. mime <- (
  14. stringCI "multipart/" *>
  15. parseMultipart
  16. ) <|> (
  17. stringCI "message/" *>
  18. parseMessage
  19. ) <|> (
  20. ContentMime . s <$> takeTill endType
  21. )
  22. A.takeWhile endType
  23. pars <- parseContentTypeParameters
  24. return (mime, pars)
  25. where
  26. endType c = C.isSpace c || c == ';'
  27. parseMultipart :: Parser ContentType
  28. parseMultipart = (
  29. stringCI "vnd.dFCMTP.Digest" *>
  30. (return . MultiPartMime $ FcmtpDigest)
  31. ) <|> (do
  32. tp <- takeTill endType
  33. return . MultiPartMime . OtherMultiPartType $ "multipart/" ++ s tp
  34. )
  35. parseMessage :: Parser ContentType
  36. parseMessage = (
  37. do
  38. stringCI "vnd.dFCMTP.Resource"
  39. return . MessageMime $ FcmtpResource
  40. ) <|> (
  41. do
  42. tp <- takeTill endType
  43. return . MessageMime . OtherMessageType $ "message/" ++ s tp
  44. )
  45. parseContentTypeParameters :: Parser ContentTypeParameters
  46. parseContentTypeParameters = parserFold parseContentTypeParameter def
  47. parseContentTypeParameter :: Parser (ContentTypeParameters -> ContentTypeParameters)
  48. parseContentTypeParameter = do
  49. A.takeWhile isSpace
  50. k' <- takeTill (\c -> C.isSpace c || c == '=')
  51. skipWhile isSpace
  52. let k = map C.toLower . s $ k'
  53. A.char '='
  54. A.skipWhile isSpace
  55. v' <- takeTill (\c -> C.isSpace c || c == ';')
  56. skipWhile isSpace
  57. let v = s v'
  58. case lookup k [
  59. ("boundary", \pp -> pp{boundary=Just v}),
  60. ("charset", \pp -> pp{charset=Just v})
  61. ] of
  62. Just f -> return f
  63. Nothing -> return (\pp -> pp{other = (k,v): other pp})
  64. parseTransferEncoding :: Parser TransferEncoding
  65. parseTransferEncoding = parseShowCI allEncodings
  66. where
  67. allEncodings = map IdentityEncoding [B7BitEncoding,
  68. B8BitEncoding,
  69. BBinaryEncoding] ++
  70. [
  71. QPEncodedBody,
  72. Base64EncodedBody
  73. ]
  74. parseBodyEncoding :: Parser BodyEncoding
  75. parseBodyEncoding = parseEnumCI