\subsection{Conferences (0x14)}

This section contains a list of saved conferences.

\begin{code}
{-# LANGUAGE DeriveGeneric   #-}
{-# LANGUAGE RecordWildCards #-}
module Network.Tox.SaveData.Conferences 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.Word                 (Word16, Word32, Word64, Word8)
import           GHC.Generics              (Generic)
import           Network.Tox.Crypto.Key    (PublicKey)
import qualified Network.Tox.SaveData.Util as Util
import           Test.QuickCheck.Arbitrary (Arbitrary (..), genericShrink)
import qualified Test.QuickCheck.Arbitrary as Arbitrary

\end{code}

\begin{tabular}{l|l}
  Length        & Contents \\
  \hline
  \texttt{?}    & List of conferences \\
\end{tabular}

\begin{code}

newtype Conferences = Conferences [Conference]
    deriving (Eq, Show, Read, Generic)

instance Binary Conferences where
    get = Conferences <$> Util.getList
    put (Conferences xs) = mapM_ put xs

instance Arbitrary Conferences where
    arbitrary = Conferences <$> arbitrary
    shrink    = genericShrink

\end{code}

Conference:

\begin{tabular}{l|l}
  Length        & Contents \\
  \hline
  \texttt{1}    & \texttt{uint8\_t} Groupchat type \\
  \texttt{32}   & Groupchat id \\
  \texttt{4}    & \texttt{uint32\_t} Message number \\
  \texttt{2}    & \texttt{uint16\_t} Lossy message number \\
  \texttt{2}    & \texttt{uint16\_t} Peer number \\
  \texttt{4}    & \texttt{uint32\_t} Number of peers \\
  \texttt{1}    & \texttt{uint8\_t} Title length \\
  \texttt{?}    & Title \\
  \texttt{?}    & List of peers \\
\end{tabular}

All peers other than the saver are saved, including frozen peers. On reload,
they all start as frozen.

\begin{code}

maxTitleLen :: Int
maxTitleLen = 128

data Conference = Conference
    { conferenceType     :: Word8
    , conferenceId       :: BS.ByteString
    , messageNumber      :: Word32
    , lossyMessageNumber :: Word16
    , selfPeerNumber     :: Word16
    , title              :: BS.ByteString
    , peers              :: [Peer]
    }
    deriving (Eq, Show, Read)

instance Binary Conference where
    get = do
        conferenceType     <- Get.getWord8
        conferenceId       <- Get.getByteString 32
        messageNumber      <- Get.getWord32le
        lossyMessageNumber <- Get.getWord16le
        selfPeerNumber     <- Get.getWord16le
        peerCount          <- Get.getWord32le
        titleLength        <- Get.getWord8
        title              <- Get.getByteString (fromIntegral titleLength)
        peers              <- mapM (const get) [1..peerCount]
        return Conference{..}

    put Conference{..} = do
        Put.putWord8      conferenceType
        Put.putByteString conferenceId
        Put.putWord32le   messageNumber
        Put.putWord16le   lossyMessageNumber
        Put.putWord16le   selfPeerNumber
        Put.putWord32le   (fromIntegral $ length peers)
        Put.putWord8      (fromIntegral $ BS.length title)
        Put.putByteString title
        mapM_ put peers


instance Arbitrary Conference where
    arbitrary = Conference
        <$> arbitrary
        <*> (BS.pack <$> Arbitrary.vector 32)
        <*> arbitrary
        <*> arbitrary
        <*> arbitrary
        <*> (BS.pack . take maxTitleLen <$> arbitrary)
        <*> arbitrary

\end{code}

Peer:

\begin{tabular}{l|l}
  Length        & Contents \\
  \hline
  \texttt{32}   & Long term public key \\
  \texttt{32}   & DHT public key \\
  \texttt{2}    & \texttt{uint16\_t} Peer number \\
  \texttt{8}    & \texttt{uint64\_t} Last active timestamp \\
  \texttt{1}    & \texttt{uint8\_t} Name length \\
  \texttt{?}    & Name \\
\end{tabular}

\begin{code}

maxNameLen :: Int
maxNameLen = 128

data Peer = Peer
    { publicKey      :: PublicKey
    , dhtPublicKey   :: PublicKey
    , peerNumber     :: Word16
    , lastActiveTime :: Word64
    , name           :: BS.ByteString
    }
    deriving (Eq, Show, Read)

instance Binary Peer where
    get = do
        publicKey      <- get
        dhtPublicKey   <- get
        peerNumber     <- Get.getWord16le
        lastActiveTime <- Get.getWord64le
        nameLength     <- Get.getWord8
        name           <- Get.getByteString (fromIntegral nameLength)
        return Peer{..}

    put Peer{..} = do
        put               publicKey
        put               dhtPublicKey
        Put.putWord16le   peerNumber
        Put.putWord64le   lastActiveTime
        Put.putWord8      (fromIntegral $ BS.length name)
        Put.putByteString name

instance Arbitrary Peer where
    arbitrary = Peer
        <$> arbitrary
        <*> arbitrary
        <*> arbitrary
        <*> arbitrary
        <*> (BS.pack . take maxNameLen <$> arbitrary)

\end{code}