Resource.hs 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. {-# LANGUAGE OverloadedStrings #-}
  2. module Data.SMTP.Types.Resource where
  3. import qualified Data.SMTP.URI as URI
  4. import qualified Data.SMTP.Types.Mime as Mime
  5. import qualified Data.SMTP.Parser.Mime as PMime
  6. import qualified Data.Attoparsec.ByteString as BA
  7. import qualified Data.ByteString as BS
  8. import qualified Data.ByteString.Lazy as LBS
  9. import qualified Text.StringConvert as SC
  10. import Data.Maybe
  11. import Data.Default.Class
  12. import qualified Data.Char as C
  13. data Header = Header {key :: String, value :: String, bare :: BS.ByteString} deriving (Read, Show, Eq, Ord)
  14. data PlainHeaders = PlainHeaders {public :: [Header], sealed :: [Header], separators :: (BS.ByteString, BS.ByteString)} deriving (Read, Show, Eq, Ord)
  15. instance Default PlainHeaders where
  16. def = PlainHeaders [] [] ("\r\n", "")
  17. data ResourceInfo = ResourceInfo {
  18. mimeType :: Mime.ContentType,
  19. mimeParameters :: Mime.ContentTypeParameters,
  20. revision :: URI.Revision,
  21. bases :: [URI.Revision],
  22. address :: [URI.URI]
  23. } deriving (Eq, Ord, Show)
  24. instance Default ResourceInfo where
  25. def = ResourceInfo def def URI.NoRevision [] []
  26. type ResourceData = LBS.ByteString
  27. -- | Creates a header from a key and a value
  28. makeHeader :: String -> String -> Header
  29. makeHeader k v = Header k v . SC.s $ k ++ ": " ++ v ++ "\r\n"
  30. -- | True if the header key matches
  31. hasKey :: String -> Header -> Bool
  32. hasKey k h = map C.toLower k == key h
  33. -- | Retrieves a single header with the given key
  34. getHeader :: [Header] -> String -> Maybe Header
  35. getHeader hh k = case getMultiple hh k of
  36. [] -> Nothing
  37. (h:_) -> Just h
  38. -- | Retrieves the value of the header that matches key
  39. getHeaderValue :: [Header] -> String -> Maybe String
  40. getHeaderValue hh k = value <$> getHeader hh k
  41. -- | Retrieves all headers that match the key
  42. getMultiple :: [Header] -> String -> [Header]
  43. getMultiple hh k = filter (hasKey k) hh
  44. -- | Retrieves all the values of the headers that match the key
  45. getMultipleValue :: [Header] -> String -> [String]
  46. getMultipleValue hh k = map value $ getMultiple hh k
  47. -- | fCMTP revision header
  48. revisionHeader :: String
  49. revisionHeader = "fCMTP-Revision"
  50. -- | fCMTP base revision header
  51. baseHeader :: String
  52. baseHeader = "fCMTP-Revision-Base"
  53. -- | fCMTP resource URI header
  54. addressHeader :: String
  55. addressHeader = "fCMTP-Address"
  56. -- | Retrieves the meta information from resource headers
  57. resourceInfo :: PlainHeaders -> ResourceInfo
  58. resourceInfo (PlainHeaders _ ss _) = let
  59. (mimet, mimep) = fromMaybe (def, def) $ getHeaderValue ss Mime.contentTypeHeaderName >>= bparse PMime.parseContentType
  60. curr = fromMaybe URI.NoRevision $ URI.Revision <$> getHeaderValue ss revisionHeader
  61. bb = map URI.Revision $ getMultipleValue ss baseHeader
  62. uu = catMaybes . map (bparse URI.parseURI) $ getMultipleValue ss addressHeader
  63. in ResourceInfo mimet mimep curr bb uu
  64. where
  65. bparse :: BA.Parser a -> String -> Maybe a
  66. bparse p v = eitherToMaybe . BA.parseOnly p $ SC.s v
  67. eitherToMaybe (Left _) = Nothing
  68. eitherToMaybe (Right v) = Just v
  69. -- | Retrieve MIME information from the resource headers
  70. getMimeData :: [Header] -> (Mime.ContentTypeHeader, Mime.TransferEncoding)
  71. getMimeData hh = (ct, te)
  72. where
  73. ct = case getHeader hh Mime.contentTypeHeaderName of
  74. Nothing -> def
  75. Just h -> case BA.parseOnly PMime.parseContentType (SC.s . value $ h) of
  76. Left _ -> def
  77. Right (ctv, ctp) -> Mime.ContentTypeHeader ctv ctp
  78. te = case getHeader hh Mime.transferEncodingHeaderName of
  79. Nothing -> def
  80. Just h -> case BA.parseOnly PMime.parseTransferEncoding (SC.s . value $ h) of
  81. Left _ -> def
  82. Right t -> t
  83. -- | Recreates the original resource text for the headers
  84. originalData :: PlainHeaders -> BS.ByteString
  85. originalData (PlainHeaders pp ss (psep, ssep)) =
  86. BS.concat [
  87. catData pp, psep,
  88. catData ss, ssep
  89. ]
  90. where
  91. catData :: [Header] -> BS.ByteString
  92. catData hh = BS.concat . map bare $ hh
  93. -- | Recreates the original resource text for the sealed headers only
  94. originalSealed :: PlainHeaders -> BS.ByteString
  95. originalSealed (PlainHeaders _ ss (_, ssep)) =
  96. (BS.concat $ map bare ss) `BS.append` ssep