packages feed

irc-ctcp (empty) → 0.1.0.0

raw patch · 4 files changed

+248/−0 lines, 4 filesdep +basedep +bytestringdep +textsetup-changed

Dependencies added: base, bytestring, text

Files

+ LICENSE view
@@ -0,0 +1,13 @@+        DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE +                    Version 2, December 2004 ++ Copyright (C) 2004 Sam Hocevar <sam@hocevar.net> ++ Everyone is permitted to copy and distribute verbatim or modified + copies of this license document, and changing it is allowed as long + as the name is changed. ++            DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE +   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION ++  0. You just DO WHAT THE FUCK YOU WANT TO.
+ Network/IRC/CTCP.hs view
@@ -0,0 +1,124 @@+-- |Functions for encoding and decoding CTCPs.+module Network.IRC.CTCP+    ( -- *Types+      CTCPByteString+    , getUnderlyingByteString++    -- *Encoding and decoding+    , toCTCP+    , fromCTCP+    , encodeCTCP+    , decodeCTCP++    -- *Utilities+    , isCTCP+    , asCTCP+    , orCTCP+    ) where++import Data.ByteString    (ByteString, pack, singleton, unpack)+import Data.List          (mapAccumL)+import Data.Maybe         (catMaybes, fromMaybe)+import Data.Text          (Text, splitOn)+import Data.Text.Encoding (decodeUtf8, encodeUtf8)+import Data.Tuple         (swap)++import qualified Data.ByteString as B+import qualified Data.Text       as T++-- |Type representing a CTCP-encoded bytestring.+newtype CTCPByteString = CBS+    { getUnderlyingByteString :: ByteString+    -- ^Get the underlying (encoded) bytestring from a CTCP+    -- bytestring.+    }++-- |Turn a command name and arguments into a CTCP-encoded bytestring.+--+-- This encodes the text with UTF-8. If another encoding is desired,+-- 'encodeCTCP' should be used directly.+toCTCP :: Text -> [Text] -> CTCPByteString+toCTCP cmd args = encodeCTCP . encodeUtf8 . T.unwords $ cmd : args++-- |Encode a bytestring according to the CTCP spec.+encodeCTCP :: ByteString -> CTCPByteString+encodeCTCP bs = CBS $ B.concat [ singleton soh+                               , escape bs+                               , singleton soh+                               ]++    where escape = B.concatMap escape'+          escape' x = case lookup x encodings of+                        -- If there is an encoding, escape it and use+                        -- that.+                        Just x' -> pack [esc, x']++                        -- Otherwise, just return the original+                        -- character.+                        Nothing -> singleton x++-- |Decode a CTCP-encoded bytestring and turn it into a command name+-- and arguments.+--+-- This decodes the text with UTF-8. If another encoding is desired,+-- 'decodeCTCP' should be used directly.+fromCTCP :: CTCPByteString -> (Text, [Text])+fromCTCP bs = case splitOn (T.pack " ") . decodeUtf8 . decodeCTCP $ bs of+                (cmd : args) -> (cmd, args)+                _            -> (T.pack "", [])++-- |Decode a CTCP bytestring. Extraeneous escapes are dropped.+decodeCTCP :: CTCPByteString -> ByteString+decodeCTCP (CBS bs) = unescape . B.tail . B.init $ bs++    where unescape = pack . catMaybes . snd . mapAccumL step False . unpack++          -- If we fail to find a decoding, ignore the escape.+          step True x = (False, Just . fromMaybe x $ lookup x decodings)++          -- Enter escape mode, this doesn't add a character to the+          -- output.+          step False 0o020 = (True, Nothing)++          step _ x = (False, Just x)++soh :: Integral i => i+soh = 0o001++esc :: Integral i => i+esc = 0o020++encodings :: Integral i => [(i, i)]+encodings = [ (0o000, 0o060)+            , (0o012, 0o156)+            , (0o015, 0o162)+            , (0o020, 0o020)+            ]++decodings :: Integral i => [(i, i)]+decodings = map swap encodings++-- |Check if a bytestring represents a CTCP.+--+-- This is intentionally very lenient, in particular it doesn't check+-- that there are no extra escape characters. This is because the spec+-- states that misplaced escape characters should be discarded by the+-- decoding process.+isCTCP :: ByteString -> Bool+isCTCP bs = and $ (B.length bs >= 2) : (B.head bs == soh) : (B.last bs == soh) : map (flip B.notElem bs . fst) encodings++-- |Check if a bytestring looks like a CTCP, and if so, wrap it up in+-- the 'CTCPByteString' type.+--+-- This uses 'isCTCP', and so is lenient with escapes.+asCTCP :: ByteString -> Maybe CTCPByteString+asCTCP bs = if isCTCP bs+            then Just $ CBS bs+            else Nothing++-- |Apply one of two functions depending on whether the bytestring+-- looks like a CTCP or not.+--+-- This uses 'asCTCP', and so is lenient with escapes.+orCTCP :: (ByteString -> a) -> (CTCPByteString -> a) -> ByteString -> a+orCTCP f g bs = maybe (f bs) g (asCTCP bs)
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ irc-ctcp.cabal view
@@ -0,0 +1,109 @@+-- Initial irc-ctcp.cabal generated by cabal init.  For further +-- documentation, see http://haskell.org/cabal/users-guide/++-- The name of the package.+name:                irc-ctcp++-- The package version.  See the Haskell package versioning policy (PVP) +-- for standards guiding when and how versions should be incremented.+-- http://www.haskell.org/haskellwiki/Package_versioning_policy+-- PVP summary:      +-+------- breaking API changes+--                   | | +----- non-breaking API additions+--                   | | | +--- code changes with no API change+version:             0.1.0.0++-- A short (one-line) description of the package.+synopsis:            A CTCP encoding and decoding library for IRC clients.++-- A longer description of the package.+description:+  CTCP (Client To Client Protocol) is a way of sending arbitrary data+  over an IRC network, which may include bytes not allowed in standard+  IRC messages. CTCPs are sent as a PRIVMSG or NOTICE, where the first+  and last characters as @\\001@ (SOH), and special bytes are escaped+  by encoding them into a two-byte sequence beginning with @\\020@+  (DLE). CTCPs consist of command name (typically in upper-case)+  followed by list of space-separated arguments, which may be empty.+  .+  One use of CTCPs supported by the vast majority of IRC clients today+  is the ACTION command, typically invoked with /me. For example, if+  the user @foo@ in the channel @#bar@ were to issue+  .+  > /me dances+  .+  everyone in the channel would receive the message+  .+  > :foo PRIVMSG #bar :\001ACTION dances\001+  .+  Other common uses of CTCP include requesting the name and version of+  a user's IRC client, their local time, determining ping times, and+  initiating file transfers (DCC).+  .+  Characters are escaped as follows:+  .+     [@\\000@ (NUL)] @\\020 \\060@ ("0")+  .+     [@\\012@ (NL)]  @\\020 \\156@ ("n")+  .+     [@\\015@ (CR)]  @\\020 \\162@ ("r")+  .+     [@\\020@ (DLE)] @\\020 \\020@+  .+  All other appearences of the escape character are errors, and are+  dropped.+  .+  See <http://www.irchelp.org/irchelp/rfc/ctcpspec.html> for more+  details.++-- URL for the project homepage or repository.+homepage:            https://github.com/barrucadu/yukibot++-- The license under which the package is released.+license:             OtherLicense++-- The file containing the license text.+license-file:        LICENSE++-- The package author(s).+author:              Michael Walker++-- An email address to which users can send suggestions, bug reports, and +-- patches.+maintainer:          mike@barrucadu.co.uk++-- A copyright notice.+-- copyright:           ++category:            Network++build-type:          Simple++-- Extra files to be distributed with the package, such as examples or a +-- README.+-- extra-source-files:  ++-- Constraint on the version of Cabal needed to build this package.+cabal-version:       >=1.10+++library+  -- Modules exported by the library.+  exposed-modules:     Network.IRC.CTCP+  +  -- Modules included in this library but not exported.+  -- other-modules:       +  +  -- LANGUAGE extensions used by modules in this package.+  -- other-extensions:    +  +  -- Other library packages from which modules are imported.+  build-depends:       base       >=4.7 && <5+                     , bytestring >=0.10+                     , text       >=1.1+  +  -- Directories containing source files.+  -- hs-source-dirs:      +  +  -- Base language which the package is written in.+  default-language:    Haskell2010+