packages feed

ftp-client 0.4.0.0 → 0.4.0.1

raw patch · 2 files changed

+52/−7 lines, 2 filesdep +containersdep ~ftp-clientPVP: minor bump suggested

API additions: PVP suggests at least a minor version bump

Dependencies added: containers

Dependency ranges changed: ftp-client

API changes (from Hackage documentation)

+ Network.FTP.Client: Mlsd :: String -> FTPCommand
+ Network.FTP.Client: MlsdResponse :: String -> Map String String -> MlsdResponse
+ Network.FTP.Client: [mrFacts] :: MlsdResponse -> Map String String
+ Network.FTP.Client: [mrFilename] :: MlsdResponse -> String
+ Network.FTP.Client: data MlsdResponse
+ Network.FTP.Client: instance GHC.Show.Show Network.FTP.Client.MlsdResponse
+ Network.FTP.Client: mlsd :: (MonadIO m, MonadMask m) => Handle -> String -> m [MlsdResponse]
+ Network.FTP.Client: parseMlsdLine :: ByteString -> MlsdResponse

Files

ftp-client.cabal view
@@ -1,5 +1,5 @@ name: ftp-client-version: 0.4.0.0+version: 0.4.0.1 cabal-version: >=1.10 build-type: Simple license: PublicDomain@@ -28,7 +28,8 @@         attoparsec >=0.10 && <0.14,         connection ==0.2.*,         transformers >=0.5.2.0 && <0.6,-        exceptions >=0.8.3 && <0.9+        exceptions >=0.8.3 && <0.9,+        containers >=0.5.7.1 && <0.6     default-language: Haskell2010     default-extensions: OverloadedStrings     hs-source-dirs: src@@ -38,7 +39,7 @@     main-is: Spec.hs     build-depends:         base >=4.9.1.0 && <4.10,-        ftp-client >=0.4.0.0 && <0.5+        ftp-client >=0.4.0.1 && <0.5     default-language: Haskell2010     hs-source-dirs: test     ghc-options: -threaded -rtsopts -with-rtsopts=-N
src/Network/FTP/Client.hs view
@@ -25,10 +25,12 @@     retr,     list,     stor,+    mlsd,     -- * Types     FTPCommand(..),     FTPResponse(..),     ResponseStatus(..),+    MlsdResponse(..),     RTypeCode(..),     PortActivity(..),     ProtType(..),@@ -44,7 +46,8 @@     getMultiLineResp,     sendCommandLine,     createSendDataCommand,-    createTLSSendDataCommand+    createTLSSendDataCommand,+    parseMlsdLine ) where  import qualified Data.ByteString.Char8 as C@@ -66,7 +69,12 @@ import Data.ByteString.Lazy.Internal (defaultChunkSize) import Data.Functor ((<$>)) import Control.Applicative ((<*>))+import Data.Map.Strict (Map)+import qualified Data.Map.Strict as Map+import Control.Arrow +import Debug.Trace+ debugging :: Bool debugging = False @@ -144,6 +152,7 @@     | Rmd String     | Pbsz Int     | Prot ProtType+    | Mlsd String     | Cwd String     | Cdup     | Ccc@@ -184,6 +193,7 @@ serializeCommand (Pbsz buf)   = "PBSZ " <> show buf serializeCommand (Prot P)     = "PROT P" serializeCommand (Prot C)     = "PROT C"+serializeCommand (Mlsd path)  = "MLSD " <> path serializeCommand (Cwd dir)    = "CWD " <> dir serializeCommand Cdup         = "CDUP" serializeCommand Ccc          = "CCC"@@ -409,7 +419,7 @@ getAllLineResp :: (MonadIO m, MonadCatch m) => Handle -> m ByteString getAllLineResp h = getAllLineResp' h []     where-        getAllLineResp' h ret = (do+        getAllLineResp' h ret = ( do             line <- liftIO $ getLineResp h             getAllLineResp' h (ret <> [line]))                 `M.catchIOError` (\_ -> return $ C.intercalate "\n" ret)@@ -418,7 +428,7 @@ recvAll :: (MonadIO m, MonadCatch m) => Handle -> m ByteString recvAll h = recvAll' ""     where-        recvAll' bs = (do+        recvAll' bs = ( do             chunk <- liftIO $ recv h defaultChunkSize             recvAll' $ bs <> chunk)                 `M.catchIOError` (\_ -> return bs)@@ -638,7 +648,7 @@ retr h path = withDataCommandSecurity h Passive [RType TI, Retr path] recvAll  list :: (MonadIO m, MonadMask m) => Handle -> [String] -> m ByteString-list h args = withDataCommandSecurity h Passive [RType TA, List args] recvAll+list h args = withDataCommandSecurity h Passive [RType TA, List args] getAllLineResp  stor     :: (MonadIO m, MonadMask m)@@ -650,3 +660,37 @@ stor h loc dat rtype =     withDataCommandSecurity h Passive [RType rtype, Stor loc]         $ sendType rtype dat++data MlsdResponse = MlsdResponse {+    mrFilename :: String,+    mrFacts :: Map String String+} deriving (Show)++splitApart :: Char -> ByteString -> (ByteString, ByteString)+splitApart on s =+    let (x0, x1) = C.break (== on) s+    in (x0, C.drop 1 x1)++parseMlsdLine :: ByteString -> MlsdResponse+parseMlsdLine line =+    let (factLine, filename) = splitApart ' ' line+        bFacts = splitApart '=' <$> C.split ';' factLine+        facts+            = Map.fromList+            $ filter (not . null . fst)+            $ join (***) C.unpack <$> bFacts+    in MlsdResponse (C.unpack filename) facts++getMlsdResponse :: (MonadIO m, MonadCatch m) => Handle -> m [MlsdResponse]+getMlsdResponse h = getMlsdResponse' h []+    where+        getMlsdResponse' h ret = ( do+            line <- liftIO $ getLineResp h+            getMlsdResponse' h $+                if C.null line+                    then ret+                    else (parseMlsdLine line):ret+            ) `M.catchIOError` (\_ -> return ret)++mlsd :: (MonadIO m, MonadMask m) => Handle -> String -> m [MlsdResponse]+mlsd h path = withDataCommandSecurity h Passive [RType TA, Mlsd path] getMlsdResponse