simpleirc (empty) → 0.1.0
raw patch · 8 files changed
+716/−0 lines, 8 filesdep +basedep +bytestringdep +containerssetup-changed
Dependencies added: base, bytestring, containers, network, old-locale, time
Files
- Network/SimpleIRC.hs +29/−0
- Network/SimpleIRC/Core.hs +340/−0
- Network/SimpleIRC/Messages.hs +143/−0
- Network/SimpleIRC/Types.hs +106/−0
- Network/SimpleIRC/Utils.hs +29/−0
- Setup.hs +4/−0
- license +25/−0
- simpleirc.cabal +40/−0
+ Network/SimpleIRC.hs view
@@ -0,0 +1,29 @@+-- |+-- Module : Network.SimpleIRC+-- Copyright : (c) Dominik Picheta 2010+-- License : BSD3+--+-- Maintainer : morfeusz8@gmail.com+-- Stability : Alpha+-- Portability : portable+--+-- Simple and efficient IRC Library+--+module Network.SimpleIRC (+ -- * Core+ module Network.SimpleIRC.Core++ -- * Messages+ , module Network.SimpleIRC.Messages+ + -- * Utils+ , module Network.SimpleIRC.Utils+ + -- * Types+ , module Network.SimpleIRC.Types+ ) where++import Network.SimpleIRC.Core+import Network.SimpleIRC.Messages+import Network.SimpleIRC.Utils+import Network.SimpleIRC.Types
+ Network/SimpleIRC/Core.hs view
@@ -0,0 +1,340 @@+-- |+-- Module : Network.SimpleIRC.Core+-- Copyright : (c) Dominik Picheta 2010+-- License : BSD3+--+-- Maintainer : morfeusz8@gmail.com+-- Stability : provisional+-- Portability : portable+--+-- For information on how to use this library please take a look at the readme file on github, <http://github.com/dom96/SimpleIRC#readme>.+{-# LANGUAGE OverloadedStrings #-}+module Network.SimpleIRC.Core+ ( + -- * Functions+ connect+ , disconnect+ , sendRaw+ , sendMsg+ , sendCmd+ , addEvent+ , changeEvents+ , remEvent+ , defaultConfig+ ) where+ +import Network+import System.IO+import Data.Maybe+import Data.Char (isNumber)+import Control.Monad+import Control.Concurrent+import Control.Concurrent.Chan+import Network.SimpleIRC.Messages+import Network.SimpleIRC.Types+import Network.SimpleIRC.Utils+import Data.Unique+import System.IO.Error+import Data.Time+import System.Locale+import qualified Data.ByteString.Char8 as B+import qualified Data.Map as Map++internalEvents = [joinChans, pong, onJoin]+internalNormEvents = [Privmsg ctcpHandler]++-- |Connects to a server+connect :: IrcConfig -- ^ Configuration+ -> Bool -- ^ Run in a new thread+ -> Bool -- ^ Print debug messages+ -> IO (Either IOError IrcServer) -- ^ IrcServer instance+connect config threaded debug = try $ do+ if debug+ then B.putStrLn $ "Connecting to " `B.append` (B.pack $ cAddr config)+ else return ()+ h <- connectTo (cAddr config) (PortNumber $ fromIntegral $ cPort config)+ hSetBuffering h NoBuffering+ + cmdChan <- newChan+ + server <- toServer config h cmdChan debug+ -- Initialize connection with the server+ greetServer server+ + -- Start listening+ if threaded+ then do listenId <- forkIO (listenLoop server)+ return server {sListenThread = Just listenId}+ else do listenLoop server+ return server+ +-- |Sends a QUIT command to the server.+disconnect :: IrcServer+ -> B.ByteString -- ^ Quit message+ -> IO ()+disconnect server quitMsg = do+ write server $ "QUIT :" `B.append` quitMsg+ return ()+ where h = fromJust $ sSock server++genUnique :: IrcEvent -> IO (Unique, IrcEvent)+genUnique e = do+ u <- newUnique+ return (u, e)++genUniqueMap :: [IrcEvent] -> IO (Map.Map Unique IrcEvent)+genUniqueMap events = do+ uEvents <- mapM genUnique events+ return $ Map.fromList uEvents++toServer :: IrcConfig -> Handle -> Chan SIrcCommand -> Bool -> IO IrcServer+toServer config h cmdChan debug = do+ uniqueEvents <- genUniqueMap $ internalNormEvents ++ (cEvents config)++ return $ IrcServer (B.pack $ cAddr config) (cPort config)+ (B.pack $ cNick config) (B.pack $ cUsername config) + (B.pack $ cRealname config) (map B.pack $ cChannels config) + uniqueEvents (Just h) Nothing cmdChan debug+ (cCTCPVersion config) (cCTCPTime config)++greetServer :: IrcServer -> IO IrcServer+greetServer server = do+ write server $ "NICK " `B.append` nick+ write server $ "USER " `B.append` user `B.append` " " `B.append`+ user `B.append` " " `B.append` addr `B.append` " :" `B.append` real+ + return server+ where nick = sNickname server+ user = sUsername server+ real = sRealname server+ addr = sAddr server++-- TODO: I think this should execute all commands that are available.+execCmds :: IrcServer -> IO IrcServer+execCmds server = do+ empty <- isEmptyChan $ sCmdChan server+ if not $ empty + then do cmd <- readChan $ sCmdChan server+ case cmd of (SIrcAddEvent uEvent) -> return server {sEvents = Map.insert (fst uEvent) (snd uEvent) (sEvents server)}+ (SIrcChangeEvents events) -> return server {sEvents = events}+ (SIrcRemoveEvent key) -> return server {sEvents = Map.delete key (sEvents server)}+ else return server++listenLoop :: IrcServer -> IO ()+listenLoop s = do+ server <- execCmds s++ let h = fromJust $ sSock server+ eof <- hIsEOF h+ -- If EOF then we are disconnected+ if eof + then do+ let comp = (\a -> a `eqEvent` (Disconnect undefined))+ events = Map.filter comp (sEvents server)+ eventCall = (\obj -> (eventFuncD $ snd obj) server)+ debugWrite s $ B.pack $ show $ length $ Map.toList events+ mapM eventCall (Map.toList events)+ return ()+ else do+ line <- B.hGetLine h+ debugWrite s $ (B.pack ">> ") `B.append` line+ + newServ <- foldM (\s f -> f s (parse line)) server internalEvents+ + callEvents newServ (parse line)++ listenLoop newServ+ +-- Internal Events - They can edit the server+joinChans :: IrcServer -> IrcMessage -> IO IrcServer+joinChans server msg = do+ if code == "001"+ then do mapM (\chan -> write server $ "JOIN " `B.append` chan) (sChannels server)+ return server {sChannels = []}+ else return server+ where h = fromJust $ sSock server+ code = mCode msg++pong :: IrcServer -> IrcMessage -> IO IrcServer+pong server msg = do+ if code == "PING"+ then do+ write server $ "PONG :" `B.append` pingMsg+ return server+ else return server+ + where h = fromJust $ sSock server+ pingMsg = mMsg msg+ code = mCode msg++onJoin :: IrcServer -> IrcMessage -> IO IrcServer+onJoin server msg+ | code == "JOIN" = do+ let nick = fromJust $ mNick msg+ chan = mMsg msg+ if nick == sNickname server+ then return server { sChannels = chan:(sChannels server) }+ else return server+ | otherwise = return server+ + where code = mCode msg++-- Internal normal events+ctcpHandler :: EventFunc+ctcpHandler server iMsg+ | msg == "\x01VERSION\x01" =+ sendCmd server+ (MNotice chan ("\x01VERSION " `B.append`+ (B.pack $ sCTCPVersion server) `B.append` "\x01"))+ | msg == "\x01TIME\x01" = do+ time <- sCTCPTime server+ sendCmd server+ (MNotice chan ("\x01TIME " `B.append`+ (B.pack time) `B.append` "\x01"))+ | otherwise = return ()+ where msg = mMsg iMsg+ chan = getChan server iMsg+-- Event code+events :: IrcServer -> IrcEvent -> IrcMessage -> IO ()+events server event msg = do+ mapM eventCall (Map.toList events)+ return ()+ where comp = (\a -> a `eqEvent` event)+ events = Map.filter comp (sEvents server)+ eventCall = (\obj -> (eventFunc $ snd obj) server msg)++callEvents :: IrcServer -> IrcMessage -> IO ()+callEvents server msg+ | mCode msg == "PRIVMSG" = do+ events server (Privmsg undefined) msg+ + | mCode msg == "PING" = do+ events server (Ping undefined) msg++ | mCode msg == "JOIN" = do+ events server (Join undefined) msg+ + | mCode msg == "PART" = do+ events server (Part undefined) msg++ | mCode msg == "MODE" = do+ events server (Mode undefined) msg++ | mCode msg == "TOPIC" = do+ events server (Topic undefined) msg++ | mCode msg == "INVITE" = do+ events server (Invite undefined) msg++ | mCode msg == "KICK" = do+ events server (Kick undefined) msg++ | mCode msg == "QUIT" = do+ events server (Quit undefined) msg++ | mCode msg == "NICK" = do+ events server (Nick undefined) msg++ | mCode msg == "NOTICE" = do+ events server (Notice undefined) msg++ | B.all isNumber (mCode msg) = do+ events server (Numeric undefined) msg+ + | otherwise = do+ events server (RawMsg undefined) msg++(Privmsg _) `eqEvent` (Privmsg _) = True+(Numeric _) `eqEvent` (Numeric _) = True+(Ping _) `eqEvent` (Ping _) = True+(Join _) `eqEvent` (Join _) = True+(Part _) `eqEvent` (Part _) = True+(Mode _) `eqEvent` (Mode _) = True+(Topic _) `eqEvent` (Topic _) = True+(Invite _) `eqEvent` (Invite _) = True+(Kick _) `eqEvent` (Kick _) = True+(Quit _) `eqEvent` (Quit _) = True+(Nick _) `eqEvent` (Nick _) = True+(Notice _) `eqEvent` (Notice _) = True+(RawMsg _) `eqEvent` (RawMsg _) = True+(Disconnect _) `eqEvent` (Disconnect _) = True+_ `eqEvent` _ = False++eventFunc :: IrcEvent -> EventFunc+eventFunc (Privmsg f) = f+eventFunc (Numeric f) = f+eventFunc (Ping f) = f+eventFunc (Join f) = f+eventFunc (Part f) = f+eventFunc (Mode f) = f+eventFunc (Topic f) = f+eventFunc (Invite f) = f+eventFunc (Kick f) = f+eventFunc (Quit f) = f+eventFunc (Nick f) = f+eventFunc (Notice f) = f+eventFunc (RawMsg f) = f++eventFuncD (Disconnect f) = f++-- |Sends a raw command to the server+sendRaw :: IrcServer -> B.ByteString -> IO ()+sendRaw server msg = write server msg++-- |Sends a message to a channel++-- |Please note: As of now this function doesn't provide flood control.+-- So be careful.+sendMsg :: IrcServer + -> B.ByteString -- ^ Channel+ -> B.ByteString -- ^ Message+ -> IO ()+sendMsg server chan msg = do+ mapM (s) lins+ return ()+ where lins = B.lines msg+ s m = sendCmd server (MPrivmsg chan m)+sendCmd :: IrcServer+ -> Command -- Command to send+ -> IO ()+sendCmd server cmd =+ sendRaw server (showCommand cmd)++addEvent :: IrcServer -> IrcEvent -> IO Unique+addEvent s event = do+ u <- newUnique+ writeChan (sCmdChan s) (SIrcAddEvent (u, event))+ return u++changeEvents :: IrcServer -> [IrcEvent] -> IO ()+changeEvents s events = do+ uniqueEvents <- genUniqueMap events+ writeChan (sCmdChan s) (SIrcChangeEvents uniqueEvents)++remEvent :: IrcServer -> Unique -> IO ()+remEvent s uniq = do+ writeChan (sCmdChan s) (SIrcRemoveEvent uniq)++debugWrite :: IrcServer -> B.ByteString -> IO ()+debugWrite s msg = do+ if sDebug s+ then B.putStrLn msg+ else return ()++write :: IrcServer -> B.ByteString -> IO ()+write s msg = do+ debugWrite s $ "<< " `B.append` msg `B.append` "\\r\\n"+ B.hPutStr h (msg `B.append` "\r\n")+ where h = fromJust $ sSock s+ ++defaultConfig = IrcConfig+ { cPort = 6667+ , cUsername = "simpleirc"+ , cRealname = "SimpleIRC Bot"+ , cChannels = []+ , cEvents = []+ , cCTCPVersion = "SimpleIRC v0.1"+ , cCTCPTime = getZonedTime >>= + (\t -> return $ formatTime defaultTimeLocale "%c" t)+ }
+ Network/SimpleIRC/Messages.hs view
@@ -0,0 +1,143 @@+-- |+-- Module : Network.SimpleIRC.Core+-- Copyright : (c) Dominik Picheta 2010+-- License : BSD3+--+-- Maintainer : morfeusz8@gmail.com+-- Stability : provisional+-- Portability : portable+--+-- Messages module+--+{-# LANGUAGE OverloadedStrings #-}+module Network.SimpleIRC.Messages + ( Command(..)+ , parse+ , showCommand + ) +where+import Data.Maybe+import Network.SimpleIRC.Types+import qualified Data.ByteString.Char8 as B++-- PING :asimov.freenode.net+-- :haskellTestBot!~test@host86-177-151-242.range86-177.btcentralplus.com JOIN :#()++-- :dom96!~dom96@unaffiliated/dom96 PRIVMSG #() :it lives!+-- :haskellTestBot MODE haskellTestBot :+i+-- :asimov.freenode.net 376 haskellTestBot :End of /MOTD command.++-- :asimov.freenode.net 332 haskellTestBot #() :Parenthesis++-- :asimov.freenode.net 333 haskellTestBot #() Raynes!~macr0@unaffiliated/raynes 1281221819++data Command = Command+ | MPrivmsg B.ByteString B.ByteString -- ^ PRIVMSG #chan :msg+ | MJoin B.ByteString (Maybe B.ByteString) -- ^ JOIN #chan key+ | MPart B.ByteString B.ByteString -- ^ PART #chan :msg+ | MMode B.ByteString B.ByteString + (Maybe B.ByteString) -- ^ MODE #chan +o user+ | MTopic B.ByteString (Maybe B.ByteString) -- ^ TOPIC #chan :topic+ | MInvite B.ByteString B.ByteString -- ^ INVITE user #chan+ | MKick B.ByteString B.ByteString B.ByteString -- ^ KICK #chan user :msg+ | MQuit B.ByteString -- ^ QUIT :msg+ | MNick B.ByteString -- ^ NICK newnick+ | MNotice B.ByteString B.ByteString -- ^ NOTICE usr/#chan :msg+ | MAction B.ByteString B.ByteString -- ^ PRIVMSG usr/#chan :\\x01ACTION msg\\x01+ deriving (Eq, Read, Show)++-- |Parse a raw IRC message+parse :: B.ByteString -> IrcMessage+parse txt = + case length split of 2 -> (parse2 split) txt+ 3 -> (parse3 split) txt+ 4 -> (parse4 split) txt + 5 -> (parse5 split) txt+ otherwise -> (parseOther split) txt+ + where split = smartSplit (takeCarriageRet txt)++parse4 :: [B.ByteString] -> (B.ByteString -> IrcMessage)+parse4 (first:code:chan:msg:_) = + let (nick, host, server) = parseFirst first+ in IrcMessage nick host server (code)+ (dropColon msg) (Just chan) Nothing++-- Nick, Host, Server+parseFirst :: B.ByteString -> (Maybe B.ByteString, Maybe B.ByteString, Maybe B.ByteString)+parseFirst first = + if '!' `B.elem` first+ then let (nick, host) = B.break (== '!') (dropColon first)+ in (Just nick, Just host, Nothing)+ else (Nothing, Nothing, Just $ dropColon first) ++dropColon :: B.ByteString -> B.ByteString+dropColon xs =+ if B.take 1 xs == (B.pack ":")+ then B.drop 1 xs+ else xs++parse2 :: [B.ByteString] -> (B.ByteString -> IrcMessage)+parse2 (code:msg:_) =+ IrcMessage Nothing Nothing Nothing (code)+ (dropColon msg) Nothing Nothing+ +parse3 :: [B.ByteString] -> (B.ByteString -> IrcMessage)+parse3 (first:code:msg:_) =+ let (nick, host, server) = parseFirst first+ in IrcMessage nick host server (code) (dropColon msg) Nothing Nothing+ +parse5 :: [B.ByteString] -> (B.ByteString -> IrcMessage)+parse5 (server:code:nick:chan:msg:_) =+ IrcMessage (Just nick) Nothing (Just server) (code)+ (dropColon msg) (Just chan) Nothing++parseOther :: [B.ByteString] -> (B.ByteString -> IrcMessage)+parseOther (server:code:nick:chan:other) =+ IrcMessage (Just nick) Nothing (Just server) (code)+ (B.unwords other) (Just chan) (Just other)++smartSplit :: B.ByteString -> [B.ByteString]+smartSplit txt+ | ':' `B.elem` (dropColon txt) =+ let (first, msg) = B.break (== ':') (dropColon txt)+ in (B.words $ takeLast first) ++ [msg]+ | otherwise = B.words $ txt++takeLast :: B.ByteString -> B.ByteString+takeLast xs = B.take (B.length xs - 1) xs++takeCarriageRet :: B.ByteString -> B.ByteString+takeCarriageRet xs = + if B.drop (B.length xs - 1) xs == (B.pack "\r")+ then takeLast xs+ else xs++showCommand :: Command -> B.ByteString+showCommand (MPrivmsg chan msg) = "PRIVMSG " `B.append` chan `B.append`+ " :" `B.append` msg+showCommand (MJoin chan (Just key)) = "JOIN " `B.append` chan `B.append` + " " `B.append` key+showCommand (MJoin chan Nothing) = "JOIN " `B.append` chan+showCommand (MPart chan msg) = "PART " `B.append` chan `B.append` + " :" `B.append` msg+showCommand (MMode chan mode (Just usr)) = "MODE " `B.append` chan `B.append`+ " " `B.append` mode `B.append`+ " " `B.append` usr+showCommand (MMode chan mode Nothing) = "MODE " `B.append` chan `B.append`+ " " `B.append` mode+showCommand (MTopic chan (Just msg)) = "TOPIC " `B.append` chan `B.append`+ " :" `B.append` msg+showCommand (MTopic chan Nothing) = "TOPIC " `B.append` chan+showCommand (MInvite usr chan) = "INVITE " `B.append` usr `B.append`+ " " `B.append` chan+showCommand (MKick chan usr msg) = "KICK " `B.append` chan `B.append`+ " " `B.append` usr `B.append`+ " :" `B.append` msg+showCommand (MQuit msg) = "QUIT :" `B.append` msg+showCommand (MNick nick) = "NICK " `B.append` nick+showCommand (MNotice chan msg) = "NOTICE " `B.append` chan `B.append`+ " :" `B.append` msg+showCommand (MAction chan msg) = showCommand $ MPrivmsg chan+ ("\x01 ACTION " `B.append` msg+ `B.append` "\x01")
+ Network/SimpleIRC/Types.hs view
@@ -0,0 +1,106 @@+{-# LANGUAGE DeriveDataTypeable #-}+module Network.SimpleIRC.Types+ ( + -- * Datatypes+ IrcConfig(..)+ , IrcServer(..)+ , SIrcCommand(..)+ , IrcEvent(..)+ , EventFunc+ , IrcMessage(..)+ ) where+import qualified Data.ByteString.Char8 as B+import Control.Concurrent (ThreadId)+import Control.Concurrent.Chan (Chan)+import System.IO (Handle)+import Data.Unique (Unique)+import Data.Map (Map)+import Data.Typeable++data IrcConfig = IrcConfig+ { cAddr :: String -- ^ Server address to connect to+ , cPort :: Int -- ^ Server port to connect to+ , cNick :: String -- ^ Nickname+ , cUsername :: String -- ^ Username+ , cRealname :: String -- ^ Realname+ , cChannels :: [String] -- ^ List of channels to join on connect+ , cEvents :: [IrcEvent] -- ^ Events to bind+ , cCTCPVersion :: String -- ^ What to send on CTCP VERSION+ , cCTCPTime :: IO String -- ^ What to send on CTCP TIME+ }+++data SIrcCommand =+ SIrcAddEvent (Unique, IrcEvent)+ | SIrcChangeEvents (Map Unique IrcEvent)+ | SIrcRemoveEvent Unique+ +data IrcServer = IrcServer+ { sAddr :: B.ByteString+ , sPort :: Int+ , sNickname :: B.ByteString+ , sUsername :: B.ByteString+ , sRealname :: B.ByteString+ , sChannels :: [B.ByteString]+ , sEvents :: Map Unique IrcEvent+ , sSock :: Maybe Handle+ , sListenThread :: Maybe ThreadId+ , sCmdChan :: Chan SIrcCommand+ , sDebug :: Bool+ -- Other info+ , sCTCPVersion :: String+ , sCTCPTime :: IO String+ }++type EventFunc = (IrcServer -> IrcMessage -> IO ())++-- When adding events here, remember add them in callEvents and in eventFunc+-- AND also in the Show instance and Eq instance++data IrcEvent = + Privmsg EventFunc -- ^ PRIVMSG+ | Numeric EventFunc -- ^ Numeric, 001, 002, 372 etc.+ | Ping EventFunc -- ^ PING+ | Join EventFunc -- ^ JOIN+ | Part EventFunc -- ^ PART+ | Mode EventFunc -- ^ MODE+ | Topic EventFunc -- ^ TOPIC+ | Invite EventFunc -- ^ INVITE+ | Kick EventFunc -- ^ KICK+ | Quit EventFunc -- ^ QUIT+ | Nick EventFunc -- ^ NICK+ | Notice EventFunc -- ^ NOTICE+ | RawMsg EventFunc -- ^ This event gets called on every message received+ | Disconnect (IrcServer -> IO ()) -- ^ This event gets called whenever the+ -- connection with the server is dropped+ + +instance Show IrcEvent where+ show (Privmsg _) = "IrcEvent - Privmsg"+ show (Numeric _) = "IrcEvent - Numeric"+ show (Ping _) = "IrcEvent - Ping"+ show (Join _) = "IrcEvent - Join"+ show (Part _) = "IrcEvent - Part"+ show (Mode _) = "IrcEvent - Mode"+ show (Topic _) = "IrcEvent - Topic"+ show (Invite _) = "IrcEvent - Invite"+ show (Kick _) = "IrcEvent - Kick"+ show (Quit _) = "IrcEvent - Quit"+ show (Nick _) = "IrcEvent - Nick"+ show (Notice _) = "IrcEvent - Notice"+ show (RawMsg _) = "IrcEvent - RawMsg"+ show (Disconnect _) = "IrcEvent - Disconnect"+ +data IrcMessage = IrcMessage+ { mNick :: Maybe B.ByteString+ , mHost :: Maybe B.ByteString+ , mServer :: Maybe B.ByteString+ , mCode :: B.ByteString+ , mMsg :: B.ByteString+ , mChan :: Maybe B.ByteString+ , mOther :: Maybe [B.ByteString]+ , mRaw :: B.ByteString+ } deriving (Show, Typeable)+ + +
+ Network/SimpleIRC/Utils.hs view
@@ -0,0 +1,29 @@+-- |+-- Module : Network.SimpleIRC.Core+-- Copyright : (c) Dominik Picheta 2010+-- License : BSD3+--+-- Maintainer : morfeusz8@gmail.com+-- Stability : provisional+-- Portability : portable+--+-- Utils module+--++module Network.SimpleIRC.Utils+ ( + -- * Functions+ getChan+ ) where+import Network.SimpleIRC.Types+import qualified Data.ByteString.Char8 as B+import Data.Maybe (fromJust)+ +-- |If the IrcMessage was sent directly to you returns the nick otherwise the channel.+getChan :: IrcServer -> IrcMessage -> B.ByteString+getChan s m =+ if sNickname s == chan+ then (fromJust $ mNick m)+ else chan+ + where chan = fromJust $ mChan m
+ Setup.hs view
@@ -0,0 +1,4 @@+import Distribution.Simple++main :: IO ()+main = defaultMain
+ license view
@@ -0,0 +1,25 @@+Copyright (c) 2010, Dominik Picheta <morfeusz8@gmail.com>+All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:+ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.+ * 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.+ * Neither the name of the author nor the+ names of its contributors may be used to endorse or promote products+ derived from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 DOMINIK PICHETA 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.+
+ simpleirc.cabal view
@@ -0,0 +1,40 @@+Name: simpleirc+Version: 0.1.0+Category: Network, IRC+Synopsis: Simple IRC Library+Package-URL: http://code.haskell.org/fastirc/+Maintainer: Dominik Picheta <dominikpicheta@googlemail.com>+Author: Dominik Picheta <dominikpicheta@googlemail.com>+Copyright: (c) 2010 Dominik Picheta+License: BSD3+License-file: license+Homepage: http://github.com/dom96/SimpleIRC +Build-type: Simple+Stability: provisional+Cabal-version: >= 1.6+Description:+ Simple IRC Library. This IRC Library aims to be simple and lightweight.++Source-repository head+ Type: git+ Location: git://github.com/dom96/SimpleIRC.git++Source-repository this+ Type: git+ Location: git://github.com/dom96/SimpleIRC.git+ tag: V0.1.0++Library+ Build-depends:+ base >= 4 && < 5,+ bytestring >= 0.9.1.7,+ network >= 2.2.1.7,+ containers >= 0.3.0.0,+ time >= 1.1.4,+ old-locale >= 1.0.0.2+ Exposed-modules:+ Network.SimpleIRC+ Network.SimpleIRC.Core+ Network.SimpleIRC.Messages+ Network.SimpleIRC.Utils+ Network.SimpleIRC.Types