From bd9bb0d226c9ea56facb60faef307c0b682bec02 Mon Sep 17 00:00:00 2001 From: wwwww Date: Wed, 4 Dec 2019 07:49:16 +0000 Subject: [PATCH] init --- .gitignore | 5 +++ ChangeLog.md | 3 ++ LICENSE | 30 ++++++++++++++ README.md | 1 + Setup.hs | 2 + app/Main.hs | 41 +++++++++++++++++++ example.json | 22 ++++++++++ haskell-basic-irc-bot.cabal | 88 ++++++++++++++++++++++++++++++++++++++++ package.yaml | 48 ++++++++++++++++++++++ src/IrcBot/BotActions.hs | 63 ++++++++++++++++++++++++++++ src/IrcBot/BotCustomCommands.hs | 72 ++++++++++++++++++++++++++++++++ src/IrcBot/BotNetwork.hs | 49 ++++++++++++++++++++++ src/IrcBot/BotNetworkCommands.hs | 59 +++++++++++++++++++++++++++ src/IrcBot/IrcBot.hs | 45 ++++++++++++++++++++ src/IrcBot/JsonConfigDecoder.hs | 35 ++++++++++++++++ src/IrcBot/MessageParser.hs | 51 +++++++++++++++++++++++ src/IrcBot/RandomFileFinder.hs | 18 ++++++++ src/IrcBot/RemoteUploader.hs | 14 +++++++ stack.yaml | 64 +++++++++++++++++++++++++++++ stack.yaml.lock | 12 ++++++ test/Spec.hs | 2 + 21 files changed, 724 insertions(+) create mode 100644 .gitignore create mode 100644 ChangeLog.md create mode 100644 LICENSE create mode 100644 README.md create mode 100644 Setup.hs create mode 100644 app/Main.hs create mode 100644 example.json create mode 100644 haskell-basic-irc-bot.cabal create mode 100644 package.yaml create mode 100644 src/IrcBot/BotActions.hs create mode 100644 src/IrcBot/BotCustomCommands.hs create mode 100644 src/IrcBot/BotNetwork.hs create mode 100644 src/IrcBot/BotNetworkCommands.hs create mode 100644 src/IrcBot/IrcBot.hs create mode 100644 src/IrcBot/JsonConfigDecoder.hs create mode 100644 src/IrcBot/MessageParser.hs create mode 100644 src/IrcBot/RandomFileFinder.hs create mode 100644 src/IrcBot/RemoteUploader.hs create mode 100644 stack.yaml create mode 100644 stack.yaml.lock create mode 100644 test/Spec.hs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6ee00f6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.connection.json +.warehouse/ +.stack-work/ +!haskell-basic-irc-bot.cabal +*~ diff --git a/ChangeLog.md b/ChangeLog.md new file mode 100644 index 0000000..f779eba --- /dev/null +++ b/ChangeLog.md @@ -0,0 +1,3 @@ +# Changelog for haskell-basic-irc-bot + +## Unreleased changes diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..102126f --- /dev/null +++ b/LICENSE @@ -0,0 +1,30 @@ +Copyright Author name here (c) 2019 + +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 Author name here nor the names of other + 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 THE COPYRIGHT +OWNER OR CONTRIBUTORS 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. diff --git a/README.md b/README.md new file mode 100644 index 0000000..9548b34 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# haskell-basic-irc-bot diff --git a/Setup.hs b/Setup.hs new file mode 100644 index 0000000..9a994af --- /dev/null +++ b/Setup.hs @@ -0,0 +1,2 @@ +import Distribution.Simple +main = defaultMain diff --git a/app/Main.hs b/app/Main.hs new file mode 100644 index 0000000..d6570e0 --- /dev/null +++ b/app/Main.hs @@ -0,0 +1,41 @@ +{-# LANGUAGE MultiWayIf #-} + + +import IrcBot.IrcBot as I +import IrcBot.JsonConfigDecoder +import qualified Data.ByteString.Lazy as C +import Data.Aeson +import Data.Maybe +import qualified Control.Concurrent as T + + + + +initWithOptions:: Maybe IOptions -> IO() +initWithOptions (Just options) = do + let serverAddresses = (servers options) + mapM (\x -> T.forkIO (I.connectToIRCServer x)) serverAddresses + print "[all threads initialized!]" + +initWithOptions _ = print "BAD OPTIONS JSON" + + +mainLoop :: IO () +mainLoop = do + T.threadDelay 1000000 + mainLoop + +main :: IO () +main = do + + let externalVar = [] + output <- C.readFile ".connection.json" + let options = decode output :: Maybe IOptions + -- let servers = decode output :: Maybe IServerAddress + initWithOptions options + -- let serverAddress = fromJust serverAddressDecoded + + -- mapM (\x -> I.connectToIRCServer x) servers + -- I.connectToIRCServer servers + mainLoop + print "its over" diff --git a/example.json b/example.json new file mode 100644 index 0000000..1eb4f85 --- /dev/null +++ b/example.json @@ -0,0 +1,22 @@ +{ + "servers": [ + { + "server": "irc.freenode.net", + "port": 6697, + "ssl": true, + "nickname": "hBotTest1", + "channels": [ + "#123123123123_test_channel" + ] + }, + { + "server": "irc.freenode.net", + "port": 6697, + "ssl": true, + "nickname": "hBotTest", + "channels": [ + "#123123123123_test_channel1" + ] + } + ] +} \ No newline at end of file diff --git a/haskell-basic-irc-bot.cabal b/haskell-basic-irc-bot.cabal new file mode 100644 index 0000000..b3819b3 --- /dev/null +++ b/haskell-basic-irc-bot.cabal @@ -0,0 +1,88 @@ +cabal-version: 1.12 + +-- This file has been generated from package.yaml by hpack version 0.31.2. +-- +-- see: https://github.com/sol/hpack +-- +-- hash: 73007a389ec8f6641f20fee7630b2329226a4677d5a1c4a2dfe3c7fcb973f5ad + +name: haskell-basic-irc-bot +version: 0.1.0.0 +description: Please see the README on GitHub at +homepage: https://github.com/githubuser/haskell-basic-irc-bot#readme +bug-reports: https://github.com/githubuser/haskell-basic-irc-bot/issues +author: Author name here +maintainer: example@example.com +copyright: 2019 Author name here +license: BSD3 +license-file: LICENSE +build-type: Simple +extra-source-files: + README.md + ChangeLog.md + +source-repository head + type: git + location: https://github.com/githubuser/haskell-basic-irc-bot + +library + exposed-modules: + IrcBot.BotNetwork + , IrcBot.BotNetworkCommands + , IrcBot.JsonConfigDecoder + , IrcBot.BotActions + , IrcBot.MessageParser + , IrcBot.RemoteUploader + , IrcBot.IrcBot + , IrcBot.RandomFileFinder + , IrcBot.BotCustomCommands + other-modules: + Paths_haskell_basic_irc_bot + hs-source-dirs: + src + build-depends: + base >=4.7 && <5 + , network + , bytestring + , text + , process + , directory + , random + , connection + , json + , aeson + , MissingH + default-language: Haskell2010 + +executable haskell-basic-irc-bot-exe + main-is: Main.hs + other-modules: + Paths_haskell_basic_irc_bot + hs-source-dirs: + app + ghc-options: -threaded -rtsopts -with-rtsopts=-N + build-depends: + base >=4.7 && <5 + , haskell-basic-irc-bot + , network + , bytestring + , text + , process + , random + , connection + , json + , aeson + default-language: Haskell2010 + +test-suite haskell-basic-irc-bot-test + type: exitcode-stdio-1.0 + main-is: Spec.hs + other-modules: + Paths_haskell_basic_irc_bot + hs-source-dirs: + test + ghc-options: -threaded -rtsopts -with-rtsopts=-N + build-depends: + base >=4.7 && <5 + , haskell-basic-irc-bot + default-language: Haskell2010 diff --git a/package.yaml b/package.yaml new file mode 100644 index 0000000..6303f83 --- /dev/null +++ b/package.yaml @@ -0,0 +1,48 @@ +name: haskell-basic-irc-bot +version: 0.1.0.0 +github: "githubuser/haskell-basic-irc-bot" +license: BSD3 +author: "Author name here" +maintainer: "example@example.com" +copyright: "2019 Author name here" + +extra-source-files: +- README.md +- ChangeLog.md + +# Metadata used when publishing your package +# synopsis: Short description of your package +# category: Web + +# To avoid duplicated efforts in documentation and dealing with the +# complications of embedding Haddock markup inside cabal files, it is +# common to point users to the README.md file. +description: Please see the README on GitHub at + +dependencies: +- base >= 4.7 && < 5 + +library: + source-dirs: src + +executables: + haskell-basic-irc-bot-exe: + main: Main.hs + source-dirs: app + ghc-options: + - -threaded + - -rtsopts + - -with-rtsopts=-N + dependencies: + - haskell-basic-irc-bot + +tests: + haskell-basic-irc-bot-test: + main: Spec.hs + source-dirs: test + ghc-options: + - -threaded + - -rtsopts + - -with-rtsopts=-N + dependencies: + - haskell-basic-irc-bot diff --git a/src/IrcBot/BotActions.hs b/src/IrcBot/BotActions.hs new file mode 100644 index 0000000..f4d38ea --- /dev/null +++ b/src/IrcBot/BotActions.hs @@ -0,0 +1,63 @@ +{-# LANGUAGE MultiWayIf #-} + +module IrcBot.BotActions where + + +import Network.Connection +import Network.Socket hiding (send, sendTo, recv, recvFrom) +import qualified Data.ByteString.Char8 as C +import IrcBot.BotNetwork +import IrcBot.BotNetworkCommands +import IrcBot.MessageParser +import IrcBot.BotCustomCommands + +messageParse:: Connection -> C.ByteString -> IO() + + +-- its kind of interface for actionFunctions +callActionFunction :: (IServerResponse -> IO()) -> IServerResponse -> IO () +callActionFunction myFunc parameter1 = myFunc parameter1 + + +messageParse sock stringData = + do + let unpackedByteString = C.unpack stringData + let debugData = "READ DATA FROM SOCKET: " ++ unpackedByteString + let userNick = parseNick unpackedByteString + let channelName = parseChannelName unpackedByteString + let messageText = parseMessageText unpackedByteString + let newServerResponse = IServerResponse { + readDataString = unpackedByteString, + readDataByteString = stringData, + sock = sock, + channelName = channelName, + nick = userNick, + messageText = messageText + } + mapM (\x -> callActionFunction (x) newServerResponse) (methods myMethodList) + let d = "PARSE PURSE MESASGE: " ++ messageText + print d + print debugData + -- if | hasStringExist "PING " stringData -> pong sock unpackedByteString + -- | hasStringExist ".sup" stringData -> sendMessage sock channelName ("sup " ++ userNick) + -- | hasStringExist " KICK #" stringData -> joinChannel sock channelName >> {-- auto connect in case of kick --} sendMessage sock channelName "fuck you" + -- | hasStringExist ".random" stringData -> basicRandomImplementation unpackedByteString >>= \commandOutput -> sendMessage sock channelName commandOutput + -- | hasStringExist ".quit" stringData -> quitFromServer sock channelName + -- | hasStringExist ".leave" stringData -> disconnectFromChannel sock channelName + -- | otherwise -> print "NO CONDITION FOUND TO PARSE" + +connectToServer :: String -> PortNumber -> Bool -> IO Connection +connectToServer server port ssl = do + open server port ssl + +connectionLoop :: Connection -> IO Connection +connectionLoop sock = + do + stringData <- readFromSocket sock + messageParse sock stringData + case stringData == C.empty of + False -> do + connectionLoop sock + True -> do + return sock + diff --git a/src/IrcBot/BotCustomCommands.hs b/src/IrcBot/BotCustomCommands.hs new file mode 100644 index 0000000..84e8e23 --- /dev/null +++ b/src/IrcBot/BotCustomCommands.hs @@ -0,0 +1,72 @@ +{-# LANGUAGE MultiWayIf #-} + +module IrcBot.BotCustomCommands where + +import Network.Connection +import qualified Data.ByteString.Char8 as C +import IrcBot.BotNetwork +import IrcBot.BotNetworkCommands +import IrcBot.MessageParser + +data IServerResponse = IServerResponse + { + readDataString :: String, + readDataByteString :: C.ByteString, + sock :: Connection, + channelName :: String, + nick :: String, + messageText :: String + } + +data MethodList = MethodList { methods :: [IServerResponse -> IO()]} + + + +hasStringExist:: String -> C.ByteString -> Bool +hasStringExist search source = + do + let byteStringSearch = C.pack search + C.isInfixOf byteStringSearch source + + + +basicEcho :: IServerResponse -> IO () +basicEcho serverResponse = do + if | hasStringExist ".echo" (readDataByteString serverResponse) -> sendMessage (sock serverResponse) (channelName serverResponse) "EXAMPLE MESSAGE" + | otherwise -> print "NO CONDITION FOUND TO PARSE" + + +ping :: IServerResponse -> IO () +ping serverResponse = do + if | hasStringExist "PING " (readDataByteString serverResponse) -> pong (sock serverResponse) (readDataString serverResponse) + | otherwise -> print "NO CONDITION FOUND TO PARSE" + + + +autoconnect :: IServerResponse -> IO () +autoconnect serverResponse = do + if | hasStringExist " KICK #" (readDataByteString serverResponse) -> joinChannel (sock serverResponse) (channelName serverResponse) >> {-- auto connect in case of kick --} sendMessage (sock serverResponse) (channelName serverResponse) "automated rejoin, if you want me to leave use .leave" + | otherwise -> print "NO CONDITION FOUND TO PARSE" + + +randomImage :: IServerResponse -> IO () +randomImage serverResponse = do + if | hasStringExist ".random" (readDataByteString serverResponse) -> basicRandomImplementation (readDataString serverResponse) >>= \commandOutput -> sendMessage (sock serverResponse) (channelName serverResponse) commandOutput + | otherwise -> print "NO CONDITION FOUND TO PARSE" + + +quit :: IServerResponse -> IO () +quit serverResponse = do + if | hasStringExist ".quit" (readDataByteString serverResponse) -> quitFromServer (sock serverResponse) (channelName serverResponse) + | otherwise -> print "NO CONDITION FOUND TO PARSE" + + + +leave :: IServerResponse -> IO () +leave serverResponse = do + if | hasStringExist ".leave" (readDataByteString serverResponse) -> disconnectFromChannel (sock serverResponse) (channelName serverResponse) + | otherwise -> print "NO CONDITION FOUND TO PARSE" + + + +myMethodList = MethodList {methods = [basicEcho, ping, autoconnect, randomImage, quit, leave] } \ No newline at end of file diff --git a/src/IrcBot/BotNetwork.hs b/src/IrcBot/BotNetwork.hs new file mode 100644 index 0000000..ba98a0f --- /dev/null +++ b/src/IrcBot/BotNetwork.hs @@ -0,0 +1,49 @@ +{-# LANGUAGE MultiWayIf #-} + +module IrcBot.BotNetwork where + +import Network.Socket hiding (send, sendTo, recv, recvFrom) +import Network.Socket.ByteString (recv, sendAll) +import qualified Data.ByteString.Char8 as C +import Network.Connection + +readFromSocket:: Connection -> IO C.ByteString +writeToSocket:: Connection -> String -> IO() + + +writeToSocket sock stringData = + do + let socketString = stringData ++ "\n" + let byteStringDataConverter = C.pack socketString + connectionPut sock byteStringDataConverter + print "SENT DATA IS: " + print byteStringDataConverter + +readFromSocket sock = + do + msg <- connectionGet sock 1024 + case msg == C.empty of + False -> do + return msg + True -> do + return C.empty + + +open:: String -> PortNumber -> Bool -> IO Connection + +open server port ssl = do + ctx <- initConnectionContext + -- sock <- socket (addrFamily addr) (addrSocketType addr) (addrProtocol addr) + print "CONNECTING" + ctx <- initConnectionContext + con <- connectTo ctx $ ConnectionParams + { connectionHostname = server + , connectionPort = port + , connectionUseSecure = case ssl of + True -> Just $ Network.Connection.TLSSettingsSimple False False True + False -> Nothing + , connectionUseSocks = Nothing + } + print "CONNECTED" + return con + diff --git a/src/IrcBot/BotNetworkCommands.hs b/src/IrcBot/BotNetworkCommands.hs new file mode 100644 index 0000000..0f5559e --- /dev/null +++ b/src/IrcBot/BotNetworkCommands.hs @@ -0,0 +1,59 @@ +module IrcBot.BotNetworkCommands where + +import IrcBot.BotNetwork (writeToSocket) +import Network.Socket hiding (send, sendTo, recv, recvFrom) +import Network.Connection +import Data.List.Utils (replace) + +sendMessage :: Connection -> String -> String -> IO () + +sendMessage sock targetChannel stringData = + do + let combiendStringData = "PRIVMSG " ++ targetChannel ++ " :" ++ stringData + writeToSocket sock combiendStringData + + + +quitFromServer :: Connection -> String -> IO () + +quitFromServer sock targetChannel = + do + writeToSocket sock "QUIT" + +disconnectFromChannel :: Connection -> String -> IO () + +disconnectFromChannel sock targetChannel = + do + writeToSocket sock ("PART " ++ targetChannel) + + + +initBotName :: Connection -> String -> IO () + +initBotName sock botName = + do + let dataString = "USER "++ botName ++" "++ botName ++" "++ botName ++" :learning purpose bot" + writeToSocket sock dataString + + +initBotNick :: Connection -> String -> IO () + +initBotNick sock botNick = + do + let nick = "NICK " ++ botNick + writeToSocket sock nick + + +joinChannel :: Connection -> String -> IO () + +joinChannel sock channelName = + do + let combinedString = "JOIN " ++ channelName + writeToSocket sock combinedString + + +pong :: Connection -> String -> IO () + +pong sock receivedStringData = do + let replacedText = replace "PING" "PONG" receivedStringData + writeToSocket sock replacedText \ No newline at end of file diff --git a/src/IrcBot/IrcBot.hs b/src/IrcBot/IrcBot.hs new file mode 100644 index 0000000..2b3accd --- /dev/null +++ b/src/IrcBot/IrcBot.hs @@ -0,0 +1,45 @@ +{-# LANGUAGE MultiParamTypeClasses #-} + +module IrcBot.IrcBot where + +import Network.Socket +import IrcBot.BotNetworkCommands +import IrcBot.BotActions +import IrcBot.BotNetwork +import Network.Connection +import qualified Control.Concurrent as T +import qualified Data.ByteString.Char8 as C + +data IServerAddress = IServerAddress + { + server :: String , + port :: Int, + ssl :: Bool, + nickname :: String, + channels :: [String] + } deriving (Show) + +data IOptions = IOptions + { + servers :: [Maybe IServerAddress] + } deriving (Show) + + + + +connectToIRCServer :: Maybe IServerAddress -> IO () +connectToIRCServer (Just serverAddress) = do + newSock <- connectToServer (server serverAddress) (fromIntegral (port serverAddress)) (ssl serverAddress) + print "[connected to server]" + initBotName newSock (nickname serverAddress) + initBotNick newSock (nickname serverAddress) + let channelsToJoin = channels serverAddress + mapM (\x -> joinChannel newSock x) channelsToJoin + connectionLoop newSock + print "sleeping 15 sec for reconnect" + -- 1000000 is 1 second + T.threadDelay (1000000 * 15) + print "reconnecting sequence initializing" + -- this is a recursive function and its maintaining own connectivity + -- how deep can i call this function? or just compiler optimizes for me? no idea + connectToIRCServer (Just serverAddress) \ No newline at end of file diff --git a/src/IrcBot/JsonConfigDecoder.hs b/src/IrcBot/JsonConfigDecoder.hs new file mode 100644 index 0000000..5e5c146 --- /dev/null +++ b/src/IrcBot/JsonConfigDecoder.hs @@ -0,0 +1,35 @@ +{-# LANGUAGE OverloadedStrings #-} + +module IrcBot.JsonConfigDecoder where + +import Data.Aeson +import Network.Socket +import IrcBot.IrcBot +import qualified Data.ByteString.Lazy as C + + +instance FromJSON IServerAddress where + parseJSON = withObject "IServerAddress" $ \o -> do + server_ <- o .: "server" + port_ <- o .: "port" + ssl_ <- o .: "ssl" + nickname_ <- o .: "nickname" + channels_ <- o .: "channels" + return $ IServerAddress server_ port_ ssl_ nickname_ channels_ + + +instance FromJSON IOptions where + parseJSON = withObject "IOptions" $ \o -> do + servers_ <- o .: "servers" + return $ IOptions servers_ + + +--readConfigFile :: Maybe IServerAddress +--readConfigFile = C.readFile ".connection.json" >>= \output -> decode output :: Maybe IServerAddress + + + + + + + diff --git a/src/IrcBot/MessageParser.hs b/src/IrcBot/MessageParser.hs new file mode 100644 index 0000000..63a68c2 --- /dev/null +++ b/src/IrcBot/MessageParser.hs @@ -0,0 +1,51 @@ +{-# LANGUAGE OverloadedStrings #-} +module IrcBot.MessageParser where + +import Data.List +import Data.Maybe +import IrcBot.RandomFileFinder +import IrcBot.RemoteUploader + +getNthElementFromString :: String -> Int -> Char +getNthElementFromString stringData step = stringData !! step + + + + +slice :: Int -> Int -> String -> String +slice start end = take (end-start-1) . drop (start+1) + + + +-- :YOUR_NICK!~YOUR_NICK@YOUR_IP PRIVMSG #91623_my_test_channel + +parseNick :: String -> String + +parseNick dataString = + do + let startIndex = elemIndex ':' dataString + let endIndex = elemIndex '!' dataString + slice (fromJust startIndex) (fromJust endIndex) dataString + +parseChannelName :: String -> String + +parseChannelName dataString = + do + let startIndex = elemIndex '#' dataString + let dropppedString = drop (fromJust startIndex) dataString + let endIndex = elemIndex ' ' dropppedString + take (fromJust endIndex) dropppedString + + + +parseMessageText :: String -> String +parseMessageText dataString = + do + (drop 1 (unwords (drop 3 (words dataString)))) + + + + +basicRandomImplementation :: String -> IO String + +basicRandomImplementation basicInput = getRandomFile "maidos" >>= \randomFileName -> uploadLocalFile randomFileName \ No newline at end of file diff --git a/src/IrcBot/RandomFileFinder.hs b/src/IrcBot/RandomFileFinder.hs new file mode 100644 index 0000000..d9d140d --- /dev/null +++ b/src/IrcBot/RandomFileFinder.hs @@ -0,0 +1,18 @@ +module IrcBot.RandomFileFinder where + +import System.Directory +import System.Random + + + +getRandomFile :: String -> IO String + + +getRandomFile directoryName = + do + let fullDirectoryName = "./.warehouse/" ++ directoryName + directoryItems <- getDirectoryContents fullDirectoryName + result <- return (length directoryItems) >>= \count -> randomRIO(4,count) :: IO Int + let fileName = directoryItems !! result + let newFileName = ".warehouse/" ++ directoryName ++ "/" ++ fileName + return newFileName diff --git a/src/IrcBot/RemoteUploader.hs b/src/IrcBot/RemoteUploader.hs new file mode 100644 index 0000000..4406cb1 --- /dev/null +++ b/src/IrcBot/RemoteUploader.hs @@ -0,0 +1,14 @@ +module IrcBot.RemoteUploader where + + +import System.Process + + +uploadLocalFile:: String -> IO String + +uploadLocalFile filePath = + do + let command = "curl" + let params = "file=@"++ filePath + readProcess command ["-F",params,"0x0.st"] "" + diff --git a/stack.yaml b/stack.yaml new file mode 100644 index 0000000..eb1d111 --- /dev/null +++ b/stack.yaml @@ -0,0 +1,64 @@ +# This file was automatically generated by 'stack init' +# +# Some commonly used options have been documented as comments in this file. +# For advanced use and comprehensive documentation of the format, please see: +# https://docs.haskellstack.org/en/stable/yaml_configuration/ + +# Resolver to choose a 'specific' stackage snapshot or a compiler version. +# A snapshot resolver dictates the compiler version and the set of packages +# to be used for project dependencies. For example: +# +# resolver: lts-3.5 +# resolver: nightly-2015-09-21 +# resolver: ghc-7.10.2 +# +# The location of a snapshot can be provided as a file or url. Stack assumes +# a snapshot provided as a file might change, whereas a url resource does not. +# +# resolver: ./custom-snapshot.yaml +# resolver: https://example.com/snapshots/2018-01-01.yaml +resolver: lts-13.28 + +# User packages to be built. +# Various formats can be used as shown in the example below. +# +# packages: +# - some-directory +# - https://example.com/foo/bar/baz-0.0.2.tar.gz +# - location: +# git: https://github.com/commercialhaskell/stack.git +# commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a +# - location: https://github.com/commercialhaskell/stack/commit/e7b331f14bcffb8367cd58fbfc8b40ec7642100a +# subdirs: +# - auto-update +# - wai +packages: +- . +# Dependency packages to be pulled from upstream that are not in the resolver +# using the same syntax as the packages field. +# (e.g., acme-missiles-0.3) +# extra-deps: [] + +# Override default flag values for local packages and extra-deps +# flags: {} + +# Extra package databases containing global packages +# extra-package-dbs: [] + +# Control whether we use the GHC we find on the path +# system-ghc: true +# +# Require a specific version of stack, using version ranges +# require-stack-version: -any # Default +# require-stack-version: ">=1.9" +# +# Override the architecture used by stack, especially useful on Windows +# arch: i386 +# arch: x86_64 +# +# Extra directories used by stack for building +# extra-include-dirs: [/path/to/dir] +# extra-lib-dirs: [/path/to/dir] +# +# Allow a newer minor version of GHC than the snapshot specifies +# compiler-check: newer-minor diff --git a/stack.yaml.lock b/stack.yaml.lock new file mode 100644 index 0000000..b984045 --- /dev/null +++ b/stack.yaml.lock @@ -0,0 +1,12 @@ +# This file was autogenerated by Stack. +# You should not edit this file by hand. +# For more information, please see the documentation at: +# https://docs.haskellstack.org/en/stable/lock_files + +packages: [] +snapshots: +- completed: + size: 500539 + url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/13/28.yaml + sha256: cdde1bfb38fdee21c6acb73d506e78f7e12e0a73892adbbbe56374ebef4d3adf + original: lts-13.28 diff --git a/test/Spec.hs b/test/Spec.hs new file mode 100644 index 0000000..cd4753f --- /dev/null +++ b/test/Spec.hs @@ -0,0 +1,2 @@ +main :: IO () +main = putStrLn "Test suite not yet implemented"