packages feed

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 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