{- This file is part of funbot. - - Written in 2015 by fr33domlover . - - ♡ 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 - . -} module FunBot.Commands ( commandSet ) where import Control.Monad (unless) import Data.List (find, intercalate) import Data.Settings.Types (showOption) import FunBot.History (quote) import FunBot.Memos (submitMemo) import FunBot.Settings import FunBot.Types (BotSession) import FunBot.UserOptions import Network.IRC.Fun.Bot.Behavior import Network.IRC.Fun.Bot.Chat import Network.IRC.Fun.Bot.State import Network.IRC.Fun.Bot.Types import Text.Printf (printf) import Text.Read (readMaybe) -- | The main command set, the only one currently commandSet = CommandSet { csetPrefix = '!' , csetCommands = [ makeCmdHelp commandSet , cmdInfo , cmdEcho , cmdPTell , cmdCTell , cmdGet , cmdSet , cmdReset , cmdEnable , cmdDisable , cmdAddSpec , cmdDeleteSpec , cmdAddRepo , cmdDeleteRepo , cmdVisit , cmdJoin , cmdLeave , cmdQuote , cmdShowOpts , cmdEnableHistory , cmdDisableHistory , cmdSetLines , cmdEraseOpts ] } ------------------------------------------------------------------------------- -- Echo command -- Send the input back to the IRC channel ------------------------------------------------------------------------------- respondEcho _mchan _nick [] send = send " " respondEcho _mchan _nick [param] send = send param respondEcho _mchan _nick params send = send $ unwords params cmdEcho = Command { cmdNames = ["echo"] , cmdRespond = respondEcho , cmdHelp = "‘echo ’ - display the given text. Probably not a \ \useful command. Exists as an example and for testing." } ------------------------------------------------------------------------------- -- Help command -- Show command help strings ------------------------------------------------------------------------------- -- Return a response function given a CommandSet respondHelp cset _mchan _nick [cname] send = case find ((cname' `elem`) . cmdNames) $ csetCommands cset of Just cmd -> send $ cmdHelp cmd ++ "\nCommand names: " ++ listNames Nothing Nothing True (cmdNames cmd) Nothing -> do succ <- respondSettingsHelp cname send unless succ $ send $ printf "No such command, or invalid settings path. \ \Maybe try just ‘%vhelp’ without a parameter." (csetPrefix cset) where cname' = case cname of [] -> cname (c:cs) -> if c == csetPrefix cset then cs else cname respondHelp cset _mchan _nick _params send = send $ cmdHelp (makeCmdHelp cset) ++ "\nAvailable commands: " ++ listPrimaryNames (Just $ csetPrefix cset) Nothing False (csetCommands cset) makeCmdHelp cset = Command { cmdNames = ["help", "Help", "h", "?"] , cmdRespond = respondHelp cset , cmdHelp = "‘help [ | ]’ - display help for the given \ \command or settings option/section. Also see ‘info’.\n\ \FunBot intends to provide interactive help, but some topics \ \may be missing. If that's the case, check out the user \ \manual (call ‘!info links’ for the URL) or ask in #freepost." } ------------------------------------------------------------------------------- -- Info command -- Ask the bot to display some information ------------------------------------------------------------------------------- topics = [ ( "intro" , "I’m fpbot. An instance of funbot, written in Haskell. I run in \ \#freepost (and some extra channels). Developed in the Freepost \ \community, I exist for fun, collaboration and learning. But I also \ \aim to provide useful tools, in particular to Freepost and related \ \projects and communities.\n\ \You can start by trying ‘!help’." ) , ( "features" , "This is a high-level list of features and subsystems I provide. It \ \will hopefully be kept up-to-date by updating it every time new \ \features are added.\n\ \• Help and information system (!help, !info)\n\ \• A settings system (!get, !set, etc.)\n\ \• Announcing commits, tags, merge requests, etc. in Git \ \repositories\n\ \• Announcing RSS/Atom feed items\n\ \• Leaving memos (requires enabling nick tracking for the channel)\n\ \• Announcing titles of URLs\n\ \• Logging and reporting channel activity\n\ \• Accepting events via an HTTP API, e.g. pastes added to a paste \ \bin\n\ \There is also an overview of the bot API features, useful to \ \contributors/developers, in the guide at \ \." ) , ( "contrib" , "Thinking about contributing to my development? Opening a ticket, \ \fixing a bug, implementing a feature? Check out the project page at \ \, which links to the \ \contribution guide, to the tickets page and more." ) , ( "copying" , "♡ Copying is an act of love. Please copy, reuse and share me! Grab a \ \copy of me from ." ) , ( "links" , "Website: http://rel4tion.org/projects/funbot\n\ \Code: https://notabug.org/fr33domlover/funbot\n\ \Tickets: http://rel4tion.org/projects/funbot/tickets\n\ \Roadmap: http://rel4tion.org/projects/funbot/ideas\n\ \Dev guide: http://rel4tion.org/projects/funbot/guide\n\ \User manual: http://rel4tion.org/projects/funbot/manual" ) , ( "git-ann" , "I can announce development related events, such as git commits and \ \merge requests. To see the list of repos being announced and their \ \settings, run ‘!get repos’. Each repo has a list of specifications, \ \one per target channel (most projects announce to a single channel, \ \some announce to two). You can modify the spec details using the \ \settings system (!get, !set, etc.). To add a new spec (channel) to \ \an existing repo, use the !add-spec command. To remove a spec, use \ \!delete-spec. To add and remove repos, use !add-repo and \ \!delete-repo respectively." ) , ( "feeds" , "TODO" ) , ( "memos" , "TODO" ) , ( "channels" , "Using bot commands, you can ask me to leave and join channels. The \ \list of channels I'm present in can therefore be controlled \ \dynamically. However, there is also an additional list of channels \ \in my configuration (in the source). Using !visit, you can ask me to \ \briefly join a channel. But I won't remember it next time. To make \ \me a permanent member, use !join. You can ask me to leave a channel \ \using !leave." ) , ( "chan-history" , "When you join a channel, I can send you the last messages sent there \ \so that you’ll know what was happenig before you came. You can \ \enable this per channel, and set the number of last messages you’d \ \like to see per channel. Note that the number of messages you’ll get \ \also depends on how many messages I myself remember for this \ \purpose (which is set in the Config.hs source file). See \ \‘!info user-options’ for usage instructions." ) , ( "user-options" , "I keep private per-user options which affect our interaction. These \ \options are /separate/ from the public settings system. The commands \ \for managing them are available only in private messages to me, and \ \don't work in IRC channels. You can view your preferences using \ \!show-opts. Edit them using !enable-history, !disable-history and \ \!set-history-lines. Reset them to defaults using !erase-opts." ) , ( "quotes" , "See the !quote command. It works, but quotes aren’t being \ \automatically published, so perhaps it isn’t very useful at the \ \moment. Perhaps unless you setup the publishing yourself." ) ] respondInfo _mchan _nick [] send = send $ "Topics: " ++ intercalate ", " (map fst topics) respondInfo mchan nick [arg] send = case lookup arg topics of Just msg -> send msg Nothing -> failBack mchan nick $ InvalidArg (Just 1) (Just arg) respondInfo mchan nick args _send = failBack mchan nick $ WrongNumArgsN (Just $ length args) Nothing cmdInfo = Command { cmdNames = ["info", "i"] , cmdRespond = respondInfo , cmdHelp = "‘info’ - list topics. Also see ‘help’.\n\ \‘info ’ - display topic information." } ------------------------------------------------------------------------------- -- Tell command -- Tell something to some other user ------------------------------------------------------------------------------- -- Given whether to always send privately, return a command response respondTell priv mchan sender (recip:msghead:msgtail) _send = submitMemo sender mchan recip priv (unwords $ msghead : msgtail) respondTell _priv mchan nick args _send = failBack mchan nick $ WrongNumArgsN (Just $ length args) Nothing cmdPTell = Command { cmdNames = ["tell", "ptell"] , cmdRespond = respondTell True , cmdHelp = "‘tell ’ - leave a memo for a user to see later. \ \Memos can be sent to the recipient privately, or publicly \ \in the channel in which they were submitted. With this \ \command, the memo will be sent privately. If that isn't your \ \intention, see the ctell command." } cmdCTell = Command { cmdNames = ["ctell"] , cmdRespond = respondTell False , cmdHelp = "‘tell ’ - leave a memo for a user to see later. \ \Memos can be sent to the recipient privately, or publicly \ \in the channel in which they were submitted. With this \ \command, the memo will be sent in the same way it was \ \submitted: If you submit it in a channel, it will be sent to \ \the recipient in the same channel. If you submit using a \ \private message to me, I will also send it privately to the \ \recipient.\n\ \If that isn't your intention, see the tell command." } ------------------------------------------------------------------------------- -- Get, set, enable and disable commands -- Manage bot settings ------------------------------------------------------------------------------- respondGet _mchan _nick [] send = respondGet' "" send respondGet _mchan _nick [path] send = respondGet' path send respondGet mchan nick args _send = failBack mchan nick $ WrongNumArgsN (Just $ length args) (Just 1) respondSet _mchan _nick [name, val] send = respondSet' name val send respondSet mchan nick args _send = failBack mchan nick $ WrongNumArgsN (Just $ length args) (Just 2) respondReset _mchan _nick [name] send = respondReset' name send respondReset mchan nick args _send = failBack mchan nick $ WrongNumArgsN (Just $ length args) (Just 1) -- Given a boolean, create an enable/disable response accordingly respondBool val _mchan _nick [name] send = respondSet' name (showOption val) send respondBool _val mchan nick args _send = failBack mchan nick $ WrongNumArgsN (Just $ length args) (Just 1) respondEnable = respondBool True respondDisable = respondBool False cmdGet = Command { cmdNames = ["get"] , cmdRespond = respondGet , cmdHelp = "‘get