Paste server written in Haskell. Fork of Hpaste, fully freedom and privacy respecting and generally improved. At the time of writing there's an instance at <http://paste.rel4tion.org>.

[[ 🗃 ^aoqmo toothpaste ]] :: [📥 Inbox] [📤 Outbox] [🐤 Followers] [🤝 Collaborators] [🛠 Commits]

Clone

HTTPS: git clone https://vervis.peers.community/repos/aoqmo

SSH: git clone USERNAME@vervis.peers.community:aoqmo

Branches

Tags

hpaste :: src / Hpaste / Model /

Announcer.hs

{-# LANGUAGE ScopedTypeVariables #-}
{-# OPTIONS -Wall -fno-warn-name-shadowing #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}

-- | IRC announcer.

module Hpaste.Model.Announcer
       (newAnnouncer
       ,announce
       )
       where

import           Hpaste.Types.Announcer
import		 Control.Monad.Fix
import           Control.Concurrent
import qualified Control.Exception       as E
import           Control.Monad
import           Control.Monad.Env       (env)
import           Control.Monad.IO        (io)
import qualified Data.ByteString    as B
import           Data.Monoid.Operator    ((++))
import 		 Data.Char
import           Data.Text          (Text,pack,unpack)
import qualified Data.Text          as T
import           Data.Text.Encoding
import Data.Time
import qualified Data.Text.IO       as T
import           Network
import           Prelude                 hiding ((++))
import           Snap.App.Types
import           System.IO

-- | Start a thread and return a channel to it.
newAnnouncer :: AnnounceConfig -> IO Announcer
newAnnouncer config = do
  putStrLn "Connecting..."
  ans <- newChan
  let self = Announcer { annChan = ans, annConfig = config }
  _ <- forkIO $ announcer self (const (return ()))
  return self

-- | Run the announcer bot.
announcer ::  Announcer -> (Handle -> IO ()) -> IO ()
announcer self@Announcer{annConfig=config,annChan=ans} cont = do
  announcements <- getChanContents ans
  forM_ announcements $ \ann ->
    E.catch (sendIfNickExists config ann)
            (\(e::IOError) -> return ())

sendIfNickExists AnnounceConfig{..} (Announcement origin line) = do
  handle <- connectTo announceHost (PortNumber $ fromIntegral announcePort)
  hSetBuffering handle LineBuffering
  let send = B.hPutStrLn handle . encodeUtf8
  send $ "PASS " ++ pack announcePass
  send $ "USER " ++ pack announceUser ++ " * * *"
  send $ "NICK " ++ pack announceUser
  send $ "WHOIS :" ++ origin
  fix $ \loop -> do
    incoming <- T.hGetLine handle
    case T.takeWhile isDigit (T.drop 1 (T.dropWhile (/=' ') incoming)) of
      "311" -> send line
      "401" -> return ()
      _ -> loop

-- | Announce something to the IRC.
announce :: Announcer -> Text -> Text -> Text -> IO ()
announce Announcer{annChan=chan} nick channel line = do
  io $ writeChan chan $ Announcement nick ("PRIVMSG " ++ channel ++ " :" ++ line)
[See repo JSON]