GrowlNotify 0.2 → 0.3
raw patch · 3 files changed
+84/−19 lines, 3 files
Files
- GrowlNotify.cabal +1/−1
- Network/GrowlNotify.hs +32/−13
- growlnotify.hs +51/−5
GrowlNotify.cabal view
@@ -1,5 +1,5 @@ Name: GrowlNotify-Version: 0.2+Version: 0.3 Author: Nick Burlett Maintainer: nickburlett@mac.com Description: Notification utility for Growl.
Network/GrowlNotify.hs view
@@ -1,3 +1,8 @@+-- | A network notification utility to work with Growl <http://growl.info/>. +-- +-- An application must register itself by sending a registrationPacket. Then, to send+-- a notification, send a notificationPacket. Any packet must have an md5sum tacked on+-- to the end before being sent. module Network.GrowlNotify ( registrationPacket , notificationPacket@@ -12,6 +17,7 @@ import qualified Char import Data.Digest.MD5 import Network.Socket+import Network.BSD growl_udp_port=9887@@ -24,9 +30,11 @@ putString :: String -> Put putString = do putLazyByteString . makeBS --- register this application and its notification with growl--- any notifications will be on by default-registrationPacket :: String -> [String] -> B.ByteString+-- | register this application and its notification with growl+-- | any notifications will be on by default+registrationPacket :: String -- ^ The name of this application+ -> [String] -- ^ A list of notifications+ -> B.ByteString -- ^ The packet registrationPacket appName notiNames = runPut $ do putWord8 growl_protocol_version putWord8 growl_type_registration@@ -43,12 +51,17 @@ putLazyByteString $ makeBS s lengthnames = length notiNames --- make a notification-notificationPacket :: String -> String -> String -> String -> B.ByteString-notificationPacket appName notification title description = runPut $ do+-- | Create a notification packet+notificationPacket :: Bool -- ^ True iff the notification should be sticky+ -> String -- ^ The name of this application+ -> String -- ^ The notification name+ -> String -- ^ The title of this notification+ -> String -- ^ The notification text+ -> B.ByteString -- ^ The packet+notificationPacket sticky appName notification title description = runPut $ do putWord8 growl_protocol_version putWord8 growl_type_notification- putWord16be 0+ putWord16be $ if sticky then 1 else 0 putLength notification putLength title putLength description@@ -60,21 +73,27 @@ where putLength = putWord16be . fromIntegral . length -addMD5Sum :: String -> B.ByteString -> B.ByteString+-- | Tack on the md5sum to the end of the message, with a (possibly empty) password+addMD5Sum :: String -- ^ The password+ -> B.ByteString -- ^ The packet (from notificationPacket or registrationPacket)+ -> B.ByteString -- ^ The message with appended md5sum, ready for sendMessage addMD5Sum password message = B.append message s where s = B.pack $ hash $ map fromIntegral $ B.unpack $ B.append message bspassword bspassword = makeBS password -sendMessage :: String -> B.ByteString -> IO ()+-- | Send the packet +sendMessage :: String -- ^ The server (an IP address or hostname)+ -> B.ByteString -- ^ The message (with md5sum) to send+ -> IO () sendMessage server m = do+ server' <- getHostByName server let d = map (Char.chr . fromIntegral) $ B.unpack m s <- socket AF_INET Datagram 0- write server s d+ write (hostAddress server') s d sClose s -write :: String -> Socket -> String -> IO ()-write server sock s = do- addr <- inet_addr server+write :: HostAddress -> Socket -> String -> IO ()+write addr sock s = do sendTo sock s (SockAddrInet (fromIntegral growl_udp_port) addr) return ()
growlnotify.hs view
@@ -1,14 +1,60 @@ import Network.GrowlNotify import System (getArgs)+import System.Console.GetOpt+import Data.Maybe ( fromMaybe ) main = do args <- getArgs- (server, password, title, message) <- case args of- server:password:title:message -> return $ (server, password, title, message)- _ -> error "Usage: server password title message"- let b = registrationPacket "growlnotify" ["Command-Line Growl Notification"]+ (opts, message) <- growlOpts args+ let Options { optSticky = sticky+ , optName = name+ , optNotification = notification+ , optTitle = title + , optServer = server+ , optPassword = password } = opts+ let b = registrationPacket name [notification] let m = addMD5Sum password b- let b2 = notificationPacket "growlnotify" "Command-Line Growl Notification" title (unwords message)+ let b2 = notificationPacket sticky name notification title (unwords message) let m2 = addMD5Sum password b2 sendMessage server m sendMessage server m2+++data Options = Options { optSticky :: Bool+ , optNotification :: String+ , optName :: String+ , optTitle :: String+ , optServer :: String+ , optPassword :: String+ }+ +startOptions :: Options+startOptions = Options { optSticky = False+ , optNotification = "Cmdline Growl Notification"+ , optName = "growlnotify"+ , optTitle = "Network Notification"+ , optServer = "127.0.0.1"+ , optPassword = ""+ }+ +options :: [OptDescr (Options -> IO Options)]+options =+ [ Option ['k'] ["sticky"] (NoArg (\opt -> return opt {optSticky=True}) ) "sticky message"+ , Option ['n'] ["programname"] (ReqArg (\arg opt -> return opt {optName=arg}) "NAME") "program registration NAME"+ , Option ['s'] ["server"] (ReqArg (\arg opt -> return opt {optServer=arg}) "SERVER") "growl SERVER"+ , Option ['p'] ["password"] (ReqArg (\arg opt -> return opt {optPassword=arg}) "PASSWORD") "growl PASSWORD"+ , Option ['N'] ["notification"] (ReqArg (\arg opt -> return opt {optNotification=arg}) "NOTIFICATION") "NOTIFICATION"+ , Option ['t'] ["title"] (ReqArg (\arg opt -> return opt {optTitle=arg}) "TITLE") "message TITLE"+ ]++++growlOpts :: [String] -> IO (Options, [String])+growlOpts argv = do+ -- Parse options, getting a list of option actions+ let (actions, nonOptions, errors) = getOpt RequireOrder options argv++ -- Here we thread startOptions through all supplied option actions+ opts <- foldl (>>=) (return startOptions) actions+ + return (opts, nonOptions)