HNM (empty) → 0.1
raw patch · 9 files changed
+775/−0 lines, 9 filesdep +basedep +containersdep +glibsetup-changed
Dependencies added: base, containers, glib, gtk, haskell98, mtl, process, regex-posix, unix
Files
- AUTHORS +1/−0
- HNM.cabal +52/−0
- HNM/WLAN.hs +208/−0
- LICENSE +22/−0
- Main.hs +457/−0
- Makefile +29/−0
- README +1/−0
- Setup.hs +2/−0
- settings.conf +3/−0
+ AUTHORS view
@@ -0,0 +1,1 @@+Cetin Sert <cetin@sertcom.de>
+ HNM.cabal view
@@ -0,0 +1,52 @@+name: HNM+version: 0.1+copyright: (c) 2008 Cetin Sert+cabal-version: >= 1.2+description: A quick and dirty applet to help you connect+ to wireless networks.+license: BSD3+license-file: LICENSE+author: Cetin Sert <cetin@sertcom.de>+maintainer: Cetin Sert <cetin@sertcom.de>+category: Network, System+homepage: http://sert.homedns.org/hs/hnm/+synopsis: Happy Network Manager+stability: experimental++build-type: Simple++data-files: settings.conf,+ Makefile++extra-source-files: AUTHORS,+ README++Library+ buildable: True+ exposed-modules: HNM.WLAN+ extensions: NoMonomorphismRestriction+ ghc-options: -O2 -fglasgow-exts+ build-depends: base,+ gtk >= 0.9.13,+ glib,+ mtl,+ unix,+ regex-posix,+ process,+ containers,+ haskell98++Executable HNM+ buildable: True+ main-is: Main.hs+ extensions: NoMonomorphismRestriction+ ghc-options: -O2 -fglasgow-exts+ build-depends: base,+ gtk >= 0.9.13,+ glib,+ mtl,+ unix,+ regex-posix,+ process,+ containers,+ haskell98
+ HNM/WLAN.hs view
@@ -0,0 +1,208 @@+{-# OPTIONS -fglasgow-exts #-}++module HNM.WLAN where++import IO+import Data.List+import System.IO+import System.Exit+import System.Process+import System.IO.Unsafe+import Text.Regex.Posix+import System.Posix.User+import System.Environment+import Control.Concurrent+import Control.Monad.State++ignore :: Monad m ⇒ m a → m ()+ignore _ = return ()++assu :: IO a → IO a → IO a+assu a b = do+ root ← userIsRoot+ case root of+ True → a+ False → b++userIsRoot :: IO Bool+userIsRoot = return . (0 ==) =<< getRealUserID++run :: String → IO String+run cmd = do+ (i,o,e,h) ← runInteractiveCommand cmd+ hGetContents o >>= \s → waitForProcess h >> return s++type Key = String+type SSID = String+type MAC = String+type Interface = String+type Cell = String+type IP = String+type AP = String++getDefaultInterface :: IO Interface+getDefaultInterface = return . head =<< getInterfaces++getInterfaces :: IO [Interface]+getInterfaces = do+ cat ← run "cat /proc/net/wireless"+ return $ filter (/= "") $ map (matching " *(.*[0-9]+):") $ lines cat++scan :: Interface → IO [Cell]+scan interface = return . drop 1 . getCells =<< run ("iwlist " ++ interface ++ " scan")++getCells :: String → [Cell]+getCells block = map unwords $ groupBy (const $ (/=) "Cell") $ words block++data Encryption = None | WEP | WPA Version+ deriving (Show, Read, Eq, Ord)++data Version = One | Two+ deriving (Show, Read, Eq, Ord)++type Quality = Int+type Unit = (MAC,Quality)++data CWLAN = CWLAN+ {+ cessid :: SSID,+ cencrypt :: Encryption,+ ccell :: [Unit]+ }+ deriving (Show, Read, Eq, Ord)++meanQuality :: [Quality] → Quality+meanQuality = round . mean . (map (fromInteger . toInteger))++mean :: Fractional a ⇒ [a] → a+mean [] = 0+mean (x:xs) = mean' (x:xs) 0 0+ where+ mean' [] s c = s / c+ mean' (x:xs) s c = mean' xs (s+x) (c+1)++data WLAN = WLAN+ {+ essid :: SSID,+ quality :: Quality,+ encryption :: Encryption, + mac :: MAC+ }+ deriving (Show, Read, Eq, Ord)++compact :: [WLAN] → [CWLAN]+compact [] = []+compact (w:ws) = CWLAN cid cen ceq_us : compact cne+ where+ cid = essid w+ cen = encryption w+ (ceq,cne) = partition ((cid ==) . essid) ws+ ceq_us = macqual w : map macqual ceq+ macqual = \ew → (mac ew, quality ew)++cellToWLAN :: Cell → WLAN+cellToWLAN c = WLAN (getEssid c) (getQuality c) (getEncrypt c) (getMac c)+ where+ getEssid = matching "ESSID:\"(.*)\""+ getMac = matching "Address: (.{17})"+ getQuality = \c → case matching "Quality=(.*)/100" c of { "" → 0; q → read q :: Int}+ getEncrypt = \c → case matching "Encryption key:(on|off)" c of+ "on" → case matching "WPA Version (.)" c of+ "1" → WPA One+ "2" → WPA Two+ _ → WEP+ "off" → None++getWLANs :: Interface → IO [WLAN]+getWLANs interface = return . {-debug . -}map cellToWLAN =<< scan interface++getLocalIP :: Interface → IO IP+getLocalIP interface = return . matching "inet addr:(.+) ." =<< run ("ifconfig " ++ interface)++getESSID :: Interface → IO SSID+getESSID interface = return . matching "ESSID:\"(.+)\"" =<< run ("iwconfig " ++ interface)++getAP :: Interface → IO AP+getAP interface = return . matching "Access Point: (.+)\n" =<< run ("iwconfig " ++ interface)++data ConnectionStatus = NotConnected | Connected IP SSID+ deriving (Show, Read, Eq, Ord)++getConnectionStatus :: Interface → IO ConnectionStatus+getConnectionStatus interface = do+ ip ← getLocalIP interface+ case ip of+ [] → return NotConnected+ ip → do+ ap ← getAP interface+ case (debug ap) of+ "Not-Associated " → return NotConnected+ ap → return . Connected ip =<< getESSID interface++matching :: String → String → String+matching = \pattern info → case info =~ pattern of { [[a,b]] → b; _ → "" }++debug :: Show a ⇒ a → a+debug a = unsafePerformIO (print a >> return a)++exec :: String → IO ()+exec cmd = runCommand cmd >>= waitForProcess >> return ()++pcom :: String → [String] → IO ()+pcom c = exec . unwords . (c:)++modprobe :: [String] → IO ()+modprobe = pcom "modprobe"++iwconfig :: [String] → IO ()+iwconfig = pcom "iwconfig"++ifconfig :: [String] → IO ()+ifconfig = pcom "ifconfig"++dhclient :: [String] → IO ()+dhclient = pcom "dhclient"++wpa_supplicant :: [String] → IO ()+wpa_supplicant = pcom "wpa_supplicant"++initHardware :: String → Interface → IO ()+initHardware driver interface = do+ disconnect interface+ modprobe ["-r", driver]+ modprobe [driver]+ ifconfig [interface, "up"]+ threadDelay 2000000+ exec $ "iwlist " ++ interface ++ " scan"+ return ()++disconnect :: Interface → IO ()+disconnect interface = do+ exec $ "killall dhclient"+ exec $ "killall wpa_supplicant"+ ifconfig [interface, "down"]++connectFree :: Interface → SSID → IO ()+connectFree interface ssid = do+ disconnect interface+ ifconfig [interface, "up"]+ iwconfig [interface, "essid", ssid]+ dhclient [interface]++connectWEP :: Interface → SSID → Key → IO ()+connectWEP interface ssid key = do+ disconnect interface+ ifconfig [interface, "up"]+ iwconfig [interface, "essid", ssid, "key", "s:" ++ key]+ dhclient [interface]++-----+data ConnectionSetting = Free SSID+ | Encrypted SSID Encryption Key+ deriving (Show, Read, Eq, Ord)++connect :: Interface → ConnectionSetting → IO ()+connect it (Free id ) = connectFree it id+connect it (Encrypted id WEP ky) = connectWEP it id ky+connect _ _ = do+ putStrLn "Only non- or WEP-encrypted networks can be connected to."
+ LICENSE view
@@ -0,0 +1,22 @@+Copyright (c) 2008 Cetin Sert. All rights reserved.++Redistribution and use in source and binary forms, with or without modification,+are permitted provided that the following conditions are met:++ 1. Redistributions of source code must retain the above copyright notice,+ this list of conditions and the following disclaimer.++ 2. Redistributions in binary form must reproduce the above copyright notice,+ this list of conditions and the following disclaimer in the documentation+ and/or other materials provided with the distribution.++THIS SOFTWARE IS PROVIDED BY THE FREEBSD PROJECT ``AS IS'' AND ANY EXPRESS OR+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT+SHALL THE FREEBSD PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Main.hs view
@@ -0,0 +1,457 @@+{-# OPTIONS -fglasgow-exts #-}++module Main where++import IO+import HNM.WLAN+import Data.List+import Data.Tree+import System.IO+import Data.IORef+import GHC.IOBase+import Data.Maybe+import System.Exit+import System.Process+import Graphics.UI.Gtk hiding (disconnect)+import System.IO.Unsafe+import Text.Regex.Posix+import System.Posix.User+import System.Environment+import Control.Concurrent+import Control.Monad.State+import System.Glib.Signals (on)+import Graphics.UI.Gtk.ModelView+import Graphics.UI.Gtk.ModelView.TreeStore+import qualified Graphics.UI.Gtk.Display.StatusIcon as I++--import HNM.Settings++main :: IO Int+main = assu (start =<< getArgs) warn+ ++warn :: IO Int+warn = do+ warnVisual MessageError ButtonsOk appName $+ "You have to be root to run " ++ appName ++ "!"+ return 1++warnVisual :: MessageType → ButtonsType → String → String → IO ResponseId+warnVisual mt bt tt msg = do+ putStrLn msg+ initGUI+ windowSetDefaultIconName "gtk-network"+ dlg ← messageDialogNewWithMarkup Nothing [] mt bt msg+ windowSetTitle dlg tt+ onResponse dlg (\_ → widgetDestroy dlg)+ dialogRun dlg+++start :: [String] → IO Int+start [] = do+ is@(i:_) ← getInterfaces+ withArgs is $ start is+start [interface] = do+ putStrLn interface+ initGUI+ windowSetDefaultIconName "gtk-network"+ icn ← statusIcon+ win ← mainWindowNew+ mainWindow =: win+ taskbarIcon =: icn+ statusIconSetVisible icn True+ mainGUI+ return 0+start [interface,driver] = do+ putStrLn driver+ initHardware driver interface+ start [interface]+++interfaceArg :: IO Interface+interfaceArg = return . (\(i:_) → i) =<< getArgs++refresh :: IO ()+refresh = refresh2++refresh1 :: IO ()+refresh1 = do+ putStrLn "refresh"+ win ← readIORef mainWindow+ widgetDestroy win+ xxx ← mainWindowNew+ mainWindow =: xxx+ return ()+++{-# NOINLINE mainWindow #-}+mainWindow :: IORef Window+mainWindow = unsafePerformIO $ newIORef $ unsafePerformIO mainWindowNew++{-# NOINLINE mainBox #-}+mainBox :: IORef VBox+mainBox = unsafePerformIO $ newIORef undefined++{-# NOINLINE mainView #-}+mainView :: IORef TreeView+mainView = unsafePerformIO $ newIORef undefined++{-# NOINLINE taskbarIcon #-}+taskbarIcon :: IORef StatusIcon+taskbarIcon = unsafePerformIO $ newIORef undefined++{-# NOINLINE mainWindowVisibility #-}+mainWindowVisibility :: IORef Bool+mainWindowVisibility = unsafePerformIO $ newIORef True+++(=:) :: IORef a → a → IO a+r =: v = writeIORef r v >> return v+++alternateMainWindowVisibility :: IO ()+alternateMainWindowVisibility = do+ vis ← mutateUsing not mainWindowVisibility+ (if vis then widgetShow+ else widgetHide) =<< readIORef mainWindow+++mutateUsing :: (a → a) → IORef a → IO a+mutateUsing f r = (r =:) . f =<< x r+ where x = readIORef+++(⇆) :: a → a → IO a+c ⇆ d = do+ it ← interfaceArg+ cs ← getConnectionStatus it+ case cs of+ Connected _ _ → return d+ _ → return c++statusIcon :: IO StatusIcon+statusIcon = do+ stc ← stockConnect ⇆ stockDisconnect+ icn ← statusIconNewFromStock stc+ statusIconSetVisible icn True+ statusIconSetTooltip icn appName+ mnu ← mkmenu icn+ I.onPopupMenu icn $ \b a → do+ widgetShowAll mnu+ print (b,a)+ menuPopup mnu $ maybe Nothing (\b' -> Just (b',a)) b+ I.onActivate icn $+ alternateMainWindowVisibility+ return icn+ where+ mkmenu s = do+ m ← menuNew+ i ← interfaceArg+ mapM_ (mkitem m) [("gtk-refresh", refresh) ,+ ("gtk-disconnect", disconnect_ i),+ ("---", undefined) ,+ ("gtk-about", showAbout) ,+ ("---", undefined) ,+ ("gtk-quit", mainQuit) ]+ return m+ where+ mkitem menu ("---",_) = do+ menuShellAppend menu =<< separatorMenuItemNew+ mkitem menu (label,act) = do+ i ← imageMenuItemNewFromStock label+ menuShellAppend menu i+ onActivateLeaf i act+ return ()+++refresh2 :: IO ()+refresh2 = do+ vbx ← readIORef mainBox+ vio ← readIORef mainView+ containerRemove vbx vio+ vin ← wlanTreeViewNew+ mainView =: vin+ containerAdd vbx vin+++mainWindowNew :: IO Window+mainWindowNew = do+ win ← windowNew+ vbx ← vBoxNew False 0++ mnu ← createMenu+ boxPackStart vbx mnu PackNatural 0++ view ← wlanTreeViewNew+ containerAdd vbx view++ sbr ← statusbarNew+ boxPackEnd vbx sbr PackNatural 0++{-txt ← textViewNew+ textViewSetEditable txt False+ widgetSetSizeRequest txt 0 160+ boxPackEnd vbx txt PackGrow 0-}+ + containerAdd win vbx+ + mainBox =: vbx+ mainView =: view++ windowSetTitle win appName++-- onDestroy win mainQuit+ widgetShowAll win++ return win +++wlanTreeViewNew :: IO TreeView+wlanTreeViewNew = do+ model ← wlanTreeModelNew+ view ← treeViewNewWithModel model+ cs@[c1,c2,c3,c4] ← replicateM 4 treeViewColumnNew+ mapM_ (\(c,t) → treeViewColumnSetTitle c t) $ zip cs+ ["essid", "quality", "encryption", "status"]+ [r1,r3] ← replicateM 2 cellRendererTextNew+ r2 ← cellRendererProgressNew+ r4 ← cellRendererToggleNew++ mapM_ (\(c,pc) → pc c) $+ zip cs ([pack r1,+ pack r2,+ pack r3,+ pack r4])++ treeViewColumnSetSizing c2 TreeViewColumnFixed+ treeViewColumnSetFixedWidth c2 150++ s ← getConnectionStatus =<< interfaceArg++ cellLayoutSetAttributes c1 r1 model $ \r → [ cellText := idof r ]+ cellLayoutSetAttributes c2 r2 model $ \r → [ cellProgressValue := qual r,+ cellProgressText := Just "" ]+ cellLayoutSetAttributes c3 r3 model $ \r → [ cellText := show (cencrypt r) ]+ cellLayoutSetAttributes c4 r4 model $ \r → [ cellToggleActive := conn s r,+ cellToggleRadio := True ]++ on r4 cellToggled (connect model)++ mapM_ (treeViewAppendColumn view) cs+ widgetShowAll view+ return view+ where+ idof r = if id == "" && ln == 1 then mac else id+ where+ id = cessid r+ cs@((mac,_):_) = ccell r+ ln = length cs+ qual = meanQuality . map snd . ccell+ pack r c = cellLayoutPackStart c r True -- continuation+ conn NotConnected _ = False+ conn (Connected _ cid) r = cid == cessid r+ connect model pathStr = do+ r ← treeStoreGetValue model path+ case cencrypt r of+ None → ((flip connectFree) (cessid r) =<< interfaceArg) >> refresh+ _ → connectUsingSettings (cessid r)+ where+ path = stringToTreePath pathStr++connectUsingSettings :: SSID → IO ()+connectUsingSettings id = do+ it ← interfaceArg+ ms ← return . find (settingEq id) =<< readSettings+ case ms of+ Just s → connect it s >> refresh+ _ → (warnVisual MessageError ButtonsOk appName $+ "No configuration for encrypted network " ++ id +++ " found in " ++ settingsFile ++ "!") >> return ()+ where+ settingEq id (Encrypted sid _ _) = id == sid+ settingEq _ _ = False++settingsFile :: String+settingsFile = "settings.conf"++readSettings :: IO [ConnectionSetting]+readSettings = return . read =<< readFile settingsFile++wlanTreeModelNew :: IO (TreeStore CWLAN)+wlanTreeModelNew = do+ treeStoreNew . (map cwlanToNode) . compact =<< getWLANs =<< interfaceArg++cwlanToNode :: CWLAN → Tree CWLAN+cwlanToNode w = Node w s+ where+ s = if ln > 1 then map (c2w w) cs else []+ where+ cs = ccell w+ ln = length cs+ c2w w c = Node (CWLAN (fst c) (cencrypt w) [([],snd c)]) []+++wlanTableNew :: IO Table+wlanTableNew = do+ it ← interfaceArg+ ws ← getWLANs it+ ln ← (return . length) ws+ tb ← tableNew 5 (ln + 2) False+ attach ws ln tb it+ where+ attach ws ln tb it = do+ att 0 =<< markup "<b>essid</b>" =<< label+ att 1 =<< markup "<b>quality</b>" =<< label+ att 2 =<< markup "<b>encryption</b>" =<< label+ att 3 =<< markup "<b>password</b>" =<< label+ att 4 =<< markup "<b>action</b>" =<< label+ populate tb ws =<< getConnectionStatus it+ return tb+ where+ att = \c w → tableAttach tb w c (c+1) 0 (0+1) exfi [] padd padd+++label = labelNew Nothing+markup = \m l → labelSetMarkup l m >> return l+settext = \t l → labelSetText l t >> return l+c f a l = f l a >> return l+ ++populate :: Table → [WLAN] → ConnectionStatus → IO ()+populate tb [] _ = return ()+populate tb ws cs = adr tb 1 (compact ws)+ where+ adr tb i [] = return ()+ adr tb i (w:ws) = do+-- ad0 0 =<< labelNew (Just id)+ ad0 0 =<< c labelSetAngle (0 ? 25) =<< settext id =<< label+ ad1 1 =<< pbar ql+ ad0 2 =<< labelNew (Just (show en))+ get ← pb+ doif (any (en ==) [None, WEP]) (ad4 4 =<< cbt get id)+ adr tb (i+1) ws+ where+ (?) = \a b → case cs of NotConnected → a; Connected _ ci → if (ci == id) then b else a+ cnc = case cs of Connected _ _ → True; _ → False+ cid = case cs of Connected _ cid → cid; _ → []+ bd = ("<b>" ++ ) . ( ++ "</b>")+ id = cessid w+ en = cencrypt w+ us = ccell w+ ln = length us+ qs = map snd us+ ql = mean $ map (fromInteger . toInteger) qs+ ad0 = \c w → tableAttach tb w c (c+1) i (i+1) ox oy px py+ ad1 = \c w → tableAttach tb w c (c+1) i (i+1) ox oy px py+ ad3 = \c w → tableAttach tb w c (c+1) i (i+1) ox oy px py+ ad4 = \c w → tableAttach tb w c (c+1) i (i+1) ox oy px py+ ox = exfi+ oy = []+ px = padd+ py = padd+ pb = do+ if any (en ==) [WEP] && (cid /= id)+ then do+ entry ← entryNew+-- entrySetVisibility entry False+ ad3 3 entry+ return $ Just (entryGetText entry)+ else do+ return $ Nothing+ cbt = \get ssid → do+ btn ← buttonNew+ buttonSetRelief btn ReliefNone+ buttonSetUseStock btn True+ buttonSetLabel btn ("gtk-connect" ? "gtk-disconnect")+ int ← interfaceArg+ onClicked btn $ (connectOBS int ssid en get) ? (disconnect_ int)+ return btn++exfi = [Expand,Fill]+padd = 4+++disconnect_ :: Interface → IO ()+disconnect_ interface = do+ disconnect interface+ ifconfig [interface, "up"]+ refresh+++connectOBS :: Interface → SSID → Encryption → Maybe (IO String) → IO ()+connectOBS interface ssid None Nothing = connectFree interface ssid >> refresh+connectOBS interface ssid WEP (Just getKey) = (connectWEP interface ssid =<< getKey) >> refresh+++pbar :: Double → IO ProgressBar+pbar val = do+ bar ← progressBarNew+ progressBarSetFraction bar (val / 100)+-- progressBarSetText bar $ show val+ return bar+++doif :: Monad m ⇒ Bool → m () → m ()+doif True act = act+doif False _ = return ()+++createMenu :: IO Widget+createMenu = do+ fma ← actionNew "FMA" "_File" Nothing Nothing+ hma ← actionNew "HMA" "_Help" Nothing Nothing++ refa ← actionNew "REFA" "_Refresh" (Just "stub") (Just stockRefresh)+ exia ← actionNew "EXIA" "_Quit" (Just "stub") (Just stockQuit)++ aboa ← actionNew "ABOA" "_About" (Just "stub") (Just stockAbout)++ agr ← actionGroupNew "AGR"+ mapM_ (actionGroupAddAction agr) [fma,hma]+ mapM_ (\act → actionGroupAddActionWithAccel agr act Nothing) [refa,exia,aboa]++ onActionActivate refa refresh+ onActionActivate exia mainQuit+ onActionActivate aboa showAbout+ + ui ← uiManagerNew+ uiManagerAddUiFromString ui menuDecl+ uiManagerInsertActionGroup ui agr 0+ + maybeMenubar ← uiManagerGetWidget ui "/ui/menubar"+ return $ fromJust maybeMenubar++menuDecl = "<ui>\+\ <menubar>\+\ <menu action=\"FMA\">\+\ <menuitem action=\"REFA\" />\+\ <menuitem action=\"EXIA\" />\+\ </menu>\+\ <menu action=\"HMA\">\+\ <menuitem action=\"ABOA\" />\+\ </menu>\+\ </menubar>\+\ </ui>"+++appName :: String+appName = "Happy Network Manager"+++showAbout :: IO ()+showAbout = do+ dlg ← aboutDialogNew+ lcs ← readFile "LICENSE" -- tryReadFile+ set dlg [+ aboutDialogName := "Happy Network Manager",+ aboutDialogVersion := "0.1",+ aboutDialogComments := "A quick and dirty applet to help you connect to wireless networks.",+ aboutDialogCopyright := "Copyright © 2008 Cetin Sert",+ aboutDialogWebsite := "http://sert.homedns.org/hs/hnm/",+ aboutDialogLicense := (Just lcs),+ aboutDialogAuthors := ["cs ^.^", "CS *^o^*"],+ aboutDialogLogoIconName := (Just "gtk-network")+ ]+ onResponse dlg (\_ → widgetDestroy dlg)+ dialogRun dlg+ return ()
+ Makefile view
@@ -0,0 +1,29 @@+DIST_PRE = HNM+TODAY = $(shell date +%Y%m%d)+VERSION = $(./version)+DIST_NAME = $(DIST_PRE)-$(VERSION)+++.PHONY: all configure build install dist clean++default all: configure build++configure:+ runhaskell Setup.hs configure++build:+ runhaskell Setup.hs build++install:+ runhaskell Setup.hs install++dist:+ cabal sdist++clean:+ -runhaskell Setup.hs clean+ -rm -rf dist+ $(MAKE) -C test clean++setup: Setup.lhs+ ghc --make -package Cabal -o setup Setup.hs
+ README view
@@ -0,0 +1,1 @@+Happy Network Manager
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ settings.conf view
@@ -0,0 +1,3 @@+[+Encrypted "o2DSL" (WEP ) "gLcfefcJcYnSU"+]