summaryrefslogtreecommitdiff
path: root/Hosts.hs
diff options
context:
space:
mode:
Diffstat (limited to 'Hosts.hs')
-rw-r--r--Hosts.hs93
1 files changed, 76 insertions, 17 deletions
diff --git a/Hosts.hs b/Hosts.hs
index 669fd09..e53d441 100644
--- a/Hosts.hs
+++ b/Hosts.hs
@@ -12,11 +12,14 @@ module Hosts
12 , encode 12 , encode
13 , decode 13 , decode
14 , diff 14 , diff
15 , plus
16 , filterAddrs
17 , namesForAddress
15 ) where 18 ) where
16 19
17import Data.Maybe 20import Data.Maybe
18import Data.Monoid ( (<>) ) 21import Data.Monoid ( (<>) )
19import Data.List (foldl') 22import Data.List as List (foldl', (\\) )
20import Data.Ord 23import Data.Ord
21import Data.Char (isSpace) 24import Data.Char (isSpace)
22import qualified Data.Map as Map 25import qualified Data.Map as Map
@@ -77,9 +80,9 @@ empty = Hosts { lineCount = 0
77 80
78parseHosts fname = do 81parseHosts fname = do
79 input <- L.readFile fname 82 input <- L.readFile fname
80 decode input 83 return $ decode input
81 84
82decode input = do 85decode input =
83 let ls = L.lines input 86 let ls = L.lines input
84 ans = map (\l->(parseLine l,l)) ls 87 ans = map (\l->(parseLine l,l)) ls
85 hosts = foldl' upd empty ans 88 hosts = foldl' upd empty ans
@@ -96,7 +99,7 @@ decode input = do
96 maybeInsert m x = maybe m 99 maybeInsert m x = maybe m
97 (\x->Map.insert x count m) 100 (\x->Map.insert x count m)
98 x 101 x
99 return hosts 102 in hosts
100 103
101 104
102hasName :: L.ByteString -> Hosts -> Bool 105hasName :: L.ByteString -> Hosts -> Bool
@@ -112,8 +115,20 @@ scrubName f line = line'
112 where oo = (.) . (.) 115 where oo = (.) . (.)
113 (a,ws') = splitAt 2 ws 116 (a,ws') = splitAt 2 ws
114 ws'' = f ws' 117 ws'' = f ws'
115 line' = if null ws'' then "# " <> line 118 line' = if null ws''
116 else L.concat (a ++ ws'') <> ign 119 then if length a==2 then "# " <> L.concat a <> ign
120 else line
121 else if length a==2
122 then L.concat (a ++ ws'') <> ign
123 else let vs = L.groupBy ( (==EQ) `oo` comparing isSpace) $ L.dropWhile isSpace
124 $ L.tail ign
125 where oo = (.) . (.)
126 (a',vs') = splitAt 2 vs
127 vs'' = L.concat vs'
128 vs''' = if L.take 1 vs'' `elem` ["#",""]
129 then vs''
130 else "# " <> vs''
131 in L.concat (a'++ws'') <> vs'''
117 132
118assignName addr name hosts = assignName0 False addr name hosts 133assignName addr name hosts = assignName0 False addr name hosts
119 134
@@ -128,23 +143,13 @@ assignName0 iscannon addr name hosts = hosts'
128 let hosts0 = -- remove name if it's present 143 let hosts0 = -- remove name if it's present
129 maybe hosts (removeName hosts) ns 144 maybe hosts (removeName hosts) ns
130 hosts1 = -- insert name, or add new line 145 hosts1 = -- insert name, or add new line
131 maybe (newLine hosts0) (appendName hosts0) a 146 maybe (newLine hosts0) (appendName iscannon name hosts0) a
132 in hosts1 147 in hosts1
133 removeName hosts nums = hosts 148 removeName hosts nums = hosts
134 { namenum = Map.delete name (namenum hosts) 149 { namenum = Map.delete name (namenum hosts)
135 , numline = foldl' scrub (numline hosts) nums 150 , numline = foldl' scrub (numline hosts) nums
136 } 151 }
137 where scrub m num = Map.adjust (scrubName $ filter (/=name)) num m 152 where scrub m num = Map.adjust (scrubName $ filter (/=name)) num m
138 appendName hosts num = hosts
139 { numline = Map.adjust (scrubName f) num (numline hosts)
140 , namenum = Map.alter (cons num) name (namenum hosts)
141 }
142 where f ws = if iscannon
143 then [name, " "] ++ ws
144 else let rs = reverse ws
145 (sp,rs') = span (L.any isSpace) rs
146 in reverse $ sp ++ [name," "] ++ rs'
147 cons v xs = Just $ maybe [v] (v:) xs
148 newLine hosts = hosts 153 newLine hosts = hosts
149 { lineCount = cnt 154 { lineCount = cnt
150 , numline = Map.insert cnt line $ numline hosts 155 , numline = Map.insert cnt line $ numline hosts
@@ -159,6 +164,17 @@ assignNewName addr name hosts =
159 if hasName name hosts then hosts 164 if hasName name hosts then hosts
160 else assignName0 True addr name hosts 165 else assignName0 True addr name hosts
161 166
167appendName iscannon name hosts num = hosts
168 { numline = Map.adjust (scrubName f) num (numline hosts)
169 , namenum = Map.alter (cons num) name (namenum hosts)
170 }
171 where f ws = if iscannon
172 then [name, " "] ++ ws
173 else let rs = reverse ws
174 (sp,rs') = span (L.any isSpace) rs
175 in reverse $ sp ++ [name," "] ++ rs'
176 cons v xs = Just $ maybe [v] (v:) xs
177
162-- Returns a list of bytestrings intended to show the 178-- Returns a list of bytestrings intended to show the
163-- differences between the two host databases. It is 179-- differences between the two host databases. It is
164-- assumed that no lines are deleted, only altered or 180-- assumed that no lines are deleted, only altered or
@@ -175,3 +191,46 @@ diff as bs = cs
175 [a,b] <- return $ map maybeToList [a,b] 191 [a,b] <- return $ map maybeToList [a,b]
176 fmap ("- " <>) a ++ fmap ("+ " <>) b 192 fmap ("- " <>) a ++ fmap ("+ " <>) b
177 193
194namesForAddress :: SockAddr -> Hosts -> [L.ByteString]
195namesForAddress addr hosts = snd $ _namesForAddress addr hosts
196
197_namesForAddress addr (Hosts {numline=numline, addrnum=addrnum}) = ns
198 where
199 ns = maybe (-1,[]) id $ do
200 n <- Map.lookup addr addrnum
201 line <- Map.lookup n numline
202 return (n, snd $ parseLine line)
203
204
205plus a b = Map.foldlWithKey' mergeAddr a (addrnum b)
206 where
207 mergeAddr a addr bnum = a'
208 where
209 (anum,ns) = _namesForAddress addr a
210 bs = maybe [] (List.\\ ns) $ do
211 line <- Map.lookup bnum (numline b)
212 return . snd $ parseLine line
213 a' = if anum/=(-1) then foldl' app a $ reverse bs
214 else newLine a
215 app a b = appendName True b a anum -- True to allow b to reassign cannonical name
216 newLine hosts = hosts
217 { lineCount = cnt
218 , numline = Map.insert cnt line $ numline hosts
219 , addrnum = Map.insert addr cnt $ addrnum hosts
220 , namenum = foldl' updnamenum (namenum hosts) bs
221 }
222 where cnt = lineCount hosts + 1
223 line = L.pack (inet_ntop addr) <> " " <> L.intercalate " " bs
224 cons v xs = Just $ maybe [v] (v:) xs
225 updnamenum m name = Map.alter (cons cnt) name m
226
227filterAddrs :: (SockAddr -> Bool) -> Hosts -> Hosts
228filterAddrs pred hosts = hosts'
229 where
230 als = Map.toList (addrnum hosts)
231 nl = foldl' f (numline hosts) als
232 f m (addr,num) = if pred addr
233 then m
234 else Map.adjust (scrubName $ const []) num m
235 lines = L.unlines . Map.elems $ nl
236 hosts' = decode lines