packages feed

irc-fun-client (empty) → 0.1.0.0

raw patch · 13 files changed

+730/−0 lines, 13 filesdep +basedep +irc-fun-messagesdep +networksetup-changed

Dependencies added: base, irc-fun-messages, network

Files

+ AUTHORS view
@@ -0,0 +1,1 @@+fr33domlover <fr33domlover@riseup.net>
+ COPYING view
@@ -0,0 +1,121 @@+Creative Commons Legal Code++CC0 1.0 Universal++    CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE+    LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN+    ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS+    INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES+    REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS+    PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM+    THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED+    HEREUNDER.++Statement of Purpose++The laws of most jurisdictions throughout the world automatically confer+exclusive Copyright and Related Rights (defined below) upon the creator+and subsequent owner(s) (each and all, an "owner") of an original work of+authorship and/or a database (each, a "Work").++Certain owners wish to permanently relinquish those rights to a Work for+the purpose of contributing to a commons of creative, cultural and+scientific works ("Commons") that the public can reliably and without fear+of later claims of infringement build upon, modify, incorporate in other+works, reuse and redistribute as freely as possible in any form whatsoever+and for any purposes, including without limitation commercial purposes.+These owners may contribute to the Commons to promote the ideal of a free+culture and the further production of creative, cultural and scientific+works, or to gain reputation or greater distribution for their Work in+part through the use and efforts of others.++For these and/or other purposes and motivations, and without any+expectation of additional consideration or compensation, the person+associating CC0 with a Work (the "Affirmer"), to the extent that he or she+is an owner of Copyright and Related Rights in the Work, voluntarily+elects to apply CC0 to the Work and publicly distribute the Work under its+terms, with knowledge of his or her Copyright and Related Rights in the+Work and the meaning and intended legal effect of CC0 on those rights.++1. Copyright and Related Rights. A Work made available under CC0 may be+protected by copyright and related or neighboring rights ("Copyright and+Related Rights"). Copyright and Related Rights include, but are not+limited to, the following:++  i. the right to reproduce, adapt, distribute, perform, display,+     communicate, and translate a Work;+ ii. moral rights retained by the original author(s) and/or performer(s);+iii. publicity and privacy rights pertaining to a person's image or+     likeness depicted in a Work;+ iv. rights protecting against unfair competition in regards to a Work,+     subject to the limitations in paragraph 4(a), below;+  v. rights protecting the extraction, dissemination, use and reuse of data+     in a Work;+ vi. database rights (such as those arising under Directive 96/9/EC of the+     European Parliament and of the Council of 11 March 1996 on the legal+     protection of databases, and under any national implementation+     thereof, including any amended or successor version of such+     directive); and+vii. other similar, equivalent or corresponding rights throughout the+     world based on applicable law or treaty, and any national+     implementations thereof.++2. Waiver. To the greatest extent permitted by, but not in contravention+of, applicable law, Affirmer hereby overtly, fully, permanently,+irrevocably and unconditionally waives, abandons, and surrenders all of+Affirmer's Copyright and Related Rights and associated claims and causes+of action, whether now known or unknown (including existing as well as+future claims and causes of action), in the Work (i) in all territories+worldwide, (ii) for the maximum duration provided by applicable law or+treaty (including future time extensions), (iii) in any current or future+medium and for any number of copies, and (iv) for any purpose whatsoever,+including without limitation commercial, advertising or promotional+purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each+member of the public at large and to the detriment of Affirmer's heirs and+successors, fully intending that such Waiver shall not be subject to+revocation, rescission, cancellation, termination, or any other legal or+equitable action to disrupt the quiet enjoyment of the Work by the public+as contemplated by Affirmer's express Statement of Purpose.++3. Public License Fallback. Should any part of the Waiver for any reason+be judged legally invalid or ineffective under applicable law, then the+Waiver shall be preserved to the maximum extent permitted taking into+account Affirmer's express Statement of Purpose. In addition, to the+extent the Waiver is so judged Affirmer hereby grants to each affected+person a royalty-free, non transferable, non sublicensable, non exclusive,+irrevocable and unconditional license to exercise Affirmer's Copyright and+Related Rights in the Work (i) in all territories worldwide, (ii) for the+maximum duration provided by applicable law or treaty (including future+time extensions), (iii) in any current or future medium and for any number+of copies, and (iv) for any purpose whatsoever, including without+limitation commercial, advertising or promotional purposes (the+"License"). The License shall be deemed effective as of the date CC0 was+applied by Affirmer to the Work. Should any part of the License for any+reason be judged legally invalid or ineffective under applicable law, such+partial invalidity or ineffectiveness shall not invalidate the remainder+of the License, and in such case Affirmer hereby affirms that he or she+will not (i) exercise any of his or her remaining Copyright and Related+Rights in the Work or (ii) assert any associated claims and causes of+action with respect to the Work, in either case contrary to Affirmer's+express Statement of Purpose.++4. Limitations and Disclaimers.++ a. No trademark or patent rights held by Affirmer are waived, abandoned,+    surrendered, licensed or otherwise affected by this document.+ b. Affirmer offers the Work as-is and makes no representations or+    warranties of any kind concerning the Work, express, implied,+    statutory or otherwise, including without limitation warranties of+    title, merchantability, fitness for a particular purpose, non+    infringement, or the absence of latent or other defects, accuracy, or+    the present or absence of errors, whether or not discoverable, all to+    the greatest extent permissible under applicable law.+ c. Affirmer disclaims responsibility for clearing rights of other persons+    that may apply to the Work or any use thereof, including without+    limitation any person's Copyright and Related Rights in the Work.+    Further, Affirmer disclaims responsibility for obtaining any necessary+    consents, permissions or other rights required for any use of the+    Work.+ d. Affirmer understands and acknowledges that Creative Commons is not a+    party to this document and has no duty or obligation with respect to+    this CC0 or use of the Work.
+ ChangeLog view
@@ -0,0 +1,17 @@+The changes are recorded by the version control system, Darcs. To see a log+quickly from the terminal, run:++  $ darcs changes --repo http://dev.rel4tion.org/fr33domlover/irc-fun-client++There is also a web interface at <http://darcs.rel4tion.org> which, among other+things, can display the history log.++To see the log in a local clone, first get a copy of the repository if you+haven't yet:++  $ darcs get http://dev.rel4tion.org/fr33domlover/irc-fun-client++Then move into the newly created directory and run darcs:++  $ cd irc-fun-client+  $ darcs changes
+ INSTALL view
@@ -0,0 +1,13 @@+Install from Hackage:++    $ cabal install irc-fun-client++Install from unpacked release tarball or source repo:++    $ cd irc-fun-client+    $ cabal install++Just play with it without installing:++    $ cabal build+    $ cabal repl
+ NEWS view
@@ -0,0 +1,23 @@+This file lists the user-visible interesting changes between releases. For a+full list of changes to the source, see the ChangeLog.++++irc-fun-client 0.1.0.0 -- 2015-08-09+====================================++General, build and documentation changes:++* (This is the first release, so everything is new)++New APIs, features and enhancements:++* (This is the first release, so everything is a new feature)++Bug fixes:++* (This is just the first release, many bugs haven't been discovered yet)++Dependency changes:++* (This is the first release)
+ README.md view
@@ -0,0 +1,14 @@+See the .cabal file for more info and link to project website the version+control.++The official download location is Hackage:++<http://hackage.haskell.org/package/irc-fun-client>++This library is free software, and is committed to software freedom. It is+released to the public domain using the CC0 Public Domain Dedication. For the+boring "legal" details see the file 'COPYING'.++See the file 'INSTALL' for hints on installation. The file 'ChangeLog' explains+how to see the history log of the changes done in the code. 'NEWS' provides a+friendly overview of the changes for each release.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ irc-fun-client.cabal view
@@ -0,0 +1,37 @@+name:                irc-fun-client+version:             0.1.0.0+synopsis:            Another library for writing IRC clients.+description:+  This is an IRC client library that uses @irc-fun-messages@ library package+  for working with the IRC protocol. It provides functions for sending messages+  and for receiving them, with the IRC protocol messages abstracted by+  convenient command and event datatypes.+homepage:            http://rel4tion.org/projects/irc-fun-client/+bug-reports:         http://rel4tion.org/projects/irc-fun-client/tickets/+license:             PublicDomain+license-file:        COPYING+author:              fr33domlover+maintainer:          fr33domlover@riseup.net+copyright:           ♡ Copying is an act of love. Please copy, reuse and share.+category:            Network, IRC+build-type:          Simple+extra-source-files:  AUTHORS ChangeLog COPYING INSTALL NEWS README.md+cabal-version:       >=1.10++source-repository head+  type:                darcs+  location:            http://dev.rel4tion.org/fr33domlover/irc-fun-client++library+  exposed-modules:     Network.IRC.Fun.Client+                     , Network.IRC.Fun.Client.Commands+                     , Network.IRC.Fun.Client.Events+                     , Network.IRC.Fun.Client.IO+                     , Network.IRC.Fun.Client.Util+  -- other-modules:+  -- other-extensions:    +  build-depends:       base             >=4.7 && <5+                     , irc-fun-messages+                     , network          >=2.3+  hs-source-dirs:      src+  default-language:    Haskell2010
+ src/Network/IRC/Fun/Client.hs view
@@ -0,0 +1,45 @@+{- This file is part of irc-fun-client.+ -+ - Written in 2015 by fr33domlover <fr33domlover@rel4tion.org>.+ -+ - ♡ Copying is an act of love. Please copy, reuse and share.+ -+ - The author(s) have dedicated all copyright and related and neighboring+ - rights to this software to the public domain worldwide. This software is+ - distributed without any warranty.+ -+ - You should have received a copy of the CC0 Public Domain Dedication along+ - with this software. If not, see+ - <http://creativecommons.org/publicdomain/zero/1.0/>.+ -}++-- | Here is an overview of the library, by module:+--+-- * "IO": Provides functions for connecting to an IRC server, and for sending+--   and receiving IRC messages.+-- * "Commands": Provides functions for sending IRC commands to the server.+-- * "Events": Provides an Event type and functions for receiving IRC events.+--   These events are an abstraction on top of IRC messages.+-- * "Util": Miscellaneous helper functions which could be useful to clients+--+-- If you're writing an IRC client, here is a suggestion for how to begin:+--+-- (1) Use functions from "IO" module to connect to an IRC server+-- (2) Use functions from "Commands" module to send common IRC commands+-- (3) Write an events loop which listens to the IRC server input and responds,+--     and a UI component which reacts to user-initiated commands. Use the+--     "Events" module to receive high-level events. If you have a specific+--     need to receive IRC messages directly, use functions from the "IO"+--     module.+module Network.IRC.Fun.Client+    ( module Network.IRC.Fun.Client.Commands+    , module Network.IRC.Fun.Client.Events+    , module Network.IRC.Fun.Client.IO+    , module Network.IRC.Fun.Client.Util+    )+where++import Network.IRC.Fun.Client.Commands+import Network.IRC.Fun.Client.Events+import Network.IRC.Fun.Client.IO+import Network.IRC.Fun.Client.Util
+ src/Network/IRC/Fun/Client/Commands.hs view
@@ -0,0 +1,128 @@+{- This file is part of irc-fun-client.+ -+ - Written in 2015 by fr33domlover <fr33domlover@rel4tion.org>.+ -+ - ♡ Copying is an act of love. Please copy, reuse and share.+ -+ - The author(s) have dedicated all copyright and related and neighboring+ - rights to this software to the public domain worldwide. This software is+ - distributed without any warranty.+ -+ - You should have received a copy of the CC0 Public Domain Dedication along+ - with this software. If not, see+ - <http://creativecommons.org/publicdomain/zero/1.0/>.+ -}++-- | This module provides convenient functions for performing common IRC client+-- actions. Some of them simply send a single IRC message, while othere send a+-- sequence of several messages.+module Network.IRC.Fun.Client.Commands+    ( ircLogin+    , ircPong+    , ircJoin+    , ircJoinMulti+    , ircPart+    , ircPartMulti+    , ircPartAll+    , ircSendToUser+    , ircSendToChannel+    , ircQuit+    )+where++import Control.Monad (unless)+import Data.Maybe (isNothing)+import Network.IRC.Fun.Messages+import Network.IRC.Fun.Messages.Types+import Network.IRC.Fun.Client.IO++-- | Log in as an IRC user with nickname and optional password, using the given+-- connection parameters.+ircLogin :: Handle     -- ^ Handle to the open socket, returned from+                       -- 'ircConnect'+         -> Connection -- ^ Connection configuration+         -> Bool       -- ^ Whether you want to be invisible (mode @+i@)+         -> Bool       -- ^ Whether you want to see wallops (mode @+w@)+         -> IO ()+ircLogin h conn i w = do+    let pass = password conn+        pass' = case pass of+            Just p  -> p+            Nothing -> ""+    unless (isNothing pass) $ hPutIrc h $ PassMessage pass'+    hPutIrc h $ UserMessage (nick conn) i w (nick conn)+    hPutIrc h $ NickMessage $ nick conn++-- | IRC servers send PING messages at regular intervals to test the presence+-- of an active client, at least if no other activity is detected on the+-- connection. The server closes the connection automatically if a PONG+-- response isn't sent from the client within a certain amount of time.+--+-- Therefore, an IRC client usually listens to these PINGs and sends back PONG+-- messages. This function sends a PONG. The parameters should simply be the+-- ones received in the PING message.+ircPong :: Handle       -- ^ Handle to the open socket+        -> String       -- ^ Server name+        -> Maybe String -- ^ Optional server to forward to+        -> IO ()+ircPong h s ms = hPutIrc h $ PongMessage s ms++-- | Join an IRC channel.+ircJoin :: Handle       -- ^ Handle to the open socket+        -> String       -- ^ Channel name+        -> Maybe String -- ^ Optional channel key (password)+        -> IO ()+ircJoin h chan key = ircJoinMulti h [(chan, key)]++-- | Join one or more IRC channels.+ircJoinMulti :: Handle                   -- ^ Handle to the open socket+             -> [(String, Maybe String)] -- ^ List of channels and optional+                                         --   keys+             -> IO ()+ircJoinMulti _ [] = return ()+ircJoinMulti h l  = do+    let nokey         = [ chan | (chan, Nothing) <- l ]+        (chans, keys) = unzip [ (chan, key) | (chan, (Just key)) <- l ]+    unless (null nokey) $ hPutIrc h $ JoinMessage $ Just (nokey, [])+    unless (null chans) $ hPutIrc h $ JoinMessage $ Just (chans, keys)++-- | Leave an IRC channel.+ircPart :: Handle+        -> String+        -> Maybe String+        -> IO ()+ircPart h chan = ircPartMulti h [chan]++-- | Leave one or more IRC channels.+ircPartMulti :: Handle+             -> [String]+             -> Maybe String+             -> IO ()+ircPartMulti _ []    _   = return ()+ircPartMulti h chans msg = hPutIrc h $ PartMessage chans msg++-- | Leave all IRC channels you joined.+ircPartAll :: Handle -> IO ()+ircPartAll h = hPutIrc h $ JoinMessage Nothing++-- | Send a private message to an IRC user.+ircSendToUser :: Handle -- ^ Handle to the open socket+              -> String -- ^ The user's nickname+              -> String -- ^ The message to send+              -> IO ()+ircSendToUser h nick msg =+    hPutIrc h $ PrivMsgMessage (UserTarget (Just nick) Nothing Nothing) msg++-- | Send a message to an IRC channel.+ircSendToChannel :: Handle -- ^ Handle to the open socket+                 -> String -- ^ The channel name+                 -> String -- ^ The message to send+                 -> IO ()+ircSendToChannel h chan msg =+    hPutIrc h $ PrivMsgMessage (ChannelTarget chan) msg++-- | Finish the IRC session, asking the server to close the connection.+ircQuit :: Handle       -- ^ Handle to the open socket+        -> Maybe String -- ^ Optional message, e.g. the reason you quit+        -> IO ()+ircQuit h m = hPutIrc h $ QuitMessage m
+ src/Network/IRC/Fun/Client/Events.hs view
@@ -0,0 +1,161 @@+{- This file is part of irc-fun-client.+ -+ - Written in 2015 by fr33domlover <fr33domlover@rel4tion.org>.+ -+ - ♡ Copying is an act of love. Please copy, reuse and share.+ -+ - The author(s) have dedicated all copyright and related and neighboring+ - rights to this software to the public domain worldwide. This software is+ - distributed without any warranty.+ -+ - You should have received a copy of the CC0 Public Domain Dedication along+ - with this software. If not, see+ - <http://creativecommons.org/publicdomain/zero/1.0/>.+ -}++-- | This module allows you to identify IRC events. Events are a wrapper around+-- IRC messages, which provide a logical layer convenient to work with (while+-- IRC messages have their lower level aspects, being plain protocol messages).+module Network.IRC.Fun.Client.Events+    ( Event (..)+    , ChannelPrivacy (..)+    , Privilege (..)+    , detectEvents+    , hGetIrcEventsOnce+    , hGetIrcEvents+    )+where++import Control.Monad (unless)+import Data.Maybe (fromMaybe, isNothing)+import Network.IRC.Fun.Client.IO (Handle, hGetIrcOnce)+import Network.IRC.Fun.Messages+import Network.IRC.Fun.Messages.Types++-- | An event triggered by an IRC message sent from the server.+data Event+    -- | A ping was sent to the bot. The parameters are the server name and+    -- optionally a server to forward the response to. They can be passed as-is+    -- directly to the PONG response.+    = Ping String (Maybe String)+    -- | One or more users have been kicked from a channel for an optionally+    -- given reason. Parameters: Channel, nicknames, reason.+    | Kick String [String] (Maybe String)+    -- | A user joined a channel. Parameters: Channel, nickname.+    | Join String String+    -- | A user left a channel, optionally with a given reason. Parameters:+    -- Channel, nickname, reason.+    | Part String String (Maybe String)+    -- | A user left the network, optonally for the given reason. Parameters:+    -- Nickname, reason.+    | Quit String (Maybe String)+    -- | TODO+    | Mode+    -- | Message sent in a channel by a user. The last parameter indicates+    -- whether the message is actually a notice. If yes, the client shouldn't+    -- automatically send a response. Parameters: Channel, nickname, message,+    -- whether notice.+    | ChannelMessage String String String Bool+    -- | A private message sent specifically to the client from a user. The+    -- last parameter indicates whether the message is actually a notice. If+    -- yes, the client shouldn't send any automatic response. Parameters:+    -- Nickname, message, whether notice.+    | PrivateMessage String String Bool+    -- | Channel topic change. Parameterss: Channel, nickname of user who+    -- changed the topic, new topic content.+    | Topic String String String+    -- | The client has been invited to a channel by another user. Parameters:+    -- Channel, nickname of inviting user.+    | Invite String String+    -- | The server sent a list of nicknames present in a channel. Parameters:+    -- Channel privacy mode, channel name, list of users. Each list item is a+    -- pair of a user privilege level in the channel, and the user's nickname.+    | Names ChannelPrivacy String [(Privilege, String)]+    -- Unrecognized or unimplemented event. The parameter contains (possibly+    -- empty) input.+    | OtherEvent String+    deriving Show++detectMessageEvents :: SpecificMessage -> Either String [Event]+detectMessageEvents sm@(SpecificMessage mpref msg) =+    case msg of+        QuitMessage reason                         ->+            if null sender+                then err+                else one $ Quit sender reason+        JoinMessage (Just ([chan], []))            ->+            if null sender+                then err+                else one $ Join chan sender+        JoinMessage _                              -> err+        PartMessage [chan] reason                  ->+            if null sender+                then err+                else one $ Part chan sender reason+        PartMessage _      _                       -> err+        TopicMessage []   _                        -> err+        TopicMessage chan topic                    ->+            if null sender+                then other+                else one $ Topic chan sender $ fromMaybe "" topic+        PingMessage s ms                           -> one $ Ping s ms+        KickMessage []     _     _                 -> err+        KickMessage _      []    _                 -> err+        KickMessage [chan] nicks comment           ->+            one $ Kick chan nicks comment+        KickMessage chans nicks comment            ->+            if length chans == length nicks+                then some $+                     map (\ (c, n) -> Kick c [n] comment) $ zip chans nicks+                else err+        PrivMsgMessage _                    []     -> other+        PrivMsgMessage (ChannelTarget chan) text   ->+            if null sender+                then other+                else one $ ChannelMessage chan sender text False+        PrivMsgMessage (UserTarget _ _ _) text ->+            if null sender+                then err+                else one $ PrivateMessage sender text False+        PrivMsgMessage (MaskTarget _)       _      -> other+        _                                          -> other+    where+    other = Right [OtherEvent $ show sm]+    one e = Right [e]+    some = Right+    err = Left $ show sm+    sender =+        case mpref of+            Just (Nick n _ _) -> n+            Nothing           -> ""++detectReplyEvents :: SpecificReply -> Either String [Event]+detectReplyEvents sr@(SpecificReply _sender _target rpl) =+    case rpl of+        NamesReply priv chan pnicks -> one $ Names priv chan pnicks+        _                           -> other+    where+    other = Right [OtherEvent $ show sr]+    one e = Right [e]+    err = Left $ show sr++-- | Try to generate events from an IRC message. If it fails, 'Left' an error+-- message is returned. Otherwise, 'Right' a list of generated events is+-- returned.+detectEvents :: Either SpecificReply SpecificMessage+             -> Either String [Event]+detectEvents = either detectReplyEvents detectMessageEvents++-- | Receive IRC events. If parsing and detecting the events fails, 'Nothing'+-- is returned.+hGetIrcEventsOnce :: Handle -> IO (Maybe [Event])+hGetIrcEventsOnce h =+    hGetIrcOnce h >>= return . \ r ->+    case r of+        Nothing   -> Nothing+        Just spec -> either (const Nothing) Just $ detectEvents spec++-- | Receive the next valid (successfully parsed and detected) series of IRC+-- events.+hGetIrcEvents :: Handle -> IO [Event]+hGetIrcEvents h = hGetIrcEventsOnce h >>= maybe (hGetIrcEvents h) return
+ src/Network/IRC/Fun/Client/IO.hs view
@@ -0,0 +1,122 @@+{- This file is part of irc-fun-client.+ -+ - Written in 2015 by fr33domlover <fr33domlover@rel4tion.org>.+ -+ - ♡ Copying is an act of love. Please copy, reuse and share.+ -+ - The author(s) have dedicated all copyright and related and neighboring+ - rights to this software to the public domain worldwide. This software is+ - distributed without any warranty.+ -+ - You should have received a copy of the CC0 Public Domain Dedication along+ - with this software. If not, see+ - <http://creativecommons.org/publicdomain/zero/1.0/>.+ -}++module Network.IRC.Fun.Client.IO+    ( Connection (..)+    , Handle+    , ircConnect+    , ircDisconnect+    , hPutIrcRaw+    , hPutIrcGeneric+    , hPutIrc+    , hGetIrcRaw+    , hGetIrcGenericOnce+    , hGetIrcGeneric+    , hGetIrcOnce+    , hGetIrc+    )+where++import Control.Exception (bracketOnError)+import Data.Maybe (fromMaybe)+import Network.IRC.Fun.Messages+import Network.IRC.Fun.Messages.Types+import Network.Socket+import System.IO++-- | Details of the connection to IRC.+data Connection = Connection+    { -- | IRC Server address, e.g. @"irc.freenode.net"@+      server   :: String+      -- | IRC server port, @6667@ should be a safe default+    , port     :: Int+      -- | Whether to make an encrypted connection via TLS (not implemented)+    , tls      :: Bool+      -- | IRC nickname for the bot, e.g. @"funbot"@+    , nick     :: String+    -- | Connection password, use if the nickname is registered+    , password :: Maybe String+    }+    deriving (Eq, Show)++-- | Connect to an IRC server using the given connection parameters, and return+-- a handle to the open socket. This just opens a TCP connection, without+-- sending any IRC commands.+ircConnect :: Connection -> IO Handle+ircConnect conn = do+    let hints = defaultHints+            { addrSocketType = Stream+            , addrFlags      = [AI_ADDRCONFIG]+            }+    addrs <- getAddrInfo (Just hints)+                         (Just $ server conn)+                         (Just $ show $ port conn)+    let addr = head addrs+    bracketOnError+        (socket (addrFamily addr) (addrSocketType addr) (addrProtocol addr))+        (\ sock -> close sock >> putStrLn "Connection failed") $+        \ sock -> do+            connect sock (addrAddress addr)+            handle <- socketToHandle sock ReadWriteMode+            hSetBuffering handle LineBuffering+            encoding <- mkTextEncoding "UTF-8//TRANSLIT"+            hSetEncoding handle encoding+            hSetNewlineMode handle (NewlineMode CRLF CRLF)+            return handle++-- | Disconnect from IRC by closing the client's side of the connection. This+-- function is mainly provided for completeness. You should probably use the+-- QUIT command of IRC to quit the network in a manner coordinated with the+-- server.+ircDisconnect :: Handle -> IO ()+ircDisconnect = hClose++-- | Send an IRC command, given in string form, to the server. The given+-- command string shouldn't contain any newlines.+hPutIrcRaw :: Handle -> String -> IO ()+hPutIrcRaw = hPutStrLn++-- | Send an IRC message represented in generic form to the server.+hPutIrcGeneric :: Handle -> GenericMessage -> IO ()+hPutIrcGeneric h = hPutIrcRaw h . serializeMessage++-- | Send an IRC message to the server.+hPutIrc :: Handle -> Message -> IO ()+hPutIrc h = hPutIrcGeneric h . buildMessage . SpecificMessage Nothing++-- | Receive an IRC message, given in string form, from the server. The+-- resulting string won't contain newlines.+hGetIrcRaw :: Handle -> IO String+hGetIrcRaw = hGetLine++-- | Receive an IRC message in generic form from the server. If parsing the+-- message read from the server fails, 'Nothing' is returned.+hGetIrcGenericOnce :: Handle -> IO (Maybe GenericMessage)+hGetIrcGenericOnce h = hGetIrcRaw h >>= return . parseMessage++-- | Receive the next valid (successfully parsed) IRC message in generic form+-- from the server.+hGetIrcGeneric :: Handle -> IO GenericMessage+hGetIrcGeneric h = hGetIrcGenericOnce h >>= maybe (hGetIrcGeneric h) return++-- | Receive an IRC message from the server. If parsing the message read from+-- the server fails, 'Nothing' is returned.+hGetIrcOnce :: Handle -> IO (Maybe (Either SpecificReply SpecificMessage))+hGetIrcOnce h = hGetIrcGenericOnce h >>=+    return . maybe Nothing ((either (const Nothing) Just) .  analyze)++-- | Receive the next valid (successfully parsed) IRC message from the server.+hGetIrc :: Handle -> IO (Either SpecificReply SpecificMessage)+hGetIrc h = hGetIrcOnce h >>= maybe (hGetIrc h) return
+ src/Network/IRC/Fun/Client/Util.hs view
@@ -0,0 +1,46 @@+{- This file is part of irc-fun-client.+ -+ - Written in 2015 by fr33domlover <fr33domlover@rel4tion.org>.+ -+ - ♡ Copying is an act of love. Please copy, reuse and share.+ -+ - The author(s) have dedicated all copyright and related and neighboring+ - rights to this software to the public domain worldwide. This software is+ - distributed without any warranty.+ -+ - You should have received a copy of the CC0 Public Domain Dedication along+ - with this software. If not, see+ - <http://creativecommons.org/publicdomain/zero/1.0/>.+ -}++module Network.IRC.Fun.Client.Util+    ( mentions+    )+where++import Data.Char (isAlphaNum)+import Data.List (isPrefixOf)++isNameChar :: Char -> Bool+isNameChar c = isAlphaNum c || c `elem` "-_|"++-- | Check if a message mentions a given nickname.+--+-- This isn't the same as substring search, since the nickname could appear+-- inside a longer word. For example, \"ron\" isn't really mentioned in+-- \"asynchronic\". Therefore, this function is a bit smarter about this,+-- trying to capturing real mentions, and works quite well in practice.+mentions :: String -- ^ Message content+         -> String -- ^ Nickname+         -> Bool+msg `mentions` nick = m msg nick True+    where+    m ""         _    _       = False+    m msg@(c:cs) nick previnc =+        if not previnc && nick `isPrefixOf` msg+            then case drop (length nick) msg of+                    ""     -> True+                    (d:ds) -> if not (isNameChar d)+                                then True+                                else m cs nick $ isNameChar c+            else m cs nick $ isNameChar c