implement descent and (ugly) merge
[pdns-pipe-nmc.git] / pdns-pipe-nmc.hs
1 {-# LANGUAGE OverloadedStrings #-}
2
3 module Main where
4
5 import Control.Monad
6 import qualified Data.ByteString.Char8 as C (pack, unpack)
7 import qualified Data.ByteString.Lazy.Char8 as L (pack, unpack)
8 import Data.ByteString.Lazy as BS hiding (reverse, putStr, putStrLn)
9 import Data.List.Split
10 import Data.Aeson (encode, decode, Value(..))
11 import Network.HTTP.Types
12 import Data.Conduit
13 import Network.HTTP.Conduit
14
15 import JsonRpcClient
16 import Config
17 import PowerDns
18 import NmcJson
19
20 confFile = "/etc/namecoin.conf"
21
22 -- HTTP/JsonRpc interface
23
24 qReq :: Config -> ByteString -> ByteString -> Request m
25 qReq cf q id = applyBasicAuth (C.pack (rpcuser cf)) (C.pack (rpcpassword cf))
26              $ def { host           = (C.pack (rpchost cf))
27                    , port           = (rpcport cf)
28                    , method         = "PUT"
29                    , requestHeaders = [ (hAccept,      "application/json")
30                                       , (hContentType, "application/json")
31                                       , (hConnection,  "Keep-Alive")
32                                       ]
33                    , requestBody    = RequestBodyLBS $ encode $
34                                       JsonRpcRequest JsonRpcV1
35                                                      "name_show"
36                                                      [q]
37                                                      (String "pdns-nmc")
38                    , checkStatus    = \_ _ _ -> Nothing
39                    }
40
41 qRsp :: Response ByteString -> Either String NmcDom
42 qRsp rsp =
43     case parseJsonRpc (responseBody rsp) :: Either JsonRpcError NmcRes of
44       Left  jerr -> 
45         case (jrpcErrCode jerr) of
46           -4 -> Right emptyNmcDom
47           _  -> Left $ "JsonRpc error response: " ++ (show jerr)
48       Right jrsp ->
49         case resValue jrsp of
50           "" -> Right emptyNmcDom
51           vstr ->
52             case decode vstr :: Maybe NmcDom of
53               Nothing  -> Left $ "Unparseable value: " ++ (show vstr)
54               Just dom -> Right dom
55
56 -- NMC interface
57
58 queryNmc :: Manager -> Config -> String -> String
59          -> IO (Either String NmcDom)
60 queryNmc mgr cfg fqdn qid = do
61   case reverse (splitOn "." fqdn) of
62     "bit":dn:xs -> do
63       rsp <- runResourceT $
64              httpLbs (qReq cfg (L.pack ("d/" ++ dn)) (L.pack qid)) mgr
65       return $ case qRsp rsp of
66         Left  err -> Left err
67         Right dom -> Right $ descendNmc xs dom
68     _           ->
69       return $ Left "Only \".bit\" domain is supported"
70
71 -- Main entry
72
73 main = do
74
75   cfg <- readConfig confFile
76
77   ver <- do
78     let
79       loopErr e = forever $ do
80         putStrLn $ "FAIL\t" ++ e
81         _ <- getLine
82         return ()
83     s <- getLine
84     case words s of
85       ["HELO", "1"] -> return 1
86       ["HELO", "2"] -> return 2
87       ["HELO", "3"] -> return 3
88       ["HELO",  x ] -> loopErr $ "unsupported ABI version " ++ (show x)
89       _             -> loopErr $ "bad HELO " ++ (show s)
90
91   putStrLn $ "OK\tDnsNmc ready to serve, protocol v." ++ (show ver)
92
93   mgr <- newManager def
94   forever $ do
95     l <- getLine
96     case pdnsParse ver l of
97       Left e -> putStr $ pdnsReport e
98       Right preq -> do
99         case preq of
100           PdnsRequestQ qname qtype id _ _ _ ->
101             queryNmc mgr cfg qname id >>= putStr . (pdnsOut ver id qname qtype)
102           PdnsRequestAXFR xfrreq ->
103             putStr $ pdnsReport ("No support for AXFR " ++ xfrreq)
104           PdnsRequestPing -> putStrLn "END"
105
106 -- for testing
107
108 ask str = do
109   cfg <- readConfig confFile
110   mgr <- newManager def
111   queryNmc mgr cfg str "askid" >>= putStr . (pdnsOut 1 "askid" str RRTypeANY)