packages feed

toxcore (empty) → 0.0.2

raw patch · 8 files changed

+1974/−0 lines, 8 filesdep +QuickCheckdep +basedep +bytestringsetup-changed

Dependencies added: QuickCheck, base, bytestring, bytestring-arbitrary, data-default-class, hspec, saltine, toxcore

Files

+ LICENSE.md view
@@ -0,0 +1,12 @@+The software is licensed under [AGPLv3](licenses/gnu-agpl-v3.0.md).++The documentation is the Markdown text extracted from the Software. The parts+of the extracted documentation that were originally part of the+[Tox-Docs](https://github.com/Tox-Docs/Text/commit/8f77b8a7c935871eea48cc5abeef26dfa42a108a)+repository are licensed under [MIT](licenses/mit.md). The parts that were not+originally part of that repository are licensed under AGPLv3.++The copyright of all contributions is owned by their respective contributors.+The TokTok project will not accept, request, or perform copyright assignments.++Contact Iphigenia Df <iphydf@gmail.com> for license inquiries.
+ Setup.lhs view
@@ -0,0 +1,3 @@+#!/usr/bin/env runhaskell+> import Distribution.Simple+> main = defaultMain
+ src/Network/Tox/C.hs view
@@ -0,0 +1,6 @@+module Network.Tox.C+  ( module M+  ) where++import           Network.Tox.C.Callbacks as M+import           Network.Tox.C.Tox       as M
+ src/Network/Tox/C/CEnum.hs view
@@ -0,0 +1,36 @@+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE ScopedTypeVariables        #-}+module Network.Tox.C.CEnum where++import           Control.Applicative   ((<$>))+import           Foreign.C.Types       (CInt)+import           Foreign.Marshal.Alloc (alloca)+import           Foreign.Ptr           (Ptr)+import           Foreign.Storable      (Storable (..))+++newtype CEnum a = CEnum { unCEnum :: CInt }+  deriving (Storable)++instance (Enum a, Show a) => Show (CEnum a) where+  show cen = show (toEnum $ fromIntegral $ unCEnum cen :: a)+++toCEnum :: Enum a => a -> CEnum a+toCEnum = CEnum . fromIntegral . fromEnum+++fromCEnum :: Enum a => CEnum a -> a+fromCEnum = toEnum . fromIntegral . unCEnum+++type CErr err = Ptr (CEnum err)++callErrFun :: (Eq err, Enum err, Bounded err)+           => (CErr err -> IO r) -> IO (Either err r)+callErrFun f = alloca $ \errPtr -> do+  res <- f errPtr+  err <- toEnum . fromIntegral . unCEnum <$> peek errPtr+  return $ if err /= minBound+    then Left  err+    else Right res
+ src/Network/Tox/C/Callbacks.hs view
@@ -0,0 +1,60 @@+module Network.Tox.C.Callbacks where++import           Control.Exception (bracket)+import           Foreign.Ptr       (FunPtr, freeHaskellFunPtr, nullFunPtr)++import           Network.Tox.C.Tox (Tox)+import qualified Network.Tox.C.Tox as Tox+++-- | Low level event handler. The functions in this class are directly+-- registered with the corresponding C callback. Since userdata @a@ needs to be+-- in C memory, we recommend to keep it small, so marshalling costs are kept to+-- a minimum. Use 'StablePtr' to pass larger opaque Haskell values around in C.+class CHandler a where+  cSelfConnectionStatus   :: Tox.SelfConnectionStatusCb   a+  cFriendName             :: Tox.FriendNameCb             a+  cFriendStatusMessage    :: Tox.FriendStatusMessageCb    a+  cFriendStatus           :: Tox.FriendStatusCb           a+  cFriendConnectionStatus :: Tox.FriendConnectionStatusCb a+  cFriendTyping           :: Tox.FriendTypingCb           a+  cFriendReadReceipt      :: Tox.FriendReadReceiptCb      a+  cFriendRequest          :: Tox.FriendRequestCb          a+  cFriendMessage          :: Tox.FriendMessageCb          a+  cFileRecvControl        :: Tox.FileRecvControlCb        a+  cFileChunkRequest       :: Tox.FileChunkRequestCb       a+  cFileRecv               :: Tox.FileRecvCb               a+  cFileRecvChunk          :: Tox.FileRecvChunkCb          a+  cFriendLossyPacket      :: Tox.FriendLossyPacketCb      a+  cFriendLosslessPacket   :: Tox.FriendLosslessPacketCb   a+++-- | Installs an event handler into the passed 'Tox' instance. After performing+-- the IO action, all event handlers are reset to null. This function does not+-- save the original event handlers.+withHandler :: CHandler a => Tox a -> IO r -> IO r+withHandler tox =+  install Tox.tox_callback_self_connection_status   (Tox.wrapSelfConnectionStatusCb   cSelfConnectionStatus  ) .+  install Tox.tox_callback_friend_name              (Tox.wrapFriendNameCb             cFriendName            ) .+  install Tox.tox_callback_friend_status_message    (Tox.wrapFriendStatusMessageCb    cFriendStatusMessage   ) .+  install Tox.tox_callback_friend_status            (Tox.wrapFriendStatusCb           cFriendStatus          ) .+  install Tox.tox_callback_friend_connection_status (Tox.wrapFriendConnectionStatusCb cFriendConnectionStatus) .+  install Tox.tox_callback_friend_typing            (Tox.wrapFriendTypingCb           cFriendTyping          ) .+  install Tox.tox_callback_friend_read_receipt      (Tox.wrapFriendReadReceiptCb      cFriendReadReceipt     ) .+  install Tox.tox_callback_friend_request           (Tox.wrapFriendRequestCb          cFriendRequest         ) .+  install Tox.tox_callback_friend_message           (Tox.wrapFriendMessageCb          cFriendMessage         ) .+  install Tox.tox_callback_file_recv_control        (Tox.wrapFileRecvControlCb        cFileRecvControl       ) .+  install Tox.tox_callback_file_chunk_request       (Tox.wrapFileChunkRequestCb       cFileChunkRequest      ) .+  install Tox.tox_callback_file_recv                (Tox.wrapFileRecvCb               cFileRecv              ) .+  install Tox.tox_callback_file_recv_chunk          (Tox.wrapFileRecvChunkCb          cFileRecvChunk         ) .+  install Tox.tox_callback_friend_lossy_packet      (Tox.wrapFriendLossyPacketCb      cFriendLossyPacket     ) .+  install Tox.tox_callback_friend_lossless_packet   (Tox.wrapFriendLosslessPacketCb   cFriendLosslessPacket  )+  where+    install cInstall wrapper action =+      bracket wrapper (uninstall cInstall) $ \cb -> do+        () <- cInstall tox cb+        action++    uninstall cInstall cb = do+      () <- cInstall tox nullFunPtr+      freeHaskellFunPtr cb
+ src/Network/Tox/C/Tox.hs view
@@ -0,0 +1,1798 @@+{-# OPTIONS_GHC -fno-warn-orphans #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE LambdaCase    #-}+{-# LANGUAGE Trustworthy   #-}+-- | Public core API for Tox clients.+--+-- Every function that can fail takes a function-specific error code pointer+-- that can be used to diagnose problems with the Tox state or the function+-- arguments. The error code pointer can be 'nullPtr', which does not influence+-- the function's behaviour, but can be done if the reason for failure is+-- irrelevant to the client.+--+-- The exception to this rule are simple allocation functions whose only failure+-- mode is allocation failure. They return 'nullPtr' in that case, and do not+-- set an error code.+--+-- Every error code type has an OK value to which functions will set their error+-- code value on success. Clients can keep their error code uninitialised before+-- passing it to a function. The library guarantees that after returning, the+-- value pointed to by the error code pointer has been initialised.+--+-- Functions with pointer parameters often have a 'nullPtr' error code, meaning+-- they could not perform any operation, because one of the required parameters+-- was 'nullPtr'. Some functions operate correctly or are defined as effectless+-- on 'nullPtr'.+--+-- Some functions additionally return a value outside their return type domain,+-- or a bool containing true on success and false on failure.+--+-- All functions that take a Tox instance pointer will cause undefined behaviour+-- when passed a 'nullPtr' Tox pointer.+--+-- All integer values are expected in host byte order.+--+-- Functions with parameters with enum types cause unspecified behaviour if the+-- enumeration value is outside the valid range of the type. If possible, the+-- function will try to use a sane default, but there will be no error code, and+-- one possible action for the function to take is to have no effect.+--+-- \subsection events Events and callbacks+--+-- Events are handled by callbacks. One callback can be registered per event.+-- All events have a callback function type named `tox_{event}_cb` and a+-- function to register it named `tox_callback_{event}`. Passing a 'nullPtr'+-- callback will result in no callback being registered for that event. Only one+-- callback per event can be registered, so if a client needs multiple event+-- listeners, it needs to implement the dispatch functionality itself.+--+-- \subsection threading Threading implications+--+-- It is possible to run multiple concurrent threads with a Tox instance for+-- each thread. It is also possible to run all Tox instances in the same thread.+-- A common way to run Tox (multiple or single instance) is to have one thread+-- running a simple tox_iterate loop, sleeping for tox_iteration_interval+-- milliseconds on each iteration.+--+-- If you want to access a single Tox instance from multiple threads, access to+-- the instance must be synchronised. While multiple threads can concurrently+-- access multiple different Tox instances, no more than one API function can+-- operate on a single instance at any given time.+--+-- Functions that write to variable length byte arrays will always have a size+-- function associated with them. The result of this size function is only valid+-- until another mutating function (one that takes a pointer to non-const Tox)+-- is called. Thus, clients must ensure that no other thread calls a mutating+-- function between the call to the size function and the call to the retrieval+-- function.+--+-- E.g. to get the current nickname, one would write+--+-- \code+-- CSize length = tox_self_get_name_size(tox);+-- CString name = malloc(length);+-- if (!name) abort();+-- tox_self_get_name(tox, name);+-- \endcode+--+-- If any other thread calls tox_self_set_name while this thread is allocating+-- memory, the length may have become invalid, and the call to tox_self_get_name+-- may cause undefined behaviour.+--+module Network.Tox.C.Tox where++import           Control.Applicative       ((<$>), (<*>))+import           Control.Exception         (bracket)+import qualified Crypto.Saltine.Class      as Sodium (encode)+import           Crypto.Saltine.Core.Box   (CombinedKey, Nonce, PublicKey,+                                            SecretKey)+import           Data.ByteString           (ByteString)+import qualified Data.ByteString           as BS+import           Data.ByteString.Arbitrary (fromABS)+import           Data.Default.Class        (Default (..))+import           Data.Word                 (Word16, Word32, Word64)+import           Foreign.C.String          (CString, peekCString, withCString)+import           Foreign.C.Types           (CInt (..), CSize (..))+import           Foreign.Ptr               (FunPtr, Ptr, nullPtr)+import           GHC.Generics              (Generic)+import           Test.QuickCheck.Arbitrary (Arbitrary (..),+                                            arbitraryBoundedEnum)++import           Network.Tox.C.CEnum++-- | The Tox instance type. All the state associated with a connection is held+-- within the instance. Multiple instances can exist and operate concurrently.+-- The maximum number of Tox instances that can exist on a single network device+-- is limited. Note that this is not just a per-process limit, since the+-- limiting factor is the number of usable ports on a device.+data ToxStruct a+type Tox a = Ptr (ToxStruct a)+++--------------------------------------------------------------------------------+--+-- :: API version+--+--------------------------------------------------------------------------------++-- | The major version number. Incremented when the API or ABI changes in an+-- incompatible way.+foreign import ccall tox_version_major :: Word32++-- | The minor version number. Incremented when functionality is added without+-- breaking the API or ABI. Set to 0 when the major version number is+-- incremented.+foreign import ccall tox_version_minor :: Word32++-- | The patch or revision number. Incremented when bugfixes are applied without+-- changing any functionality or API or ABI.+foreign import ccall tox_version_patch :: Word32++-- | Return whether the compiled library version is compatible with the passed+-- version numbers.+foreign import ccall tox_version_is_compatible :: Word32 -> Word32 -> Word32 -> Bool+++--------------------------------------------------------------------------------+--+-- :: Numeric constants+--+--------------------------------------------------------------------------------++-- | The size of a Tox Public Key in bytes.+foreign import ccall tox_public_key_size :: Word32++-- | The size of a Tox Secret Key in bytes.+foreign import ccall tox_secret_key_size :: Word32++-- | The size of a Tox address in bytes. Tox addresses are in the format+-- [Public Key ('tox_public_key_size' bytes)][nospam (4 bytes)][checksum (2 bytes)].+--+-- The checksum is computed over the Public Key and the nospam value. The first+-- byte is an XOR of all the even bytes (0, 2, 4, ...), the second byte is an+-- XOR of all the odd bytes (1, 3, 5, ...) of the Public Key and nospam.+foreign import ccall tox_address_size :: Word32++-- | Maximum length of a nickname in bytes.+foreign import ccall tox_max_name_length :: Word32++-- | Maximum length of a status message in bytes.+foreign import ccall tox_max_status_message_length :: Word32++-- | Maximum length of a friend request message in bytes.+foreign import ccall tox_max_friend_request_length :: Word32++-- | Maximum length of a single message after which it should be split.+foreign import ccall tox_max_message_length :: Word32++-- | Maximum size of custom packets. TODO: should be LENGTH?+foreign import ccall tox_max_custom_packet_size :: Word32++-- | The number of bytes in a hash generated by tox_hash.+foreign import ccall tox_hash_length :: Word32++-- | The number of bytes in a file id.+foreign import ccall tox_file_id_length :: Word32++-- | Maximum file name length for file transfers.+foreign import ccall tox_max_filename_length :: Word32+++--------------------------------------------------------------------------------+--+-- :: Global enumerations+--+--------------------------------------------------------------------------------+++-- | Represents the possible statuses a client can have.+data UserStatus+  = UserStatusNone+    -- ^ User is online and available.+  | UserStatusAway+    -- ^ User is away. Clients can set this e.g. after a user defined inactivity+    -- time.+  | UserStatusBusy+    -- ^ User is busy. Signals to other clients that this client does not+    -- currently wish to communicate.+  deriving (Eq, Ord, Enum, Bounded, Read, Show)++instance Arbitrary UserStatus where+  arbitrary = arbitraryBoundedEnum+++-- | Represents message types for tox_friend_send_message and group chat+-- messages.+data MessageType+  = MessageTypeNormal+    -- ^ Normal text message. Similar to PRIVMSG on IRC.+  | MessageTypeAction+    -- ^ A message describing an user action. This is similar to /me (CTCP+    -- ACTION) on IRC.+  deriving (Eq, Ord, Enum, Bounded, Read, Show)++instance Arbitrary MessageType where+  arbitrary = arbitraryBoundedEnum+++--------------------------------------------------------------------------------+--+-- :: Startup options+--+--------------------------------------------------------------------------------+++-- | Type of proxy used to connect to TCP relays.+data ProxyType+  = ProxyTypeNone+    -- Don't use a proxy.+  | ProxyTypeHttp+    -- HTTP proxy using CONNECT.+  | ProxyTypeSocks5+    -- SOCKS proxy for simple socket pipes.+  deriving (Eq, Ord, Enum, Bounded, Read, Show)++instance Arbitrary ProxyType where+  arbitrary = arbitraryBoundedEnum+++-- Type of savedata to create the Tox instance from.+data SavedataType+  = SavedataTypeNone+    -- No savedata.+  | SavedataTypeToxSave+    -- Savedata is one that was obtained from tox_get_savedata+  | SavedataTypeSecretKey+    -- Savedata is a secret key of length 'tox_secret_key_size'+  deriving (Eq, Ord, Enum, Bounded, Read, Show)++instance Arbitrary SavedataType where+  arbitrary = arbitraryBoundedEnum+++-- This struct contains all the startup options for Tox. You can either allocate+-- this object yourself, and pass it to tox_options_default, or call+-- tox_options_new to get a new default options object.+data Options = Options+  { ipv6Enabled  :: Bool+    -- The type of socket to create.+    --+    -- If this is set to false, an IPv4 socket is created, which subsequently+    -- only allows IPv4 communication.+    -- If it is set to true, an IPv6 socket is created, allowing both IPv4 and+    -- IPv6 communication.++  , udpEnabled   :: Bool+    -- Enable the use of UDP communication when available.+    --+    -- Setting this to false will force Tox to use TCP only. Communications will+    -- need to be relayed through a TCP relay node, potentially slowing them+    -- down. Disabling UDP support is necessary when using anonymous proxies or+    -- Tor.++  , proxyType    :: ProxyType+    -- Pass communications through a proxy.++  , proxyHost    :: String+    -- The IP address or DNS name of the proxy to be used.+    --+    -- If used, this must be non-'nullPtr' and be a valid DNS name. The name+    -- must not exceed 255 ('tox_max_filename_length') characters, and be in a+    -- NUL-terminated C string format (255 chars + 1 NUL byte).+    --+    -- This member is ignored (it can be 'nullPtr') if proxy_type is+    -- ProxyTypeNone.++  , proxyPort    :: Word16+    -- The port to use to connect to the proxy server.+    --+    -- Ports must be in the range (1, 65535). The value is ignored if proxy_type+    -- is ProxyTypeNone.++  , startPort    :: Word16+    -- The start port of the inclusive port range to attempt to use.+    --+    -- If both 'startPort' and 'endPort' are 0, the default port range will be+    -- used: [33445, 33545].+    --+    -- If either 'startPort' or 'endPort' is 0 while the other is non-zero, the+    -- non-zero port will be the only port in the range.+    --+    -- Having 'startPort' > 'endport' will yield the same behavior as if+    -- 'startPort' and 'endPort' were swapped.++  , endPort      :: Word16+    -- The end port of the inclusive port range to attempt to use.++  , tcpPort      :: Word16+    -- The port to use for the TCP server (relay). If 0, the TCP server is+    -- disabled.+    --+    -- Enabling it is not required for Tox to function properly.+    --+    -- When enabled, your Tox instance can act as a TCP relay for other Tox+    -- instance. This leads to increased traffic, thus when writing a client it+    -- is recommended to enable TCP server only if the user has an option to+    -- disable it.++  , savedataType :: SavedataType+    -- The type of savedata to load from.++  , savedataData :: ByteString+    -- The savedata bytes.+  }+  deriving (Eq, Read, Show, Generic)+++instance Default Options where+  def = Options+    { ipv6Enabled  = True+    , udpEnabled   = True+    , proxyType    = ProxyTypeNone+    , proxyHost    = ""+    , proxyPort    = 0+    , startPort    = 0+    , endPort      = 0+    , tcpPort      = 0+    , savedataType = SavedataTypeNone+    , savedataData = BS.empty+    }+++instance Arbitrary Options where+  arbitrary = Options+    <$> arbitrary+    <*> arbitrary+    <*> arbitrary+    <*> arbitraryCString+    <*> arbitrary+    <*> arbitrary+    <*> arbitrary+    <*> arbitrary+    <*> arbitrary+    <*> (fromABS <$> arbitrary)+    where+      arbitraryCString = filter (/= '\NUL') <$> arbitrary+++data OptionsStruct+type OptionsPtr = Ptr OptionsStruct+++foreign import ccall tox_options_get_ipv6_enabled     :: OptionsPtr -> IO Bool+foreign import ccall tox_options_get_udp_enabled      :: OptionsPtr -> IO Bool+foreign import ccall tox_options_get_proxy_type       :: OptionsPtr -> IO (CEnum ProxyType)+foreign import ccall tox_options_get_proxy_host       :: OptionsPtr -> IO CString+foreign import ccall tox_options_get_proxy_port       :: OptionsPtr -> IO Word16+foreign import ccall tox_options_get_start_port       :: OptionsPtr -> IO Word16+foreign import ccall tox_options_get_end_port         :: OptionsPtr -> IO Word16+foreign import ccall tox_options_get_tcp_port         :: OptionsPtr -> IO Word16+foreign import ccall tox_options_get_savedata_type    :: OptionsPtr -> IO (CEnum SavedataType)+foreign import ccall tox_options_get_savedata_data    :: OptionsPtr -> IO CString+foreign import ccall tox_options_get_savedata_length  :: OptionsPtr -> IO CSize++foreign import ccall tox_options_set_ipv6_enabled     :: OptionsPtr -> Bool -> IO ()+foreign import ccall tox_options_set_udp_enabled      :: OptionsPtr -> Bool -> IO ()+foreign import ccall tox_options_set_proxy_type       :: OptionsPtr -> CEnum ProxyType -> IO ()+foreign import ccall tox_options_set_proxy_host       :: OptionsPtr -> CString -> IO ()+foreign import ccall tox_options_set_proxy_port       :: OptionsPtr -> Word16 -> IO ()+foreign import ccall tox_options_set_start_port       :: OptionsPtr -> Word16 -> IO ()+foreign import ccall tox_options_set_end_port         :: OptionsPtr -> Word16 -> IO ()+foreign import ccall tox_options_set_tcp_port         :: OptionsPtr -> Word16 -> IO ()+foreign import ccall tox_options_set_savedata_type    :: OptionsPtr -> CEnum SavedataType -> IO ()+foreign import ccall tox_options_set_savedata_data    :: OptionsPtr -> CString -> CSize -> IO ()+foreign import ccall tox_options_set_savedata_length  :: OptionsPtr -> CSize -> IO ()+++data ErrOptionsNew+  = ErrOptionsNewOk+    -- The function returned successfully.++  | ErrOptionsNewMalloc+    -- The function was unable to allocate enough memory to store the internal+    -- structures for the Tox options object.+  deriving (Eq, Ord, Enum, Bounded, Read, Show)+++-- | Allocates a new Tox_Options object and initialises it with the default+-- options. This function can be used to preserve long term ABI compatibility by+-- giving the responsibility of allocation and deallocation to the Tox library.+--+-- Objects returned from this function must be freed using the tox_options_free+-- function.+--+-- @return A new 'OptionsPtr' with default options or 'nullPtr' on failure.+foreign import ccall tox_options_new :: CErr ErrOptionsNew -> IO OptionsPtr++toxOptionsNew :: IO (Either ErrOptionsNew OptionsPtr)+toxOptionsNew = callErrFun tox_options_new+++-- | Releases all resources associated with an options objects.+--+-- Passing a pointer that was not returned by tox_options_new results in+-- undefined behaviour.+foreign import ccall tox_options_free :: OptionsPtr -> IO ()+++withToxOptions :: (OptionsPtr -> IO r) -> IO (Either ErrOptionsNew r)+withToxOptions f =+  bracket toxOptionsNew (either (const $ return ()) tox_options_free) $ \case+    Left err -> return $ Left err+    Right ok -> Right <$> f ok+++-- | Read 'Options' from an 'OptionsPtr'.+--+-- If the passed pointer is 'nullPtr', the behaviour is undefined.+peekToxOptions :: OptionsPtr -> IO Options+peekToxOptions ptr = do+  cIpv6Enabled    <- tox_options_get_ipv6_enabled    ptr+  cUdpEnabled     <- tox_options_get_udp_enabled     ptr+  cProxyType      <- tox_options_get_proxy_type      ptr+  cProxyHost      <- tox_options_get_proxy_host      ptr >>= peekNullableString+  cProxyPort      <- tox_options_get_proxy_port      ptr+  cStartPort      <- tox_options_get_start_port      ptr+  cEndPort        <- tox_options_get_end_port        ptr+  cTcpPort        <- tox_options_get_tcp_port        ptr+  cSavedataType   <- tox_options_get_savedata_type   ptr+  cSavedataData   <- tox_options_get_savedata_data   ptr+  cSavedataLength <- tox_options_get_savedata_length ptr+  cSavedata       <- BS.packCStringLen+                           ( cSavedataData+                           , fromIntegral cSavedataLength)+  return Options+    { ipv6Enabled    = cIpv6Enabled+    , udpEnabled     = cUdpEnabled+    , proxyType      = fromCEnum cProxyType+    , proxyHost      = cProxyHost+    , proxyPort      = cProxyPort+    , startPort      = cStartPort+    , endPort        = cEndPort+    , tcpPort        = cTcpPort+    , savedataType   = fromCEnum cSavedataType+    , savedataData   = cSavedata+    }++  where+    -- 'peekCString' doesn't handle NULL strings as empty, unlike+    -- 'packCStringLen', which ignores the pointer to zero-length 'CString's.+    peekNullableString p =+      if p == nullPtr+        then return ""+        else peekCString p+++-- | Save the options from the passed 'OptionsPtr', perform an IO action, and+-- restore the original values.+--+-- If the passed pointer is 'nullPtr', the behaviour is undefined.+saveToxOptions :: OptionsPtr -> IO r -> IO r+saveToxOptions ptr =+  bracket saveOptions restoreOptions . const+  where+    saveOptions = do+      v0 <- tox_options_get_ipv6_enabled    ptr+      v1 <- tox_options_get_udp_enabled     ptr+      v2 <- tox_options_get_proxy_type      ptr+      v3 <- tox_options_get_proxy_host      ptr+      v4 <- tox_options_get_proxy_port      ptr+      v5 <- tox_options_get_start_port      ptr+      v6 <- tox_options_get_end_port        ptr+      v7 <- tox_options_get_tcp_port        ptr+      v8 <- tox_options_get_savedata_type   ptr+      sd <- tox_options_get_savedata_data   ptr+      sl <- tox_options_get_savedata_length ptr+      return (v0, v1, v2, v3, v4, v5, v6, v7, v8, sd, sl)++    restoreOptions (v0, v1, v2, v3, v4, v5, v6, v7, v8, sd, sl) = do+      tox_options_set_ipv6_enabled    ptr v0+      tox_options_set_udp_enabled     ptr v1+      tox_options_set_proxy_type      ptr v2+      tox_options_set_proxy_host      ptr v3+      tox_options_set_proxy_port      ptr v4+      tox_options_set_start_port      ptr v5+      tox_options_set_end_port        ptr v6+      tox_options_set_tcp_port        ptr v7+      tox_options_set_savedata_type   ptr v8+      tox_options_set_savedata_data   ptr sd sl+      tox_options_set_savedata_length ptr sl+++-- | Fill in the 'Options' values into the 'OptionsPtr' and perform the IO+-- action afterwards.+--+-- This function restores the original values from the 'OptionsPtr' after+-- performing the action.+--+-- If the passed pointer is 'nullPtr', the behaviour is undefined.+pokeToxOptions :: Options -> OptionsPtr -> IO r -> IO r+pokeToxOptions options ptr action =+  saveToxOptions ptr $+    withCString (proxyHost options) $ \host ->+      BS.useAsCStringLen (savedataData options) $ \(saveData, saveLenInt) -> do+        let saveLen = fromIntegral saveLenInt+        tox_options_set_ipv6_enabled    ptr $ ipv6Enabled options+        tox_options_set_udp_enabled     ptr $ udpEnabled options+        tox_options_set_proxy_type      ptr $ toCEnum $ proxyType options+        tox_options_set_proxy_host      ptr host+        tox_options_set_proxy_port      ptr $ proxyPort options+        tox_options_set_start_port      ptr $ startPort options+        tox_options_set_end_port        ptr $ endPort options+        tox_options_set_tcp_port        ptr $ tcpPort options+        tox_options_set_savedata_type   ptr $ toCEnum $ savedataType options+        tox_options_set_savedata_data   ptr saveData saveLen+        tox_options_set_savedata_length ptr saveLen+        action+++-- | Allocate a new C options pointer, fills in the values from 'Options',+-- calls the processor function, and deallocates the options pointer.+--+-- The 'OptionsPtr' passed to the processor function is never 'nullPtr'. If+-- allocation fails, the IO action evaluates to 'Left' with an appropriate+-- error code.+withOptions :: Options -> (OptionsPtr -> IO r) -> IO (Either ErrOptionsNew r)+withOptions options f =+  withToxOptions $ \ptr ->+    pokeToxOptions options ptr (f ptr)+++--------------------------------------------------------------------------------+--+-- :: Creation and destruction+--+--------------------------------------------------------------------------------+++data ErrNew+  = ErrNewOk+    -- The function returned successfully.++  | ErrNewNull+    -- One of the arguments to the function was 'nullPtr' when it was not+    -- expected.++  | ErrNewMalloc+    -- The function was unable to allocate enough memory to store the internal+    -- structures for the Tox object.++  | ErrNewPortAlloc+    -- The function was unable to bind to a port. This may mean that all ports+    -- have already been bound, e.g. by other Tox instances, or it may mean a+    -- permission error. You may be able to gather more information from errno.++  | ErrNewProxyBadType+    -- proxy_type was invalid.++  | ErrNewProxyBadHost+    -- proxy_type was valid but the proxy_host passed had an invalid format or+    -- was 'nullPtr'.++  | ErrNewProxyBadPort+    -- proxy_type was valid, but the proxy_port was invalid.++  | ErrNewProxyNotFound+    -- The proxy address passed could not be resolved.++  | ErrNewLoadEncrypted+    -- The byte array to be loaded contained an encrypted save.++  | ErrNewLoadBadFormat+    -- The data format was invalid. This can happen when loading data that was+    -- saved by an older version of Tox, or when the data has been corrupted.+    -- When loading from badly formatted data, some data may have been loaded,+    -- and the rest is discarded. Passing an invalid length parameter also+    -- causes this error.+  deriving (Eq, Ord, Enum, Bounded, Read, Show)+++-- @brief Creates and initialises a new Tox instance with the options passed.+--+-- This function will bring the instance into a valid state. Running the event+-- loop with a new instance will operate correctly.+--+-- If loading failed or succeeded only partially, the new or partially loaded+-- instance is returned and an error code is set.+--+-- @param options An options object as described above. If this parameter is+--   'nullPtr', the default options are used.+--+-- @see tox_iterate for the event loop.+--+-- @return A new Tox instance pointer on success or 'nullPtr' on failure.+foreign import ccall tox_new :: OptionsPtr -> CErr ErrNew -> IO (Tox a)++toxNew :: OptionsPtr -> IO (Either ErrNew (Tox a))+toxNew = callErrFun . tox_new++-- | Releases all resources associated with the Tox instance and disconnects+-- from the network.+--+-- After calling this function, the Tox pointer becomes invalid. No other+-- functions can be called, and the pointer value can no longer be read.+foreign import ccall tox_kill :: Tox a -> IO ()++withTox :: OptionsPtr -> (Tox a -> IO r) -> IO (Either ErrNew r)+withTox options f =+  bracket (toxNew options) (either (const $ return ()) tox_kill) $ \case+    Left err -> return $ Left err+    Right ok -> Right <$> f ok+++withDefaultTox :: (Tox a -> IO r) -> IO (Either ErrNew r)+withDefaultTox = withTox nullPtr+++-- | Calculates the number of bytes required to store the tox instance with+-- tox_get_savedata. This function cannot fail. The result is always greater+-- than 0.+--+-- @see threading for concurrency implications.+foreign import ccall tox_get_savedata_size :: Tox a -> IO CSize++-- | Store all information associated with the tox instance to a byte array.+--+-- @param data A memory region large enough to store the tox instance data.+--   Call tox_get_savedata_size to find the number of bytes required. If this+--   parameter is 'nullPtr', this function has no effect.+foreign import ccall tox_get_savedata :: Tox a -> CString -> IO ()+++--------------------------------------------------------------------------------+--+-- :: Connection lifecycle and event loop+--+--------------------------------------------------------------------------------+++data ErrBootstrap+  = ErrBootstrapOk+    -- The function returned successfully.++  | ErrBootstrapNull+    -- One of the arguments to the function was 'nullPtr' when it was not+    -- expected.++  | ErrBootstrapBadHost+    -- The address could not be resolved to an IP address, or the IP address+    -- passed was invalid.++  | ErrBootstrapBadPort+    -- The port passed was invalid. The valid port range is (1, 65535).+  deriving (Eq, Ord, Enum, Bounded, Read, Show)+++-- | Sends a "get nodes" request to the given bootstrap node with IP, port, and+-- public key to setup connections.+--+-- This function will attempt to connect to the node using UDP. You must use+-- this function even if COptions.udp_enabled was set to false.+--+-- @param address The hostname or IP address (IPv4 or IPv6) of the node.+-- @param port The port on the host on which the bootstrap Tox instance is+--   listening.+-- @param public_key The long term public key of the bootstrap node+--   ('tox_public_key_size' bytes).+-- @return true on success.+foreign import ccall tox_bootstrap :: Tox a -> CString -> Word16 -> CString -> CErr ErrBootstrap -> IO ()++callBootstrapFun+  :: (Tox a -> CString -> Word16 -> CString -> CErr ErrBootstrap -> IO ())+  -> Tox a -> String -> Word16 -> PublicKey -> IO (Either ErrBootstrap ())+callBootstrapFun f tox address port pubKey =+  withCString address $ \address' ->+    BS.useAsCString (Sodium.encode pubKey) $ \pubKey' ->+      callErrFun $ f tox address' (fromIntegral port) pubKey'++toxBootstrap :: Tox a -> String -> Word16 -> PublicKey -> IO (Either ErrBootstrap ())+toxBootstrap = callBootstrapFun tox_bootstrap+++-- | Adds additional host:port pair as TCP relay.+--+-- This function can be used to initiate TCP connections to different ports on+-- the same bootstrap node, or to add TCP relays without using them as+-- bootstrap nodes.+--+-- @param address The hostname or IP address (IPv4 or IPv6) of the TCP relay.+-- @param port The port on the host on which the TCP relay is listening.+-- @param public_key The long term public key of the TCP relay+--   ('tox_public_key_size' bytes).+-- @return true on success.+foreign import ccall tox_add_tcp_relay :: Tox a -> CString -> Word16 -> CString -> CErr ErrBootstrap -> IO ()++toxAddTcpRelay :: Tox a -> String -> Word16 -> PublicKey -> IO (Either ErrBootstrap ())+toxAddTcpRelay = callBootstrapFun tox_add_tcp_relay+++-- | Protocols that can be used to connect to the network or friends.+data Connection+  = ConnectionNone+    -- There is no connection. This instance, or the friend the state change is+    -- about, is now offline.++  | ConnectionTcp+    -- A TCP connection has been established. For the own instance, this means+    -- it is connected through a TCP relay, only. For a friend, this means that+    -- the connection to that particular friend goes through a TCP relay.++  | ConnectionUdp+    -- A UDP connection has been established. For the own instance, this means+    -- it is able to send UDP packets to DHT nodes, but may still be connected+    -- to a TCP relay. For a friend, this means that the connection to that+    -- particular friend was built using direct UDP packets.+  deriving (Eq, Ord, Enum, Bounded, Read, Show)++instance Arbitrary Connection where+  arbitrary = arbitraryBoundedEnum+++-- | @param connection_status Whether we are connected to the DHT.+type SelfConnectionStatusCb a = Tox a -> CEnum Connection -> Ptr a -> IO ()+foreign import ccall "wrapper" wrapSelfConnectionStatusCb :: SelfConnectionStatusCb a -> IO (FunPtr (SelfConnectionStatusCb a))+++-- | Set the callback for the `self_connection_status` event. Pass 'nullPtr' to+-- unset.+--+-- This event is triggered whenever there is a change in the DHT connection+-- state. When disconnected, a client may choose to call tox_bootstrap again, to+-- reconnect to the DHT. Note that this state may frequently change for short+-- amounts of time. Clients should therefore not immediately bootstrap on+-- receiving a disconnect.+--+-- TODO: how long should a client wait before bootstrapping again?+foreign import ccall tox_callback_self_connection_status :: Tox a -> FunPtr (SelfConnectionStatusCb a) -> IO ()++-- | Return the time in milliseconds before tox_iterate() should be called again+-- for optimal performance.+foreign import ccall tox_iteration_interval :: Tox a -> IO Word32++-- | The main loop that needs to be run in intervals of tox_iteration_interval()+-- milliseconds.+foreign import ccall tox_iterate :: Tox a -> Ptr a -> IO ()+++--------------------------------------------------------------------------------+--+-- :: Internal client information (Tox address/id)+--+--------------------------------------------------------------------------------+++-- | Writes the Tox friend address of the client to a byte array. The address is+-- not in human-readable format. If a client wants to display the address,+-- formatting is required.+--+-- @param address A memory region of at least 'tox_address_size' bytes. If this+--   parameter is 'nullPtr', this function has no effect.+-- @see 'tox_address_size' for the address format.+foreign import ccall tox_self_get_address :: Tox a -> CString -> IO ()++-- | Set the 4-byte nospam part of the address.+--+-- @param nospam Any 32 bit unsigned integer.+foreign import ccall tox_self_set_nospam :: Tox a -> Word32 -> IO ()++-- | Get the 4-byte nospam part of the address.+foreign import ccall tox_self_get_nospam :: Tox a -> IO Word32++-- | Copy the Tox Public Key (long term) from the Tox object.+--+-- @param public_key A memory region of at least 'tox_public_key_size' bytes. If+--   this parameter is 'nullPtr', this function has no effect.+foreign import ccall tox_self_get_public_key :: Tox a -> CString -> IO ()++-- | Copy the Tox Secret Key from the Tox object.+--+-- @param secret_key A memory region of at least 'tox_secret_key_size' bytes. If+--   this parameter is 'nullPtr', this function has no effect.+foreign import ccall tox_self_get_secret_key :: Tox a -> CString -> IO ()+++--------------------------------------------------------------------------------+--+-- :: User-visible client information (nickname/status)+--+--------------------------------------------------------------------------------+++-- | Common error codes for all functions that set a piece of user-visible+-- client information.+data ErrSetInfo+  = ErrSetInfoOk+    -- The function returned successfully.++  | ErrSetInfoNull+    -- One of the arguments to the function was 'nullPtr' when it was not+    -- expected.++  | ErrSetInfoTooLong+    -- Information length exceeded maximum permissible size.+  deriving (Eq, Ord, Enum, Bounded, Read, Show)+++-- | Set the nickname for the Tox client.+--+-- Nickname length cannot exceed 'tox_max_name_length'. If length is 0, the name+-- parameter is ignored (it can be 'nullPtr'), and the nickname is set back to+-- empty.+--+-- @param name A byte array containing the new nickname.+-- @param length The size of the name byte array.+--+-- @return true on success.+foreign import ccall tox_self_set_name :: Tox a -> CString -> CSize -> CErr ErrSetInfo -> IO ()++-- | Set the client's status message.+--+-- Status message length cannot exceed 'tox_max_status_message_length'. If+-- length is 0, the status parameter is ignored (it can be 'nullPtr'), and the+-- user status is set back to empty.+foreign import ccall tox_self_set_status_message :: Tox a -> CString -> CSize -> CErr ErrSetInfo -> IO ()++-- | Set the client's user status.+--+-- @param user_status One of the user statuses listed in the enumeration above.+foreign import ccall tox_self_set_status :: Tox a -> CEnum UserStatus -> IO ()+++--------------------------------------------------------------------------------+--+-- :: Friend list management+--+--------------------------------------------------------------------------------+++data ErrFriendAdd+  = ErrFriendAddOk+    -- The function returned successfully.++  | ErrFriendAddNull+    -- One of the arguments to the function was 'nullPtr' when it was not+    -- expected.++  | ErrFriendAddTooLong+    -- The length of the friend request message exceeded+    -- 'tox_max_friend_request_length'.++  | ErrFriendAddNoMessage+    -- The friend request message was empty. This, and the TooLong code will+    -- never be returned from tox_friend_add_norequest.++  | ErrFriendAddOwnKey+    -- The friend address belongs to the sending client.++  | ErrFriendAddAlreadySent+    -- A friend request has already been sent, or the address belongs to a+    -- friend that is already on the friend list.++  | ErrFriendAddBadChecksum+    -- The friend address checksum failed.++  | ErrFriendAddSetNewNospam+    -- The friend was already there, but the nospam value was different.++  | ErrFriendAddMalloc+    -- A memory allocation failed when trying to increase the friend list size.+  deriving (Eq, Ord, Enum, Bounded, Read, Show)+++-- | Add a friend to the friend list and send a friend request.+--+-- A friend request message must be at least 1 byte long and at most+-- 'tox_max_friend_request_length'.+--+-- Friend numbers are unique identifiers used in all functions that operate on+-- friends. Once added, a friend number is stable for the lifetime of the Tox+-- object. After saving the state and reloading it, the friend numbers may not+-- be the same as before. Deleting a friend creates a gap in the friend number+-- set, which is filled by the next adding of a friend. Any pattern in friend+-- numbers should not be relied on.+--+-- If more than INT32_MAX friends are added, this function causes undefined+-- behaviour.+--+-- @param address The address of the friend (returned by tox_self_get_address of+--   the friend you wish to add) it must be 'tox_address_size' bytes.+-- @param message The message that will be sent along with the friend request.+-- @param length The length of the data byte array.+--+-- @return the friend number on success, UINT32_MAX on failure.+foreign import ccall tox_friend_add :: Tox a -> CString -> CString -> CSize -> CErr ErrFriendAdd -> IO Word32++-- | Add a friend without sending a friend request.+--+-- This function is used to add a friend in response to a friend request. If the+-- client receives a friend request, it can be reasonably sure that the other+-- client added this client as a friend, eliminating the need for a friend+-- request.+--+-- This function is also useful in a situation where both instances are+-- controlled by the same entity, so that this entity can perform the mutual+-- friend adding. In this case, there is no need for a friend request, either.+--+-- @param public_key A byte array of length 'tox_public_key_size' containing the+--   Public Key (not the Address) of the friend to add.+--+-- @return the friend number on success, UINT32_MAX on failure.+-- @see tox_friend_add for a more detailed description of friend numbers.+foreign import ccall tox_friend_add_norequest :: Tox a -> CString -> CErr ErrFriendAdd -> IO Word32+++data ErrFriendDelete+  = ErrFriendDeleteOk+    -- The function returned successfully.++  | ErrFriendDeleteFriendNotFound+    -- There was no friend with the given friend number. No friends were+    -- deleted.+  deriving (Eq, Ord, Enum, Bounded, Read, Show)+++-- | Remove a friend from the friend list.+--+-- This does not notify the friend of their deletion. After calling this+-- function, this client will appear offline to the friend and no communication+-- can occur between the two.+--+-- @param friend_number Friend number for the friend to be deleted.+--+-- @return true on success.+foreign import ccall tox_friend_delete :: Tox a -> Word32 -> CErr ErrFriendDelete -> IO ()+++--------------------------------------------------------------------------------+--+-- :: Friend list queries+--+--------------------------------------------------------------------------------+++data ErrFriendByPublicKey+  = ErrFriendByPublicKeyOk+    -- The function returned successfully.++  | ErrFriendByPublicKeyNull+    -- One of the arguments to the function was 'nullPtr' when it was not+    -- expected.++  | ErrFriendByPublicKeyNotFound+    -- No friend with the given Public Key exists on the friend list.+  deriving (Eq, Ord, Enum, Bounded, Read, Show)+++-- | Return the friend number associated with that Public Key.+--+-- @return the friend number on success, UINT32_MAX on failure.+-- @param public_key A byte array containing the Public Key.+foreign import ccall tox_friend_by_public_key :: Tox a -> CString -> CErr ErrFriendByPublicKey -> IO Word32++-- | Checks if a friend with the given friend number exists and returns true if+-- it does.+foreign import ccall tox_friend_exists :: Tox a -> Word32 -> IO Bool++-- | Return the number of friends on the friend list.+--+-- This function can be used to determine how much memory to allocate for+-- tox_self_get_friend_list.+foreign import ccall tox_self_get_friend_list_size :: Tox a -> IO CSize++-- | Copy a list of valid friend numbers into an array.+--+-- Call tox_self_get_friend_list_size to determine the number of elements to+-- allocate.+--+-- @param list A memory region with enough space to hold the friend list. If+--   this parameter is 'nullPtr', this function has no effect.+foreign import ccall tox_self_get_friend_list :: Tox a -> Ptr Word32 -> IO ()++data ErrFriendGetPublicKey+  = ErrFriendGetPublicKeyOk+    -- The function returned successfully.++  | ErrFriendGetPublicKeyFriendNotFound+    -- No friend with the given number exists on the friend list.+  deriving (Eq, Ord, Enum, Bounded, Read, Show)+++-- | Copies the Public Key associated with a given friend number to a byte+-- array.+--+-- @param friend_number The friend number you want the Public Key of.+-- @param public_key A memory region of at least 'tox_public_key_size' bytes. If+--   this parameter is 'nullPtr', this function has no effect.+--+-- @return true on success.+foreign import ccall tox_friend_get_public_key :: Tox a -> Word32 -> CString -> CErr ErrFriendGetPublicKey -> IO Bool+++--------------------------------------------------------------------------------+--+-- :: Friend-specific state queries (can also be received through callbacks)+--+--------------------------------------------------------------------------------+++-- | @param friend_number The friend number of the friend whose name changed.+-- @param name A byte array containing the same data as+--   tox_friend_get_name would write to its `name` parameter.+-- @param length A value equal to the return value of+--   tox_friend_get_name_size.+type FriendNameCb a = Tox a -> Word32 -> CString -> CSize -> Ptr a+foreign import ccall "wrapper" wrapFriendNameCb :: FriendNameCb a -> IO (FunPtr (FriendNameCb a))++-- | Set the callback for the `friend_name` event. Pass 'nullPtr' to unset.+--+-- This event is triggered when a friend changes their name.+foreign import ccall tox_callback_friend_name :: Tox a -> FunPtr (FriendNameCb a) -> IO ()+++-- | @param friend_number The friend number of the friend whose status message+--   changed.+-- @param message A byte array containing the same data as+--   tox_friend_get_status_message would write to its `status_message`+--   parameter.+-- @param length A value equal to the return value of+--   tox_friend_get_status_message_size.+type FriendStatusMessageCb a = Tox a -> Word32 -> CString -> CSize -> Ptr a -> IO ()+foreign import ccall "wrapper" wrapFriendStatusMessageCb :: FriendStatusMessageCb a -> IO (FunPtr (FriendStatusMessageCb a))++-- | Set the callback for the `friend_status_message` event. Pass 'nullPtr' to+-- unset.+--+-- This event is triggered when a friend changes their status message.+foreign import ccall tox_callback_friend_status_message :: Tox a -> FunPtr (FriendStatusMessageCb a) -> IO ()+++-- | @param friend_number The friend number of the friend whose user status+--   changed.+-- @param status The new user status.+type FriendStatusCb a = Tox a -> Word32 -> CEnum UserStatus -> Ptr a -> IO ()+foreign import ccall "wrapper" wrapFriendStatusCb :: FriendStatusCb a -> IO (FunPtr (FriendStatusCb a))+++-- | Set the callback for the `friend_status` event. Pass 'nullPtr' to unset.+--+-- This event is triggered when a friend changes their user status.+foreign import ccall tox_callback_friend_status :: Tox a -> FunPtr (FriendStatusCb a) -> IO ()+++-- | @param friend_number The friend number of the friend whose connection+--   status changed.+-- @param connection_status The result of calling+--   tox_friend_get_connection_status on the passed friend_number.+type FriendConnectionStatusCb a = Tox a -> Word32 -> CEnum Connection -> Ptr a -> IO ()+foreign import ccall "wrapper" wrapFriendConnectionStatusCb :: FriendConnectionStatusCb a -> IO (FunPtr (FriendConnectionStatusCb a))++-- | Set the callback for the `friend_connection_status` event. Pass 'nullPtr'+-- to unset.+--+-- This event is triggered when a friend goes offline after having been online,+-- or when a friend goes online.+--+-- This callback is not called when adding friends. It is assumed that when+-- adding friends, their connection status is initially offline.+foreign import ccall tox_callback_friend_connection_status :: Tox a -> FunPtr (FriendConnectionStatusCb a) -> IO ()+++-- | @param friend_number The friend number of the friend who started or stopped+--   typing.+-- @param is_typing The result of calling tox_friend_get_typing on the passed+--   friend_number.+type FriendTypingCb a = Tox a -> Word32 -> Bool -> Ptr a -> IO ()+foreign import ccall "wrapper" wrapFriendTypingCb :: FriendTypingCb a -> IO (FunPtr (FriendTypingCb a))++-- | Set the callback for the `friend_typing` event. Pass 'nullPtr' to unset.+--+-- This event is triggered when a friend starts or stops typing.+foreign import ccall tox_callback_friend_typing :: Tox a -> FunPtr (FriendTypingCb a) -> IO ()+++--------------------------------------------------------------------------------+--+-- :: Sending private messages+--+--------------------------------------------------------------------------------+++data ErrSetTyping+  = ErrSetTypingOk+    -- The function returned successfully.++  | ErrSetTypingFriendNotFound+    -- The friend number did not designate a valid friend.+  deriving (Eq, Ord, Enum, Bounded, Read, Show)+++-- | Set the client's typing status for a friend.+--+-- The client is responsible for turning it on or off.+--+-- @param friend_number The friend to which the client is typing a message.+-- @param typing The typing status. True means the client is typing.+--+-- @return true on success.+foreign import ccall tox_self_set_typing :: Tox a -> Word32 -> Bool -> CErr ErrSetTyping -> IO Bool++data ErrFriendSendMessage+  = ErrFriendSendMessageOk+    -- The function returned successfully.++  | ErrFriendSendMessageNull+    -- One of the arguments to the function was 'nullPtr' when it was not+    -- expected.++  | ErrFriendSendMessageFriendNotFound+    -- The friend number did not designate a valid friend.++  | ErrFriendSendMessageFriendNotConnected+    -- This client is currently not connected to the friend.++  | ErrFriendSendMessageSendq+    -- An allocation error occurred while increasing the send queue size.++  | ErrFriendSendMessageTooLong+    -- Message length exceeded 'tox_max_message_length'.++  | ErrFriendSendMessageEmpty+    -- Attempted to send a zero-length message.+  deriving (Eq, Ord, Enum, Bounded, Read, Show)+++-- | Send a text chat message to an online friend.+--+-- This function creates a chat message packet and pushes it into the send+-- queue.+--+-- The message length may not exceed 'tox_max_message_length'. Larger messages+-- must be split by the client and sent as separate messages. Other clients can+-- then reassemble the fragments. Messages may not be empty.+--+-- The return value of this function is the message ID. If a read receipt is+-- received, the triggered `friend_read_receipt` event will be passed this+-- message ID.+--+-- Message IDs are unique per friend. The first message ID is 0. Message IDs are+-- incremented by 1 each time a message is sent. If UINT32_MAX messages were+-- sent, the next message ID is 0.+--+-- @param type Message type (normal, action, ...).+-- @param friend_number The friend number of the friend to send the message to.+-- @param message A non-'nullPtr' pointer to the first element of a byte array+--   containing the message text.+-- @param length Length of the message to be sent.+foreign import ccall tox_friend_send_message :: Tox a -> Word32 -> CEnum MessageType -> CString -> CSize -> CErr ErrFriendSendMessage -> IO Word32++-- | @param friend_number The friend number of the friend who received the+--   message.+-- @param message_id The message ID as returned from tox_friend_send_message+--   corresponding to the message sent.+type FriendReadReceiptCb a = Tox a -> Word32 -> Word32 -> Ptr a -> IO ()+foreign import ccall "wrapper" wrapFriendReadReceiptCb :: FriendReadReceiptCb a -> IO (FunPtr (FriendReadReceiptCb a))+++-- | Set the callback for the `friend_read_receipt` event. Pass 'nullPtr' to+-- unset.+--+-- This event is triggered when the friend receives the message sent with+-- tox_friend_send_message with the corresponding message ID.+foreign import ccall tox_callback_friend_read_receipt :: Tox a -> FunPtr (FriendReadReceiptCb a) -> IO ()+++--------------------------------------------------------------------------------+--+-- :: Receiving private messages and friend requests+--+--------------------------------------------------------------------------------+++-- | @param public_key The Public Key of the user who sent the friend request.+-- @param time_delta A delta in seconds between when the message was composed+--   and when it is being transmitted. For messages that are sent immediately,+--   it will be 0. If a message was written and couldn't be sent immediately+--   (due to a connection failure, for example), the time_delta is an+--   approximation of when it was composed.+-- @param message The message they sent along with the request.+-- @param length The size of the message byte array.+type FriendRequestCb a = Tox a -> CString -> CString -> CSize -> Ptr a -> IO ()+foreign import ccall "wrapper" wrapFriendRequestCb :: FriendRequestCb a -> IO (FunPtr (FriendRequestCb a))+++-- | Set the callback for the `friend_request` event. Pass 'nullPtr' to unset.+--+-- This event is triggered when a friend request is received.+foreign import ccall tox_callback_friend_request :: Tox a -> FunPtr (FriendRequestCb a) -> IO ()++-- | @param friend_number The friend number of the friend who sent the message.+-- @param time_delta Time between composition and sending.+-- @param message The message data they sent.+-- @param length The size of the message byte array.+--+-- @see friend_request for more information on time_delta.+type FriendMessageCb a = Tox a -> Word32 -> CEnum MessageType -> CString -> CSize -> Ptr a -> IO ()+foreign import ccall "wrapper" wrapFriendMessageCb :: FriendMessageCb a -> IO (FunPtr (FriendMessageCb a))+++-- | Set the callback for the `friend_message` event. Pass 'nullPtr' to unset.+--+-- This event is triggered when a message from a friend is received.+foreign import ccall tox_callback_friend_message :: Tox a -> FunPtr (FriendMessageCb a) -> IO ()+++--------------------------------------------------------------------------------+--+-- :: File transmission: common between sending and receiving+--+--------------------------------------------------------------------------------+++-- | Generates a cryptographic hash of the given data.+--+-- This function may be used by clients for any purpose, but is provided+-- primarily for validating cached avatars. This use is highly recommended to+-- avoid unnecessary avatar updates.+--+-- If hash is 'nullPtr' or data is 'nullPtr' while length is not 0 the function+-- returns false, otherwise it returns true.+--+-- This function is a wrapper to internal message-digest functions.+--+-- @param hash A valid memory location the hash data. It must be at least+--   'tox_hash_length' bytes in size.+-- @param data Data to be hashed or 'nullPtr'.+-- @param length Size of the data array or 0.+--+-- @return true if hash was not 'nullPtr'.+foreign import ccall tox_hash :: CString -> CString -> CSize -> IO Bool++data FileKind++  = FileKindData+    -- Arbitrary file data. Clients can choose to handle it based on the file+    -- name or magic or any other way they choose.++  | FileKindAvatar+    -- Avatar file_id. This consists of tox_hash(image).  Avatar data. This+    -- consists of the image data.+    --+    -- Avatars can be sent at any time the client wishes. Generally, a client+    -- will send the avatar to a friend when that friend comes online, and to+    -- all friends when the avatar changed. A client can save some traffic by+    -- remembering which friend received the updated avatar already and only+    -- send it if the friend has an out of date avatar.+    --+    -- Clients who receive avatar send requests can reject it (by sending+    -- FileControlCancel before any other controls), or accept it (by sending+    -- FileControlResume). The file_id of length 'tox_hash_length' bytes (same+    -- length as 'tox_file_id_length') will contain the hash. A client can+    -- compare this hash with a saved hash and send FileControlCancel to+    -- terminate the avatar transfer if it matches.+    --+    -- When file_size is set to 0 in the transfer request it means that the+    -- client has no avatar.+  deriving (Eq, Ord, Enum, Bounded, Read, Show)++instance Arbitrary FileKind where+  arbitrary = arbitraryBoundedEnum+++data FileControl+  = FileControlResume+    -- Sent by the receiving side to accept a file send request. Also sent after+    -- a FileControlPause command to continue sending or receiving.++  | FileControlPause+    -- Sent by clients to pause the file transfer. The initial state of a file+    -- transfer is always paused on the receiving side and running on the+    -- sending side. If both the sending and receiving side pause the transfer,+    -- then both need to send FileControlResume for the transfer to resume.++  | FileControlCancel+    -- Sent by the receiving side to reject a file send request before any other+    -- commands are sent. Also sent by either side to terminate a file transfer.+  deriving (Eq, Ord, Enum, Bounded, Read, Show)++instance Arbitrary FileControl where+  arbitrary = arbitraryBoundedEnum+++data ErrFileControl+  = ErrFileControlOk+    -- The function returned successfully.++  | ErrFileControlFriendNotFound+    -- The friend_number passed did not designate a valid friend.++  | ErrFileControlFriendNotConnected+    -- This client is currently not connected to the friend.++  | ErrFileControlNotFound+    -- No file transfer with the given file number was found for the given friend.++  | ErrFileControlNotPaused+    -- A Resume control was sent, but the file transfer is running normally.++  | ErrFileControlDenied+    -- A Resume control was sent, but the file transfer was paused by the other+    -- party. Only the party that paused the transfer can resume it.++  | ErrFileControlAlreadyPaused+    -- A Pause control was sent, but the file transfer was already paused.++  | ErrFileControlSendq+    -- Packet queue is full.+  deriving (Eq, Ord, Enum, Bounded, Read, Show)+++-- | Sends a file control command to a friend for a given file transfer.+--+-- @param friend_number The friend number of the friend the file is being+--   transferred to or received from.+-- @param file_number The friend-specific identifier for the file transfer.+-- @param control The control command to send.+--+-- @return true on success.+foreign import ccall tox_file_control :: Tox a -> Word32 -> Word32 -> CEnum FileControl -> CErr ErrFileControl -> IO Bool++-- | When receiving FileControlCancel, the client should release the+-- resources associated with the file number and consider the transfer failed.+--+-- @param friend_number The friend number of the friend who is sending the file.+-- @param file_number The friend-specific file number the data received is+--   associated with.+-- @param control The file control command received.+type FileRecvControlCb a = Tox a -> Word32 -> Word32 -> CEnum FileControl -> Ptr a -> IO ()+foreign import ccall "wrapper" wrapFileRecvControlCb :: FileRecvControlCb a -> IO (FunPtr (FileRecvControlCb a))+++-- | Set the callback for the `file_recv_control` event. Pass 'nullPtr' to+-- unset.+--+-- This event is triggered when a file control command is received from a+-- friend.+foreign import ccall tox_callback_file_recv_control :: Tox a -> FunPtr (FileRecvControlCb a) -> IO ()++data ErrFileSeek+  = ErrFileSeekOk+    -- The function returned successfully.++  | ErrFileSeekFriendNotFound+    -- The friend_number passed did not designate a valid friend.++  | ErrFileSeekFriendNotConnected+    -- This client is currently not connected to the friend.++  | ErrFileSeekNotFound+    -- No file transfer with the given file number was found for the given friend.++  | ErrFileSeekDenied+    -- File was not in a state where it could be seeked.++  | ErrFileSeekInvalidPosition+    -- Seek position was invalid++  | ErrFileSeekSendq+    -- Packet queue is full.+  deriving (Eq, Ord, Enum, Bounded, Read, Show)+++-- | Sends a file seek control command to a friend for a given file transfer.+--+-- This function can only be called to resume a file transfer right before+-- FileControlResume is sent.+--+-- @param friend_number The friend number of the friend the file is being+--   received from.+-- @param file_number The friend-specific identifier for the file transfer.+-- @param position The position that the file should be seeked to.+foreign import ccall tox_file_seek :: Tox a -> Word32 -> Word32 -> Word64 -> CErr ErrFileSeek -> IO Bool++data ErrFileGet+  = ErrFileGetOk+    -- The function returned successfully.++  | ErrFileGetNull+    -- One of the arguments to the function was 'nullPtr' when it was not+    -- expected.++  | ErrFileGetFriendNotFound+    -- The friend_number passed did not designate a valid friend.++  | ErrFileGetNotFound+    -- No file transfer with the given file number was found for the given friend.+  deriving (Eq, Ord, Enum, Bounded, Read, Show)+++-- | Copy the file id associated to the file transfer to a byte array.+--+-- @param friend_number The friend number of the friend the file is being+--   transferred to or received from.+-- @param file_number The friend-specific identifier for the file transfer.+-- @param file_id A memory region of at least 'tox_file_id_length' bytes. If+--   this parameter is 'nullPtr', this function has no effect.+--+-- @return true on success.+foreign import ccall tox_file_get_file_id :: Tox a -> Word32 -> Word32 -> CString -> CErr ErrFileGet -> IO Bool+++--------------------------------------------------------------------------------+--+-- :: File transmission: sending+--+--------------------------------------------------------------------------------+++data ErrFileSend+  = ErrFileSendOk+    -- The function returned successfully.++  | ErrFileSendNull+    -- One of the arguments to the function was 'nullPtr' when it was not+    -- expected.++  | ErrFileSendFriendNotFound+    -- The friend_number passed did not designate a valid friend.++  | ErrFileSendFriendNotConnected+    -- This client is currently not connected to the friend.++  | ErrFileSendNameTooLong+    -- Filename length exceeded 'tox_max_filename_length' bytes.++  | ErrFileSendTooMany+    -- Too many ongoing transfers. The maximum number of concurrent file transfers+    -- is 256 per friend per direction (sending and receiving).+  deriving (Eq, Ord, Enum, Bounded, Read, Show)+++-- | Send a file transmission request.+--+-- Maximum filename length is 'tox_max_filename_length' bytes. The filename+-- should generally just be a file name, not a path with directory names.+--+-- If a non-UINT64_MAX file size is provided, it can be used by both sides to+-- determine the sending progress. File size can be set to UINT64_MAX for+-- streaming data of unknown size.+--+-- File transmission occurs in chunks, which are requested through the+-- `file_chunk_request` event.+--+-- When a friend goes offline, all file transfers associated with the friend are+-- purged from core.+--+-- If the file contents change during a transfer, the behaviour is unspecified+-- in general. What will actually happen depends on the mode in which the file+-- was modified and how the client determines the file size.+--+-- - If the file size was increased+--   - and sending mode was streaming (file_size = UINT64_MAX), the behaviour+--     will be as expected.+--   - and sending mode was file (file_size != UINT64_MAX), the+--     file_chunk_request callback will receive length = 0 when Core thinks+--     the file transfer has finished. If the client remembers the file size as+--     it was when sending the request, it will terminate the transfer normally.+--     If the client re-reads the size, it will think the friend cancelled the+--     transfer.+-- - If the file size was decreased+--   - and sending mode was streaming, the behaviour is as expected.+--   - and sending mode was file, the callback will return 0 at the new+--     (earlier) end-of-file, signalling to the friend that the transfer was+--     cancelled.+-- - If the file contents were modified+--   - at a position before the current read, the two files (local and remote)+--     will differ after the transfer terminates.+--   - at a position after the current read, the file transfer will succeed as+--     expected.+--   - In either case, both sides will regard the transfer as complete and+--     successful.+--+-- @param friend_number The friend number of the friend the file send request+--   should be sent to.+-- @param kind The meaning of the file to be sent.+-- @param file_size Size in bytes of the file the client wants to send,+--   UINT64_MAX if unknown or streaming.+-- @param file_id A file identifier of length 'tox_file_id_length' that can be+--   used to uniquely identify file transfers across core restarts. If+--   'nullPtr', a random one will be generated by core. It can then be obtained+--   by using tox_file_get_file_id().+-- @param filename Name of the file. Does not need to be the actual name. This+--   name will be sent along with the file send request.+-- @param filename_length Size in bytes of the filename.+--+-- @return A file number used as an identifier in subsequent callbacks. This+--   number is per friend. File numbers are reused after a transfer terminates.+--   On failure, this function returns UINT32_MAX. Any pattern in file numbers+--   should not be relied on.+foreign import ccall tox_file_send :: Tox a -> Word32 -> Word32 -> Word64 -> CString -> CString -> CSize -> CErr ErrFileSend -> IO Word32++data ErrFileSendChunk+  = ErrFileSendChunkOk+    -- The function returned successfully.++  | ErrFileSendChunkNull+    -- The length parameter was non-zero, but data was 'nullPtr'.++  | ErrFileSendChunkFriendNotFound+    -- The friend_number passed did not designate a valid friend.++  | ErrFileSendChunkFriendNotConnected+    -- This client is currently not connected to the friend.++  | ErrFileSendChunkNotFound+    -- No file transfer with the given file number was found for the given friend.++  | ErrFileSendChunkNotTransferring+    -- File transfer was found but isn't in a transferring state: (paused, done,+    -- broken, etc...) (happens only when not called from the request chunk+    -- callback).++  | ErrFileSendChunkInvalidLength+    -- Attempted to send more or less data than requested. The requested data+    -- size is adjusted according to maximum transmission unit and the expected+    -- end of the file. Trying to send less or more than requested will return+    -- this error.++  | ErrFileSendChunkSendq+    -- Packet queue is full.++  | ErrFileSendChunkWrongPosition+    -- Position parameter was wrong.+  deriving (Eq, Ord, Enum, Bounded, Read, Show)+++-- | Send a chunk of file data to a friend.+--+-- This function is called in response to the `file_chunk_request` callback.+-- The length parameter should be equal to the one received though the+-- callback.  If it is zero, the transfer is assumed complete. For files with+-- known size, Core will know that the transfer is complete after the last byte+-- has been received, so it is not necessary (though not harmful) to send a+-- zero-length chunk to terminate. For streams, core will know that the+-- transfer is finished if a chunk with length less than the length requested+-- in the callback is sent.+--+-- @param friend_number The friend number of the receiving friend for this file.+-- @param file_number The file transfer identifier returned by tox_file_send.+-- @param position The file or stream position from which to continue reading.+-- @return true on success.+foreign import ccall tox_file_send_chunk :: Tox a -> Word32 -> Word32 -> Word64 -> CString -> CSize -> CErr ErrFileSendChunk -> IO Bool++-- | If the length parameter is 0, the file transfer is finished, and the+-- client's resources associated with the file number should be released. After+-- a call with zero length, the file number can be reused for future file+-- transfers.+--+-- If the requested position is not equal to the client's idea of the current+-- file or stream position, it will need to seek. In case of read-once streams,+-- the client should keep the last read chunk so that a seek back can be+-- supported. A seek-back only ever needs to read from the last requested+-- chunk.  This happens when a chunk was requested, but the send failed. A+-- seek-back request can occur an arbitrary number of times for any given+-- chunk.+--+-- In response to receiving this callback, the client should call the function+-- `tox_file_send_chunk` with the requested chunk. If the number of bytes sent+-- through that function is zero, the file transfer is assumed complete. A+-- client must send the full length of data requested with this callback.+--+-- @param friend_number The friend number of the receiving friend for this file.+-- @param file_number The file transfer identifier returned by tox_file_send.+-- @param position The file or stream position from which to continue reading.+-- @param length The number of bytes requested for the current chunk.+type FileChunkRequestCb a = Tox a -> Word32 -> Word32 -> Word64 -> CSize -> Ptr a -> IO ()+foreign import ccall "wrapper" wrapFileChunkRequestCb :: FileChunkRequestCb a -> IO (FunPtr (FileChunkRequestCb a))+++-- | Set the callback for the `file_chunk_request` event. Pass 'nullPtr' to+-- unset.+--+-- This event is triggered when Core is ready to send more file data.+foreign import ccall tox_callback_file_chunk_request :: Tox a -> FunPtr (FileChunkRequestCb a) -> IO ()+++--------------------------------------------------------------------------------+--+-- :: File transmission: receiving+--+--------------------------------------------------------------------------------+++-- | The client should acquire resources to be associated with the file+-- transfer.  Incoming file transfers start in the Paused state. After this+-- callback returns, a transfer can be rejected by sending a FileControlCancel+-- control command before any other control commands. It can be accepted by+-- sending FileControlResume.+--+-- @param friend_number The friend number of the friend who is sending the file+--   transfer request.+-- @param file_number The friend-specific file number the data received is+--   associated with.+-- @param kind The meaning of the file to be sent.+-- @param file_size Size in bytes of the file the client wants to send,+--   UINT64_MAX if unknown or streaming.+-- @param filename Name of the file. Does not need to be the actual name. This+--   name will be sent along with the file send request.+-- @param filename_length Size in bytes of the filename.+type FileRecvCb a = Tox a -> Word32 -> Word32 -> Word32 -> Word64 -> CString -> CSize -> Ptr a -> IO ()+foreign import ccall "wrapper" wrapFileRecvCb :: FileRecvCb a -> IO (FunPtr (FileRecvCb a))+++-- | Set the callback for the `file_recv` event. Pass 'nullPtr' to unset.+--+-- This event is triggered when a file transfer request is received.+foreign import ccall tox_callback_file_recv :: Tox a -> FunPtr (FileRecvCb a) -> IO ()++-- | When length is 0, the transfer is finished and the client should release+-- the resources it acquired for the transfer. After a call with length = 0,+-- the file number can be reused for new file transfers.+--+-- If position is equal to file_size (received in the file_receive callback)+-- when the transfer finishes, the file was received completely. Otherwise, if+-- file_size was UINT64_MAX, streaming ended successfully when length is 0.+--+-- @param friend_number The friend number of the friend who is sending the file.+-- @param file_number The friend-specific file number the data received is+--   associated with.+-- @param position The file position of the first byte in data.+-- @param data A byte array containing the received chunk.+-- @param length The length of the received chunk.+type FileRecvChunkCb a = Tox a -> Word32 -> Word32 -> Word64 -> CString -> CSize -> Ptr a -> IO ()+foreign import ccall "wrapper" wrapFileRecvChunkCb :: FileRecvChunkCb a -> IO (FunPtr (FileRecvChunkCb a))+++-- | Set the callback for the `file_recv_chunk` event. Pass 'nullPtr' to unset.+--+-- This event is first triggered when a file transfer request is received, and+-- subsequently when a chunk of file data for an accepted request was received.+foreign import ccall tox_callback_file_recv_chunk :: Tox a -> FunPtr (FileRecvChunkCb a) -> IO ()+++--------------------------------------------------------------------------------+--+-- :: Group chat management+--+--------------------------------------------------------------------------------+++--------------------------------------------------------------------------------+--+-- :: Group chat message sending and receiving+--+--------------------------------------------------------------------------------+++--------------------------------------------------------------------------------+--+-- :: Low-level custom packet sending and receiving+--+--------------------------------------------------------------------------------+++data ErrFriendCustomPacket+  = ErrFriendCustomPacketOk+    -- The function returned successfully.++  | ErrFriendCustomPacketNull+    -- One of the arguments to the function was 'nullPtr' when it was not+    -- expected.++  | ErrFriendCustomPacketFriendNotFound+    -- The friend number did not designate a valid friend.++  | ErrFriendCustomPacketFriendNotConnected+    -- This client is currently not connected to the friend.++  | ErrFriendCustomPacketInvalid+    -- The first byte of data was not in the specified range for the packet+    -- type. This range is 200-254 for lossy, and 160-191 for lossless packets.++  | ErrFriendCustomPacketEmpty+    -- Attempted to send an empty packet.++  | ErrFriendCustomPacketTooLong+    -- Packet data length exceeded 'tox_max_custom_packet_size'.++  | ErrFriendCustomPacketSendq+    -- Packet queue is full.+  deriving (Eq, Ord, Enum, Bounded, Read, Show)+++-- | Send a custom lossy packet to a friend.+--+-- The first byte of data must be in the range 200-254. Maximum length of a+-- custom packet is 'tox_max_custom_packet_size'.+--+-- Lossy packets behave like UDP packets, meaning they might never reach the+-- other side or might arrive more than once (if someone is messing with the+-- connection) or might arrive in the wrong order.+--+-- Unless latency is an issue, it is recommended that you use lossless custom+-- packets instead.+--+-- @param friend_number The friend number of the friend this lossy packet+--   should be sent to.+-- @param data A byte array containing the packet data.+-- @param length The length of the packet data byte array.+--+-- @return true on success.+foreign import ccall tox_friend_send_lossy_packet :: Tox a -> Word32 -> CString -> CSize -> CErr ErrFriendCustomPacket -> IO Bool++-- | Send a custom lossless packet to a friend.+--+-- The first byte of data must be in the range 160-191. Maximum length of a+-- custom packet is 'tox_max_custom_packet_size'.+--+-- Lossless packet behaviour is comparable to TCP (reliability, arrive in order)+-- but with packets instead of a stream.+--+-- @param friend_number The friend number of the friend this lossless packet+--   should be sent to.+-- @param data A byte array containing the packet data.+-- @param length The length of the packet data byte array.+--+-- @return true on success.+foreign import ccall tox_friend_send_lossless_packet :: Tox a -> Word32 -> CString -> CSize -> CErr ErrFriendCustomPacket -> IO Bool++-- | @param friend_number The friend number of the friend who sent a lossy+-- packet.+-- @param data A byte array containing the received packet data.+-- @param length The length of the packet data byte array.+type FriendLossyPacketCb a = Tox a -> Word32 -> CString -> CSize -> Ptr a -> IO ()+foreign import ccall "wrapper" wrapFriendLossyPacketCb :: FriendLossyPacketCb a -> IO (FunPtr (FriendLossyPacketCb a))+++-- | Set the callback for the `friend_lossy_packet` event. Pass 'nullPtr' to+-- unset.+--+foreign import ccall tox_callback_friend_lossy_packet :: Tox a -> FunPtr (FriendLossyPacketCb a) -> IO ()++-- | @param friend_number The friend number of the friend who sent the packet.+-- @param data A byte array containing the received packet data.+-- @param length The length of the packet data byte array.+type FriendLosslessPacketCb a = Tox a -> Word32 -> CString -> CSize -> Ptr a -> IO ()+foreign import ccall "wrapper" wrapFriendLosslessPacketCb :: FriendLosslessPacketCb a -> IO (FunPtr (FriendLosslessPacketCb a))+++-- | Set the callback for the `friend_lossless_packet` event. Pass 'nullPtr' to+-- unset.+--+foreign import ccall tox_callback_friend_lossless_packet :: Tox a -> FunPtr (FriendLosslessPacketCb a) -> IO ()+++--------------------------------------------------------------------------------+--+-- :: Low-level network information+--+--------------------------------------------------------------------------------+++-- | Writes the temporary DHT public key of this instance to a byte array.+--+-- This can be used in combination with an externally accessible IP address and+-- the bound port (from tox_self_get_udp_port) to run a temporary bootstrap+-- node.+--+-- Be aware that every time a new instance is created, the DHT public key+-- changes, meaning this cannot be used to run a permanent bootstrap node.+--+-- @param dht_id A memory region of at least 'tox_public_key_size' bytes. If+--   this parameter is 'nullPtr', this function has no effect.+foreign import ccall tox_self_get_dht_id :: Tox a -> CString -> IO ()++data ErrGetPort+  = ErrGetPortOk+    -- The function returned successfully.++  | ErrGetPortNotBound+    -- The instance was not bound to any port.+  deriving (Eq, Ord, Enum, Bounded, Read, Show)+++-- | Return the UDP port this Tox instance is bound to.+foreign import ccall tox_self_get_udp_port :: Tox a -> CErr ErrGetPort -> IO Word16++-- | Return the TCP port this Tox instance is bound to. This is only relevant if+-- the instance is acting as a TCP relay.+foreign import ccall tox_self_get_tcp_port :: Tox a -> CErr ErrGetPort -> IO Word16
+ test/testsuite.hs view
@@ -0,0 +1,1 @@+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
+ toxcore.cabal view
@@ -0,0 +1,58 @@+name:                 toxcore+synopsis:             Haskell bindings to the C reference implementation of Tox+version:              0.0.2+cabal-version:        >= 1.10+license:              AGPL-3+license-file:         LICENSE.md+build-type:           Simple+author:               iphy+maintainer:           iphy+copyright:            © 2016 iphy+homepage:             https://toktok.github.io+category:             Network+description:+  Haskell bindings to the C reference implementation of Tox.+  .+  See <https://github.com/TokTok/toxcore>.++source-repository head+  type: git+  location: https://github.com/TokTok/hs-toxcore++library+  default-language: Haskell2010+  hs-source-dirs:+      src+  ghc-options:+      -Wall+      -fno-warn-unused-imports+  extra-libraries: toxcore+  build-depends:+      base < 5+    , QuickCheck >= 2.9.1+    , bytestring+    , bytestring-arbitrary+    , data-default-class+    , saltine+  exposed-modules:+      Network.Tox.C+      Network.Tox.C.Callbacks+      Network.Tox.C.CEnum+      Network.Tox.C.Tox++test-suite testsuite+  default-language: Haskell2010+  type: exitcode-stdio-1.0+  hs-source-dirs:+      test+  ghc-options:+      -Wall+      -fno-warn-unused-imports+  build-depends:+      base < 5+    , QuickCheck >= 2.9.1+    , data-default-class+    , hspec+    , saltine+    , toxcore+  main-is: testsuite.hs