module System.Miniplex.Sekrit ( pathFromTag , reallySend , reallyRecv , bytesFromInt , intFromBytes , closeOnExec , enoents , eexists , mode644 ) where import Control.Exception import Control.Monad import Foreign.C.Error import Network.Socket import Data.Bits import System.Directory import System.IO.Error import System.Posix.Files import System.Posix.IO import System.Posix.Types good :: String -> Bool good s = not (null s) && head s /= '.' && all (`elem` chs) s where chs = ['a' .. 'z'] ++ ['A' .. 'Z'] ++ ['0' .. '9'] ++ ",=-#%.+_^&'@~()[]{}" pathFromTag :: String -> String -> IO (String, String, String) pathFromTag context what | not $ good what = ioError $ errnoToIOError context eADDRNOTAVAIL Nothing (Just what) | otherwise = do dir <- getAppUserDataDirectory "miniplex" createDirectoryIfMissing False dir let d x = dir ++ "/" ++ x return (d what, d $ "L$$", d $ "R$" ++ what) reallySend :: Socket -> String -> IO () reallySend sock = step where step "" = return () step msg = do w <- send sock msg step (drop w msg) reallyRecv :: Socket -> Int -> IO String reallyRecv sock = step where step n | n <= 0 = return "" | otherwise = do (s, r) <- recvLen sock n t <- step (n - r) return (s ++ t) bytesFromInt :: Int -> String bytesFromInt n = map (toEnum . (.&.) 255 . shiftR n . (*) 8) . reverse $ [0 .. 3] intFromBytes :: String -> Int intFromBytes = sum . zipWith (\n c -> fromEnum c `shiftL` (8 * n)) (reverse [0 .. 3]) closeOnExec :: Socket -> IO () closeOnExec (MkSocket fd _ _ _ _) = setFdOption (Fd fd) CloseOnExec True {- killSocket :: Socket -> IO () killSocket s = do bracket (openFd "/dev/null" WriteOnly Nothing defaultFileFlags) closeFd (`dupTo` Fd (fdSocket s)) return () -} enoents :: Exception -> Maybe Exception enoents e = do io <- ioErrors e guard $ isDoesNotExistError io return e eexists :: Exception -> Maybe Exception eexists e = do io <- ioErrors e guard $ isAlreadyExistsError io return e mode644 :: FileMode mode644 = ownerReadMode .|. ownerWriteMode .|. groupReadMode .|. otherReadMode