\begin{code} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-} 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.Monoid ((<>)) import Data.Word (Word32, Word64, Word8) 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 { status :: Word8 , publicKey :: PublicKey , friendRequest :: BS.ByteString , name :: BS.ByteString , statusMessage :: BS.ByteString , userStatus :: Word8 , nospam :: Word32 , lastSeenTime :: Word64 } deriving (Eq, Show, Read) maxFriendRequestLen :: Int maxFriendRequestLen = 1024 maxNameLen :: Int maxNameLen = 128 maxStatusMessageLen :: Int maxStatusMessageLen = 1007 instance Binary Friend where get = do status <- Get.getWord8 publicKey <- get friendRequest' <- Get.getByteString maxFriendRequestLen _ <- Get.getWord8 friendRequestLen <- Get.getWord16be name' <- Get.getByteString maxNameLen nameLen <- Get.getWord16be statusMessage' <- Get.getByteString maxStatusMessageLen _ <- Get.getWord8 statusMessageLen <- Get.getWord16be userStatus <- Get.getWord8 _ <- Get.getByteString 3 nospam <- Get.getWord32be lastSeenTime <- Get.getWord64be let friendRequest = BS.take (fromIntegral friendRequestLen) friendRequest' let name = BS.take (fromIntegral nameLen) name' let statusMessage = BS.take (fromIntegral statusMessageLen) statusMessage' return Friend{..} put Friend {..} = do let friendRequestLen = BS.length friendRequest let friendRequest' = friendRequest <> BS.replicate (maxFriendRequestLen - friendRequestLen) 0 let nameLen = BS.length name let name' = name <> BS.replicate (maxNameLen - nameLen) 0 let statusMessageLen = BS.length statusMessage let statusMessage' = statusMessage <> BS.replicate (maxStatusMessageLen - statusMessageLen) 0 Put.putWord8 status put publicKey Put.putByteString friendRequest' Put.putWord8 0 Put.putWord16be (fromIntegral friendRequestLen) Put.putByteString name' Put.putWord16be (fromIntegral nameLen) Put.putByteString statusMessage' Put.putWord8 0 Put.putWord16be (fromIntegral statusMessageLen) Put.putWord8 userStatus Put.putByteString "\0\0\0" Put.putWord32be nospam Put.putWord64be lastSeenTime instance Arbitrary Friend where arbitrary = Friend <$> arbitrary <*> arbitrary <*> (BS.pack . take maxFriendRequestLen <$> arbitrary) <*> (BS.pack . take maxNameLen <$> arbitrary) <*> (BS.pack . take maxStatusMessageLen <$> arbitrary) <*> arbitrary <*> arbitrary <*> arbitrary \end{code}