\begin{code} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE StrictData #-} module Network.Tox.SaveData.Friend where import Data.Binary (Binary (..)) import qualified Data.Binary.Get as Get import qualified Data.Binary.Put as Put import qualified Data.ByteString as BS import Data.MessagePack (MessagePack) import Data.Word (Word32, Word64, Word8) import GHC.Generics (Generic) import Network.Tox.Crypto.Key (PublicKey) import Test.QuickCheck.Arbitrary (Arbitrary, arbitrary) \end{code} Friend: The integers in this structure are stored in Big Endian format. \begin{tabular}{l|l} Length & Contents \\ \hline \texttt{1} & \texttt{uint8\_t} Status \\ \texttt{32} & Long term public key \\ \texttt{1024} & Friend request message as a byte string \\ \texttt{1} & PADDING \\ \texttt{2} & \texttt{uint16\_t} Size of the friend request message \\ \texttt{128} & Name as a byte string \\ \texttt{2} & \texttt{uint16\_t} Size of the name \\ \texttt{1007} & Status message as a byte string \\ \texttt{1} & PADDING \\ \texttt{2} & \texttt{uint16\_t} Size of the status message \\ \texttt{1} & \texttt{uint8\_t} User status (see also: \texttt{USERSTATUS}) \\ \texttt{3} & PADDING \\ \texttt{4} & \texttt{uint32\_t} Nospam (only used for sending a friend request) \\ \texttt{8} & \texttt{uint64\_t} Last seen time \\ \end{tabular} Status can be one of: \begin{tabular}{l|l} Status & Meaning \\ \hline 0 & Not a friend \\ 1 & Friend added \\ 2 & Friend request sent \\ 3 & Confirmed friend \\ 4 & Friend online \\ \end{tabular} \begin{code} data Friend = Friend { Friend -> Word8 status :: Word8 , Friend -> PublicKey publicKey :: PublicKey , Friend -> ByteString friendRequest :: BS.ByteString , Friend -> ByteString name :: BS.ByteString , Friend -> ByteString statusMessage :: BS.ByteString , Friend -> Word8 userStatus :: Word8 , Friend -> Word32 nospam :: Word32 , Friend -> Word64 lastSeenTime :: Word64 } deriving (Friend -> Friend -> Bool (Friend -> Friend -> Bool) -> (Friend -> Friend -> Bool) -> Eq Friend forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a /= :: Friend -> Friend -> Bool $c/= :: Friend -> Friend -> Bool == :: Friend -> Friend -> Bool $c== :: Friend -> Friend -> Bool Eq, Int -> Friend -> ShowS [Friend] -> ShowS Friend -> String (Int -> Friend -> ShowS) -> (Friend -> String) -> ([Friend] -> ShowS) -> Show Friend forall a. (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a showList :: [Friend] -> ShowS $cshowList :: [Friend] -> ShowS show :: Friend -> String $cshow :: Friend -> String showsPrec :: Int -> Friend -> ShowS $cshowsPrec :: Int -> Friend -> ShowS Show, ReadPrec [Friend] ReadPrec Friend Int -> ReadS Friend ReadS [Friend] (Int -> ReadS Friend) -> ReadS [Friend] -> ReadPrec Friend -> ReadPrec [Friend] -> Read Friend forall a. (Int -> ReadS a) -> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a readListPrec :: ReadPrec [Friend] $creadListPrec :: ReadPrec [Friend] readPrec :: ReadPrec Friend $creadPrec :: ReadPrec Friend readList :: ReadS [Friend] $creadList :: ReadS [Friend] readsPrec :: Int -> ReadS Friend $creadsPrec :: Int -> ReadS Friend Read, (forall x. Friend -> Rep Friend x) -> (forall x. Rep Friend x -> Friend) -> Generic Friend forall x. Rep Friend x -> Friend forall x. Friend -> Rep Friend x forall a. (forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a $cto :: forall x. Rep Friend x -> Friend $cfrom :: forall x. Friend -> Rep Friend x Generic) instance MessagePack Friend maxFriendRequestLen :: Int maxFriendRequestLen :: Int maxFriendRequestLen = Int 1024 maxNameLen :: Int maxNameLen :: Int maxNameLen = Int 128 maxStatusMessageLen :: Int maxStatusMessageLen :: Int maxStatusMessageLen = Int 1007 instance Binary Friend where get :: Get Friend get = do Word8 status <- Get Word8 Get.getWord8 PublicKey publicKey <- Get PublicKey forall t. Binary t => Get t get ByteString friendRequest' <- Int -> Get ByteString Get.getByteString Int maxFriendRequestLen Word8 _ <- Get Word8 Get.getWord8 Word16 friendRequestLen <- Get Word16 Get.getWord16be ByteString name' <- Int -> Get ByteString Get.getByteString Int maxNameLen Word16 nameLen <- Get Word16 Get.getWord16be ByteString statusMessage' <- Int -> Get ByteString Get.getByteString Int maxStatusMessageLen Word8 _ <- Get Word8 Get.getWord8 Word16 statusMessageLen <- Get Word16 Get.getWord16be Word8 userStatus <- Get Word8 Get.getWord8 ByteString _ <- Int -> Get ByteString Get.getByteString Int 3 Word32 nospam <- Get Word32 Get.getWord32be Word64 lastSeenTime <- Get Word64 Get.getWord64be let friendRequest :: ByteString friendRequest = Int -> ByteString -> ByteString BS.take (Word16 -> Int forall a b. (Integral a, Num b) => a -> b fromIntegral Word16 friendRequestLen) ByteString friendRequest' let name :: ByteString name = Int -> ByteString -> ByteString BS.take (Word16 -> Int forall a b. (Integral a, Num b) => a -> b fromIntegral Word16 nameLen) ByteString name' let statusMessage :: ByteString statusMessage = Int -> ByteString -> ByteString BS.take (Word16 -> Int forall a b. (Integral a, Num b) => a -> b fromIntegral Word16 statusMessageLen) ByteString statusMessage' Friend -> Get Friend forall (m :: * -> *) a. Monad m => a -> m a return Friend :: Word8 -> PublicKey -> ByteString -> ByteString -> ByteString -> Word8 -> Word32 -> Word64 -> Friend Friend{Word8 Word32 Word64 ByteString PublicKey statusMessage :: ByteString name :: ByteString friendRequest :: ByteString lastSeenTime :: Word64 nospam :: Word32 userStatus :: Word8 publicKey :: PublicKey status :: Word8 lastSeenTime :: Word64 nospam :: Word32 userStatus :: Word8 statusMessage :: ByteString name :: ByteString friendRequest :: ByteString publicKey :: PublicKey status :: Word8 ..} put :: Friend -> Put put Friend {Word8 Word32 Word64 ByteString PublicKey lastSeenTime :: Word64 nospam :: Word32 userStatus :: Word8 statusMessage :: ByteString name :: ByteString friendRequest :: ByteString publicKey :: PublicKey status :: Word8 lastSeenTime :: Friend -> Word64 nospam :: Friend -> Word32 userStatus :: Friend -> Word8 statusMessage :: Friend -> ByteString name :: Friend -> ByteString friendRequest :: Friend -> ByteString publicKey :: Friend -> PublicKey status :: Friend -> Word8 ..} = do let friendRequestLen :: Int friendRequestLen = ByteString -> Int BS.length ByteString friendRequest let friendRequest' :: ByteString friendRequest' = ByteString friendRequest ByteString -> ByteString -> ByteString forall a. Semigroup a => a -> a -> a <> Int -> Word8 -> ByteString BS.replicate (Int maxFriendRequestLen Int -> Int -> Int forall a. Num a => a -> a -> a - Int friendRequestLen) Word8 0 let nameLen :: Int nameLen = ByteString -> Int BS.length ByteString name let name' :: ByteString name' = ByteString name ByteString -> ByteString -> ByteString forall a. Semigroup a => a -> a -> a <> Int -> Word8 -> ByteString BS.replicate (Int maxNameLen Int -> Int -> Int forall a. Num a => a -> a -> a - Int nameLen) Word8 0 let statusMessageLen :: Int statusMessageLen = ByteString -> Int BS.length ByteString statusMessage let statusMessage' :: ByteString statusMessage' = ByteString statusMessage ByteString -> ByteString -> ByteString forall a. Semigroup a => a -> a -> a <> Int -> Word8 -> ByteString BS.replicate (Int maxStatusMessageLen Int -> Int -> Int forall a. Num a => a -> a -> a - Int statusMessageLen) Word8 0 Word8 -> Put Put.putWord8 Word8 status PublicKey -> Put forall t. Binary t => t -> Put put PublicKey publicKey ByteString -> Put Put.putByteString ByteString friendRequest' Word8 -> Put Put.putWord8 Word8 0 Word16 -> Put Put.putWord16be (Int -> Word16 forall a b. (Integral a, Num b) => a -> b fromIntegral Int friendRequestLen) ByteString -> Put Put.putByteString ByteString name' Word16 -> Put Put.putWord16be (Int -> Word16 forall a b. (Integral a, Num b) => a -> b fromIntegral Int nameLen) ByteString -> Put Put.putByteString ByteString statusMessage' Word8 -> Put Put.putWord8 Word8 0 Word16 -> Put Put.putWord16be (Int -> Word16 forall a b. (Integral a, Num b) => a -> b fromIntegral Int statusMessageLen) Word8 -> Put Put.putWord8 Word8 userStatus ByteString -> Put Put.putByteString ByteString "\0\0\0" Word32 -> Put Put.putWord32be Word32 nospam Word64 -> Put Put.putWord64be Word64 lastSeenTime instance Arbitrary Friend where arbitrary :: Gen Friend arbitrary = Word8 -> PublicKey -> ByteString -> ByteString -> ByteString -> Word8 -> Word32 -> Word64 -> Friend Friend (Word8 -> PublicKey -> ByteString -> ByteString -> ByteString -> Word8 -> Word32 -> Word64 -> Friend) -> Gen Word8 -> Gen (PublicKey -> ByteString -> ByteString -> ByteString -> Word8 -> Word32 -> Word64 -> Friend) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b <$> Gen Word8 forall a. Arbitrary a => Gen a arbitrary Gen (PublicKey -> ByteString -> ByteString -> ByteString -> Word8 -> Word32 -> Word64 -> Friend) -> Gen PublicKey -> Gen (ByteString -> ByteString -> ByteString -> Word8 -> Word32 -> Word64 -> Friend) forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b <*> Gen PublicKey forall a. Arbitrary a => Gen a arbitrary Gen (ByteString -> ByteString -> ByteString -> Word8 -> Word32 -> Word64 -> Friend) -> Gen ByteString -> Gen (ByteString -> ByteString -> Word8 -> Word32 -> Word64 -> Friend) forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b <*> ([Word8] -> ByteString BS.pack ([Word8] -> ByteString) -> ([Word8] -> [Word8]) -> [Word8] -> ByteString forall b c a. (b -> c) -> (a -> b) -> a -> c . Int -> [Word8] -> [Word8] forall a. Int -> [a] -> [a] take Int maxFriendRequestLen ([Word8] -> ByteString) -> Gen [Word8] -> Gen ByteString forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b <$> Gen [Word8] forall a. Arbitrary a => Gen a arbitrary) Gen (ByteString -> ByteString -> Word8 -> Word32 -> Word64 -> Friend) -> Gen ByteString -> Gen (ByteString -> Word8 -> Word32 -> Word64 -> Friend) forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b <*> ([Word8] -> ByteString BS.pack ([Word8] -> ByteString) -> ([Word8] -> [Word8]) -> [Word8] -> ByteString forall b c a. (b -> c) -> (a -> b) -> a -> c . Int -> [Word8] -> [Word8] forall a. Int -> [a] -> [a] take Int maxNameLen ([Word8] -> ByteString) -> Gen [Word8] -> Gen ByteString forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b <$> Gen [Word8] forall a. Arbitrary a => Gen a arbitrary) Gen (ByteString -> Word8 -> Word32 -> Word64 -> Friend) -> Gen ByteString -> Gen (Word8 -> Word32 -> Word64 -> Friend) forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b <*> ([Word8] -> ByteString BS.pack ([Word8] -> ByteString) -> ([Word8] -> [Word8]) -> [Word8] -> ByteString forall b c a. (b -> c) -> (a -> b) -> a -> c . Int -> [Word8] -> [Word8] forall a. Int -> [a] -> [a] take Int maxStatusMessageLen ([Word8] -> ByteString) -> Gen [Word8] -> Gen ByteString forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b <$> Gen [Word8] forall a. Arbitrary a => Gen a arbitrary) Gen (Word8 -> Word32 -> Word64 -> Friend) -> Gen Word8 -> Gen (Word32 -> Word64 -> Friend) forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b <*> Gen Word8 forall a. Arbitrary a => Gen a arbitrary Gen (Word32 -> Word64 -> Friend) -> Gen Word32 -> Gen (Word64 -> Friend) forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b <*> Gen Word32 forall a. Arbitrary a => Gen a arbitrary Gen (Word64 -> Friend) -> Gen Word64 -> Gen Friend forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b <*> Gen Word64 forall a. Arbitrary a => Gen a arbitrary \end{code}