summaryrefslogtreecommitdiff
path: root/ymir/mlmmj-expose.nix
blob: b07396aab94b92595dea25383c7ff4cbe1d63505 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
{ config, pkgs, ... }:

let
  haskellEnv = pkgs.haskellPackages.ghcWithPackages (pkgs: with pkgs; [ filepath directory cryptonite bytestring uuid ]);
  mlmmj-exposed = pkgs.stdenv.mkDerivation {
    name = "mlmmj-exposed";
    src = pkgs.writeText "mlmmj-exposed.hs" ''
      {-# LANGUAGE ViewPatterns #-}

      import System.IO
      import System.IO.Error
      import System.FilePath
      import System.Environment
      import System.Exit
      import System.Directory
      import System.Process

      import Data.Char

      import Control.Monad

      -- import Codec.Crypto.SimpleAES

      import Crypto.Hash

      import qualified Data.ByteString.Lazy as LBS
      import qualified Data.ByteString.Lazy.Char8 as CLBS
      import qualified Data.ByteString as BS
      import qualified Data.ByteString.Char8 as CBS

      -- import Data.Hex

      import qualified Data.UUID as UUID (toString)
      import qualified Data.UUID.V4 as UUID (nextRandom)

      main :: IO ()
      main = do
        progName <- takeFileName <$> getProgName
        case progName of
          "mlmmj-exposed" -> do
            args <- getArgs
            case args of
              [listDir, (map toLower -> extension)] -> do
                setCurrentDirectory listDir
                identities <- getIdentities
                subscribers <- getSubscribers
                let hashes = filter ((==) extension . snd) [((ident, sub), hash' (ident, sub)) | ident <- identities, sub <- subscribers]
                case hashes of
                  [((_, recipient), _)] -> do
                    uuid <- UUID.nextRandom
                    let fName = "queue" </> "exposed" <.> UUID.toString uuid
                    getContents >>= writeFile fName
                    callProcess "${pkgs.mlmmj}/bin/mlmmj-send" ["-L", listDir, "-l", "6", "-m", fName, "-T", recipient]
                    removeFile fName
                  [] -> die "Unknown extension"
                  _ -> die "Ambiguous extension"
              _ -> hPutStrLn stderr ("Called without expected arguments (<listDirectory> <recipientExtension>)") >> exitWith (ExitFailure 2)
          "mlmmj-expose" -> do
            args <- getArgs
            case args of
              [listDir, (map toLower -> ident)] -> do
                setCurrentDirectory listDir
                identities <- getIdentities
                case ident `elem` identities of
                  True -> putStrLn "Identity is already known"
                  False -> writeFile "exposed.ids" . unlines $ ident : identities
              _ -> hPutStrLn stderr ("Called without expected arguments (<listDirectory> <senderIdentity>)") >> exitWith (ExitFailure 2)
          "mlmmj-get-exposed" -> do
            args <- getArgs
            case args of
              (dropTrailingPathSeparator -> listDir) : (map toLower -> ident) : (map (map toLower) -> recipients) -> do
                setCurrentDirectory listDir
                identities <- getIdentities
                unless (ident `elem` identities) . die $ "Unknown sender: ‘" ++ ident ++ "’"
                subscribers <- getSubscribers
                forM_ recipients (\recipient -> do {
                  unless (recipient `elem` subscribers) . die $ "Unknown recipient: ‘" ++ recipient ++ "’";
                  putStrLn $ takeFileName listDir ++ "+" ++ hash' (ident, recipient) ++ "@subs.lists.yggdrasil.li";
                })
              _ -> hPutStrLn stderr ("Called without expected arguments (<listDirectory> <senderIdentity> [<recipient> [...]])") >> exitWith (ExitFailure 2)
          _ -> hPutStrLn stderr ("Called under unsupported name ‘" ++ progName ++ "’") >> exitWith (ExitFailure 2)
      getIdentities :: IO [String]
      getIdentities = (filter (not . null) . lines <$> readFile "exposed.ids") `catchIOError` (\e -> if isDoesNotExistError e then return [] else ioError e)

      getSubscribers :: IO [String]
      getSubscribers = map (map toLower) . concat <$> mapM (flip catchIOError (\e -> if isDoesNotExistError e then return [] else ioError e) . readDir) ["subscribers.d", "digesters.d"]
        where
          readDir dir = concat <$> (mapM (fmap lines . readFile) . map (dir </>) . filter (not . (`elem` [".", ".."]))=<< (getDirectoryContents dir))

      hash' :: Show a => a -> String
      hash' = take len . map toLower . show . (hash :: BS.ByteString -> Digest SHA256) . CBS.pack . map toLower . show

      len :: Int
      len = 32
    '';
    buildCommand = ''
      mkdir -p $out/bin
      #cp $src $out/bin/.mlmmj-exposed
      ${haskellEnv}/bin/ghc -o $out/bin/.mlmmj-exposed -odir . -hidir . $src
      for f in mlmmj-exposed mlmmj-expose mlmmj-get-exposed; do
        ln -s .mlmmj-exposed $out/bin/$f
      done
    '';
  };
in rec {
  nixpkgs.config.packageOverrides = pkgs: rec {
    inherit mlmmj-exposed;
  };
  environment.systemPackages = [ mlmmj-exposed ];
}