htalkat-0.1.1: Incoming.hs
-- This file is part of htalkat
-- Copyright (C) 2021 Martin Bays <mbays@sdf.org>
--
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of version 3 of the GNU General Public License as
-- published by the Free Software Foundation, or any later version.
--
-- You should have received a copy of the GNU General Public License
-- along with this program. If not, see http://www.gnu.org/licenses/.
module Incoming where
import Control.Monad (filterM, forM, forM_)
import Data.List ((\\))
import Data.Maybe (catMaybes)
import Safe (maximumMay, readMay)
import System.Directory
import System.FileLock (SharedExclusive (..), withFileLock)
import System.FilePath ((</>))
import Certificate
import Fingerprint
import LookupPetname
import Mundanities
import Petname
import Util
type Incoming = Int
addIncoming :: FilePath -> Certificate -> FilePath -> Int -> IO Incoming
addIncoming ddir cert sockPath serial = do
let idir = incomingDir ddir
createDirectoryIfMissing True idir
withFileLock (idir </> ".lock") Exclusive $ \_ -> do
ns <- incomingNs ddir
let n = head $ [1..] \\ ns
let ndir = idir </> show n
createDirectoryIfMissing False ndir
writeFile (ndir </> "fp") . showFingerprint $ spkiFingerprint cert
writeFile (ndir </> "publicName") $ certCN cert
writeFile (ndir </> "sock") sockPath
writeFile (ndir </> "serial") $ show serial
pure n
cleanAllIncoming :: FilePath -> IO ()
cleanAllIncoming ddir = do
ns <- incomingNs ddir
forM_ ns $ cleanIncoming ddir Nothing
cleanIncoming :: FilePath -> Maybe Int -> Incoming -> IO ()
cleanIncoming ddir mSerial n =
let path = incomingPath ddir n
serialOk | Just s <- mSerial =
(== Just s) <$> ignoreIOErrAlt (readMay <$> readFile (path </> "serial"))
| otherwise = pure True
in doesDirectoryExist path >>? serialOk >>? removeDirectoryRecursive path
incomingDir :: FilePath -> FilePath
incomingDir = (</> "incoming")
incomingNs :: FilePath -> IO [Int]
incomingNs ddir = catMaybes . (readMay <$>) <$>
listDirectory (incomingDir ddir)
incomingPath :: FilePath -> Incoming -> FilePath
incomingPath ddir n = incomingDir ddir </> show n
lastIncoming :: FilePath -> Maybe Fingerprint -> IO (Maybe Incoming)
lastIncoming ddir mFp = do
ns <- incomingNs ddir
maximumMay <$> filterM checkFp ns
where
checkFp _ | Nothing <- mFp = pure True
checkFp n | Just fp <- mFp = (== Just fp) . parseFingerprint <$>
readFile (incomingPath ddir n </> "fp")
listIncoming :: FilePath -> IO [String]
listIncoming ddir = do
ns <- incomingNs ddir
forM ns $ \n -> do
let idir = incomingPath ddir n
t <- getModificationTime idir
petname <- incomingPetname ddir n
((show t <> ": " <> showPetname petname) <>) <$> case petname of
Named _ -> pure ""
_ -> do
Just fp <- parseFingerprint <$> readFile (idir </> "fp")
cn <- readFile (idir </> "publicName")
pure $ " " <> showFingerprint fp <>
if null cn then "" else " \"" <> cn <> "\""
incomingPetname :: FilePath -> Incoming -> IO Petname
incomingPetname ddir n = do
Just fp <- parseFingerprint <$> readFile (incomingPath ddir n </> "fp")
lookupOrAddPetname ddir fp