URI.hs 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. module Data.SMTP.Types.URI where
  2. import qualified Network.URI as N
  3. import Data.SMTP.Account
  4. import qualified Data.SMTP.Seal as Seal
  5. import Data.List
  6. import qualified Text.StringConvert as SC
  7. import qualified Data.Attoparsec.Text as A
  8. newtype Path = Path [String] deriving (Eq, Ord, Read, Show)
  9. data Revision = NoRevision | Revision String deriving (Eq, Ord, Read, Show)
  10. data Parameter = Parameter String String deriving (Eq, Ord, Read, Show)
  11. data URI = URI {account :: Account, path :: Path, revision :: Revision, parameters :: [Parameter]}
  12. deriving (Eq, Ord)
  13. {- |
  14. Returns the entire path of the URI.
  15. -}
  16. fullPath :: URI -> String
  17. fullPath URI{path=Path p} = intercalate "/" $ map uriEncode p
  18. {- |
  19. Returns the entire path of the URI, except for the leading slash (/).
  20. -}
  21. relativePath :: URI -> String
  22. relativePath URI{path=Path p} = intercalate "/" . map uriEncode $ drop 1 p
  23. -- | Entire textual representation of the URI
  24. fullURI :: URI -> String
  25. fullURI u@(URI{account=a, revision=r, parameters=pp}) =
  26. concat $ ["FCMTP://", SC.s . fullAccount $ a, fullPath u] ++ (
  27. case r of
  28. NoRevision -> []
  29. Revision r' -> [":", r']
  30. ) ++ (
  31. if null pp
  32. then []
  33. else ["?", intercalate "&" $ map formatParameter pp]
  34. )
  35. where
  36. formatParameter (Parameter nm vl) = concat [uriEncode nm, "=", uriEncode vl]
  37. uriEncode :: String -> String
  38. uriEncode = N.escapeURIString N.isUnescapedInURIComponent
  39. instance Show URI where
  40. show = fullURI
  41. -- | Retrieves a parameter from the URI by key name
  42. getParameter :: String -> URI -> Maybe String
  43. getParameter p u = case map (\(Parameter _ vl) -> vl) .
  44. filter (\(Parameter nm _) -> nm == p) $
  45. parameters u of
  46. [] -> Nothing
  47. (v:_) -> Just v
  48. getSeal :: URI -> Maybe Seal.Seal
  49. getSeal u = do
  50. bare <- getParameter Seal.sealURIParam u
  51. right2Just . A.parseOnly Seal.parseURISeal $ SC.s bare
  52. where
  53. right2Just (Left _) = Nothing
  54. right2Just (Right v) = Just v
  55. -- | Return revision string or a default value
  56. fromRevision :: String -> Revision -> String
  57. fromRevision d NoRevision = d
  58. fromRevision _ (Revision r) = r
  59. -- | Appends a new segment at the end of the path
  60. appendPath :: Path -> String -> Path
  61. appendPath (Path pp) e = Path $ pp ++ [e]