blob: 5e6aace61606ba926b0757497b6f73932858186c (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
|
{-# LANGUAGE ViewPatterns #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PatternSynonyms #-}
import Control.Monad.IO.Class
import Control.Concurrent
import Control.Concurrent.STM
import qualified Data.ByteString.Char8 as B
import Data.ByteString (ByteString)
import Data.Char
import qualified Data.Conduit as Conduit
import Data.Conduit ((.|))
import qualified Data.Conduit.Binary as Conduit
import Data.Conduit.Cereal
import Data.Function
import qualified Data.Map.Strict as Map
import Data.Monoid
import qualified Data.Serialize as S
import Data.Serialize (Get(..), Put(..))
import qualified Data.Text as T
import Data.Text.Encoding (encodeUtf8,decodeUtf8)
import Network.Tox.Crypto.Transport
import Network.Tox.Crypto.Handlers
import Network.Tox.NodeId
import System.Console.ANSI
import qualified System.Console.Terminal.Size as Term
import System.Environment
import System.Exit
import System.FilePath
import System.IO
import System.IO.Unsafe (unsafePerformIO)
import qualified System.Posix.Env.ByteString as B
import System.Posix.IO.ByteString
import System.Posix.Types
import Text.Read
-- Some Global State --
{-# NOINLINE sMe #-}
sMe :: TVar NodeId
sMe = unsafePerformIO $ newTVarIO zero
where Right zero = (S.decode $ B.replicate 32 '\NUL')
{-# NOINLINE sThem #-}
sThem :: TVar NodeId
sThem = unsafePerformIO $ newTVarIO zero
where Right zero = (S.decode $ B.replicate 32 '\NUL')
{-# NOINLINE sMap #-}
sMap :: TVar (Map.Map Key ViewSnapshot)
sMap = unsafePerformIO $ newTVarIO (Map.empty)
-----------------------
puts :: MonadIO m => ByteString -> m ()
puts = liftIO . B.putStrLn
packUtf8 :: String -> ByteString
packUtf8 = encodeUtf8 . T.pack
pshow :: Show a => a -> ByteString
pshow = packUtf8 . show
usage = do
hPutStrLn stderr "Usage: atox <INPUT-FILE-DESCRIPTOR> <OUTPUT-FILE-DESCRIPTOR>"
exitFailure
processArgs usage doit [readNum,writeNum] | Just i <- readMaybe readNum
, Just o <- readMaybe writeNum = doit i o
processArgs usage _ _ = usage
main = getArgs >>= processArgs usage doit
pattern IPC = Padding
-- | Interprocess command
data SetCmd = SetME
| SetTHEM
| SetView
deriving (Eq,Bounded,Ord,Enum,Show)
forkToxInputThread myRead = forkIO $ do
let myconduit = Conduit.sourceHandle myRead .| conduitGet2 (S.get :: Get CryptoMessage) -- :: ConduitT i CryptoMessage IO ()
Conduit.runConduit (myconduit .| Conduit.awaitForever handle)
where
handle (UpToN IPC (B.uncons -> Just (ord -> toEnum -> i,arg))) = updateState i arg
handle msg = puts (pshow msg)
updateState SetME arg = case S.decode arg of
Left str -> puts (packUtf8 str)
Right x -> liftIO . atomically . writeTVar sMe $ x
updateState SetTHEM arg = case S.decode arg of
Left str -> puts (packUtf8 str)
Right x -> liftIO . atomically . writeTVar sThem $ x
updateState SetView arg = case S.decode arg of
Left str -> puts (packUtf8 str)
Right view -> liftIO . atomically $ do
me <- readTVar sMe
them <- readTVar sThem
let key = Key me them
modifyTVar' sMap (Map.insert key view)
doit :: Fd -> Fd -> IO ()
doit myReadFd myWriteFd = do
myRead <- fdToHandle myReadFd
myWrite <- fdToHandle myWriteFd
forkToxInputThread myRead
terminalInputLoop myWrite
hSend :: MonadIO m => Handle -> CryptoMessage -> m ()
hSend h msg = liftIO $ B.hPutStrLn h (S.encode msg)
terminalInputLoop myWriteH = fix $ \loop -> do
line <- B.getLine
if "/" `B.isPrefixOf` line then let (B.drop 1 -> cmd, B.drop 1 -> arg) = B.break (==' ') line
in slashCommand myWriteH (B.drop 1 line) arg
else hSend myWriteH (UpToN MESSAGE line)
loop
slashCommand :: MonadIO m => Handle -> ByteString -> ByteString -> m ()
slashCommand h "quit" _ = do
hSend h (OneByte OFFLINE)
hSend h (OneByte KillPacket)
puts "Exiting..."
liftIO $ exitSuccess
slashCommand h "nick" (B.words -> take 1 -> [nick]) = hSend h (UpToN NICKNAME nick)
slashCommand h "away" msg = do
hSend h (TwoByte USERSTATUS (fromEnum8 Away))
hSend h (UpToN STATUSMESSAGE msg)
slashCommand h "back" msg = do
hSend h (TwoByte USERSTATUS (fromEnum8 Online))
hSend h (UpToN STATUSMESSAGE msg)
slashCommand h cmd _ = do
puts $ "UNKNOWN COMMAND: " <> cmd
|