diff options
Diffstat (limited to 'Hosts.hs')
-rw-r--r-- | Hosts.hs | 93 |
1 files changed, 76 insertions, 17 deletions
@@ -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 | ||
17 | import Data.Maybe | 20 | import Data.Maybe |
18 | import Data.Monoid ( (<>) ) | 21 | import Data.Monoid ( (<>) ) |
19 | import Data.List (foldl') | 22 | import Data.List as List (foldl', (\\) ) |
20 | import Data.Ord | 23 | import Data.Ord |
21 | import Data.Char (isSpace) | 24 | import Data.Char (isSpace) |
22 | import qualified Data.Map as Map | 25 | import qualified Data.Map as Map |
@@ -77,9 +80,9 @@ empty = Hosts { lineCount = 0 | |||
77 | 80 | ||
78 | parseHosts fname = do | 81 | parseHosts fname = do |
79 | input <- L.readFile fname | 82 | input <- L.readFile fname |
80 | decode input | 83 | return $ decode input |
81 | 84 | ||
82 | decode input = do | 85 | decode 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 | ||
102 | hasName :: L.ByteString -> Hosts -> Bool | 105 | hasName :: 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 | ||
118 | assignName addr name hosts = assignName0 False addr name hosts | 133 | assignName 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 | ||
167 | appendName 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 | ||
194 | namesForAddress :: SockAddr -> Hosts -> [L.ByteString] | ||
195 | namesForAddress 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 | |||
205 | plus 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 | |||
227 | filterAddrs :: (SockAddr -> Bool) -> Hosts -> Hosts | ||
228 | filterAddrs 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 | ||