toxcore-c 0.2.11 → 0.2.19
raw patch · 18 files changed
+2719/−3155 lines, 18 filesdep +cryptohashdep +generic-arbitrarydep +msgpack-binarydep −bytestring-arbitrarydep −data-default-classdep ~QuickCheckdep ~base16-bytestring
Dependencies added: cryptohash, generic-arbitrary, msgpack-binary, quickcheck-instances, text, vector
Dependencies removed: bytestring-arbitrary, data-default-class
Dependency ranges changed: QuickCheck, base16-bytestring
Files
- LICENSE +4/−5
- src/FFI/Tox/Tox.hs +881/−0
- src/Foreign/C/Enum.hs +36/−0
- src/Network/Tox/C.hs +36/−6
- src/Network/Tox/C/CEnum.hs +0/−37
- src/Network/Tox/C/Callbacks.hs +0/−89
- src/Network/Tox/C/Constants.hs +1/−2
- src/Network/Tox/C/Options.hs +164/−226
- src/Network/Tox/C/Tox.hs +1118/−2405
- src/Network/Tox/C/Type.hs +19/−12
- src/Network/Tox/C/Version.hs +1/−1
- src/Network/Tox/Types/Events.hs +88/−0
- test/Network/Tox/C/ToxSpec.hs +78/−83
- test/Network/Tox/CSpec.hs +0/−96
- test/Network/Tox/Types/EventsSpec.hs +74/−0
- tools/groupbot.hs +169/−0
- tools/groupbot/Main.hs +0/−143
- toxcore-c.cabal +50/−50
LICENSE view
@@ -1,7 +1,7 @@ GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 - Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>+ Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/> Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. @@ -645,7 +645,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License- along with this program. If not, see <http://www.gnu.org/licenses/>.+ along with this program. If not, see <https://www.gnu.org/licenses/>. Also add information on how to contact you by electronic and paper mail. @@ -664,12 +664,11 @@ You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see-<http://www.gnu.org/licenses/>.+<https://www.gnu.org/licenses/>. The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read-<http://www.gnu.org/philosophy/why-not-lgpl.html>.-+<https://www.gnu.org/licenses/why-not-lgpl.html>.
+ src/FFI/Tox/Tox.hs view
@@ -0,0 +1,881 @@+-- bazel-out/k8-fastbuild/bin/c-toxcore/tox/tox.h+{-# LANGUAGE DeriveGeneric #-}+module FFI.Tox.Tox where++import Data.MessagePack (MessagePack)+import Data.Word (Word16, Word32, Word64)+import Foreign.C.Enum (CEnum (..), CErr)+import Foreign.C.String (CString)+import Foreign.C.Types (CInt (..), CSize (..))+import Foreign.Ptr (FunPtr, Ptr)+import GHC.Generics (Generic)+import Test.QuickCheck.Arbitrary (Arbitrary (..),+ arbitraryBoundedEnum)++data ToxStruct+type ToxPtr = Ptr ToxStruct+foreign import ccall tox_version_major :: Word32+foreign import ccall tox_version_minor :: Word32+foreign import ccall tox_version_patch :: Word32+foreign import ccall tox_version_is_compatible :: Word32 -> Word32 -> Word32 -> IO Bool+foreign import ccall tox_public_key_size :: Word32+foreign import ccall tox_secret_key_size :: Word32+foreign import ccall tox_conference_uid_size :: Word32+foreign import ccall tox_conference_id_size :: Word32+foreign import ccall tox_nospam_size :: Word32+foreign import ccall tox_address_size :: Word32+foreign import ccall tox_max_name_length :: Word32+foreign import ccall tox_max_status_message_length :: Word32+foreign import ccall tox_max_friend_request_length :: Word32+foreign import ccall tox_max_message_length :: Word32+foreign import ccall tox_max_custom_packet_size :: Word32+foreign import ccall tox_hash_length :: Word32+foreign import ccall tox_file_id_length :: Word32+foreign import ccall tox_max_filename_length :: Word32+foreign import ccall tox_max_hostname_length :: Word32+data UserStatus+ = UserStatusNone+ | UserStatusAway+ | UserStatusBusy+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack UserStatus+instance Arbitrary UserStatus where arbitrary = arbitraryBoundedEnum+data MessageType+ = MessageTypeNormal+ | MessageTypeAction+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack MessageType+instance Arbitrary MessageType where arbitrary = arbitraryBoundedEnum+data ProxyType+ = ProxyTypeNone+ | ProxyTypeHttp+ | ProxyTypeSocks5+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack ProxyType+instance Arbitrary ProxyType where arbitrary = arbitraryBoundedEnum+data SavedataType+ = SavedataTypeNone+ | SavedataTypeToxSave+ | SavedataTypeSecretKey+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack SavedataType+instance Arbitrary SavedataType where arbitrary = arbitraryBoundedEnum+data LogLevel+ = LogLevelTrace+ | LogLevelDebug+ | LogLevelInfo+ | LogLevelWarning+ | LogLevelError+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack LogLevel+instance Arbitrary LogLevel where arbitrary = arbitraryBoundedEnum+type LogCb = ToxPtr -> CEnum LogLevel -> CString -> Word32 -> CString -> CString -> Ptr () -> IO ()+foreign import ccall "wrapper" wrapLogCb :: LogCb -> IO (FunPtr LogCb)+data OptionsStruct+type OptionsPtr = Ptr OptionsStruct+foreign import ccall tox_options_get_ipv6_enabled :: OptionsPtr -> IO Bool+foreign import ccall tox_options_set_ipv6_enabled :: OptionsPtr -> Bool -> IO ()+foreign import ccall tox_options_get_udp_enabled :: OptionsPtr -> IO Bool+foreign import ccall tox_options_set_udp_enabled :: OptionsPtr -> Bool -> IO ()+foreign import ccall tox_options_get_local_discovery_enabled :: OptionsPtr -> IO Bool+foreign import ccall tox_options_set_local_discovery_enabled :: OptionsPtr -> Bool -> IO ()+foreign import ccall tox_options_get_dht_announcements_enabled :: OptionsPtr -> IO Bool+foreign import ccall tox_options_set_dht_announcements_enabled :: OptionsPtr -> Bool -> IO ()+foreign import ccall tox_options_get_proxy_type :: OptionsPtr -> IO (CEnum ProxyType)+foreign import ccall tox_options_set_proxy_type :: OptionsPtr -> CEnum ProxyType -> IO ()+foreign import ccall tox_options_get_proxy_host :: OptionsPtr -> IO CString+foreign import ccall tox_options_set_proxy_host :: OptionsPtr -> CString -> IO ()+foreign import ccall tox_options_get_proxy_port :: OptionsPtr -> IO Word16+foreign import ccall tox_options_set_proxy_port :: OptionsPtr -> Word16 -> IO ()+foreign import ccall tox_options_get_start_port :: OptionsPtr -> IO Word16+foreign import ccall tox_options_set_start_port :: OptionsPtr -> Word16 -> IO ()+foreign import ccall tox_options_get_end_port :: OptionsPtr -> IO Word16+foreign import ccall tox_options_set_end_port :: OptionsPtr -> Word16 -> IO ()+foreign import ccall tox_options_get_tcp_port :: OptionsPtr -> IO Word16+foreign import ccall tox_options_set_tcp_port :: OptionsPtr -> Word16 -> IO ()+foreign import ccall tox_options_get_hole_punching_enabled :: OptionsPtr -> IO Bool+foreign import ccall tox_options_set_hole_punching_enabled :: OptionsPtr -> Bool -> IO ()+foreign import ccall tox_options_get_savedata_type :: OptionsPtr -> IO (CEnum SavedataType)+foreign import ccall tox_options_set_savedata_type :: OptionsPtr -> CEnum SavedataType -> IO ()+foreign import ccall tox_options_get_savedata_data :: OptionsPtr -> IO CString+foreign import ccall tox_options_set_savedata_data :: OptionsPtr -> CString -> CSize -> IO ()+foreign import ccall tox_options_get_savedata_length :: OptionsPtr -> IO CSize+foreign import ccall tox_options_set_savedata_length :: OptionsPtr -> CSize -> IO ()+foreign import ccall tox_options_get_log_callback :: OptionsPtr -> IO (FunPtr LogCb)+foreign import ccall tox_options_set_log_callback :: OptionsPtr -> FunPtr LogCb -> IO ()+foreign import ccall tox_options_get_log_user_data :: OptionsPtr -> IO (Ptr ())+foreign import ccall tox_options_set_log_user_data :: OptionsPtr -> Ptr () -> IO ()+foreign import ccall tox_options_get_experimental_thread_safety :: OptionsPtr -> IO Bool+foreign import ccall tox_options_set_experimental_thread_safety :: OptionsPtr -> Bool -> IO ()+foreign import ccall tox_options_default :: OptionsPtr -> IO ()+data ErrOptionsNew+ = ErrOptionsNewMalloc+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack ErrOptionsNew+instance Arbitrary ErrOptionsNew where arbitrary = arbitraryBoundedEnum+foreign import ccall tox_options_new :: CErr ErrOptionsNew -> IO OptionsPtr+foreign import ccall tox_options_free :: OptionsPtr -> IO ()+data ErrNew+ = ErrNewNull+ | ErrNewMalloc+ | ErrNewPortAlloc+ | ErrNewProxyBadType+ | ErrNewProxyBadHost+ | ErrNewProxyBadPort+ | ErrNewProxyNotFound+ | ErrNewLoadEncrypted+ | ErrNewLoadBadFormat+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack ErrNew+instance Arbitrary ErrNew where arbitrary = arbitraryBoundedEnum+foreign import ccall tox_new :: OptionsPtr -> CErr ErrNew -> IO ToxPtr+foreign import ccall tox_kill :: ToxPtr -> IO ()+foreign import ccall tox_get_savedata_size :: ToxPtr -> IO CSize+foreign import ccall tox_get_savedata :: ToxPtr -> CString -> IO ()+data ErrBootstrap+ = ErrBootstrapNull+ | ErrBootstrapBadHost+ | ErrBootstrapBadPort+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack ErrBootstrap+instance Arbitrary ErrBootstrap where arbitrary = arbitraryBoundedEnum+foreign import ccall tox_bootstrap :: ToxPtr -> CString -> Word16 -> CString -> CErr ErrBootstrap -> IO Bool+foreign import ccall tox_add_tcp_relay :: ToxPtr -> CString -> Word16 -> CString -> CErr ErrBootstrap -> IO Bool+data Connection+ = ConnectionNone+ | ConnectionTcp+ | ConnectionUdp+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack Connection+instance Arbitrary Connection where arbitrary = arbitraryBoundedEnum+foreign import ccall tox_self_get_connection_status :: ToxPtr -> IO (CEnum Connection)+type SelfConnectionStatusCb = ToxPtr -> CEnum Connection -> Ptr () -> IO ()+foreign import ccall "wrapper" wrapSelfConnectionStatusCb :: SelfConnectionStatusCb -> IO (FunPtr SelfConnectionStatusCb)+foreign import ccall tox_callback_self_connection_status :: ToxPtr -> FunPtr SelfConnectionStatusCb -> IO ()+foreign import ccall tox_iteration_interval :: ToxPtr -> IO Word32+foreign import ccall tox_iterate :: ToxPtr -> Ptr () -> IO ()+foreign import ccall tox_self_get_address :: ToxPtr -> CString -> IO ()+foreign import ccall tox_self_set_nospam :: ToxPtr -> Word32 -> IO ()+foreign import ccall tox_self_get_nospam :: ToxPtr -> IO Word32+foreign import ccall tox_self_get_public_key :: ToxPtr -> CString -> IO ()+foreign import ccall tox_self_get_secret_key :: ToxPtr -> CString -> IO ()+data ErrSetInfo+ = ErrSetInfoNull+ | ErrSetInfoTooLong+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack ErrSetInfo+instance Arbitrary ErrSetInfo where arbitrary = arbitraryBoundedEnum+foreign import ccall tox_self_set_name :: ToxPtr -> CString -> CSize -> CErr ErrSetInfo -> IO Bool+foreign import ccall tox_self_get_name_size :: ToxPtr -> IO CSize+foreign import ccall tox_self_get_name :: ToxPtr -> CString -> IO ()+foreign import ccall tox_self_set_status_message :: ToxPtr -> CString -> CSize -> CErr ErrSetInfo -> IO Bool+foreign import ccall tox_self_get_status_message_size :: ToxPtr -> IO CSize+foreign import ccall tox_self_get_status_message :: ToxPtr -> CString -> IO ()+foreign import ccall tox_self_set_status :: ToxPtr -> CEnum UserStatus -> IO ()+foreign import ccall tox_self_get_status :: ToxPtr -> IO (CEnum UserStatus)+data ErrFriendAdd+ = ErrFriendAddNull+ | ErrFriendAddTooLong+ | ErrFriendAddNoMessage+ | ErrFriendAddOwnKey+ | ErrFriendAddAlreadySent+ | ErrFriendAddBadChecksum+ | ErrFriendAddSetNewNospam+ | ErrFriendAddMalloc+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack ErrFriendAdd+instance Arbitrary ErrFriendAdd where arbitrary = arbitraryBoundedEnum+foreign import ccall tox_friend_add :: ToxPtr -> CString -> CString -> CSize -> CErr ErrFriendAdd -> IO Word32+foreign import ccall tox_friend_add_norequest :: ToxPtr -> CString -> CErr ErrFriendAdd -> IO Word32+data ErrFriendDelete+ = ErrFriendDeleteFriendNotFound+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack ErrFriendDelete+instance Arbitrary ErrFriendDelete where arbitrary = arbitraryBoundedEnum+foreign import ccall tox_friend_delete :: ToxPtr -> Word32 -> CErr ErrFriendDelete -> IO Bool+data ErrFriendByPublicKey+ = ErrFriendByPublicKeyNull+ | ErrFriendByPublicKeyNotFound+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack ErrFriendByPublicKey+instance Arbitrary ErrFriendByPublicKey where arbitrary = arbitraryBoundedEnum+foreign import ccall tox_friend_by_public_key :: ToxPtr -> CString -> CErr ErrFriendByPublicKey -> IO Word32+foreign import ccall tox_friend_exists :: ToxPtr -> Word32 -> IO Bool+foreign import ccall tox_self_get_friend_list_size :: ToxPtr -> IO CSize+foreign import ccall tox_self_get_friend_list :: ToxPtr -> Ptr Word32 -> IO ()+data ErrFriendGetPublicKey+ = ErrFriendGetPublicKeyFriendNotFound+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack ErrFriendGetPublicKey+instance Arbitrary ErrFriendGetPublicKey where arbitrary = arbitraryBoundedEnum+foreign import ccall tox_friend_get_public_key :: ToxPtr -> Word32 -> CString -> CErr ErrFriendGetPublicKey -> IO Bool+data ErrFriendGetLastOnline+ = ErrFriendGetLastOnlineFriendNotFound+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack ErrFriendGetLastOnline+instance Arbitrary ErrFriendGetLastOnline where arbitrary = arbitraryBoundedEnum+foreign import ccall tox_friend_get_last_online :: ToxPtr -> Word32 -> CErr ErrFriendGetLastOnline -> IO Word64+data ErrFriendQuery+ = ErrFriendQueryNull+ | ErrFriendQueryFriendNotFound+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack ErrFriendQuery+instance Arbitrary ErrFriendQuery where arbitrary = arbitraryBoundedEnum+foreign import ccall tox_friend_get_name_size :: ToxPtr -> Word32 -> CErr ErrFriendQuery -> IO CSize+foreign import ccall tox_friend_get_name :: ToxPtr -> Word32 -> CString -> CErr ErrFriendQuery -> IO Bool+type FriendNameCb = ToxPtr -> Word32 -> CString -> CSize -> Ptr () -> IO ()+foreign import ccall "wrapper" wrapFriendNameCb :: FriendNameCb -> IO (FunPtr FriendNameCb)+foreign import ccall tox_callback_friend_name :: ToxPtr -> FunPtr FriendNameCb -> IO ()+foreign import ccall tox_friend_get_status_message_size :: ToxPtr -> Word32 -> CErr ErrFriendQuery -> IO CSize+foreign import ccall tox_friend_get_status_message :: ToxPtr -> Word32 -> CString -> CErr ErrFriendQuery -> IO Bool+type FriendStatusMessageCb = ToxPtr -> Word32 -> CString -> CSize -> Ptr () -> IO ()+foreign import ccall "wrapper" wrapFriendStatusMessageCb :: FriendStatusMessageCb -> IO (FunPtr FriendStatusMessageCb)+foreign import ccall tox_callback_friend_status_message :: ToxPtr -> FunPtr FriendStatusMessageCb -> IO ()+foreign import ccall tox_friend_get_status :: ToxPtr -> Word32 -> CErr ErrFriendQuery -> IO (CEnum UserStatus)+type FriendStatusCb = ToxPtr -> Word32 -> CEnum UserStatus -> Ptr () -> IO ()+foreign import ccall "wrapper" wrapFriendStatusCb :: FriendStatusCb -> IO (FunPtr FriendStatusCb)+foreign import ccall tox_callback_friend_status :: ToxPtr -> FunPtr FriendStatusCb -> IO ()+foreign import ccall tox_friend_get_connection_status :: ToxPtr -> Word32 -> CErr ErrFriendQuery -> IO (CEnum Connection)+type FriendConnectionStatusCb = ToxPtr -> Word32 -> CEnum Connection -> Ptr () -> IO ()+foreign import ccall "wrapper" wrapFriendConnectionStatusCb :: FriendConnectionStatusCb -> IO (FunPtr FriendConnectionStatusCb)+foreign import ccall tox_callback_friend_connection_status :: ToxPtr -> FunPtr FriendConnectionStatusCb -> IO ()+foreign import ccall tox_friend_get_typing :: ToxPtr -> Word32 -> CErr ErrFriendQuery -> IO Bool+type FriendTypingCb = ToxPtr -> Word32 -> Bool -> Ptr () -> IO ()+foreign import ccall "wrapper" wrapFriendTypingCb :: FriendTypingCb -> IO (FunPtr FriendTypingCb)+foreign import ccall tox_callback_friend_typing :: ToxPtr -> FunPtr FriendTypingCb -> IO ()+data ErrSetTyping+ = ErrSetTypingFriendNotFound+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack ErrSetTyping+instance Arbitrary ErrSetTyping where arbitrary = arbitraryBoundedEnum+foreign import ccall tox_self_set_typing :: ToxPtr -> Word32 -> Bool -> CErr ErrSetTyping -> IO Bool+data ErrFriendSendMessage+ = ErrFriendSendMessageNull+ | ErrFriendSendMessageFriendNotFound+ | ErrFriendSendMessageFriendNotConnected+ | ErrFriendSendMessageSendq+ | ErrFriendSendMessageTooLong+ | ErrFriendSendMessageEmpty+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack ErrFriendSendMessage+instance Arbitrary ErrFriendSendMessage where arbitrary = arbitraryBoundedEnum+foreign import ccall tox_friend_send_message :: ToxPtr -> Word32 -> CEnum MessageType -> CString -> CSize -> CErr ErrFriendSendMessage -> IO Word32+type FriendReadReceiptCb = ToxPtr -> Word32 -> Word32 -> Ptr () -> IO ()+foreign import ccall "wrapper" wrapFriendReadReceiptCb :: FriendReadReceiptCb -> IO (FunPtr FriendReadReceiptCb)+foreign import ccall tox_callback_friend_read_receipt :: ToxPtr -> FunPtr FriendReadReceiptCb -> IO ()+type FriendRequestCb = ToxPtr -> CString -> CString -> CSize -> Ptr () -> IO ()+foreign import ccall "wrapper" wrapFriendRequestCb :: FriendRequestCb -> IO (FunPtr FriendRequestCb)+foreign import ccall tox_callback_friend_request :: ToxPtr -> FunPtr FriendRequestCb -> IO ()+type FriendMessageCb = ToxPtr -> Word32 -> CEnum MessageType -> CString -> CSize -> Ptr () -> IO ()+foreign import ccall "wrapper" wrapFriendMessageCb :: FriendMessageCb -> IO (FunPtr FriendMessageCb)+foreign import ccall tox_callback_friend_message :: ToxPtr -> FunPtr FriendMessageCb -> IO ()+foreign import ccall tox_hash :: CString -> CString -> CSize -> IO Bool+data FileKind+ = FileKindData+ | FileKindAvatar+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack FileKind+instance Arbitrary FileKind where arbitrary = arbitraryBoundedEnum+data FileControl+ = FileControlResume+ | FileControlPause+ | FileControlCancel+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack FileControl+instance Arbitrary FileControl where arbitrary = arbitraryBoundedEnum+data ErrFileControl+ = ErrFileControlFriendNotFound+ | ErrFileControlFriendNotConnected+ | ErrFileControlNotFound+ | ErrFileControlNotPaused+ | ErrFileControlDenied+ | ErrFileControlAlreadyPaused+ | ErrFileControlSendq+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack ErrFileControl+instance Arbitrary ErrFileControl where arbitrary = arbitraryBoundedEnum+foreign import ccall tox_file_control :: ToxPtr -> Word32 -> Word32 -> CEnum FileControl -> CErr ErrFileControl -> IO Bool+type FileRecvControlCb = ToxPtr -> Word32 -> Word32 -> CEnum FileControl -> Ptr () -> IO ()+foreign import ccall "wrapper" wrapFileRecvControlCb :: FileRecvControlCb -> IO (FunPtr FileRecvControlCb)+foreign import ccall tox_callback_file_recv_control :: ToxPtr -> FunPtr FileRecvControlCb -> IO ()+data ErrFileSeek+ = ErrFileSeekFriendNotFound+ | ErrFileSeekFriendNotConnected+ | ErrFileSeekNotFound+ | ErrFileSeekDenied+ | ErrFileSeekInvalidPosition+ | ErrFileSeekSendq+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack ErrFileSeek+instance Arbitrary ErrFileSeek where arbitrary = arbitraryBoundedEnum+foreign import ccall tox_file_seek :: ToxPtr -> Word32 -> Word32 -> Word64 -> CErr ErrFileSeek -> IO Bool+data ErrFileGet+ = ErrFileGetNull+ | ErrFileGetFriendNotFound+ | ErrFileGetNotFound+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack ErrFileGet+instance Arbitrary ErrFileGet where arbitrary = arbitraryBoundedEnum+foreign import ccall tox_file_get_file_id :: ToxPtr -> Word32 -> Word32 -> CString -> CErr ErrFileGet -> IO Bool+data ErrFileSend+ = ErrFileSendNull+ | ErrFileSendFriendNotFound+ | ErrFileSendFriendNotConnected+ | ErrFileSendNameTooLong+ | ErrFileSendTooMany+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack ErrFileSend+instance Arbitrary ErrFileSend where arbitrary = arbitraryBoundedEnum+foreign import ccall tox_file_send :: ToxPtr -> Word32 -> Word32 -> Word64 -> CString -> CString -> CSize -> CErr ErrFileSend -> IO Word32+data ErrFileSendChunk+ = ErrFileSendChunkNull+ | ErrFileSendChunkFriendNotFound+ | ErrFileSendChunkFriendNotConnected+ | ErrFileSendChunkNotFound+ | ErrFileSendChunkNotTransferring+ | ErrFileSendChunkInvalidLength+ | ErrFileSendChunkSendq+ | ErrFileSendChunkWrongPosition+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack ErrFileSendChunk+instance Arbitrary ErrFileSendChunk where arbitrary = arbitraryBoundedEnum+foreign import ccall tox_file_send_chunk :: ToxPtr -> Word32 -> Word32 -> Word64 -> CString -> CSize -> CErr ErrFileSendChunk -> IO Bool+type FileChunkRequestCb = ToxPtr -> Word32 -> Word32 -> Word64 -> CSize -> Ptr () -> IO ()+foreign import ccall "wrapper" wrapFileChunkRequestCb :: FileChunkRequestCb -> IO (FunPtr FileChunkRequestCb)+foreign import ccall tox_callback_file_chunk_request :: ToxPtr -> FunPtr FileChunkRequestCb -> IO ()+type FileRecvCb = ToxPtr -> Word32 -> Word32 -> Word32 -> Word64 -> CString -> CSize -> Ptr () -> IO ()+foreign import ccall "wrapper" wrapFileRecvCb :: FileRecvCb -> IO (FunPtr FileRecvCb)+foreign import ccall tox_callback_file_recv :: ToxPtr -> FunPtr FileRecvCb -> IO ()+type FileRecvChunkCb = ToxPtr -> Word32 -> Word32 -> Word64 -> CString -> CSize -> Ptr () -> IO ()+foreign import ccall "wrapper" wrapFileRecvChunkCb :: FileRecvChunkCb -> IO (FunPtr FileRecvChunkCb)+foreign import ccall tox_callback_file_recv_chunk :: ToxPtr -> FunPtr FileRecvChunkCb -> IO ()+data ConferenceType+ = ConferenceTypeText+ | ConferenceTypeAv+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack ConferenceType+instance Arbitrary ConferenceType where arbitrary = arbitraryBoundedEnum+type ConferenceInviteCb = ToxPtr -> Word32 -> CEnum ConferenceType -> CString -> CSize -> Ptr () -> IO ()+foreign import ccall "wrapper" wrapConferenceInviteCb :: ConferenceInviteCb -> IO (FunPtr ConferenceInviteCb)+foreign import ccall tox_callback_conference_invite :: ToxPtr -> FunPtr ConferenceInviteCb -> IO ()+type ConferenceConnectedCb = ToxPtr -> Word32 -> Ptr () -> IO ()+foreign import ccall "wrapper" wrapConferenceConnectedCb :: ConferenceConnectedCb -> IO (FunPtr ConferenceConnectedCb)+foreign import ccall tox_callback_conference_connected :: ToxPtr -> FunPtr ConferenceConnectedCb -> IO ()+type ConferenceMessageCb = ToxPtr -> Word32 -> Word32 -> CEnum MessageType -> CString -> CSize -> Ptr () -> IO ()+foreign import ccall "wrapper" wrapConferenceMessageCb :: ConferenceMessageCb -> IO (FunPtr ConferenceMessageCb)+foreign import ccall tox_callback_conference_message :: ToxPtr -> FunPtr ConferenceMessageCb -> IO ()+type ConferenceTitleCb = ToxPtr -> Word32 -> Word32 -> CString -> CSize -> Ptr () -> IO ()+foreign import ccall "wrapper" wrapConferenceTitleCb :: ConferenceTitleCb -> IO (FunPtr ConferenceTitleCb)+foreign import ccall tox_callback_conference_title :: ToxPtr -> FunPtr ConferenceTitleCb -> IO ()+type ConferencePeerNameCb = ToxPtr -> Word32 -> Word32 -> CString -> CSize -> Ptr () -> IO ()+foreign import ccall "wrapper" wrapConferencePeerNameCb :: ConferencePeerNameCb -> IO (FunPtr ConferencePeerNameCb)+foreign import ccall tox_callback_conference_peer_name :: ToxPtr -> FunPtr ConferencePeerNameCb -> IO ()+type ConferencePeerListChangedCb = ToxPtr -> Word32 -> Ptr () -> IO ()+foreign import ccall "wrapper" wrapConferencePeerListChangedCb :: ConferencePeerListChangedCb -> IO (FunPtr ConferencePeerListChangedCb)+foreign import ccall tox_callback_conference_peer_list_changed :: ToxPtr -> FunPtr ConferencePeerListChangedCb -> IO ()+data ErrConferenceNew+ = ErrConferenceNewInit+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack ErrConferenceNew+instance Arbitrary ErrConferenceNew where arbitrary = arbitraryBoundedEnum+foreign import ccall tox_conference_new :: ToxPtr -> CErr ErrConferenceNew -> IO Word32+data ErrConferenceDelete+ = ErrConferenceDeleteConferenceNotFound+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack ErrConferenceDelete+instance Arbitrary ErrConferenceDelete where arbitrary = arbitraryBoundedEnum+foreign import ccall tox_conference_delete :: ToxPtr -> Word32 -> CErr ErrConferenceDelete -> IO Bool+data ErrConferencePeerQuery+ = ErrConferencePeerQueryConferenceNotFound+ | ErrConferencePeerQueryPeerNotFound+ | ErrConferencePeerQueryNoConnection+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack ErrConferencePeerQuery+instance Arbitrary ErrConferencePeerQuery where arbitrary = arbitraryBoundedEnum+foreign import ccall tox_conference_peer_count :: ToxPtr -> Word32 -> CErr ErrConferencePeerQuery -> IO Word32+foreign import ccall tox_conference_peer_get_name_size :: ToxPtr -> Word32 -> Word32 -> CErr ErrConferencePeerQuery -> IO CSize+foreign import ccall tox_conference_peer_get_name :: ToxPtr -> Word32 -> Word32 -> CString -> CErr ErrConferencePeerQuery -> IO Bool+foreign import ccall tox_conference_peer_get_public_key :: ToxPtr -> Word32 -> Word32 -> CString -> CErr ErrConferencePeerQuery -> IO Bool+foreign import ccall tox_conference_peer_number_is_ours :: ToxPtr -> Word32 -> Word32 -> CErr ErrConferencePeerQuery -> IO Bool+foreign import ccall tox_conference_offline_peer_count :: ToxPtr -> Word32 -> CErr ErrConferencePeerQuery -> IO Word32+foreign import ccall tox_conference_offline_peer_get_name_size :: ToxPtr -> Word32 -> Word32 -> CErr ErrConferencePeerQuery -> IO CSize+foreign import ccall tox_conference_offline_peer_get_name :: ToxPtr -> Word32 -> Word32 -> CString -> CErr ErrConferencePeerQuery -> IO Bool+foreign import ccall tox_conference_offline_peer_get_public_key :: ToxPtr -> Word32 -> Word32 -> CString -> CErr ErrConferencePeerQuery -> IO Bool+foreign import ccall tox_conference_offline_peer_get_last_active :: ToxPtr -> Word32 -> Word32 -> CErr ErrConferencePeerQuery -> IO Word64+data ErrConferenceSetMaxOffline+ = ErrConferenceSetMaxOfflineConferenceNotFound+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack ErrConferenceSetMaxOffline+instance Arbitrary ErrConferenceSetMaxOffline where arbitrary = arbitraryBoundedEnum+foreign import ccall tox_conference_set_max_offline :: ToxPtr -> Word32 -> Word32 -> CErr ErrConferenceSetMaxOffline -> IO Bool+data ErrConferenceInvite+ = ErrConferenceInviteConferenceNotFound+ | ErrConferenceInviteFailSend+ | ErrConferenceInviteNoConnection+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack ErrConferenceInvite+instance Arbitrary ErrConferenceInvite where arbitrary = arbitraryBoundedEnum+foreign import ccall tox_conference_invite :: ToxPtr -> Word32 -> Word32 -> CErr ErrConferenceInvite -> IO Bool+data ErrConferenceJoin+ = ErrConferenceJoinInvalidLength+ | ErrConferenceJoinWrongType+ | ErrConferenceJoinFriendNotFound+ | ErrConferenceJoinDuplicate+ | ErrConferenceJoinInitFail+ | ErrConferenceJoinFailSend+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack ErrConferenceJoin+instance Arbitrary ErrConferenceJoin where arbitrary = arbitraryBoundedEnum+foreign import ccall tox_conference_join :: ToxPtr -> Word32 -> CString -> CSize -> CErr ErrConferenceJoin -> IO Word32+data ErrConferenceSendMessage+ = ErrConferenceSendMessageConferenceNotFound+ | ErrConferenceSendMessageTooLong+ | ErrConferenceSendMessageNoConnection+ | ErrConferenceSendMessageFailSend+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack ErrConferenceSendMessage+instance Arbitrary ErrConferenceSendMessage where arbitrary = arbitraryBoundedEnum+foreign import ccall tox_conference_send_message :: ToxPtr -> Word32 -> CEnum MessageType -> CString -> CSize -> CErr ErrConferenceSendMessage -> IO Bool+data ErrConferenceTitle+ = ErrConferenceTitleConferenceNotFound+ | ErrConferenceTitleInvalidLength+ | ErrConferenceTitleFailSend+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack ErrConferenceTitle+instance Arbitrary ErrConferenceTitle where arbitrary = arbitraryBoundedEnum+foreign import ccall tox_conference_get_title_size :: ToxPtr -> Word32 -> CErr ErrConferenceTitle -> IO CSize+foreign import ccall tox_conference_get_title :: ToxPtr -> Word32 -> CString -> CErr ErrConferenceTitle -> IO Bool+foreign import ccall tox_conference_set_title :: ToxPtr -> Word32 -> CString -> CSize -> CErr ErrConferenceTitle -> IO Bool+foreign import ccall tox_conference_get_chatlist_size :: ToxPtr -> IO CSize+foreign import ccall tox_conference_get_chatlist :: ToxPtr -> Ptr Word32 -> IO ()+data ErrConferenceGetType+ = ErrConferenceGetTypeConferenceNotFound+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack ErrConferenceGetType+instance Arbitrary ErrConferenceGetType where arbitrary = arbitraryBoundedEnum+foreign import ccall tox_conference_get_type :: ToxPtr -> Word32 -> CErr ErrConferenceGetType -> IO (CEnum ConferenceType)+foreign import ccall tox_conference_get_id :: ToxPtr -> Word32 -> CString -> IO Bool+data ErrConferenceById+ = ErrConferenceByIdNull+ | ErrConferenceByIdNotFound+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack ErrConferenceById+instance Arbitrary ErrConferenceById where arbitrary = arbitraryBoundedEnum+foreign import ccall tox_conference_by_id :: ToxPtr -> CString -> CErr ErrConferenceById -> IO Word32+foreign import ccall tox_conference_get_uid :: ToxPtr -> Word32 -> CString -> IO Bool+data ErrConferenceByUid+ = ErrConferenceByUidNull+ | ErrConferenceByUidNotFound+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack ErrConferenceByUid+instance Arbitrary ErrConferenceByUid where arbitrary = arbitraryBoundedEnum+foreign import ccall tox_conference_by_uid :: ToxPtr -> CString -> CErr ErrConferenceByUid -> IO Word32+data ErrFriendCustomPacket+ = ErrFriendCustomPacketNull+ | ErrFriendCustomPacketFriendNotFound+ | ErrFriendCustomPacketFriendNotConnected+ | ErrFriendCustomPacketInvalid+ | ErrFriendCustomPacketEmpty+ | ErrFriendCustomPacketTooLong+ | ErrFriendCustomPacketSendq+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack ErrFriendCustomPacket+instance Arbitrary ErrFriendCustomPacket where arbitrary = arbitraryBoundedEnum+foreign import ccall tox_friend_send_lossy_packet :: ToxPtr -> Word32 -> CString -> CSize -> CErr ErrFriendCustomPacket -> IO Bool+foreign import ccall tox_friend_send_lossless_packet :: ToxPtr -> Word32 -> CString -> CSize -> CErr ErrFriendCustomPacket -> IO Bool+type FriendLossyPacketCb = ToxPtr -> Word32 -> CString -> CSize -> Ptr () -> IO ()+foreign import ccall "wrapper" wrapFriendLossyPacketCb :: FriendLossyPacketCb -> IO (FunPtr FriendLossyPacketCb)+foreign import ccall tox_callback_friend_lossy_packet :: ToxPtr -> FunPtr FriendLossyPacketCb -> IO ()+type FriendLosslessPacketCb = ToxPtr -> Word32 -> CString -> CSize -> Ptr () -> IO ()+foreign import ccall "wrapper" wrapFriendLosslessPacketCb :: FriendLosslessPacketCb -> IO (FunPtr FriendLosslessPacketCb)+foreign import ccall tox_callback_friend_lossless_packet :: ToxPtr -> FunPtr FriendLosslessPacketCb -> IO ()+data ErrGetPort+ = ErrGetPortNotBound+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack ErrGetPort+instance Arbitrary ErrGetPort where arbitrary = arbitraryBoundedEnum+foreign import ccall tox_self_get_dht_id :: ToxPtr -> CString -> IO ()+foreign import ccall tox_self_get_udp_port :: ToxPtr -> CErr ErrGetPort -> IO Word16+foreign import ccall tox_self_get_tcp_port :: ToxPtr -> CErr ErrGetPort -> IO Word16+foreign import ccall tox_group_max_topic_length :: Word32+foreign import ccall tox_group_max_part_length :: Word32+foreign import ccall tox_group_max_message_length :: Word32+foreign import ccall tox_group_max_custom_lossy_packet_length :: Word32+foreign import ccall tox_group_max_custom_lossless_packet_length :: Word32+foreign import ccall tox_group_max_group_name_length :: Word32+foreign import ccall tox_group_max_password_size :: Word32+foreign import ccall tox_group_chat_id_size :: Word32+foreign import ccall tox_group_peer_public_key_size :: Word32+data GroupPrivacyState+ = GroupPrivacyStatePublic+ | GroupPrivacyStatePrivate+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack GroupPrivacyState+instance Arbitrary GroupPrivacyState where arbitrary = arbitraryBoundedEnum+data GroupTopicLock+ = GroupTopicLockEnabled+ | GroupTopicLockDisabled+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack GroupTopicLock+instance Arbitrary GroupTopicLock where arbitrary = arbitraryBoundedEnum+data GroupVoiceState+ = GroupVoiceStateAll+ | GroupVoiceStateModerator+ | GroupVoiceStateFounder+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack GroupVoiceState+instance Arbitrary GroupVoiceState where arbitrary = arbitraryBoundedEnum+data GroupRole+ = GroupRoleFounder+ | GroupRoleModerator+ | GroupRoleUser+ | GroupRoleObserver+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack GroupRole+instance Arbitrary GroupRole where arbitrary = arbitraryBoundedEnum+data ErrGroupNew+ = ErrGroupNewTooLong+ | ErrGroupNewEmpty+ | ErrGroupNewInit+ | ErrGroupNewState+ | ErrGroupNewAnnounce+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack ErrGroupNew+instance Arbitrary ErrGroupNew where arbitrary = arbitraryBoundedEnum+foreign import ccall tox_group_new :: ToxPtr -> CEnum GroupPrivacyState -> CString -> CSize -> CString -> CSize -> CErr ErrGroupNew -> IO Word32+data ErrGroupJoin+ = ErrGroupJoinInit+ | ErrGroupJoinBadChatId+ | ErrGroupJoinEmpty+ | ErrGroupJoinTooLong+ | ErrGroupJoinPassword+ | ErrGroupJoinCore+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack ErrGroupJoin+instance Arbitrary ErrGroupJoin where arbitrary = arbitraryBoundedEnum+foreign import ccall tox_group_join :: ToxPtr -> CString -> CString -> CSize -> CString -> CSize -> CErr ErrGroupJoin -> IO Word32+data ErrGroupIsConnected+ = ErrGroupIsConnectedGroupNotFound+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack ErrGroupIsConnected+instance Arbitrary ErrGroupIsConnected where arbitrary = arbitraryBoundedEnum+foreign import ccall tox_group_is_connected :: ToxPtr -> Word32 -> CErr ErrGroupIsConnected -> IO Bool+data ErrGroupDisconnect+ = ErrGroupDisconnectGroupNotFound+ | ErrGroupDisconnectAlreadyDisconnected+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack ErrGroupDisconnect+instance Arbitrary ErrGroupDisconnect where arbitrary = arbitraryBoundedEnum+foreign import ccall tox_group_disconnect :: ToxPtr -> Word32 -> CErr ErrGroupDisconnect -> IO Bool+data ErrGroupReconnect+ = ErrGroupReconnectGroupNotFound+ | ErrGroupReconnectCore+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack ErrGroupReconnect+instance Arbitrary ErrGroupReconnect where arbitrary = arbitraryBoundedEnum+foreign import ccall tox_group_reconnect :: ToxPtr -> Word32 -> CErr ErrGroupReconnect -> IO Bool+data ErrGroupLeave+ = ErrGroupLeaveGroupNotFound+ | ErrGroupLeaveTooLong+ | ErrGroupLeaveFailSend+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack ErrGroupLeave+instance Arbitrary ErrGroupLeave where arbitrary = arbitraryBoundedEnum+foreign import ccall tox_group_leave :: ToxPtr -> Word32 -> CString -> CSize -> CErr ErrGroupLeave -> IO Bool+data ErrGroupSelfQuery+ = ErrGroupSelfQueryGroupNotFound+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack ErrGroupSelfQuery+instance Arbitrary ErrGroupSelfQuery where arbitrary = arbitraryBoundedEnum+data ErrGroupSelfNameSet+ = ErrGroupSelfNameSetGroupNotFound+ | ErrGroupSelfNameSetTooLong+ | ErrGroupSelfNameSetInvalid+ | ErrGroupSelfNameSetFailSend+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack ErrGroupSelfNameSet+instance Arbitrary ErrGroupSelfNameSet where arbitrary = arbitraryBoundedEnum+foreign import ccall tox_group_self_set_name :: ToxPtr -> Word32 -> CString -> CSize -> CErr ErrGroupSelfNameSet -> IO Bool+foreign import ccall tox_group_self_get_name_size :: ToxPtr -> Word32 -> CErr ErrGroupSelfQuery -> IO CSize+foreign import ccall tox_group_self_get_name :: ToxPtr -> Word32 -> CString -> CErr ErrGroupSelfQuery -> IO Bool+data ErrGroupSelfStatusSet+ = ErrGroupSelfStatusSetGroupNotFound+ | ErrGroupSelfStatusSetFailSend+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack ErrGroupSelfStatusSet+instance Arbitrary ErrGroupSelfStatusSet where arbitrary = arbitraryBoundedEnum+foreign import ccall tox_group_self_set_status :: ToxPtr -> Word32 -> CEnum UserStatus -> CErr ErrGroupSelfStatusSet -> IO Bool+foreign import ccall tox_group_self_get_status :: ToxPtr -> Word32 -> CErr ErrGroupSelfQuery -> IO (CEnum UserStatus)+foreign import ccall tox_group_self_get_role :: ToxPtr -> Word32 -> CErr ErrGroupSelfQuery -> IO (CEnum GroupRole)+foreign import ccall tox_group_self_get_peer_id :: ToxPtr -> Word32 -> CErr ErrGroupSelfQuery -> IO Word32+foreign import ccall tox_group_self_get_public_key :: ToxPtr -> Word32 -> CString -> CErr ErrGroupSelfQuery -> IO Bool+data ErrGroupPeerQuery+ = ErrGroupPeerQueryGroupNotFound+ | ErrGroupPeerQueryPeerNotFound+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack ErrGroupPeerQuery+instance Arbitrary ErrGroupPeerQuery where arbitrary = arbitraryBoundedEnum+foreign import ccall tox_group_peer_get_name_size :: ToxPtr -> Word32 -> Word32 -> CErr ErrGroupPeerQuery -> IO CSize+foreign import ccall tox_group_peer_get_name :: ToxPtr -> Word32 -> Word32 -> CString -> CErr ErrGroupPeerQuery -> IO Bool+foreign import ccall tox_group_peer_get_status :: ToxPtr -> Word32 -> Word32 -> CErr ErrGroupPeerQuery -> IO (CEnum UserStatus)+foreign import ccall tox_group_peer_get_role :: ToxPtr -> Word32 -> Word32 -> CErr ErrGroupPeerQuery -> IO (CEnum GroupRole)+foreign import ccall tox_group_peer_get_connection_status :: ToxPtr -> Word32 -> Word32 -> CErr ErrGroupPeerQuery -> IO (CEnum Connection)+foreign import ccall tox_group_peer_get_public_key :: ToxPtr -> Word32 -> Word32 -> CString -> CErr ErrGroupPeerQuery -> IO Bool+type GroupPeerNameCb = ToxPtr -> Word32 -> Word32 -> CString -> CSize -> Ptr () -> IO ()+foreign import ccall "wrapper" wrapGroupPeerNameCb :: GroupPeerNameCb -> IO (FunPtr GroupPeerNameCb)+foreign import ccall tox_callback_group_peer_name :: ToxPtr -> FunPtr GroupPeerNameCb -> IO ()+type GroupPeerStatusCb = ToxPtr -> Word32 -> Word32 -> CEnum UserStatus -> Ptr () -> IO ()+foreign import ccall "wrapper" wrapGroupPeerStatusCb :: GroupPeerStatusCb -> IO (FunPtr GroupPeerStatusCb)+foreign import ccall tox_callback_group_peer_status :: ToxPtr -> FunPtr GroupPeerStatusCb -> IO ()+data ErrGroupStateQueries+ = ErrGroupStateQueriesGroupNotFound+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack ErrGroupStateQueries+instance Arbitrary ErrGroupStateQueries where arbitrary = arbitraryBoundedEnum+data ErrGroupTopicSet+ = ErrGroupTopicSetGroupNotFound+ | ErrGroupTopicSetTooLong+ | ErrGroupTopicSetPermissions+ | ErrGroupTopicSetFailCreate+ | ErrGroupTopicSetFailSend+ | ErrGroupTopicSetDisconnected+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack ErrGroupTopicSet+instance Arbitrary ErrGroupTopicSet where arbitrary = arbitraryBoundedEnum+foreign import ccall tox_group_set_topic :: ToxPtr -> Word32 -> CString -> CSize -> CErr ErrGroupTopicSet -> IO Bool+foreign import ccall tox_group_get_topic_size :: ToxPtr -> Word32 -> CErr ErrGroupStateQueries -> IO CSize+foreign import ccall tox_group_get_topic :: ToxPtr -> Word32 -> CString -> CErr ErrGroupStateQueries -> IO Bool+type GroupTopicCb = ToxPtr -> Word32 -> Word32 -> CString -> CSize -> Ptr () -> IO ()+foreign import ccall "wrapper" wrapGroupTopicCb :: GroupTopicCb -> IO (FunPtr GroupTopicCb)+foreign import ccall tox_callback_group_topic :: ToxPtr -> FunPtr GroupTopicCb -> IO ()+foreign import ccall tox_group_get_name_size :: ToxPtr -> Word32 -> CErr ErrGroupStateQueries -> IO CSize+foreign import ccall tox_group_get_name :: ToxPtr -> Word32 -> CString -> CErr ErrGroupStateQueries -> IO Bool+foreign import ccall tox_group_get_chat_id :: ToxPtr -> Word32 -> CString -> CErr ErrGroupStateQueries -> IO Bool+foreign import ccall tox_group_get_number_groups :: ToxPtr -> IO Word32+foreign import ccall tox_group_get_privacy_state :: ToxPtr -> Word32 -> CErr ErrGroupStateQueries -> IO (CEnum GroupPrivacyState)+type GroupPrivacyStateCb = ToxPtr -> Word32 -> CEnum GroupPrivacyState -> Ptr () -> IO ()+foreign import ccall "wrapper" wrapGroupPrivacyStateCb :: GroupPrivacyStateCb -> IO (FunPtr GroupPrivacyStateCb)+foreign import ccall tox_callback_group_privacy_state :: ToxPtr -> FunPtr GroupPrivacyStateCb -> IO ()+foreign import ccall tox_group_get_voice_state :: ToxPtr -> Word32 -> CErr ErrGroupStateQueries -> IO (CEnum GroupVoiceState)+type GroupVoiceStateCb = ToxPtr -> Word32 -> CEnum GroupVoiceState -> Ptr () -> IO ()+foreign import ccall "wrapper" wrapGroupVoiceStateCb :: GroupVoiceStateCb -> IO (FunPtr GroupVoiceStateCb)+foreign import ccall tox_callback_group_voice_state :: ToxPtr -> FunPtr GroupVoiceStateCb -> IO ()+foreign import ccall tox_group_get_topic_lock :: ToxPtr -> Word32 -> CErr ErrGroupStateQueries -> IO (CEnum GroupTopicLock)+type GroupTopicLockCb = ToxPtr -> Word32 -> CEnum GroupTopicLock -> Ptr () -> IO ()+foreign import ccall "wrapper" wrapGroupTopicLockCb :: GroupTopicLockCb -> IO (FunPtr GroupTopicLockCb)+foreign import ccall tox_callback_group_topic_lock :: ToxPtr -> FunPtr GroupTopicLockCb -> IO ()+foreign import ccall tox_group_get_peer_limit :: ToxPtr -> Word32 -> CErr ErrGroupStateQueries -> IO Word16+type GroupPeerLimitCb = ToxPtr -> Word32 -> Word32 -> Ptr () -> IO ()+foreign import ccall "wrapper" wrapGroupPeerLimitCb :: GroupPeerLimitCb -> IO (FunPtr GroupPeerLimitCb)+foreign import ccall tox_callback_group_peer_limit :: ToxPtr -> FunPtr GroupPeerLimitCb -> IO ()+foreign import ccall tox_group_get_password_size :: ToxPtr -> Word32 -> CErr ErrGroupStateQueries -> IO CSize+foreign import ccall tox_group_get_password :: ToxPtr -> Word32 -> CString -> CErr ErrGroupStateQueries -> IO Bool+type GroupPasswordCb = ToxPtr -> Word32 -> CString -> CSize -> Ptr () -> IO ()+foreign import ccall "wrapper" wrapGroupPasswordCb :: GroupPasswordCb -> IO (FunPtr GroupPasswordCb)+foreign import ccall tox_callback_group_password :: ToxPtr -> FunPtr GroupPasswordCb -> IO ()+data ErrGroupSendMessage+ = ErrGroupSendMessageGroupNotFound+ | ErrGroupSendMessageTooLong+ | ErrGroupSendMessageEmpty+ | ErrGroupSendMessageBadType+ | ErrGroupSendMessagePermissions+ | ErrGroupSendMessageFailSend+ | ErrGroupSendMessageDisconnected+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack ErrGroupSendMessage+instance Arbitrary ErrGroupSendMessage where arbitrary = arbitraryBoundedEnum+foreign import ccall tox_group_send_message :: ToxPtr -> Word32 -> CEnum MessageType -> CString -> CSize -> Ptr Word32 -> CErr ErrGroupSendMessage -> IO Bool+data ErrGroupSendPrivateMessage+ = ErrGroupSendPrivateMessageGroupNotFound+ | ErrGroupSendPrivateMessagePeerNotFound+ | ErrGroupSendPrivateMessageTooLong+ | ErrGroupSendPrivateMessageEmpty+ | ErrGroupSendPrivateMessagePermissions+ | ErrGroupSendPrivateMessageFailSend+ | ErrGroupSendPrivateMessageDisconnected+ | ErrGroupSendPrivateMessageBadType+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack ErrGroupSendPrivateMessage+instance Arbitrary ErrGroupSendPrivateMessage where arbitrary = arbitraryBoundedEnum+foreign import ccall tox_group_send_private_message :: ToxPtr -> Word32 -> Word32 -> CEnum MessageType -> CString -> CSize -> CErr ErrGroupSendPrivateMessage -> IO Bool+data ErrGroupSendCustomPacket+ = ErrGroupSendCustomPacketGroupNotFound+ | ErrGroupSendCustomPacketTooLong+ | ErrGroupSendCustomPacketEmpty+ | ErrGroupSendCustomPacketPermissions+ | ErrGroupSendCustomPacketDisconnected+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack ErrGroupSendCustomPacket+instance Arbitrary ErrGroupSendCustomPacket where arbitrary = arbitraryBoundedEnum+foreign import ccall tox_group_send_custom_packet :: ToxPtr -> Word32 -> Bool -> CString -> CSize -> CErr ErrGroupSendCustomPacket -> IO Bool+data ErrGroupSendCustomPrivatePacket+ = ErrGroupSendCustomPrivatePacketGroupNotFound+ | ErrGroupSendCustomPrivatePacketTooLong+ | ErrGroupSendCustomPrivatePacketEmpty+ | ErrGroupSendCustomPrivatePacketPeerNotFound+ | ErrGroupSendCustomPrivatePacketPermissions+ | ErrGroupSendCustomPrivatePacketFailSend+ | ErrGroupSendCustomPrivatePacketDisconnected+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack ErrGroupSendCustomPrivatePacket+instance Arbitrary ErrGroupSendCustomPrivatePacket where arbitrary = arbitraryBoundedEnum+foreign import ccall tox_group_send_custom_private_packet :: ToxPtr -> Word32 -> Word32 -> Bool -> CString -> CSize -> CErr ErrGroupSendCustomPrivatePacket -> IO Bool+type GroupMessageCb = ToxPtr -> Word32 -> Word32 -> CEnum MessageType -> CString -> CSize -> Word32 -> Ptr () -> IO ()+foreign import ccall "wrapper" wrapGroupMessageCb :: GroupMessageCb -> IO (FunPtr GroupMessageCb)+foreign import ccall tox_callback_group_message :: ToxPtr -> FunPtr GroupMessageCb -> IO ()+type GroupPrivateMessageCb = ToxPtr -> Word32 -> Word32 -> CEnum MessageType -> CString -> CSize -> Ptr () -> IO ()+foreign import ccall "wrapper" wrapGroupPrivateMessageCb :: GroupPrivateMessageCb -> IO (FunPtr GroupPrivateMessageCb)+foreign import ccall tox_callback_group_private_message :: ToxPtr -> FunPtr GroupPrivateMessageCb -> IO ()+type GroupCustomPacketCb = ToxPtr -> Word32 -> Word32 -> CString -> CSize -> Ptr () -> IO ()+foreign import ccall "wrapper" wrapGroupCustomPacketCb :: GroupCustomPacketCb -> IO (FunPtr GroupCustomPacketCb)+foreign import ccall tox_callback_group_custom_packet :: ToxPtr -> FunPtr GroupCustomPacketCb -> IO ()+type GroupCustomPrivatePacketCb = ToxPtr -> Word32 -> Word32 -> CString -> CSize -> Ptr () -> IO ()+foreign import ccall "wrapper" wrapGroupCustomPrivatePacketCb :: GroupCustomPrivatePacketCb -> IO (FunPtr GroupCustomPrivatePacketCb)+foreign import ccall tox_callback_group_custom_private_packet :: ToxPtr -> FunPtr GroupCustomPrivatePacketCb -> IO ()+data ErrGroupInviteFriend+ = ErrGroupInviteFriendGroupNotFound+ | ErrGroupInviteFriendFriendNotFound+ | ErrGroupInviteFriendInviteFail+ | ErrGroupInviteFriendFailSend+ | ErrGroupInviteFriendDisconnected+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack ErrGroupInviteFriend+instance Arbitrary ErrGroupInviteFriend where arbitrary = arbitraryBoundedEnum+foreign import ccall tox_group_invite_friend :: ToxPtr -> Word32 -> Word32 -> CErr ErrGroupInviteFriend -> IO Bool+data ErrGroupInviteAccept+ = ErrGroupInviteAcceptBadInvite+ | ErrGroupInviteAcceptInitFailed+ | ErrGroupInviteAcceptTooLong+ | ErrGroupInviteAcceptEmpty+ | ErrGroupInviteAcceptPassword+ | ErrGroupInviteAcceptCore+ | ErrGroupInviteAcceptFailSend+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack ErrGroupInviteAccept+instance Arbitrary ErrGroupInviteAccept where arbitrary = arbitraryBoundedEnum+foreign import ccall tox_group_invite_accept :: ToxPtr -> Word32 -> CString -> CSize -> CString -> CSize -> CString -> CSize -> CErr ErrGroupInviteAccept -> IO Word32+type GroupInviteCb = ToxPtr -> Word32 -> CString -> CSize -> CString -> CSize -> Ptr () -> IO ()+foreign import ccall "wrapper" wrapGroupInviteCb :: GroupInviteCb -> IO (FunPtr GroupInviteCb)+foreign import ccall tox_callback_group_invite :: ToxPtr -> FunPtr GroupInviteCb -> IO ()+type GroupPeerJoinCb = ToxPtr -> Word32 -> Word32 -> Ptr () -> IO ()+foreign import ccall "wrapper" wrapGroupPeerJoinCb :: GroupPeerJoinCb -> IO (FunPtr GroupPeerJoinCb)+foreign import ccall tox_callback_group_peer_join :: ToxPtr -> FunPtr GroupPeerJoinCb -> IO ()+data GroupExitType+ = GroupExitTypeQuit+ | GroupExitTypeTimeout+ | GroupExitTypeDisconnected+ | GroupExitTypeSelfDisconnected+ | GroupExitTypeKick+ | GroupExitTypeSyncError+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack GroupExitType+instance Arbitrary GroupExitType where arbitrary = arbitraryBoundedEnum+type GroupPeerExitCb = ToxPtr -> Word32 -> Word32 -> CEnum GroupExitType -> CString -> CSize -> CString -> CSize -> Ptr () -> IO ()+foreign import ccall "wrapper" wrapGroupPeerExitCb :: GroupPeerExitCb -> IO (FunPtr GroupPeerExitCb)+foreign import ccall tox_callback_group_peer_exit :: ToxPtr -> FunPtr GroupPeerExitCb -> IO ()+type GroupSelfJoinCb = ToxPtr -> Word32 -> Ptr () -> IO ()+foreign import ccall "wrapper" wrapGroupSelfJoinCb :: GroupSelfJoinCb -> IO (FunPtr GroupSelfJoinCb)+foreign import ccall tox_callback_group_self_join :: ToxPtr -> FunPtr GroupSelfJoinCb -> IO ()+data GroupJoinFail+ = GroupJoinFailPeerLimit+ | GroupJoinFailInvalidPassword+ | GroupJoinFailUnknown+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack GroupJoinFail+instance Arbitrary GroupJoinFail where arbitrary = arbitraryBoundedEnum+type GroupJoinFailCb = ToxPtr -> Word32 -> CEnum GroupJoinFail -> Ptr () -> IO ()+foreign import ccall "wrapper" wrapGroupJoinFailCb :: GroupJoinFailCb -> IO (FunPtr GroupJoinFailCb)+foreign import ccall tox_callback_group_join_fail :: ToxPtr -> FunPtr GroupJoinFailCb -> IO ()+data ErrGroupSetPassword+ = ErrGroupSetPasswordGroupNotFound+ | ErrGroupSetPasswordPermissions+ | ErrGroupSetPasswordTooLong+ | ErrGroupSetPasswordFailSend+ | ErrGroupSetPasswordMalloc+ | ErrGroupSetPasswordDisconnected+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack ErrGroupSetPassword+instance Arbitrary ErrGroupSetPassword where arbitrary = arbitraryBoundedEnum+foreign import ccall tox_group_set_password :: ToxPtr -> Word32 -> CString -> CSize -> CErr ErrGroupSetPassword -> IO Bool+data ErrGroupSetTopicLock+ = ErrGroupSetTopicLockGroupNotFound+ | ErrGroupSetTopicLockInvalid+ | ErrGroupSetTopicLockPermissions+ | ErrGroupSetTopicLockFailSet+ | ErrGroupSetTopicLockFailSend+ | ErrGroupSetTopicLockDisconnected+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack ErrGroupSetTopicLock+instance Arbitrary ErrGroupSetTopicLock where arbitrary = arbitraryBoundedEnum+foreign import ccall tox_group_set_topic_lock :: ToxPtr -> Word32 -> CEnum GroupTopicLock -> CErr ErrGroupSetTopicLock -> IO Bool+data ErrGroupSetVoiceState+ = ErrGroupSetVoiceStateGroupNotFound+ | ErrGroupSetVoiceStatePermissions+ | ErrGroupSetVoiceStateFailSet+ | ErrGroupSetVoiceStateFailSend+ | ErrGroupSetVoiceStateDisconnected+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack ErrGroupSetVoiceState+instance Arbitrary ErrGroupSetVoiceState where arbitrary = arbitraryBoundedEnum+foreign import ccall tox_group_set_voice_state :: ToxPtr -> Word32 -> CEnum GroupVoiceState -> CErr ErrGroupSetVoiceState -> IO Bool+data ErrGroupSetPrivacyState+ = ErrGroupSetPrivacyStateGroupNotFound+ | ErrGroupSetPrivacyStatePermissions+ | ErrGroupSetPrivacyStateFailSet+ | ErrGroupSetPrivacyStateFailSend+ | ErrGroupSetPrivacyStateDisconnected+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack ErrGroupSetPrivacyState+instance Arbitrary ErrGroupSetPrivacyState where arbitrary = arbitraryBoundedEnum+foreign import ccall tox_group_set_privacy_state :: ToxPtr -> Word32 -> CEnum GroupPrivacyState -> CErr ErrGroupSetPrivacyState -> IO Bool+data ErrGroupSetPeerLimit+ = ErrGroupSetPeerLimitGroupNotFound+ | ErrGroupSetPeerLimitPermissions+ | ErrGroupSetPeerLimitFailSet+ | ErrGroupSetPeerLimitFailSend+ | ErrGroupSetPeerLimitDisconnected+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack ErrGroupSetPeerLimit+instance Arbitrary ErrGroupSetPeerLimit where arbitrary = arbitraryBoundedEnum+foreign import ccall tox_group_set_peer_limit :: ToxPtr -> Word32 -> Word16 -> CErr ErrGroupSetPeerLimit -> IO Bool+data ErrGroupSetIgnore+ = ErrGroupSetIgnoreGroupNotFound+ | ErrGroupSetIgnorePeerNotFound+ | ErrGroupSetIgnoreSelf+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack ErrGroupSetIgnore+instance Arbitrary ErrGroupSetIgnore where arbitrary = arbitraryBoundedEnum+foreign import ccall tox_group_set_ignore :: ToxPtr -> Word32 -> Word32 -> Bool -> CErr ErrGroupSetIgnore -> IO Bool+data ErrGroupSetRole+ = ErrGroupSetRoleGroupNotFound+ | ErrGroupSetRolePeerNotFound+ | ErrGroupSetRolePermissions+ | ErrGroupSetRoleAssignment+ | ErrGroupSetRoleFailAction+ | ErrGroupSetRoleSelf+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack ErrGroupSetRole+instance Arbitrary ErrGroupSetRole where arbitrary = arbitraryBoundedEnum+foreign import ccall tox_group_set_role :: ToxPtr -> Word32 -> Word32 -> CEnum GroupRole -> CErr ErrGroupSetRole -> IO Bool+data ErrGroupKickPeer+ = ErrGroupKickPeerGroupNotFound+ | ErrGroupKickPeerPeerNotFound+ | ErrGroupKickPeerPermissions+ | ErrGroupKickPeerFailAction+ | ErrGroupKickPeerFailSend+ | ErrGroupKickPeerSelf+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack ErrGroupKickPeer+instance Arbitrary ErrGroupKickPeer where arbitrary = arbitraryBoundedEnum+foreign import ccall tox_group_kick_peer :: ToxPtr -> Word32 -> Word32 -> CErr ErrGroupKickPeer -> IO Bool+data GroupModEvent+ = GroupModEventKick+ | GroupModEventObserver+ | GroupModEventUser+ | GroupModEventModerator+ deriving (Eq, Ord, Enum, Bounded, Read, Show, Generic)+instance MessagePack GroupModEvent+instance Arbitrary GroupModEvent where arbitrary = arbitraryBoundedEnum+type GroupModerationCb = ToxPtr -> Word32 -> Word32 -> Word32 -> CEnum GroupModEvent -> Ptr () -> IO ()+foreign import ccall "wrapper" wrapGroupModerationCb :: GroupModerationCb -> IO (FunPtr GroupModerationCb)+foreign import ccall tox_callback_group_moderation :: ToxPtr -> FunPtr GroupModerationCb -> IO ()
+ src/Foreign/C/Enum.hs view
@@ -0,0 +1,36 @@+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE StrictData #-}+module Foreign.C.Enum where++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 <- unCEnum <$> peek errPtr+ return $ if err > 0+ then Left . toEnum . fromIntegral $ err - 1+ else Right res
src/Network/Tox/C.hs view
@@ -2,9 +2,39 @@ ( module M ) where -import Network.Tox.C.Callbacks as M-import Network.Tox.C.Constants as M-import Network.Tox.C.Options as M-import Network.Tox.C.Tox as M-import Network.Tox.C.Type as M-import Network.Tox.C.Version as M+import FFI.Tox.Tox as M (Connection (..),+ ErrBootstrap (..),+ ErrConferenceDelete (..),+ ErrConferenceGetType (..),+ ErrConferenceInvite (..),+ ErrConferenceJoin (..),+ ErrConferenceNew (..),+ ErrConferencePeerQuery (..),+ ErrConferenceSendMessage (..),+ ErrConferenceTitle (..),+ ErrFileControl (..),+ ErrFileGet (..),+ ErrFileSeek (..),+ ErrFileSend (..),+ ErrFileSendChunk (..),+ ErrFriendAdd (..),+ ErrFriendByPublicKey (..),+ ErrFriendCustomPacket (..),+ ErrFriendDelete (..),+ ErrFriendGetLastOnline (..),+ ErrFriendGetPublicKey (..),+ ErrFriendQuery (..),+ ErrFriendSendMessage (..),+ ErrGetPort (..), ErrNew (..),+ ErrSetInfo (..),+ ErrSetTyping (..),+ FileKind (..), LogLevel (..),+ MessageType (..),+ ProxyType (..),+ SavedataType (..), ToxPtr)+import Network.Tox.C.Constants as M+import Network.Tox.C.Options as M+import Network.Tox.C.Tox as M+import Network.Tox.C.Type as M+import Network.Tox.C.Version as M+import Network.Tox.Types.Events as M
− src/Network/Tox/C/CEnum.hs
@@ -1,37 +0,0 @@-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE Trustworthy #-}-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
@@ -1,89 +0,0 @@-module Network.Tox.C.Callbacks where--import Control.Exception (bracket)-import Foreign.Ptr (freeHaskellFunPtr, nullFunPtr)--import qualified Network.Tox.C.Tox as Tox-import Network.Tox.C.Type (Tox)----- | Low level event handler. The functions in this class are directly--- registered with the corresponding C callback. We use 'StablePtr' to pass--- opaque Haskell values around in C.-class CHandler a where- cSelfConnectionStatus :: Tox.SelfConnectionStatusCb a- cSelfConnectionStatus _ _ = return- cFriendName :: Tox.FriendNameCb a- cFriendName _ _ _ = return- cFriendStatusMessage :: Tox.FriendStatusMessageCb a- cFriendStatusMessage _ _ _ = return- cFriendStatus :: Tox.FriendStatusCb a- cFriendStatus _ _ _ = return- cFriendConnectionStatus :: Tox.FriendConnectionStatusCb a- cFriendConnectionStatus _ _ _ = return- cFriendTyping :: Tox.FriendTypingCb a- cFriendTyping _ _ _ = return- cFriendReadReceipt :: Tox.FriendReadReceiptCb a- cFriendReadReceipt _ _ _ = return- cFriendRequest :: Tox.FriendRequestCb a- cFriendRequest _ _ _ = return- cFriendMessage :: Tox.FriendMessageCb a- cFriendMessage _ _ _ _ = return- cFileRecvControl :: Tox.FileRecvControlCb a- cFileRecvControl _ _ _ _ = return- cFileChunkRequest :: Tox.FileChunkRequestCb a- cFileChunkRequest _ _ _ _ _ = return- cFileRecv :: Tox.FileRecvCb a- cFileRecv _ _ _ _ _ _ = return- cFileRecvChunk :: Tox.FileRecvChunkCb a- cFileRecvChunk _ _ _ _ _ = return- cConferenceInvite :: Tox.ConferenceInviteCb a- cConferenceInvite _ _ _ _ = return- cConferenceMessage :: Tox.ConferenceMessageCb a- cConferenceMessage _ _ _ _ _ = return- cConferenceTitle :: Tox.ConferenceTitleCb a- cConferenceTitle _ _ _ _ = return- cConferencePeerName :: Tox.ConferencePeerNameCb a- cConferencePeerName _ _ _ _ = return- cConferencePeerListChanged :: Tox.ConferencePeerListChangedCb a- cConferencePeerListChanged _ _ = return- cFriendLossyPacket :: Tox.FriendLossyPacketCb a- cFriendLossyPacket _ _ _ = return- cFriendLosslessPacket :: Tox.FriendLosslessPacketCb a- cFriendLosslessPacket _ _ _ = return----- | 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.-withCHandler :: CHandler a => Tox a -> IO r -> IO r-withCHandler tox =- install Tox.tox_callback_self_connection_status (Tox.selfConnectionStatusCb cSelfConnectionStatus ) .- install Tox.tox_callback_friend_name (Tox.friendNameCb cFriendName ) .- install Tox.tox_callback_friend_status_message (Tox.friendStatusMessageCb cFriendStatusMessage ) .- install Tox.tox_callback_friend_status (Tox.friendStatusCb cFriendStatus ) .- install Tox.tox_callback_friend_connection_status (Tox.friendConnectionStatusCb cFriendConnectionStatus ) .- install Tox.tox_callback_friend_typing (Tox.friendTypingCb cFriendTyping ) .- install Tox.tox_callback_friend_read_receipt (Tox.friendReadReceiptCb cFriendReadReceipt ) .- install Tox.tox_callback_friend_request (Tox.friendRequestCb cFriendRequest ) .- install Tox.tox_callback_friend_message (Tox.friendMessageCb cFriendMessage ) .- install Tox.tox_callback_file_recv_control (Tox.fileRecvControlCb cFileRecvControl ) .- install Tox.tox_callback_file_chunk_request (Tox.fileChunkRequestCb cFileChunkRequest ) .- install Tox.tox_callback_file_recv (Tox.fileRecvCb cFileRecv ) .- install Tox.tox_callback_file_recv_chunk (Tox.fileRecvChunkCb cFileRecvChunk ) .- install Tox.tox_callback_conference_invite (Tox.conferenceInviteCb cConferenceInvite ) .- install Tox.tox_callback_conference_message (Tox.conferenceMessageCb cConferenceMessage ) .- install Tox.tox_callback_conference_title (Tox.conferenceTitleCb cConferenceTitle ) .- install Tox.tox_callback_conference_peer_name (Tox.conferencePeerNameCb cConferencePeerName ) .- install Tox.tox_callback_conference_peer_list_changed (Tox.conferencePeerListChangedCb cConferencePeerListChanged ) .- install Tox.tox_callback_friend_lossy_packet (Tox.friendLossyPacketCb cFriendLossyPacket ) .- install Tox.tox_callback_friend_lossless_packet (Tox.friendLosslessPacketCb cFriendLosslessPacket )- where- install cInstall wrapper action =- bracket wrapper (uninstall cInstall) $ \cb -> do- () <- cInstall tox cb- action-- uninstall cInstall cb = do- freeHaskellFunPtr cb- cInstall tox nullFunPtr
src/Network/Tox/C/Constants.hs view
@@ -1,5 +1,4 @@-{-# OPTIONS_GHC -fno-warn-orphans #-}-{-# LANGUAGE Trustworthy #-}+{-# LANGUAGE StrictData #-} module Network.Tox.C.Constants where import Data.Word (Word32)
src/Network/Tox/C/Options.hs view
@@ -1,20 +1,42 @@ {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE LambdaCase #-}-{-# LANGUAGE Safe #-}+{-# LANGUAGE StrictData #-} module Network.Tox.C.Options where -import Control.Applicative ((<$>))-import Control.Exception (bracket)-import Data.ByteString (ByteString)-import qualified Data.ByteString as BS-import Data.Default.Class (Default (..))-import Data.Word (Word16)-import Foreign.C.String (CString, peekCString, withCString)-import Foreign.C.Types (CInt (..), CSize (..))-import Foreign.Ptr (Ptr, nullPtr)-import GHC.Generics (Generic)+import Control.Exception (bracket)+import Data.ByteString (ByteString)+import qualified Data.ByteString as BS+import Data.Word (Word16)+import Foreign.C.Enum+import Foreign.C.String (peekCString, withCString)+import Foreign.Ptr (nullPtr)+import GHC.Generics (Generic) -import Network.Tox.C.CEnum+import FFI.Tox.Tox (LogCb, LogLevel (..), OptionsPtr,+ ProxyType (..), SavedataType (..),+ tox_options_get_end_port,+ tox_options_get_ipv6_enabled,+ tox_options_get_proxy_host,+ tox_options_get_proxy_port,+ tox_options_get_proxy_type,+ tox_options_get_savedata_data,+ tox_options_get_savedata_length,+ tox_options_get_savedata_type,+ tox_options_get_start_port,+ tox_options_get_tcp_port,+ tox_options_get_udp_enabled,+ tox_options_set_end_port,+ tox_options_set_ipv6_enabled,+ tox_options_set_log_callback,+ tox_options_set_proxy_host,+ tox_options_set_proxy_port,+ tox_options_set_proxy_type,+ tox_options_set_savedata_data,+ tox_options_set_savedata_length,+ tox_options_set_savedata_type,+ tox_options_set_start_port,+ tox_options_set_tcp_port,+ tox_options_set_udp_enabled, wrapLogCb) -------------------------------------------------------------------------------- --@@ -23,104 +45,82 @@ -------------------------------------------------------------------------------- --- | 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, Generic)----- 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, Generic)-- -- 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.+ { 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.+ , 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.+ , 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.+ , 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.+ , 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.+ , 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.+ , 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.+ , 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.+ , savedataType :: SavedataType+ -- The type of savedata to load from. - , savedataData :: ByteString- -- The savedata bytes.- }- deriving (Eq, Read, Show, Generic)+ , savedataData :: ByteString+ -- The savedata bytes.+ }+ deriving (Eq, Read, Show, Generic) -instance Default Options where- def = Options+defaultOptions :: Options+defaultOptions = Options { ipv6Enabled = True , udpEnabled = True , proxyType = ProxyTypeNone@@ -134,43 +134,29 @@ } -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+logLevelName :: LogLevel -> Char+logLevelName LogLevelTrace = 'T'+logLevelName LogLevelDebug = 'D'+logLevelName LogLevelInfo = 'I'+logLevelName LogLevelWarning = 'W'+logLevelName LogLevelError = 'E' -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 ()+logHandler :: LogCb+logHandler _ cLevel cFile line cFunc cMsg _ = do+ let level = fromCEnum cLevel+ file <- peekCString cFile+ func <- peekCString cFunc+ msg <- peekCString cMsg+ case level of+ LogLevelTrace -> return ()+ _ -> putStrLn $ logLevelName level : ' ' : file <> ":" <> show line <> "(" <> func <> "): " <> msg 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)+ = 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@@ -191,14 +177,14 @@ -- -- Passing a pointer that was not returned by tox_options_new results in -- undefined behaviour.-foreign import ccall tox_options_free :: OptionsPtr -> IO ()+foreign import ccall "tox_options_free" toxOptionsFree :: 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+ bracket toxOptionsNew (either (const $ return ()) toxOptionsFree) $ \case+ Left err -> return $ Left err+ Right ok -> Right <$> f ok -- | Read 'Options' from an 'OptionsPtr'.@@ -206,103 +192,40 @@ -- 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- }+ 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+ if p == nullPtr+ then return ""+ else peekCString p -- | Allocate a new C options pointer, fills in the values from 'Options',@@ -313,5 +236,20 @@ -- error code. withOptions :: Options -> (OptionsPtr -> IO r) -> IO (Either ErrOptionsNew r) withOptions options f =- withToxOptions $ \ptr ->- pokeToxOptions options ptr (f ptr)+ withToxOptions $ \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+ tox_options_set_log_callback ptr =<< wrapLogCb logHandler+ f ptr
src/Network/Tox/C/Tox.hs view
@@ -1,2405 +1,1118 @@-{-# OPTIONS_GHC -fno-warn-orphans #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE Safe #-}--- | 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.Concurrent.MVar (MVar, modifyMVar_)-import Control.Exception (bracket)-import Control.Monad ((>=>))-import qualified Data.ByteString as BS-import Data.Word (Word16, Word32, Word64)-import Foreign.C.String (CString, peekCStringLen, withCString,- withCStringLen)-import Foreign.C.Types (CChar (..), CInt (..), CSize (..),- CTime (..))-import Foreign.Marshal.Alloc (alloca)-import Foreign.Marshal.Array (allocaArray, peekArray)-import Foreign.Ptr (FunPtr, Ptr, nullPtr)-import Foreign.StablePtr (deRefStablePtr, freeStablePtr,- newStablePtr)-import Foreign.Storable (peek)-import System.Posix.Types (EpochTime)--import Network.Tox.C.CEnum-import Network.Tox.C.Constants-import Network.Tox.C.Options-import Network.Tox.C.Type----------------------------------------------------------------------------------------- :: Global types---------------------------------------------------------------------------------------- Should we introduce such types?--- newtype FriendNum = FriendNum { friendNum :: Word32 } deriving (Eq, Ord, Read, Show)--- newtype ConferenceNum = ConferenceNum { conferenceNum :: Word32 } deriving (Eq, Ord, Read, Show)--- newtype PeerNum = PeerNum { peerNum :: Word32 } deriving (Eq, Ord, Read, Show)--- newtype FileNum = FileNum { fileNum :: Word32 } deriving (Eq, Ord, Read, Show)---- | 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)----- | 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)----------------------------------------------------------------------------------------- :: 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 ()--toxKill :: Tox a -> IO ()-toxKill = tox_kill--withTox :: OptionsPtr -> (Tox a -> IO r) -> IO (Either ErrNew r)-withTox options f =- bracket (toxNew options) (either (const $ return ()) toxKill) $ \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 ()--toxGetSavedata :: Tox a -> IO BS.ByteString-toxGetSavedata tox = do- savedataLen <- tox_get_savedata_size tox- allocaArray (fromIntegral savedataLen) $ \savedataPtr -> do- tox_get_savedata tox savedataPtr- BS.packCStringLen (savedataPtr, fromIntegral savedataLen)----------------------------------------------------------------------------------------- :: 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 Options.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 -> BS.ByteString -> IO (Either ErrBootstrap ())-callBootstrapFun f tox address port pubKey =- withCString address $ \address' ->- BS.useAsCString pubKey $ \pubKey' ->- callErrFun $ f tox address' (fromIntegral port) pubKey'--toxBootstrap :: Tox a -> String -> Word16 -> BS.ByteString -> 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 -> BS.ByteString -> 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)----- | @param connection_status Whether we are connected to the DHT.-type SelfConnectionStatusCb a = Tox a -> Connection -> a -> IO a-type CSelfConnectionStatusCb a = Tox a -> CEnum Connection -> UserData a -> IO ()-foreign import ccall "wrapper" wrapSelfConnectionStatusCb :: CSelfConnectionStatusCb a -> IO (FunPtr (CSelfConnectionStatusCb a))--callSelfConnectionStatusCb :: SelfConnectionStatusCb a -> CSelfConnectionStatusCb a-callSelfConnectionStatusCb f tox conn = deRefStablePtr >=> (`modifyMVar_` f tox (fromCEnum conn))--selfConnectionStatusCb :: SelfConnectionStatusCb a -> IO (FunPtr (CSelfConnectionStatusCb a))-selfConnectionStatusCb = wrapSelfConnectionStatusCb . callSelfConnectionStatusCb----- | 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 (CSelfConnectionStatusCb 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-toxIterationInterval :: Tox a -> IO Word32-toxIterationInterval = tox_iteration_interval---- | The main loop that needs to be run in intervals of tox_iteration_interval()--- milliseconds.-foreign import ccall tox_iterate :: Tox a -> UserData a -> IO ()-toxIterate :: Tox a -> MVar a -> IO ()-toxIterate tox ud = bracket (newStablePtr ud) freeStablePtr (tox_iterate tox)----------------------------------------------------------------------------------------- :: 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 ()--toxSelfGetAddress :: Tox a -> IO BS.ByteString-toxSelfGetAddress tox =- let addrLen = fromIntegral tox_address_size in- allocaArray addrLen $ \addrPtr -> do- tox_self_get_address tox addrPtr- BS.packCStringLen (addrPtr, addrLen)---- | 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 ()-toxSelfSetNospam :: Tox a -> Word32 -> IO ()-toxSelfSetNospam = tox_self_set_nospam---- | Get the 4-byte nospam part of the address.-foreign import ccall tox_self_get_nospam :: Tox a -> IO Word32-toxSelfGetNospam :: Tox a -> IO Word32-toxSelfGetNospam = tox_self_get_nospam---- | 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 ()--toxSelfGetPublicKey :: Tox a -> IO BS.ByteString-toxSelfGetPublicKey tox =- let pkLen = fromIntegral tox_public_key_size in- allocaArray pkLen $ \pkPtr -> do- tox_self_get_public_key tox pkPtr- BS.packCStringLen (pkPtr, pkLen)---- | 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 ()--toxSelfGetSecretKey :: Tox a -> IO BS.ByteString-toxSelfGetSecretKey tox =- let skLen = fromIntegral tox_secret_key_size in- allocaArray skLen $ \skPtr -> do- tox_self_get_secret_key tox skPtr- BS.packCStringLen (skPtr, skLen)----------------------------------------------------------------------------------------- :: 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 ()-callSelfSetNameFun :: (Tox a -> CString -> CSize -> CErr ErrSetInfo -> IO ()) ->- Tox a -> String -> IO (Either ErrSetInfo ())-callSelfSetNameFun f tox name =- withCStringLen name $ \(nameStr, nameLen) ->- callErrFun $ f tox nameStr (fromIntegral nameLen)--toxSelfSetName :: Tox a -> String -> IO (Either ErrSetInfo ())-toxSelfSetName = callSelfSetNameFun tox_self_set_name----- | Return the length of the current nickname as passed to tox_self_set_name.------ If no nickname was set before calling this function, the name is empty,--- and this function returns 0.------ @see threading for concurrency implications.-foreign import ccall tox_self_get_name_size :: Tox a -> IO CSize---- | Write the nickname set by tox_self_set_name to a byte array.------ If no nickname was set before calling this function, the name is empty,--- and this function has no effect.------ Call tox_self_get_name_size to find out how much memory to allocate for--- the result.------ @param name A valid memory location large enough to hold the nickname.--- If this parameter is NULL, the function has no effect.-foreign import ccall tox_self_get_name :: Tox a -> CString -> IO ()--toxSelfGetName :: Tox a -> IO String-toxSelfGetName tox = do- nameLen <- tox_self_get_name_size tox- allocaArray (fromIntegral nameLen) $ \namePtr -> do- tox_self_get_name tox namePtr- peekCStringLen (namePtr, fromIntegral nameLen)----- | 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 ()-callSelfSetStatusMessageFun :: (Tox a -> CString -> CSize -> CErr ErrSetInfo -> IO ()) ->- Tox a -> String -> IO (Either ErrSetInfo ())-callSelfSetStatusMessageFun f tox statusMsg =- withCStringLen statusMsg $ \(statusMsgStr, statusMsgLen) ->- callErrFun $ f tox statusMsgStr (fromIntegral statusMsgLen)--toxSelfSetStatusMessage :: Tox a -> String -> IO (Either ErrSetInfo ())-toxSelfSetStatusMessage = callSelfSetStatusMessageFun tox_self_set_status_message----- | Return the length of the current status message as passed to tox_self_set_status_message.------ If no status message was set before calling this function, the status--- is empty, and this function returns 0.------ @see threading for concurrency implications.-foreign import ccall tox_self_get_status_message_size :: Tox a -> IO CSize----- | Write the status message set by tox_self_set_status_message to a byte array.------ If no status message was set before calling this function, the status is--- empty, and this function has no effect.------ Call tox_self_get_status_message_size to find out how much memory to allocate for--- the result.------ @param status_message A valid memory location large enough to hold the--- status message. If this parameter is NULL, the function has no effect.-foreign import ccall tox_self_get_status_message :: Tox a -> CString -> IO ()--toxSelfGetStatusMessage :: Tox a -> IO String-toxSelfGetStatusMessage tox = do- statusMessageLen <- tox_self_get_status_message_size tox- allocaArray (fromIntegral statusMessageLen) $ \statusMessagePtr -> do- tox_self_get_status_message tox statusMessagePtr- peekCStringLen (statusMessagePtr, fromIntegral statusMessageLen)----- | 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 ()-toxSelfSetStatus :: Tox a -> UserStatus -> IO ()-toxSelfSetStatus tox userStatus = tox_self_set_status tox $ toCEnum userStatus----------------------------------------------------------------------------------------- :: 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-callFriendAddFun :: (Tox a -> CString -> CString -> CSize -> CErr ErrFriendAdd -> IO Word32) ->- Tox a -> BS.ByteString -> String -> IO (Either ErrFriendAdd Word32)-callFriendAddFun f tox address message =- withCStringLen message $ \(msgStr, msgLen) ->- BS.useAsCString address $ \addr' ->- callErrFun $ f tox addr' msgStr (fromIntegral msgLen)--toxFriendAdd :: Tox a -> BS.ByteString -> String -> IO (Either ErrFriendAdd Word32)-toxFriendAdd = callFriendAddFun tox_friend_add---- | 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-callFriendAddNorequestFun :: (Tox a -> CString -> CErr ErrFriendAdd -> IO Word32) ->- Tox a -> BS.ByteString -> IO (Either ErrFriendAdd Word32)-callFriendAddNorequestFun f tox address =- BS.useAsCString address $ \addr' ->- callErrFun $ f tox addr'--toxFriendAddNorequest :: Tox a -> BS.ByteString -> IO (Either ErrFriendAdd Word32)-toxFriendAddNorequest = callFriendAddNorequestFun tox_friend_add_norequest---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 ()--toxFriendDelete :: Tox a -> Word32 -> IO (Either ErrFriendDelete ())-toxFriendDelete tox fn = callErrFun $ tox_friend_delete tox fn----------------------------------------------------------------------------------------- :: 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-callFriendByPublicKey :: (Tox a -> CString -> CErr ErrFriendByPublicKey -> IO Word32) ->- Tox a -> BS.ByteString -> IO (Either ErrFriendByPublicKey Word32)-callFriendByPublicKey f tox address =- BS.useAsCString address $ \addr' ->- callErrFun $ f tox addr'--toxFriendByPublicKey :: Tox a -> BS.ByteString -> IO (Either ErrFriendByPublicKey Word32)-toxFriendByPublicKey = callFriendByPublicKey tox_friend_by_public_key---- | 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-toxFriendExists :: Tox a -> Word32 -> IO Bool-toxFriendExists = tox_friend_exists---- | 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 ()--toxSelfGetFriendList :: Tox a -> IO [Word32]-toxSelfGetFriendList tox = do- friendListSize <- tox_self_get_friend_list_size tox- allocaArray (fromIntegral friendListSize) $ \friendListPtr -> do- tox_self_get_friend_list tox friendListPtr- peekArray (fromIntegral friendListSize) friendListPtr--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-callFriendGetPublicKey :: (Tox a -> Word32 -> CString -> CErr ErrFriendGetPublicKey -> IO Bool) ->- Tox a -> Word32 -> IO (Either ErrFriendGetPublicKey BS.ByteString)-callFriendGetPublicKey f tox fn =- let pkLen = fromIntegral tox_public_key_size in- alloca $ \errPtr ->- allocaArray pkLen $ \pkPtr -> do- _ <- f tox fn pkPtr errPtr- callGetPublicKey errPtr pkPtr pkLen--callGetPublicKey- :: (Bounded err, Enum err, Eq err)- => Ptr (CEnum err)- -> Ptr CChar- -> Int- -> IO (Either err BS.ByteString)-callGetPublicKey errPtr pkPtr pkLen = do- err <- toEnum . fromIntegral . unCEnum <$> peek errPtr- str <- BS.packCStringLen (pkPtr, pkLen)- return $ if err /= minBound- then Left err- else Right str--toxFriendGetPublicKey :: Tox a -> Word32 -> IO (Either ErrFriendGetPublicKey BS.ByteString)-toxFriendGetPublicKey = callFriendGetPublicKey tox_friend_get_public_key---data ErrFriendGetLastOnline- = ErrFriendGetLastOnlineOk- -- The function returned successfully.-- | ErrFriendGetLastOnlineFriendNotFound- -- No friend with the given number exists on the friend list.- deriving (Eq, Ord, Enum, Bounded, Read, Show)----- | Return a unix-time timestamp of the last time the friend associated with a given--- friend number was seen online. This function will return UINT64_MAX on error.------ @param friend_number The friend number you want to query.-foreign import ccall tox_friend_get_last_online :: Tox a -> Word32 -> CErr ErrFriendGetLastOnline -> IO Word64-callFriendGetLastOnline :: (Tox a -> Word32 -> CErr ErrFriendGetLastOnline -> IO Word64) ->- Tox a -> Word32 -> IO (Either ErrFriendGetLastOnline EpochTime)-callFriendGetLastOnline f tox fn = callErrFun (f tox fn >=> (return . CTime . fromIntegral))--toxFriendGetLastOnline :: Tox a -> Word32 -> IO (Either ErrFriendGetLastOnline EpochTime)-toxFriendGetLastOnline = callFriendGetLastOnline tox_friend_get_last_online----------------------------------------------------------------------------------------- :: Friend-specific state queries (can also be received through callbacks)----------------------------------------------------------------------------------------- | Common error codes for friend state query functions.-data ErrFriendQuery- = ErrFriendQueryOk- -- The function returned successfully.-- | ErrFriendQueryNull- -- The pointer parameter for storing the query result (name, message) was- -- NULL. Unlike the `_self_` variants of these functions, which have no effect- -- when a parameter is NULL, these functions return an error in that case.-- | ErrFriendQueryFriendNotFound- -- The friend_number did not designate a valid friend.- deriving (Eq, Ord, Enum, Bounded, Read, Show)----- | Return the length of the friend's name. If the friend number is invalid, the--- return value is unspecified.------ The return value is equal to the `length` argument received by the last--- `friend_name` callback.-foreign import ccall tox_friend_get_name_size :: Tox a -> Word32 -> CErr ErrFriendQuery -> IO CSize---- | Write the name of the friend designated by the given friend number to a byte--- array.------ Call tox_friend_get_name_size to determine the allocation size for the `name`--- parameter.------ The data written to `name` is equal to the data received by the last--- `friend_name` callback.------ @param name A valid memory region large enough to store the friend's name.------ @return true on success.-foreign import ccall tox_friend_get_name :: Tox a -> Word32 -> CString -> CErr ErrFriendQuery -> IO Bool--toxFriendGetName :: Tox a -> Word32 -> IO (Either ErrFriendQuery String)-toxFriendGetName tox fn = do- nameLenRes <- callErrFun $ tox_friend_get_name_size tox fn- case nameLenRes of- Left err -> return $ Left err- Right nameLen -> allocaArray (fromIntegral nameLen) $ \namePtr -> do- nameRes <- callErrFun $ tox_friend_get_name tox fn namePtr- case nameRes of- Left err -> return $ Left err- Right _ ->- Right <$> peekCStringLen (namePtr, fromIntegral nameLen)----- | @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 -> String -> a -> IO a-type CFriendNameCb a = Tox a -> Word32 -> CString -> CSize -> UserData a -> IO ()-foreign import ccall "wrapper" wrapFriendNameCb :: CFriendNameCb a -> IO (FunPtr (CFriendNameCb a))--callFriendNameCb :: FriendNameCb a -> CFriendNameCb a-callFriendNameCb f tox fn nameStr nameLen udPtr = do- ud <- deRefStablePtr udPtr- name <- peekCStringLen (nameStr, fromIntegral nameLen)- modifyMVar_ ud $ f tox fn name--friendNameCb :: FriendNameCb a -> IO (FunPtr (CFriendNameCb a))-friendNameCb = wrapFriendNameCb . callFriendNameCb----- | 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 (CFriendNameCb 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 -> String -> a -> IO a-type CFriendStatusMessageCb a = Tox a -> Word32 -> CString -> CSize -> UserData a -> IO ()-foreign import ccall "wrapper" wrapFriendStatusMessageCb :: CFriendStatusMessageCb a -> IO (FunPtr (CFriendStatusMessageCb a))--callFriendStatusMessageCb :: FriendStatusMessageCb a -> CFriendStatusMessageCb a-callFriendStatusMessageCb f tox fn statusMessageStr statusMessageLen udPtr = do- ud <- deRefStablePtr udPtr- statusMessage <- peekCStringLen (statusMessageStr, fromIntegral statusMessageLen)- modifyMVar_ ud $ f tox fn statusMessage--friendStatusMessageCb :: FriendStatusMessageCb a -> IO (FunPtr (CFriendStatusMessageCb a))-friendStatusMessageCb = wrapFriendStatusMessageCb . callFriendStatusMessageCb----- | Return the length of the friend's status message. If the friend number is--- invalid, the return value is SIZE_MAX.-foreign import ccall tox_friend_get_status_message_size :: Tox a -> Word32 -> CErr ErrFriendQuery -> IO CSize---- | Write the status message of the friend designated by the given friend number to a byte--- array.------ Call tox_friend_get_status_message_size to determine the allocation size for the `status_name`--- parameter.------ The data written to `status_message` is equal to the data received by the last--- `friend_status_message` callback.------ @param status_message A valid memory region large enough to store the friend's status message.-foreign import ccall tox_friend_get_status_message :: Tox a -> Word32 -> CString -> CErr ErrFriendQuery -> IO Bool--toxFriendGetStatusMessage :: Tox a -> Word32 -> IO (Either ErrFriendQuery String)-toxFriendGetStatusMessage tox fn = do- statusMessageLenRes <- callErrFun $ tox_friend_get_status_message_size tox fn- case statusMessageLenRes of- Left err -> return $ Left err- Right statusMessageLen -> allocaArray (fromIntegral statusMessageLen) $ \statusMessagePtr -> do- statusMessageRes <- callErrFun $ tox_friend_get_status_message tox fn statusMessagePtr- case statusMessageRes of- Left err -> return $ Left err- Right _ ->- Right <$> peekCStringLen (statusMessagePtr, fromIntegral statusMessageLen)----- | 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 (CFriendStatusMessageCb 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 -> UserStatus -> a -> IO a-type CFriendStatusCb a = Tox a -> Word32 -> CEnum UserStatus -> UserData a -> IO ()-foreign import ccall "wrapper" wrapFriendStatusCb :: CFriendStatusCb a -> IO (FunPtr (CFriendStatusCb a))--callFriendStatusCb :: FriendStatusCb a -> CFriendStatusCb a-callFriendStatusCb f tox fn status = deRefStablePtr >=> (`modifyMVar_` f tox fn (fromCEnum status))--friendStatusCb :: FriendStatusCb a -> IO (FunPtr (CFriendStatusCb a))-friendStatusCb = wrapFriendStatusCb . callFriendStatusCb----- | 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 (CFriendStatusCb a) -> IO ()----- | Check whether a friend is currently connected to this client.------ The result of this function is equal to the last value received by the--- `friend_connection_status` callback.------ @param friend_number The friend number for which to query the connection--- status.------ @return the friend's connection status as it was received through the--- `friend_connection_status` event.-foreign import ccall tox_friend_get_connection_status :: Tox a -> Word32 -> CErr ErrFriendQuery -> IO (CEnum Connection)--callFriendGetConnectionStatus :: (Tox a -> Word32 -> CErr ErrFriendQuery -> IO (CEnum Connection)) ->- Tox a -> Word32 -> IO (Either ErrFriendQuery Connection)-callFriendGetConnectionStatus f tox fn = callErrFun (f tox fn >=> (return . fromCEnum))--toxFriendGetConnectionStatus :: Tox a -> Word32 -> IO (Either ErrFriendQuery Connection)-toxFriendGetConnectionStatus = callFriendGetConnectionStatus tox_friend_get_connection_status----- | @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 -> Connection -> a -> IO a-type CFriendConnectionStatusCb a = Tox a -> Word32 -> CEnum Connection -> UserData a -> IO ()-foreign import ccall "wrapper" wrapFriendConnectionStatusCb :: CFriendConnectionStatusCb a -> IO (FunPtr (CFriendConnectionStatusCb a))--callFriendConnectionStatusCb :: FriendConnectionStatusCb a -> CFriendConnectionStatusCb a-callFriendConnectionStatusCb f tox fn connectionStatus = deRefStablePtr >=> (`modifyMVar_` f tox fn (fromCEnum connectionStatus))--friendConnectionStatusCb :: FriendConnectionStatusCb a -> IO (FunPtr (CFriendConnectionStatusCb a))-friendConnectionStatusCb = wrapFriendConnectionStatusCb . callFriendConnectionStatusCb----- | 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 (CFriendConnectionStatusCb a) -> IO ()----- | Check whether a friend is currently typing a message.------ @param friend_number The friend number for which to query the typing status.------ @return true if the friend is typing.--- @return false if the friend is not typing, or the friend number was--- invalid. Inspect the error code to determine which case it is.-foreign import ccall tox_friend_get_typing :: Tox a -> Word32 -> CErr ErrFriendQuery -> IO Bool--callFriendGetTyping :: (Tox a -> Word32 -> CErr ErrFriendQuery -> IO Bool) ->- Tox a -> Word32 -> IO (Either ErrFriendQuery Bool)-callFriendGetTyping f tox fn = callErrFun $ f tox fn--toxFriendGetTyping :: Tox a -> Word32 -> IO (Either ErrFriendQuery Bool)-toxFriendGetTyping = callFriendGetTyping tox_friend_get_typing----- | @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 -> a -> IO a-type CFriendTypingCb a = Tox a -> Word32 -> Bool -> UserData a -> IO ()-foreign import ccall "wrapper" wrapFriendTypingCb :: CFriendTypingCb a -> IO (FunPtr (CFriendTypingCb a))--callFriendTypingCb :: FriendTypingCb a -> CFriendTypingCb a-callFriendTypingCb f tox fn typing = deRefStablePtr >=> (`modifyMVar_` f tox fn typing)--friendTypingCb :: FriendTypingCb a -> IO (FunPtr (CFriendTypingCb a))-friendTypingCb = wrapFriendTypingCb . callFriendTypingCb---- | 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 (CFriendTypingCb 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-callSelfSetTyping :: (Tox a -> Word32 -> Bool -> CErr ErrSetTyping -> IO Bool) ->- Tox a -> Word32 -> Bool -> IO (Either ErrSetTyping Bool)-callSelfSetTyping f tox fn typing = callErrFun $ f tox fn typing--toxSelfSetTyping :: Tox a -> Word32 -> Bool -> IO (Either ErrSetTyping Bool)-toxSelfSetTyping = callSelfSetTyping tox_self_set_typing--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-callFriendSendMessage :: (Tox a -> Word32 -> CEnum MessageType -> CString -> CSize -> CErr ErrFriendSendMessage -> IO Word32) ->- Tox a -> Word32 -> MessageType -> String -> IO (Either ErrFriendSendMessage Word32)-callFriendSendMessage f tox fn messageType message =- withCStringLen message $ \(msgStr, msgLen) ->- callErrFun $ f tox fn (toCEnum messageType) msgStr (fromIntegral msgLen)--toxFriendSendMessage :: Tox a -> Word32 -> MessageType -> String -> IO (Either ErrFriendSendMessage Word32)-toxFriendSendMessage = callFriendSendMessage tox_friend_send_message----- | @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 -> a -> IO a-type CFriendReadReceiptCb a = Tox a -> Word32 -> Word32 -> UserData a -> IO ()-foreign import ccall "wrapper" wrapFriendReadReceiptCb :: CFriendReadReceiptCb a -> IO (FunPtr (CFriendReadReceiptCb a))--callFriendReadReceiptCb :: FriendReadReceiptCb a -> CFriendReadReceiptCb a-callFriendReadReceiptCb f tox fn msgId = deRefStablePtr >=> (`modifyMVar_` f tox fn msgId)--friendReadReceiptCb :: FriendReadReceiptCb a -> IO (FunPtr (CFriendReadReceiptCb a))-friendReadReceiptCb = wrapFriendReadReceiptCb . callFriendReadReceiptCb----- | 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 (CFriendReadReceiptCb 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 -> BS.ByteString -> String -> a -> IO a-type CFriendRequestCb a = Tox a -> CString -> CString -> CSize -> UserData a -> IO ()-foreign import ccall "wrapper" wrapFriendRequestCb :: CFriendRequestCb a -> IO (FunPtr (CFriendRequestCb a))--callFriendRequestCb :: FriendRequestCb a -> CFriendRequestCb a-callFriendRequestCb f tox addrPtr nameStr nameLen udPtr = do- let addrLen = fromIntegral tox_address_size- ud <- deRefStablePtr udPtr- addr <- BS.packCStringLen (addrPtr, addrLen)- name <- peekCStringLen (nameStr, fromIntegral nameLen)- modifyMVar_ ud $ f tox addr name--friendRequestCb :: FriendRequestCb a -> IO (FunPtr (CFriendRequestCb a))-friendRequestCb = wrapFriendRequestCb . callFriendRequestCb----- | 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 (CFriendRequestCb 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 -> MessageType -> String -> a -> IO a-type CFriendMessageCb a = Tox a -> Word32 -> CEnum MessageType -> CString -> CSize -> UserData a -> IO ()-foreign import ccall "wrapper" wrapFriendMessageCb :: CFriendMessageCb a -> IO (FunPtr (CFriendMessageCb a))--callFriendMessageCb :: FriendMessageCb a -> CFriendMessageCb a-callFriendMessageCb f tox fn msgType msgStr msgLen udPtr = do- ud <- deRefStablePtr udPtr- msg <- peekCStringLen (msgStr, fromIntegral msgLen)- modifyMVar_ ud $ f tox fn (fromCEnum msgType) msg--friendMessageCb :: FriendMessageCb a -> IO (FunPtr (CFriendMessageCb a))-friendMessageCb = wrapFriendMessageCb . callFriendMessageCb----- | 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 (CFriendMessageCb 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--toxHash :: BS.ByteString -> IO BS.ByteString-toxHash d =- let hashLen = fromIntegral tox_hash_length in- allocaArray hashLen $ \hashPtr ->- BS.useAsCStringLen d $ \(dataPtr, dataLen) -> do- _ <- tox_hash hashPtr dataPtr (fromIntegral dataLen)- BS.packCStringLen (dataPtr, fromIntegral dataLen)--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)---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)---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--callFileControl :: (Tox a -> Word32 -> Word32 -> CEnum FileControl -> CErr ErrFileControl -> IO Bool) ->- Tox a -> Word32 -> Word32 -> FileControl -> IO (Either ErrFileControl Bool)-callFileControl f tox fn fileNum control = callErrFun $ f tox fn fileNum (toCEnum control)--toxFileControl :: Tox a -> Word32 -> Word32 -> FileControl -> IO (Either ErrFileControl Bool)-toxFileControl = callFileControl tox_file_control---- | 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 -> FileControl -> a -> IO a-type CFileRecvControlCb a = Tox a -> Word32 -> Word32 -> CEnum FileControl -> UserData a -> IO ()-foreign import ccall "wrapper" wrapFileRecvControlCb :: CFileRecvControlCb a -> IO (FunPtr (CFileRecvControlCb a))--callFileRecvControlCb :: FileRecvControlCb a -> CFileRecvControlCb a-callFileRecvControlCb f tox fn fileNum ctrlCmd = deRefStablePtr >=> (`modifyMVar_` f tox fn fileNum (fromCEnum ctrlCmd))--fileRecvControlCb :: FileRecvControlCb a -> IO (FunPtr (CFileRecvControlCb a))-fileRecvControlCb = wrapFileRecvControlCb . callFileRecvControlCb----- | 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 (CFileRecvControlCb 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--callFileSeek :: (Tox a -> Word32 -> Word32 -> Word64 -> CErr ErrFileSeek -> IO Bool) ->- Tox a -> Word32 -> Word32 -> Word64 -> IO (Either ErrFileSeek Bool)-callFileSeek f tox fn fileNum pos = callErrFun $ f tox fn fileNum pos--toxFileSeek :: Tox a -> Word32 -> Word32 -> Word64 -> IO (Either ErrFileSeek Bool)-toxFileSeek = callFileSeek tox_file_seek---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--callFileGetFileId :: (Tox a -> Word32 -> Word32 -> CString -> CErr ErrFileGet -> IO Bool) ->- Tox a -> Word32 -> Word32 -> IO (Either ErrFileGet BS.ByteString)-callFileGetFileId f tox fn fileNum =- let fileIdLen = fromIntegral tox_file_id_length in- alloca $ \errPtr ->- allocaArray fileIdLen $ \fileIdPtr -> do- _ <- f tox fn fileNum fileIdPtr errPtr- err <- toEnum . fromIntegral . unCEnum <$> peek errPtr- fileId <- BS.packCStringLen (fileIdPtr, fileIdLen)- return $ if err /= minBound- then Left err- else Right fileId--toxFileGetFileId :: Tox a -> Word32 -> Word32 -> IO (Either ErrFileGet BS.ByteString)-toxFileGetFileId = callFileGetFileId tox_file_get_file_id----------------------------------------------------------------------------------------- :: 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 -> CEnum FileKind -> Word64 -> CString -> CString -> CSize -> CErr ErrFileSend -> IO Word32-callFileSend :: (Tox a -> Word32 -> CEnum FileKind -> Word64 -> CString -> CString -> CSize -> CErr ErrFileSend -> IO Word32) ->- Tox a -> Word32 -> FileKind -> Word64 -> String -> IO (Either ErrFileSend Word32)-callFileSend f tox fn fileKind fileSize fileName =- withCStringLen fileName $ \(fileNamePtr, fileNameLen) ->- callErrFun $ f tox fn (toCEnum fileKind) fileSize nullPtr fileNamePtr (fromIntegral fileNameLen)--toxFileSend :: Tox a -> Word32 -> FileKind -> Word64 -> String -> IO (Either ErrFileSend Word32)-toxFileSend = callFileSend tox_file_send--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-callFileSendChunk :: (Tox a -> Word32 -> Word32 -> Word64 -> CString -> CSize -> CErr ErrFileSendChunk -> IO Bool) ->- Tox a -> Word32 -> Word32 -> Word64 -> BS.ByteString -> IO (Either ErrFileSendChunk Bool)-callFileSendChunk f tox fn fileNum pos d =- BS.useAsCStringLen d $ \(dataPtr, dataLen) ->- callErrFun $ f tox fn fileNum pos dataPtr (fromIntegral dataLen)--toxFileSendChunk :: Tox a -> Word32 -> Word32 -> Word64 -> BS.ByteString -> IO (Either ErrFileSendChunk Bool)-toxFileSendChunk = callFileSendChunk tox_file_send_chunk---- | 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 -> a -> IO a-type CFileChunkRequestCb a = Tox a -> Word32 -> Word32 -> Word64 -> CSize -> UserData a -> IO ()-foreign import ccall "wrapper" wrapFileChunkRequestCb :: CFileChunkRequestCb a -> IO (FunPtr (CFileChunkRequestCb a))--callFileChunkRequestCb :: FileChunkRequestCb a -> CFileChunkRequestCb a-callFileChunkRequestCb f tox fn fileNum pos len = deRefStablePtr >=> (`modifyMVar_` f tox fn fileNum pos len)--fileChunkRequestCb :: FileChunkRequestCb a -> IO (FunPtr (CFileChunkRequestCb a))-fileChunkRequestCb = wrapFileChunkRequestCb . callFileChunkRequestCb---- | 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 (CFileChunkRequestCb 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 -> FileKind -> Word64 -> String -> a -> IO a-type CFileRecvCb a = Tox a -> Word32 -> Word32 -> CEnum FileKind -> Word64 -> CString -> CSize -> UserData a -> IO ()-foreign import ccall "wrapper" wrapFileRecvCb :: CFileRecvCb a -> IO (FunPtr (CFileRecvCb a))--callFileRecvCb :: FileRecvCb a -> CFileRecvCb a-callFileRecvCb f tox fn fileNum fileKind fileSize fileNameStr fileNameLen udPtr = do- ud <- deRefStablePtr udPtr- fileName <- peekCStringLen (fileNameStr, fromIntegral fileNameLen)- modifyMVar_ ud $ f tox fn fileNum (fromCEnum fileKind) fileSize fileName--fileRecvCb :: FileRecvCb a -> IO (FunPtr (CFileRecvCb a))-fileRecvCb = wrapFileRecvCb . callFileRecvCb----- | 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 (CFileRecvCb 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 -> BS.ByteString -> a -> IO a-type CFileRecvChunkCb a = Tox a -> Word32 -> Word32 -> Word64 -> CString -> CSize -> UserData a -> IO ()-foreign import ccall "wrapper" wrapFileRecvChunkCb :: CFileRecvChunkCb a -> IO (FunPtr (CFileRecvChunkCb a))--callFileRecvChunkCb :: FileRecvChunkCb a -> CFileRecvChunkCb a-callFileRecvChunkCb f tox fn fileNum pos dataPtr dataLen udPtr = do- ud <- deRefStablePtr udPtr- d <- BS.packCStringLen (dataPtr, fromIntegral dataLen)- modifyMVar_ ud $ f tox fn fileNum pos d--fileRecvChunkCb :: FileRecvChunkCb a -> IO (FunPtr (CFileRecvChunkCb a))-fileRecvChunkCb = wrapFileRecvChunkCb . callFileRecvChunkCb----- | 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 (CFileRecvChunkCb a) -> IO ()----------------------------------------------------------------------------------------- :: Conference management----------------------------------------------------------------------------------------- | Conference types for the conference_invite event.-data ConferenceType- = ConferenceTypeText- -- Text-only conferences that must be accepted with the tox_conference_join function.-- | ConferenceTypeAv- -- Video conference. The function to accept these is in toxav.- deriving (Eq, Ord, Enum, Bounded, Read, Show)----- | The invitation will remain valid until the inviting friend goes offline--- or exits the conference.------ @param friend_number The friend who invited us.--- @param type The conference type (text only or audio/video).--- @param cookie A piece of data of variable length required to join the--- conference.--- @param length The length of the cookie.-type ConferenceInviteCb a = Tox a -> Word32 -> ConferenceType -> BS.ByteString -> a -> IO a-type CConferenceInviteCb a = Tox a -> Word32 -> CEnum ConferenceType -> CString -> CSize -> UserData a -> IO ()-foreign import ccall "wrapper" wrapConferenceInviteCb :: CConferenceInviteCb a -> IO (FunPtr (CConferenceInviteCb a))--callConferenceInviteCb :: ConferenceInviteCb a -> CConferenceInviteCb a-callConferenceInviteCb f tox fn confType cookiePtr cookieLen udPtr = do- ud <- deRefStablePtr udPtr- cookie <- BS.packCStringLen (cookiePtr, fromIntegral cookieLen)- modifyMVar_ ud $ f tox fn (fromCEnum confType) cookie--conferenceInviteCb :: ConferenceInviteCb a -> IO (FunPtr (CConferenceInviteCb a))-conferenceInviteCb = wrapConferenceInviteCb . callConferenceInviteCb----- | Set the callback for the `conference_invite` event. Pass NULL to unset.------ This event is triggered when the client is invited to join a conference.-foreign import ccall tox_callback_conference_invite :: Tox a -> FunPtr (CConferenceInviteCb a) -> IO ()----- | @param conference_number The conference number of the conference the message is intended for.--- @param peer_number The ID of the peer who sent the message.--- @param type The type of message (normal, action, ...).--- @param message The message data.--- @param length The length of the message.-type ConferenceMessageCb a = Tox a -> Word32 -> Word32 -> MessageType -> String -> a -> IO a-type CConferenceMessageCb a = Tox a -> Word32 -> Word32 -> CEnum MessageType -> CString -> CSize -> UserData a -> IO ()-foreign import ccall "wrapper" wrapConferenceMessageCb :: CConferenceMessageCb a -> IO (FunPtr (CConferenceMessageCb a))--callConferenceMessageCb :: ConferenceMessageCb a -> CConferenceMessageCb a-callConferenceMessageCb f tox gn pn msgType msgStr msgLen udPtr = do- ud <- deRefStablePtr udPtr- msg <- peekCStringLen (msgStr, fromIntegral msgLen)- modifyMVar_ ud $ f tox gn pn (fromCEnum msgType) msg--conferenceMessageCb :: ConferenceMessageCb a -> IO (FunPtr (CConferenceMessageCb a))-conferenceMessageCb = wrapConferenceMessageCb . callConferenceMessageCb----- | Set the callback for the `conference_message` event. Pass NULL to unset.------ This event is triggered when the client receives a conference message.-foreign import ccall tox_callback_conference_message :: Tox a -> FunPtr (CConferenceMessageCb a) -> IO ()----- | @param conference_number The conference number of the conference the title change is intended for.--- @param peer_number The ID of the peer who changed the title.--- @param title The title data.--- @param length The title length.-type ConferenceTitleCb a = Tox a -> Word32 -> Word32 -> String -> a -> IO a-type CConferenceTitleCb a = Tox a -> Word32 -> Word32 -> CString -> CSize -> UserData a -> IO ()-foreign import ccall "wrapper" wrapConferenceTitleCb :: CConferenceTitleCb a -> IO (FunPtr (CConferenceTitleCb a))--callConferenceTitleCb :: ConferenceTitleCb a -> CConferenceTitleCb a-callConferenceTitleCb f tox gn pn titleStr titleLen udPtr = do- ud <- deRefStablePtr udPtr- title <- peekCStringLen (titleStr, fromIntegral titleLen)- modifyMVar_ ud $ f tox gn pn title--conferenceTitleCb :: ConferenceTitleCb a -> IO (FunPtr (CConferenceTitleCb a))-conferenceTitleCb = wrapConferenceTitleCb . callConferenceTitleCb----- | Set the callback for the `conference_title` event. Pass NULL to unset.------ This event is triggered when a peer changes the conference title.------ If peer_number == UINT32_MAX, then author is unknown (e.g. initial joining the conference).-foreign import ccall tox_callback_conference_title :: Tox a -> FunPtr (CConferenceTitleCb a) -> IO ()----- | @param conference_number The conference number of the conference the peer is in.--- @param peer_number The ID of the peer who changed their name.--- @param name The new name of the peer.-type ConferencePeerNameCb a = Tox a -> Word32 -> Word32 -> String -> a -> IO a-type CConferencePeerNameCb a = Tox a -> Word32 -> Word32 -> CString -> CSize -> UserData a -> IO ()-foreign import ccall "wrapper" wrapConferencePeerNameCb :: CConferencePeerNameCb a -> IO (FunPtr (CConferencePeerNameCb a))--callConferencePeerNameCb :: ConferencePeerNameCb a -> CConferencePeerNameCb a-callConferencePeerNameCb f tox gn pn nameStr nameLen udPtr = do- ud <- deRefStablePtr udPtr- name <- peekCStringLen (nameStr, fromIntegral nameLen)- modifyMVar_ ud $ f tox gn pn name--conferencePeerNameCb :: ConferencePeerNameCb a -> IO (FunPtr (CConferencePeerNameCb a))-conferencePeerNameCb = wrapConferencePeerNameCb . callConferencePeerNameCb----- | Set the callback for the `conference_peer_name` event. Pass NULL to unset.------ This event is triggered when the peer changes their nickname.-foreign import ccall tox_callback_conference_peer_name :: Tox a -> FunPtr (CConferencePeerNameCb a) -> IO ()----- | @param conference_number The conference number of the conference for which the peer list changed.-type ConferencePeerListChangedCb a = Tox a -> Word32 -> a -> IO a-type CConferencePeerListChangedCb a = Tox a -> Word32 -> UserData a -> IO ()-foreign import ccall "wrapper" wrapConferencePeerListChangedCb :: CConferencePeerListChangedCb a -> IO (FunPtr (CConferencePeerListChangedCb a))--callConferencePeerListChangedCb :: ConferencePeerListChangedCb a -> CConferencePeerListChangedCb a-callConferencePeerListChangedCb f tox gn = deRefStablePtr >=> (`modifyMVar_` f tox gn)--conferencePeerListChangedCb :: ConferencePeerListChangedCb a -> IO (FunPtr (CConferencePeerListChangedCb a))-conferencePeerListChangedCb = wrapConferencePeerListChangedCb . callConferencePeerListChangedCb----- | Set the callback for the `conference_peer_list_changed` event. Pass NULL to unset.------ This event is triggered when the peer list changes (peer join, peer exit).-foreign import ccall tox_callback_conference_peer_list_changed :: Tox a -> FunPtr (CConferencePeerListChangedCb a) -> IO ()---data ErrConferenceNew- = ErrConferenceNewOk- -- The function returned successfully.-- | ErrConferenceNewInit- -- The conference instance failed to initialize.- deriving (Eq, Ord, Enum, Bounded, Read, Show)----- | Creates a new conference.------ This function creates a new text conference.------ @return conference number on success, or UINT32_MAX on failure.-foreign import ccall tox_conference_new :: Tox a -> CErr ErrConferenceNew -> IO Word32-callConferenceNew :: (Tox a -> CErr ErrConferenceNew -> IO Word32) ->- Tox a -> IO (Either ErrConferenceNew Word32)-callConferenceNew f tox = callErrFun $ f tox--toxConferenceNew :: Tox a -> IO (Either ErrConferenceNew Word32)-toxConferenceNew = callConferenceNew tox_conference_new---data ErrConferenceDelete- = ErrConferenceDeleteOk- -- The function returned successfully.-- | ErrConferenceDeleteConferenceNotFound- -- The conference number passed did not designate a valid conference.- deriving (Eq, Ord, Enum, Bounded, Read, Show)----- | This function deletes a conference.------ @param conference_number The conference number of the conference to be deleted.------ @return true on success.-foreign import ccall tox_conference_delete :: Tox a -> Word32 -> CErr ErrConferenceDelete -> IO Bool-callConferenceDelete :: (Tox a -> Word32 -> CErr ErrConferenceDelete -> IO Bool) ->- Tox a -> Word32 -> IO (Either ErrConferenceDelete Bool)-callConferenceDelete f tox gn = callErrFun $ f tox gn--toxConferenceDelete :: Tox a -> Word32 -> IO (Either ErrConferenceDelete Bool)-toxConferenceDelete = callConferenceDelete tox_conference_delete----- | Error codes for peer info queries.-data ErrConferencePeerQuery- = ErrConferencePeerQueryOk- -- The function returned successfully.-- | ErrConferencePeerQueryConferenceNotFound- -- The conference number passed did not designate a valid conference.-- | ErrConferencePeerQueryPeerNotFound- -- The peer number passed did not designate a valid peer.-- | ErrConferencePeerQueryNoConnection- -- The client is not connected to the conference.- deriving (Eq, Ord, Enum, Bounded, Read, Show)------ | Return the number of peers in the conference. Return value is unspecified on failure.-foreign import ccall tox_conference_peer_count :: Tox a -> Word32 -> CErr ErrConferencePeerQuery -> IO Word32-callConferencePeerCount :: (Tox a -> Word32 -> CErr ErrConferencePeerQuery -> IO Word32) ->- Tox a -> Word32 -> IO (Either ErrConferencePeerQuery Word32)-callConferencePeerCount f tox gn = callErrFun $ f tox gn--toxConferencePeerCount :: Tox a -> Word32 -> IO (Either ErrConferencePeerQuery Word32)-toxConferencePeerCount = callConferencePeerCount tox_conference_peer_count----- | Return the length of the peer's name. Return value is unspecified on failure.-foreign import ccall tox_conference_peer_get_name_size :: Tox a -> Word32 -> Word32 -> CErr ErrConferencePeerQuery -> IO CSize----- | Copy the name of peer_number who is in conference_number to name.--- name must be at least TOX_MAX_NAME_LENGTH long.------ @return true on success.-foreign import ccall tox_conference_peer_get_name :: Tox a -> Word32 -> Word32 -> CString -> CErr ErrConferencePeerQuery -> IO Bool--toxConferencePeerGetName :: Tox a -> Word32 -> Word32 -> IO (Either ErrConferencePeerQuery String)-toxConferencePeerGetName tox gn pn = do- nameLenRes <- callErrFun $ tox_conference_peer_get_name_size tox gn pn- case nameLenRes of- Left err -> return $ Left err- Right nameLen -> allocaArray (fromIntegral nameLen) $ \namePtr -> do- nameRes <- callErrFun $ tox_conference_peer_get_name tox gn pn namePtr- case nameRes of- Left err -> return $ Left err- Right _ ->- Right <$> peekCStringLen (namePtr, fromIntegral nameLen)----- | Copy the public key of peer_number who is in conference_number to public_key.--- public_key must be TOX_PUBLIC_KEY_SIZE long.------ @return true on success.-foreign import ccall tox_conference_peer_get_public_key :: Tox a -> Word32 -> Word32 -> CString -> CErr ErrConferencePeerQuery -> IO Bool-callConferencePeerGetPublicKey :: (Tox a -> Word32 -> Word32 -> CString -> CErr ErrConferencePeerQuery -> IO Bool) ->- Tox a -> Word32 -> Word32 -> IO (Either ErrConferencePeerQuery BS.ByteString)-callConferencePeerGetPublicKey f tox gn pn =- let pkLen = fromIntegral tox_public_key_size in- alloca $ \errPtr ->- allocaArray pkLen $ \pkPtr -> do- _ <- f tox gn pn pkPtr errPtr- callGetPublicKey errPtr pkPtr pkLen--toxConferencePeerGetPublicKey :: Tox a -> Word32 -> Word32 -> IO (Either ErrConferencePeerQuery BS.ByteString)-toxConferencePeerGetPublicKey = callConferencePeerGetPublicKey tox_conference_peer_get_public_key----- | Return true if passed peer_number corresponds to our own.-foreign import ccall tox_conference_peer_number_is_ours :: Tox a -> Word32 -> Word32 -> CErr ErrConferencePeerQuery -> IO Bool-callConferencePeerNumberIsOurs :: (Tox a -> Word32 -> Word32 -> CErr ErrConferencePeerQuery -> IO Bool) ->- Tox a -> Word32 -> Word32 -> IO (Either ErrConferencePeerQuery Bool)-callConferencePeerNumberIsOurs f tox gn pn = callErrFun $ f tox gn pn--toxConferencePeerNumberIsOurs :: Tox a -> Word32 -> Word32 -> IO (Either ErrConferencePeerQuery Bool)-toxConferencePeerNumberIsOurs = callConferencePeerNumberIsOurs tox_conference_peer_number_is_ours---data ErrConferenceInvite- = ErrConferenceInviteOk- -- The function returned successfully.-- | ErrConferenceInviteConferenceNotFound- -- The conference number passed did not designate a valid conference.-- | ErrConferenceInviteFailSend- -- The invite packet failed to send.- deriving (Eq, Ord, Enum, Bounded, Read, Show)------ | Invites a friend to a conference.------ @param friend_number The friend number of the friend we want to invite.--- @param conference_number The conference number of the conference we want to invite the friend to.------ @return true on success.-foreign import ccall tox_conference_invite :: Tox a -> Word32 -> Word32 -> CErr ErrConferenceInvite -> IO Bool-callConferenceInvite :: (Tox a -> Word32 -> Word32 -> CErr ErrConferenceInvite -> IO Bool) ->- Tox a -> Word32 -> Word32 -> IO (Either ErrConferenceInvite Bool)-callConferenceInvite f tox fn gn = callErrFun $ f tox fn gn--toxConferenceInvite :: Tox a -> Word32 -> Word32 -> IO (Either ErrConferenceInvite Bool)-toxConferenceInvite = callConferenceInvite tox_conference_invite---data ErrConferenceJoin- = ErrConferenceJoinOk- -- The function returned successfully.-- | ErrConferenceJoinInvalidLength- -- The cookie passed has an invalid length.-- | ErrConferenceJoinWrongType- -- The conference is not the expected type. This indicates an invalid cookie.-- | ErrConferenceJoinFriendNotFound- -- The friend number passed does not designate a valid friend.-- | ErrConferenceJoinDuplicate- -- Client is already in this conference.-- | ErrConferenceJoinInitFail- -- Conference instance failed to initialize.-- | ErrConferenceJoinFailSend- -- The join packet failed to send.- deriving (Eq, Ord, Enum, Bounded, Read, Show)------ | Joins a conference that the client has been invited to.------ @param friend_number The friend number of the friend who sent the invite.--- @param cookie Received via the `conference_invite` event.--- @param length The size of cookie.------ @return conference number on success, UINT32_MAX on failure.-foreign import ccall tox_conference_join :: Tox a -> Word32 -> CString -> CSize -> CErr ErrConferenceJoin -> IO Word32-callConferenceJoin :: (Tox a -> Word32 -> CString -> CSize -> CErr ErrConferenceJoin -> IO Word32) ->- Tox a -> Word32 -> BS.ByteString -> IO (Either ErrConferenceJoin Word32)-callConferenceJoin f tox fn cookie =- BS.useAsCStringLen cookie $ \(cookiePtr, cookieLen) ->- callErrFun $ f tox fn cookiePtr (fromIntegral cookieLen)--toxConferenceJoin :: Tox a -> Word32 -> BS.ByteString -> IO (Either ErrConferenceJoin Word32)-toxConferenceJoin = callConferenceJoin tox_conference_join---data ErrConferenceSendMessage- = ErrConferenceSendMessageOk- -- The function returned successfully.-- | ErrConferenceSendMessageConferenceNotFound- -- The conference number passed did not designate a valid conference.-- | ErrConferenceSendMessageTooLong- -- The message is too long.-- | ErrConferenceSendMessageNoConnection- -- The client is not connected to the conference.-- | ErrConferenceSendMessageFailSend- -- The message packet failed to send.- deriving (Eq, Ord, Enum, Bounded, Read, Show)------ | Send a text chat message to the conference.------ This function creates a conference 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.------ @param conference_number The conference number of the conference the message is intended for.--- @param type Message type (normal, action, ...).--- @param message A non-NULL pointer to the first element of a byte array--- containing the message text.--- @param length Length of the message to be sent.------ @return true on success.-foreign import ccall tox_conference_send_message :: Tox a -> Word32 -> CEnum MessageType -> CString -> CSize -> CErr ErrConferenceSendMessage -> IO Bool-callConferenceSendMessage :: (Tox a -> Word32 -> CEnum MessageType -> CString -> CSize -> CErr ErrConferenceSendMessage -> IO Bool) ->- Tox a -> Word32 -> MessageType -> String -> IO (Either ErrConferenceSendMessage Bool)-callConferenceSendMessage f tox gn messageType message =- withCStringLen message $ \(msgPtr, msgLen) ->- callErrFun $ f tox gn (toCEnum messageType) msgPtr (fromIntegral msgLen)--toxConferenceSendMessage :: Tox a -> Word32 -> MessageType -> String -> IO (Either ErrConferenceSendMessage Bool)-toxConferenceSendMessage = callConferenceSendMessage tox_conference_send_message---data ErrConferenceTitle- = ErrConferenceTitleOk- -- The function returned successfully.-- | ErrConferenceTitleConferenceNotFound- -- The conference number passed did not designate a valid conference.-- | ErrConferenceTitleInvalidLength- -- The title is too long or empty.-- | ErrConferenceTitleFailSend- -- The title packet failed to send.- deriving (Eq, Ord, Enum, Bounded, Read, Show)------ | Return the length of the conference title. Return value is unspecified on failure.------ The return value is equal to the `length` argument received by the last--- `conference_title` callback.-foreign import ccall tox_conference_get_title_size :: Tox a -> Word32 -> CErr ErrConferenceTitle -> IO CSize----- | Write the title designated by the given conference number to a byte array.------ Call tox_conference_get_title_size to determine the allocation size for the `title` parameter.------ The data written to `title` is equal to the data received by the last--- `conference_title` callback.------ @param title A valid memory region large enough to store the title.--- If this parameter is NULL, this function has no effect.------ @return true on success.-foreign import ccall tox_conference_get_title :: Tox a -> Word32 -> CString -> CErr ErrConferenceTitle -> IO Bool--toxConferenceGetTitle :: Tox a -> Word32 -> IO (Either ErrConferenceTitle String)-toxConferenceGetTitle tox gn = do- titleLenRes <- callErrFun $ tox_conference_get_title_size tox gn- case titleLenRes of- Left err -> return $ Left err- Right titleLen -> allocaArray (fromIntegral titleLen) $ \titlePtr -> do- titleRes <- callErrFun $ tox_conference_get_title tox gn titlePtr- case titleRes of- Left err -> return $ Left err- Right _ ->- Right <$> peekCStringLen (titlePtr, fromIntegral titleLen)---- | Set the conference title and broadcast it to the rest of the conference.------ Title length cannot be longer than TOX_MAX_NAME_LENGTH.------ @return true on success.-foreign import ccall tox_conference_set_title :: Tox a -> Word32 -> CString -> CSize -> CErr ErrConferenceTitle -> IO Bool-callConferenceSetTitle :: (Tox a -> Word32 -> CString -> CSize -> CErr ErrConferenceTitle -> IO Bool) ->- Tox a -> Word32 -> String -> IO (Either ErrConferenceTitle Bool)-callConferenceSetTitle f tox gn title =- withCStringLen title $ \(titlePtr, titleLen) ->- callErrFun $ f tox gn titlePtr (fromIntegral titleLen)--toxConferenceSetTitle :: Tox a -> Word32 -> String -> IO (Either ErrConferenceTitle Bool)-toxConferenceSetTitle = callConferenceSetTitle tox_conference_set_title----- | Return the number of conferences in the Tox instance.--- This should be used to determine how much memory to allocate for `tox_conference_get_chatlist`.-foreign import ccall tox_conference_get_chatlist_size :: Tox a -> IO CSize----- | Copy a list of valid conference IDs into the array chatlist. Determine how much space--- to allocate for the array with the `tox_conference_get_chatlist_size` function.-foreign import ccall tox_conference_get_chatlist :: Tox a -> Ptr Word32 -> IO ()--toxConferenceGetChatlist :: Tox a -> IO [Word32]-toxConferenceGetChatlist tox = do- chatListSize <- tox_conference_get_chatlist_size tox- allocaArray (fromIntegral chatListSize) $ \chatListPtr -> do- tox_conference_get_chatlist tox chatListPtr- peekArray (fromIntegral chatListSize) chatListPtr---- | Returns the type of conference (TOX_CONFERENCE_TYPE) that conference_number is. Return value is--- unspecified on failure.-data ErrConferenceGetType- = ErrConferenceGetTypeOk- -- The function returned successfully.-- | ErrConferenceGetTypeConferenceNotFound- -- The conference number passed did not designate a valid conference.- deriving (Eq, Ord, Enum, Bounded, Read, Show)--foreign import ccall tox_conference_get_type :: Tox a -> Word32 -> CErr ErrConferenceGetType -> IO (CEnum ConferenceType)-callConferenceGetType :: (Tox a -> Word32 -> CErr ErrConferenceGetType -> IO (CEnum ConferenceType)) ->- Tox a -> Word32 -> IO (Either ErrConferenceGetType ConferenceType)-callConferenceGetType f tox gn = callErrFun (f tox gn >=> (return . fromCEnum))--toxConferenceGetType :: Tox a -> Word32 -> IO (Either ErrConferenceGetType ConferenceType)-toxConferenceGetType = callConferenceGetType tox_conference_get_type----------------------------------------------------------------------------------------- :: 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-callFriendLossyPacket :: (Tox a -> Word32 -> CString -> CSize -> CErr ErrFriendCustomPacket -> IO Bool) ->- Tox a -> Word32 -> BS.ByteString -> IO (Either ErrFriendCustomPacket Bool)-callFriendLossyPacket f tox fn d =- BS.useAsCStringLen d $ \(dataPtr, dataLen) ->- callErrFun $ f tox fn dataPtr (fromIntegral dataLen)--toxFriendLossyPacket :: Tox a -> Word32 -> BS.ByteString -> IO (Either ErrFriendCustomPacket Bool)-toxFriendLossyPacket = callFriendLossyPacket tox_friend_send_lossy_packet---- | 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-callFriendLosslessPacket :: (Tox a -> Word32 -> CString -> CSize -> CErr ErrFriendCustomPacket -> IO Bool) ->- Tox a -> Word32 -> BS.ByteString -> IO (Either ErrFriendCustomPacket Bool)-callFriendLosslessPacket f tox fn d =- BS.useAsCStringLen d $ \(dataPtr, dataLen) ->- callErrFun $ f tox fn dataPtr (fromIntegral dataLen)--toxFriendLosslessPacket :: Tox a -> Word32 -> BS.ByteString -> IO (Either ErrFriendCustomPacket Bool)-toxFriendLosslessPacket = callFriendLosslessPacket tox_friend_send_lossless_packet--callFriendCustomPacketCb :: FriendLosslessPacketCb a -> CFriendLosslessPacketCb a-callFriendCustomPacketCb f tox fn dataPtr dataLen udPtr = do- ud <- deRefStablePtr udPtr- d <- BS.packCStringLen (dataPtr, fromIntegral dataLen)- modifyMVar_ ud $ f tox fn d---- | @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 -> BS.ByteString -> a -> IO a-type CFriendLossyPacketCb a = Tox a -> Word32 -> CString -> CSize -> UserData a -> IO ()-foreign import ccall "wrapper" wrapFriendLossyPacketCb :: CFriendLossyPacketCb a -> IO (FunPtr (CFriendLossyPacketCb a))--callFriendLossyPacketCb :: FriendLossyPacketCb a -> CFriendLossyPacketCb a-callFriendLossyPacketCb = callFriendCustomPacketCb--friendLossyPacketCb :: FriendLossyPacketCb a -> IO (FunPtr (CFriendLossyPacketCb a))-friendLossyPacketCb = wrapFriendLossyPacketCb . callFriendLossyPacketCb----- | Set the callback for the `friend_lossy_packet` event. Pass 'nullPtr' to--- unset.----foreign import ccall tox_callback_friend_lossy_packet :: Tox a -> FunPtr (CFriendLossyPacketCb 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 -> BS.ByteString -> a -> IO a-type CFriendLosslessPacketCb a = Tox a -> Word32 -> CString -> CSize -> UserData a -> IO ()-foreign import ccall "wrapper" wrapFriendLosslessPacketCb :: CFriendLosslessPacketCb a -> IO (FunPtr (CFriendLosslessPacketCb a))--callFriendLosslessPacketCb :: FriendLosslessPacketCb a -> CFriendLosslessPacketCb a-callFriendLosslessPacketCb = callFriendCustomPacketCb--friendLosslessPacketCb :: FriendLosslessPacketCb a -> IO (FunPtr (CFriendLosslessPacketCb a))-friendLosslessPacketCb = wrapFriendLosslessPacketCb . callFriendLosslessPacketCb----- | Set the callback for the `friend_lossless_packet` event. Pass 'nullPtr' to--- unset.----foreign import ccall tox_callback_friend_lossless_packet :: Tox a -> FunPtr (CFriendLosslessPacketCb 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 ()--toxSelfGetDhtId :: Tox a -> IO BS.ByteString-toxSelfGetDhtId tox =- let idLen = fromIntegral tox_public_key_size in- allocaArray idLen $ \idPtr -> do- tox_self_get_dht_id tox idPtr- BS.packCStringLen (idPtr, idLen)--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-callSelfGetUdpPort :: (Tox a -> CErr ErrGetPort -> IO Word16) ->- Tox a -> IO (Either ErrGetPort Word16)-callSelfGetUdpPort f tox = callErrFun $ f tox--toxSelfGetUdpPort :: Tox a -> IO (Either ErrGetPort Word16)-toxSelfGetUdpPort = callSelfGetUdpPort tox_self_get_udp_port---- | 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-callSelfGetTcpPort :: (Tox a -> CErr ErrGetPort -> IO Word16) ->- Tox a -> IO (Either ErrGetPort Word16)-callSelfGetTcpPort f tox = callErrFun $ f tox--toxSelfGetTcpPort :: Tox a -> IO (Either ErrGetPort Word16)-toxSelfGetTcpPort = callSelfGetTcpPort tox_self_get_udp_port+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE StrictData #-}+-- | 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.Exception (bracket)+import Control.Monad ((>=>))+import qualified Data.ByteString as BS+import qualified Data.ByteString.Lazy as LBS+import qualified Data.MessagePack as MP+import Data.Word (Word16, Word32, Word64)+import Foreign.C.Enum+import Foreign.C.String (CString, withCString)+import Foreign.C.Types (CTime (..))+import Foreign.Marshal.Array (allocaArray, peekArray)+import Foreign.Ptr (Ptr, nullPtr)+import System.Posix.Types (EpochTime)++import FFI.Tox.Tox (ConferenceType, Connection,+ ErrBootstrap (..),+ ErrConferenceDelete (..),+ ErrConferenceGetType (..),+ ErrConferenceInvite (..),+ ErrConferenceJoin (..),+ ErrConferenceNew (..),+ ErrConferencePeerQuery (..),+ ErrConferenceSendMessage (..),+ ErrConferenceTitle (..),+ ErrFileControl (..), ErrFileGet (..),+ ErrFileSeek (..), ErrFileSend (..),+ ErrFileSendChunk (..),+ ErrFriendAdd (..),+ ErrFriendByPublicKey (..),+ ErrFriendCustomPacket (..),+ ErrFriendDelete (..),+ ErrFriendGetLastOnline (..),+ ErrFriendGetPublicKey (..),+ ErrFriendQuery (..),+ ErrFriendSendMessage (..),+ ErrGetPort (..), ErrNew (..),+ ErrSetInfo (..), ErrSetTyping (..),+ FileControl, FileKind (..),+ MessageType, ToxPtr, UserStatus,+ tox_add_tcp_relay, tox_bootstrap,+ tox_conference_delete,+ tox_conference_get_chatlist,+ tox_conference_get_chatlist_size,+ tox_conference_get_title,+ tox_conference_get_title_size,+ tox_conference_get_type,+ tox_conference_invite,+ tox_conference_join,+ tox_conference_new,+ tox_conference_peer_count,+ tox_conference_peer_get_name,+ tox_conference_peer_get_name_size,+ tox_conference_peer_get_public_key,+ tox_conference_peer_number_is_ours,+ tox_conference_send_message,+ tox_conference_set_title,+ tox_file_control,+ tox_file_get_file_id, tox_file_seek,+ tox_file_send, tox_file_send_chunk,+ tox_friend_add,+ tox_friend_add_norequest,+ tox_friend_by_public_key,+ tox_friend_delete, tox_friend_exists,+ tox_friend_get_connection_status,+ tox_friend_get_last_online,+ tox_friend_get_name,+ tox_friend_get_name_size,+ tox_friend_get_public_key,+ tox_friend_get_status_message,+ tox_friend_get_status_message_size,+ tox_friend_get_typing,+ tox_friend_send_lossless_packet,+ tox_friend_send_lossy_packet,+ tox_friend_send_message,+ tox_get_savedata,+ tox_get_savedata_size, tox_hash,+ tox_iteration_interval, tox_kill,+ tox_new, tox_self_get_address,+ tox_self_get_dht_id,+ tox_self_get_friend_list,+ tox_self_get_friend_list_size,+ tox_self_get_name,+ tox_self_get_name_size,+ tox_self_get_nospam,+ tox_self_get_public_key,+ tox_self_get_secret_key,+ tox_self_get_status_message,+ tox_self_get_status_message_size,+ tox_self_get_tcp_port,+ tox_self_get_udp_port,+ tox_self_set_name,+ tox_self_set_nospam,+ tox_self_set_status,+ tox_self_set_status_message,+ tox_self_set_typing)+import Network.Tox.C.Constants+import Network.Tox.C.Options+import Network.Tox.Types.Events (Event)+++--------------------------------------------------------------------------------+--+-- :: Global types+--+--------------------------------------------------------------------------------++-- Should we introduce such types?+-- newtype FriendNum = FriendNum { friendNum :: Word32 } deriving (Eq, Ord, Read, Show)+-- newtype ConferenceNum = ConferenceNum { conferenceNum :: Word32 } deriving (Eq, Ord, Read, Show)+-- newtype PeerNum = PeerNum { peerNum :: Word32 } deriving (Eq, Ord, Read, Show)+-- newtype FileNum = FileNum { fileNum :: Word32 } deriving (Eq, Ord, Read, Show)+++--------------------------------------------------------------------------------+--+-- :: Creation and destruction+--+--------------------------------------------------------------------------------++withTox :: Options -> (ToxPtr -> IO a) -> IO (Either ErrNew a)+withTox opts f =+ fmap mapErr . withOptions opts $ \copts -> do+ result <- callErrFun . tox_new $ copts+ case result of+ Left err ->+ return $ Left err+ Right tox -> do+ tox_events_init tox+ res <- f tox+ tox_kill tox+ return $ Right res++ where+ mapErr (Left ErrOptionsNewMalloc) = Left ErrNewMalloc+ mapErr (Right ok) = ok++toxGetSavedata :: ToxPtr -> IO BS.ByteString+toxGetSavedata tox = do+ savedataLen <- tox_get_savedata_size tox+ allocaArray (fromIntegral savedataLen) $ \savedataPtr -> do+ tox_get_savedata tox savedataPtr+ BS.packCStringLen (savedataPtr, fromIntegral savedataLen)+++--------------------------------------------------------------------------------+--+-- :: Connection lifecycle and event loop+--+--------------------------------------------------------------------------------+++-- | 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 Options.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.+toxBootstrap :: ToxPtr -> String -> Word16 -> BS.ByteString -> IO (Either ErrBootstrap Bool)+toxBootstrap tox address port pubKey =+ withCString address $ \address' ->+ BS.useAsCString pubKey $ \pubKey' ->+ callErrFun $ tox_bootstrap tox address' (fromIntegral port) pubKey'+++-- | 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.+toxAddTcpRelay :: ToxPtr -> String -> Word16 -> BS.ByteString -> IO (Either ErrBootstrap Bool)+toxAddTcpRelay tox address port pubKey =+ withCString address $ \address' ->+ BS.useAsCString pubKey $ \pubKey' ->+ callErrFun $ tox_add_tcp_relay tox address' (fromIntegral port) pubKey'+++data ToxEventsStruct+type ToxEvents = Ptr ToxEventsStruct++-- | Common error codes for all functions that set a piece of user-visible+-- client information.+data ErrEventsIterate+ = ErrEventsIterateMalloc+ -- The function failed to allocate enough memory to store the events.++ | ErrEventsDecode+ -- Failed to encode or decode events in msgpack.+ deriving (Eq, Ord, Enum, Bounded, Read, Show)++foreign import ccall tox_events_init :: ToxPtr -> IO ()+foreign import ccall tox_events_iterate :: ToxPtr -> Bool -> CErr ErrEventsIterate -> IO ToxEvents++foreign import ccall tox_events_bytes_size :: ToxEvents -> IO Word32+foreign import ccall tox_events_get_bytes :: ToxEvents -> CString -> IO ()++foreign import ccall tox_events_load :: CString -> Word32 -> IO ToxEvents+foreign import ccall tox_events_free :: ToxEvents -> IO ()++toxEventsToPtr :: [Event] -> IO ToxEvents+toxEventsToPtr events =+ let encoded = MP.pack events in+ BS.useAsCStringLen (LBS.toStrict encoded) $ \(ptr, len) ->+ tox_events_load ptr (fromIntegral len)++toxEventsFromPtr :: ToxEvents -> IO (Either String [Event])+toxEventsFromPtr evPtr = do+ bytes <- bracket (return evPtr) tox_events_free $ const $ do+ len <- tox_events_bytes_size evPtr+ allocaArray (fromIntegral len) $ \ptr -> do+ tox_events_get_bytes evPtr ptr+ BS.packCStringLen (ptr, fromIntegral len)+ case MP.unpackEither $ LBS.fromStrict bytes of+ Left err -> do+ print (MP.unpackEither $ LBS.fromStrict bytes :: Either MP.DecodeError MP.Object)+ return $ Left $ show err+ Right ok -> return $ Right ok++toxEventsIterate :: ToxPtr -> IO (Either String [Event])+toxEventsIterate tox =+ callErrFun (tox_events_iterate tox True) >>= \case+ Left err -> return $ Left $ show err+ Right evPtr -> toxEventsFromPtr evPtr+++-- | Return the time in milliseconds before tox_iterate() should be called again+-- for optimal performance.+toxIterationInterval :: ToxPtr -> IO Word32+toxIterationInterval = tox_iteration_interval++--------------------------------------------------------------------------------+--+-- :: 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.+toxSelfGetAddress :: ToxPtr -> IO BS.ByteString+toxSelfGetAddress tox =+ let addrLen = fromIntegral tox_address_size in+ allocaArray addrLen $ \addrPtr -> do+ tox_self_get_address tox addrPtr+ BS.packCStringLen (addrPtr, addrLen)++-- | Set the 4-byte nospam part of the address.+--+-- @param nospam Any 32 bit unsigned integer.+toxSelfSetNospam :: ToxPtr -> Word32 -> IO ()+toxSelfSetNospam = tox_self_set_nospam++-- | Get the 4-byte nospam part of the address.+toxSelfGetNospam :: ToxPtr -> IO Word32+toxSelfGetNospam = tox_self_get_nospam++-- | 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.+toxSelfGetPublicKey :: ToxPtr -> IO BS.ByteString+toxSelfGetPublicKey tox =+ let pkLen = fromIntegral tox_public_key_size in+ allocaArray pkLen $ \pkPtr -> do+ tox_self_get_public_key tox pkPtr+ BS.packCStringLen (pkPtr, pkLen)++-- | 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.+toxSelfGetSecretKey :: ToxPtr -> IO BS.ByteString+toxSelfGetSecretKey tox =+ let skLen = fromIntegral tox_secret_key_size in+ allocaArray skLen $ \skPtr -> do+ tox_self_get_secret_key tox skPtr+ BS.packCStringLen (skPtr, skLen)+++--------------------------------------------------------------------------------+--+-- :: User-visible client information (nickname/status)+--+--------------------------------------------------------------------------------+++-- | 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.+toxSelfSetName :: ToxPtr -> BS.ByteString -> IO (Either ErrSetInfo Bool)+toxSelfSetName tox name =+ BS.useAsCStringLen name $ \(nameStr, nameLen) ->+ callErrFun $ tox_self_set_name tox nameStr (fromIntegral nameLen)++-- | Write the nickname set by tox_self_set_name to a byte array.+--+-- If no nickname was set before calling this function, the name is empty,+-- and this function has no effect.+--+-- Call tox_self_get_name_size to find out how much memory to allocate for+-- the result.+--+-- @param name A valid memory location large enough to hold the nickname.+-- If this parameter is NULL, the function has no effect.+toxSelfGetName :: ToxPtr -> IO BS.ByteString+toxSelfGetName tox = do+ nameLen <- tox_self_get_name_size tox+ allocaArray (fromIntegral nameLen) $ \namePtr -> do+ tox_self_get_name tox namePtr+ BS.packCStringLen (namePtr, fromIntegral nameLen)+++-- | 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.+toxSelfSetStatusMessage :: ToxPtr -> BS.ByteString -> IO (Either ErrSetInfo Bool)+toxSelfSetStatusMessage tox statusMsg =+ BS.useAsCStringLen statusMsg $ \(statusMsgStr, statusMsgLen) ->+ callErrFun $ tox_self_set_status_message tox statusMsgStr (fromIntegral statusMsgLen)+++-- | Write the status message set by tox_self_set_status_message to a byte array.+--+-- If no status message was set before calling this function, the status is+-- empty, and this function has no effect.+--+-- Call tox_self_get_status_message_size to find out how much memory to allocate for+-- the result.+--+-- @param status_message A valid memory location large enough to hold the+-- status message. If this parameter is NULL, the function has no effect.+toxSelfGetStatusMessage :: ToxPtr -> IO BS.ByteString+toxSelfGetStatusMessage tox = do+ statusMessageLen <- tox_self_get_status_message_size tox+ allocaArray (fromIntegral statusMessageLen) $ \statusMessagePtr -> do+ tox_self_get_status_message tox statusMessagePtr+ BS.packCStringLen (statusMessagePtr, fromIntegral statusMessageLen)+++-- | Set the client's user status.+--+-- @param user_status One of the user statuses listed in the enumeration above.+toxSelfSetStatus :: ToxPtr -> UserStatus -> IO ()+toxSelfSetStatus tox userStatus =+ tox_self_set_status tox $ toCEnum userStatus+++--------------------------------------------------------------------------------+--+-- :: Friend list management+--+--------------------------------------------------------------------------------+++-- | 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.+toxFriendAdd :: ToxPtr -> BS.ByteString -> BS.ByteString -> IO (Either ErrFriendAdd Word32)+toxFriendAdd tox address message =+ BS.useAsCStringLen message $ \(msgStr, msgLen) ->+ BS.useAsCString address $ \addr' ->+ callErrFun $ tox_friend_add tox addr' msgStr (fromIntegral msgLen)++-- | 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.+toxFriendAddNorequest :: ToxPtr -> BS.ByteString -> IO (Either ErrFriendAdd Word32)+toxFriendAddNorequest tox address =+ BS.useAsCString address $ \addr' ->+ callErrFun $ tox_friend_add_norequest tox addr'+++-- | 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.+toxFriendDelete :: ToxPtr -> Word32 -> IO (Either ErrFriendDelete Bool)+toxFriendDelete tox fn = callErrFun $ tox_friend_delete tox fn+++--------------------------------------------------------------------------------+--+-- :: Friend list queries+--+--------------------------------------------------------------------------------+++-- | 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.+toxFriendByPublicKey :: ToxPtr -> BS.ByteString -> IO (Either ErrFriendByPublicKey Word32)+toxFriendByPublicKey tox address =+ BS.useAsCString address $ \addr' ->+ callErrFun $ tox_friend_by_public_key tox addr'++-- | Checks if a friend with the given friend number exists and returns true if+-- it does.+toxFriendExists :: ToxPtr -> Word32 -> IO Bool+toxFriendExists = tox_friend_exists++-- | 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.+toxSelfGetFriendList :: ToxPtr -> IO [Word32]+toxSelfGetFriendList tox = do+ friendListSize <- tox_self_get_friend_list_size tox+ allocaArray (fromIntegral friendListSize) $ \friendListPtr -> do+ tox_self_get_friend_list tox friendListPtr+ peekArray (fromIntegral friendListSize) friendListPtr+++-- | 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.+toxFriendGetPublicKey :: ToxPtr -> Word32 -> IO (Either ErrFriendGetPublicKey BS.ByteString)+toxFriendGetPublicKey tox fn =+ let pkLen = fromIntegral tox_public_key_size in+ allocaArray pkLen $ \pkPtr -> do+ nameRes <- callErrFun $ tox_friend_get_public_key tox fn pkPtr+ case nameRes of+ Left err -> return $ Left err+ Right _ -> Right <$> BS.packCStringLen (pkPtr, pkLen)+++-- | Return a unix-time timestamp of the last time the friend associated with a given+-- friend number was seen online. This function will return UINT64_MAX on error.+--+-- @param friend_number The friend number you want to query.+toxFriendGetLastOnline :: ToxPtr -> Word32 -> IO (Either ErrFriendGetLastOnline EpochTime)+toxFriendGetLastOnline tox fn =+ callErrFun (tox_friend_get_last_online tox fn >=> (return . CTime . fromIntegral))+++--------------------------------------------------------------------------------+--+-- :: Friend-specific state queries (can also be received through callbacks)+--+--------------------------------------------------------------------------------+++-- | Write the name of the friend designated by the given friend number to a byte+-- array.+--+-- Call tox_friend_get_name_size to determine the allocation size for the `name`+-- parameter.+--+-- The data written to `name` is equal to the data received by the last+-- `friend_name` callback.+--+-- @param name A valid memory region large enough to store the friend's name.+--+-- @return true on success.+toxFriendGetName :: ToxPtr -> Word32 -> IO (Either ErrFriendQuery BS.ByteString)+toxFriendGetName tox fn = do+ nameLenRes <- callErrFun $ tox_friend_get_name_size tox fn+ case nameLenRes of+ Left err -> return $ Left err+ Right nameLen -> allocaArray (fromIntegral nameLen) $ \namePtr -> do+ nameRes <- callErrFun $ tox_friend_get_name tox fn namePtr+ case nameRes of+ Left err -> return $ Left err+ Right _ -> Right <$> BS.packCStringLen (namePtr, fromIntegral nameLen)+++-- | Write the status message of the friend designated by the given friend number to a byte+-- array.+--+-- Call tox_friend_get_status_message_size to determine the allocation size for the `status_name`+-- parameter.+--+-- The data written to `status_message` is equal to the data received by the last+-- `friend_status_message` callback.+--+-- @param status_message A valid memory region large enough to store the friend's status message.+toxFriendGetStatusMessage :: ToxPtr -> Word32 -> IO (Either ErrFriendQuery BS.ByteString)+toxFriendGetStatusMessage tox fn = do+ statusMessageLenRes <- callErrFun $ tox_friend_get_status_message_size tox fn+ case statusMessageLenRes of+ Left err -> return $ Left err+ Right statusMessageLen -> allocaArray (fromIntegral statusMessageLen) $ \statusMessagePtr -> do+ statusMessageRes <- callErrFun $ tox_friend_get_status_message tox fn statusMessagePtr+ case statusMessageRes of+ Left err -> return $ Left err+ Right _ -> Right <$> BS.packCStringLen (statusMessagePtr, fromIntegral statusMessageLen)+++-- | Check whether a friend is currently connected to this client.+--+-- The result of this function is equal to the last value received by the+-- `friend_connection_status` callback.+--+-- @param friend_number The friend number for which to query the connection+-- status.+--+-- @return the friend's connection status as it was received through the+-- `friend_connection_status` event.+toxFriendGetConnectionStatus :: ToxPtr -> Word32 -> IO (Either ErrFriendQuery Connection)+toxFriendGetConnectionStatus tox fn =+ callErrFun (tox_friend_get_connection_status tox fn >=> return . fromCEnum)+++-- | Check whether a friend is currently typing a message.+--+-- @param friend_number The friend number for which to query the typing status.+--+-- @return true if the friend is typing.+-- @return false if the friend is not typing, or the friend number was+-- invalid. Inspect the error code to determine which case it is.+toxFriendGetTyping :: ToxPtr -> Word32 -> IO (Either ErrFriendQuery Bool)+toxFriendGetTyping tox fn = callErrFun $ tox_friend_get_typing tox fn+++--------------------------------------------------------------------------------+--+-- :: Sending private messages+--+--------------------------------------------------------------------------------+++-- | 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.+toxSelfSetTyping :: ToxPtr -> Word32 -> Bool -> IO (Either ErrSetTyping Bool)+toxSelfSetTyping tox fn typing = callErrFun $ tox_self_set_typing tox fn typing+++-- | 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.+toxFriendSendMessage :: ToxPtr -> Word32 -> MessageType -> BS.ByteString -> IO (Either ErrFriendSendMessage Word32)+toxFriendSendMessage tox fn messageType message =+ BS.useAsCStringLen message $ \(msgStr, msgLen) ->+ callErrFun $ tox_friend_send_message tox fn (toCEnum messageType) msgStr (fromIntegral msgLen)+++--------------------------------------------------------------------------------+--+-- :: 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'.+toxHash :: BS.ByteString -> IO BS.ByteString+toxHash d =+ let hashLen = fromIntegral tox_hash_length in+ allocaArray hashLen $ \hashPtr ->+ BS.useAsCStringLen d $ \(dataPtr, dataLen) -> do+ _ <- tox_hash hashPtr dataPtr (fromIntegral dataLen)+ BS.packCStringLen (dataPtr, fromIntegral dataLen)+++-- | 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.+toxFileControl :: ToxPtr -> Word32 -> Word32 -> FileControl -> IO (Either ErrFileControl Bool)+toxFileControl tox fn fileNum control = callErrFun $ tox_file_control tox fn fileNum (toCEnum control)+++-- | 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.+toxFileSeek :: ToxPtr -> Word32 -> Word32 -> Word64 -> IO (Either ErrFileSeek Bool)+toxFileSeek tox fn fileNum pos = callErrFun $ tox_file_seek tox fn fileNum pos+++-- | 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.+toxFileGetFileId :: ToxPtr -> Word32 -> Word32 -> IO (Either ErrFileGet BS.ByteString)+toxFileGetFileId tox fn fileNum =+ let fileIdLen = fromIntegral tox_file_id_length in+ allocaArray fileIdLen $ \fileIdPtr -> do+ idRes <- callErrFun $ tox_file_get_file_id tox fn fileNum fileIdPtr+ case idRes of+ Left err -> return $ Left err+ Right _ -> Right <$> BS.packCStringLen (fileIdPtr, fileIdLen)+++--------------------------------------------------------------------------------+--+-- :: File transmission: sending+--+--------------------------------------------------------------------------------+++-- | 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.+toxFileSend :: ToxPtr -> Word32 -> FileKind -> Word64 -> BS.ByteString -> IO (Either ErrFileSend Word32)+toxFileSend tox fn fileKind fileSize fileName =+ BS.useAsCStringLen fileName $ \(fileNamePtr, fileNameLen) ->+ callErrFun $ tox_file_send tox fn (fromIntegral $ fromEnum fileKind) fileSize nullPtr fileNamePtr (fromIntegral fileNameLen)+++-- | 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.+toxFileSendChunk :: ToxPtr -> Word32 -> Word32 -> Word64 -> BS.ByteString -> IO (Either ErrFileSendChunk Bool)+toxFileSendChunk tox fn fileNum pos d =+ BS.useAsCStringLen d $ \(dataPtr, dataLen) ->+ callErrFun $ tox_file_send_chunk tox fn fileNum pos dataPtr (fromIntegral dataLen)+++--------------------------------------------------------------------------------+--+-- :: Conference management+--+--------------------------------------------------------------------------------+++-- | Creates a new conference.+--+-- This function creates a new text conference.+--+-- @return conference number on success, or UINT32_MAX on failure.+toxConferenceNew :: ToxPtr -> IO (Either ErrConferenceNew Word32)+toxConferenceNew tox = callErrFun $ tox_conference_new tox+++-- | This function deletes a conference.+--+-- @param conference_number The conference number of the conference to be deleted.+--+-- @return true on success.+toxConferenceDelete :: ToxPtr -> Word32 -> IO (Either ErrConferenceDelete Bool)+toxConferenceDelete tox gn = callErrFun $ tox_conference_delete tox gn+++-- | Return the number of peers in the conference. Return value is unspecified on failure.+toxConferencePeerCount :: ToxPtr -> Word32 -> IO (Either ErrConferencePeerQuery Word32)+toxConferencePeerCount tox gn = callErrFun $ tox_conference_peer_count tox gn+++-- | Copy the name of peer_number who is in conference_number to name.+-- name must be at least TOX_MAX_NAME_LENGTH long.+--+-- @return true on success.+toxConferencePeerGetName :: ToxPtr -> Word32 -> Word32 -> IO (Either ErrConferencePeerQuery BS.ByteString)+toxConferencePeerGetName tox gn pn = do+ nameLenRes <- callErrFun $ tox_conference_peer_get_name_size tox gn pn+ case nameLenRes of+ Left err -> return $ Left err+ Right nameLen -> allocaArray (fromIntegral nameLen) $ \namePtr -> do+ nameRes <- callErrFun $ tox_conference_peer_get_name tox gn pn namePtr+ case nameRes of+ Left err -> return $ Left err+ Right _ -> Right <$> BS.packCStringLen (namePtr, fromIntegral nameLen)+++-- | Copy the public key of peer_number who is in conference_number to public_key.+-- public_key must be TOX_PUBLIC_KEY_SIZE long.+--+-- @return true on success.+toxConferencePeerGetPublicKey :: ToxPtr -> Word32 -> Word32 -> IO (Either ErrConferencePeerQuery BS.ByteString)+toxConferencePeerGetPublicKey tox gn pn =+ let pkLen = fromIntegral tox_public_key_size in+ allocaArray pkLen $ \pkPtr -> do+ nameRes <- callErrFun $ tox_conference_peer_get_public_key tox gn pn pkPtr+ case nameRes of+ Left err -> return $ Left err+ Right _ -> Right <$> BS.packCStringLen (pkPtr, pkLen)+++-- | Return true if passed peer_number corresponds to our own.+toxConferencePeerNumberIsOurs :: ToxPtr -> Word32 -> Word32 -> IO (Either ErrConferencePeerQuery Bool)+toxConferencePeerNumberIsOurs tox gn pn = callErrFun $ tox_conference_peer_number_is_ours tox gn pn+++-- | Invites a friend to a conference.+--+-- @param friend_number The friend number of the friend we want to invite.+-- @param conference_number The conference number of the conference we want to invite the friend to.+--+-- @return true on success.+toxConferenceInvite :: ToxPtr -> Word32 -> Word32 -> IO (Either ErrConferenceInvite Bool)+toxConferenceInvite tox fn gn = callErrFun $ tox_conference_invite tox fn gn+++-- | Joins a conference that the client has been invited to.+--+-- @param friend_number The friend number of the friend who sent the invite.+-- @param cookie Received via the `conference_invite` event.+-- @param length The size of cookie.+--+-- @return conference number on success, UINT32_MAX on failure.+toxConferenceJoin :: ToxPtr -> Word32 -> BS.ByteString -> IO (Either ErrConferenceJoin Word32)+toxConferenceJoin tox fn cookie =+ BS.useAsCStringLen cookie $ \(cookiePtr, cookieLen) ->+ callErrFun $ tox_conference_join tox fn cookiePtr (fromIntegral cookieLen)+++-- | Send a text chat message to the conference.+--+-- This function creates a conference 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.+--+-- @param conference_number The conference number of the conference the message is intended for.+-- @param type Message type (normal, action, ...).+-- @param message A non-NULL pointer to the first element of a byte array+-- containing the message text.+-- @param length Length of the message to be sent.+--+-- @return true on success.+toxConferenceSendMessage :: ToxPtr -> Word32 -> MessageType -> BS.ByteString -> IO (Either ErrConferenceSendMessage Bool)+toxConferenceSendMessage tox gn messageType message =+ BS.useAsCStringLen message $ \(msgPtr, msgLen) ->+ callErrFun $ tox_conference_send_message tox gn (toCEnum messageType) msgPtr (fromIntegral msgLen)+++-- | Write the title designated by the given conference number to a byte array.+--+-- Call tox_conference_get_title_size to determine the allocation size for the `title` parameter.+--+-- The data written to `title` is equal to the data received by the last+-- `conference_title` callback.+--+-- @param title A valid memory region large enough to store the title.+-- If this parameter is NULL, this function has no effect.+--+-- @return true on success.+toxConferenceGetTitle :: ToxPtr -> Word32 -> IO (Either ErrConferenceTitle BS.ByteString)+toxConferenceGetTitle tox gn = do+ titleLenRes <- callErrFun $ tox_conference_get_title_size tox gn+ case titleLenRes of+ Left err -> return $ Left err+ Right titleLen -> allocaArray (fromIntegral titleLen) $ \titlePtr -> do+ titleRes <- callErrFun $ tox_conference_get_title tox gn titlePtr+ case titleRes of+ Left err -> return $ Left err+ Right _ -> Right <$> BS.packCStringLen (titlePtr, fromIntegral titleLen)++-- | Set the conference title and broadcast it to the rest of the conference.+--+-- Title length cannot be longer than TOX_MAX_NAME_LENGTH.+--+-- @return true on success.+toxConferenceSetTitle :: ToxPtr -> Word32 -> BS.ByteString -> IO (Either ErrConferenceTitle Bool)+toxConferenceSetTitle tox gn title =+ BS.useAsCStringLen title $ \(titlePtr, titleLen) ->+ callErrFun $ tox_conference_set_title tox gn titlePtr (fromIntegral titleLen)+++-- | Copy a list of valid conference IDs into the array chatlist. Determine how much space+-- to allocate for the array with the `tox_conference_get_chatlist_size` function.+toxConferenceGetChatlist :: ToxPtr -> IO [Word32]+toxConferenceGetChatlist tox = do+ chatListSize <- tox_conference_get_chatlist_size tox+ allocaArray (fromIntegral chatListSize) $ \chatListPtr -> do+ tox_conference_get_chatlist tox chatListPtr+ peekArray (fromIntegral chatListSize) chatListPtr++toxConferenceGetType :: ToxPtr -> Word32 -> IO (Either ErrConferenceGetType ConferenceType)+toxConferenceGetType tox gn = callErrFun (tox_conference_get_type tox gn >=> (return . fromCEnum))+++--------------------------------------------------------------------------------+--+-- :: Low-level custom packet sending and receiving+--+--------------------------------------------------------------------------------+++-- | 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.+toxFriendLossyPacket :: ToxPtr -> Word32 -> BS.ByteString -> IO (Either ErrFriendCustomPacket Bool)+toxFriendLossyPacket tox fn d =+ BS.useAsCStringLen d $ \(dataPtr, dataLen) ->+ callErrFun $ tox_friend_send_lossy_packet tox fn dataPtr (fromIntegral dataLen)++-- | 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.+toxFriendLosslessPacket :: ToxPtr -> Word32 -> BS.ByteString -> IO (Either ErrFriendCustomPacket Bool)+toxFriendLosslessPacket tox fn d =+ BS.useAsCStringLen d $ \(dataPtr, dataLen) ->+ callErrFun $ tox_friend_send_lossless_packet tox fn dataPtr (fromIntegral dataLen)+++--------------------------------------------------------------------------------+--+-- :: 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.+toxSelfGetDhtId :: ToxPtr -> IO BS.ByteString+toxSelfGetDhtId tox =+ let idLen = fromIntegral tox_public_key_size in+ allocaArray idLen $ \idPtr -> do+ tox_self_get_dht_id tox idPtr+ BS.packCStringLen (idPtr, idLen)++-- | Return the UDP port this Tox instance is bound to.+toxSelfGetUdpPort :: ToxPtr -> IO (Either ErrGetPort Word16)+toxSelfGetUdpPort tox = callErrFun $ tox_self_get_udp_port tox++-- | Return the TCP port this Tox instance is bound to. This is only relevant if+-- the instance is acting as a TCP relay.+toxSelfGetTcpPort :: ToxPtr -> IO (Either ErrGetPort Word16)+toxSelfGetTcpPort tox = callErrFun $ tox_self_get_tcp_port tox
src/Network/Tox/C/Type.hs view
@@ -1,17 +1,24 @@-{-# LANGUAGE Safe #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE StrictData #-} module Network.Tox.C.Type where -import Control.Concurrent.MVar (MVar)-import Foreign.Ptr (Ptr)-import Foreign.StablePtr (StablePtr)+import qualified Data.ByteString as BS+import Data.MessagePack (MessagePack)+import GHC.Generics (Generic)+import GHC.TypeNats (Nat)+import Test.QuickCheck.Arbitrary (Arbitrary (..)) --- | 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)+newtype FixedByteString (size :: Nat) = FixedByteString BS.ByteString+ deriving (Ord, Eq, Show, Generic) -type UserData a = StablePtr (MVar a)+instance MessagePack (FixedByteString size)++instance Arbitrary (FixedByteString size) where+ arbitrary = pure $ FixedByteString "00000000000000000000000000000000"+++type PublicKey = FixedByteString 32
src/Network/Tox/C/Version.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE Trustworthy #-}+{-# LANGUAGE StrictData #-} module Network.Tox.C.Version where import Data.Word (Word32)
+ src/Network/Tox/Types/Events.hs view
@@ -0,0 +1,88 @@+{-# OPTIONS_GHC -fconstraint-solver-iterations=10 #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE StrictData #-}+module Network.Tox.Types.Events where++import qualified Data.ByteString as BS+import Data.MessagePack (MessagePack)+import Data.Word (Word16, Word32, Word64)+import FFI.Tox.Tox (ConferenceType,+ Connection, FileControl,+ GroupExitType,+ GroupJoinFail,+ GroupModEvent,+ GroupPrivacyState,+ GroupTopicLock,+ GroupVoiceState,+ MessageType, UserStatus)+import GHC.Generics (Generic)+import Network.Tox.C.Type (PublicKey)+import Test.QuickCheck.Arbitrary (Arbitrary (..))+import Test.QuickCheck.Arbitrary.Generic (genericArbitrary,+ genericShrink)+import Test.QuickCheck.Instances.ByteString ()+++data Event+ = SelfConnectionStatus { connectionStatus :: Connection }++ | FriendRequest { publicKey :: PublicKey, message :: BS.ByteString }+ | FriendConnectionStatus { friendNumber :: Word32, connectionStatus :: Connection }+ | FriendLossyPacket { friendNumber :: Word32, data' :: BS.ByteString }+ | FriendLosslessPacket { friendNumber :: Word32, data' :: BS.ByteString }++ | FriendName { friendNumber :: Word32, name :: BS.ByteString }+ | FriendStatus { friendNumber :: Word32, status :: UserStatus }+ | FriendStatusMessage { friendNumber :: Word32, statusMessage :: BS.ByteString }++ | FriendMessage { friendNumber :: Word32, messageType :: MessageType, message :: BS.ByteString }+ | FriendReadReceipt { friendNumber :: Word32, messageId :: Word32 }+ | FriendTyping { friendNumber :: Word32, typing :: Bool }++ | FileChunkRequest { friendNumber :: Word32, fileNumber :: Word32, position :: Word64, length :: Word16 }+ | FileRecv { friendNumber :: Word32, fileNumber :: Word32, kind :: Word32, fileSize :: Word64, filename :: BS.ByteString }+ | FileRecvChunk { friendNumber :: Word32, fileNumber :: Word32, position :: Word64, data' :: BS.ByteString }+ | FileRecvControl { friendNumber :: Word32, fileNumber :: Word32, control :: FileControl }++ | ConferenceInvite { friendNumber :: Word32, conferenceType :: ConferenceType, cookie :: BS.ByteString }+ | ConferenceConnected { conferenceNumber :: Word32 }+ | ConferencePeerListChanged { conferenceNumber :: Word32 }+ | ConferencePeerName { conferenceNumber :: Word32, peerNumber :: Word32, name :: BS.ByteString }+ | ConferenceTitle { conferenceNumber :: Word32, peerNumber :: Word32, title :: BS.ByteString }++ | ConferenceMessage { conferenceNumber :: Word32, peerNumber :: Word32, messageType :: MessageType, message :: BS.ByteString }++ | GroupPeerName { groupNumber :: Word32, peerId :: Word32, name :: BS.ByteString }+ | GroupPeerStatus { groupNumber :: Word32, peerId :: Word32, status :: UserStatus }+ | GroupTopic { groupNumber :: Word32, peerId :: Word32, topic :: BS.ByteString }+ | GroupPrivacyState { groupNumber :: Word32, privacyState :: GroupPrivacyState }+ | GroupVoiceState { groupNumber :: Word32, voiceState :: GroupVoiceState }+ | GroupTopicLock { groupNumber :: Word32, topicLock :: GroupTopicLock }+ | GroupPeerLimit { groupNumber :: Word32, peerLimit :: Word32 }+ | GroupPassword { groupNumber :: Word32, password :: BS.ByteString }+ | GroupMessage { groupNumber :: Word32, peerId :: Word32, messageType :: MessageType, message :: BS.ByteString, messageId :: Word32 }+ | GroupPrivateMessage { groupNumber :: Word32, peerId :: Word32, messageType :: MessageType, message :: BS.ByteString }+ | GroupCustomPacket { groupNumber :: Word32, peerId :: Word32, data' :: BS.ByteString }+ | GroupCustomPrivatePacket { groupNumber :: Word32, peerId :: Word32, data' :: BS.ByteString }+ | GroupInvite { groupNumber :: Word32, inviteData :: BS.ByteString, groupName :: BS.ByteString }+ | GroupPeerJoin { groupNumber :: Word32, peerId :: Word32 }+ | GroupPeerExit { groupNumber :: Word32, peerId :: Word32, exitType :: GroupExitType, name :: BS.ByteString, partMessage :: BS.ByteString }+ | GroupSelfJoin { groupNumber :: Word32 }+ | GroupJoinFail { groupNumber :: Word32, failType :: GroupJoinFail }+ | GroupModeration { groupNumber :: Word32, sourcePeerId :: Word32, targetPeerId :: Word32, modType :: GroupModEvent }++ | DhtGetNodesResponse { publicKey :: PublicKey, ip :: BS.ByteString, port :: Word16 }+ deriving (Ord, Eq, Show, Generic)++instance MessagePack Event+instance Arbitrary Event where+ arbitrary = genericArbitrary+ shrink = genericShrink++data Events = Events [Event]+ deriving (Ord, Eq, Show, Generic)++instance MessagePack Events+instance Arbitrary Events where+ arbitrary = genericArbitrary+ shrink = genericShrink
test/Network/Tox/C/ToxSpec.hs view
@@ -1,31 +1,21 @@ {-# OPTIONS_GHC -fno-warn-orphans #-}+{-# LANGUAGE StrictData #-} {-# LANGUAGE Trustworthy #-} module Network.Tox.C.ToxSpec where -import Control.Applicative ((<$>), (<*>))-import qualified Crypto.Saltine.Internal.ByteSizes as Sodium (boxPK, boxSK)-import qualified Data.ByteString as BS-import Data.ByteString.Arbitrary (fromABS)-import Data.Default.Class (def)+import Control.Monad (when)+import qualified Data.ByteString as BS import Test.Hspec import Test.QuickCheck-import Test.QuickCheck.Arbitrary (arbitraryBoundedEnum,- genericShrink) -import qualified Network.Tox.C as C---instance Arbitrary C.ProxyType where- shrink = genericShrink- arbitrary = arbitraryBoundedEnum+import qualified Network.Tox.C as C -instance Arbitrary C.SavedataType where- shrink = genericShrink- arbitrary = arbitraryBoundedEnum+{-# ANN module "HLint: ignore Reduce duplication" #-}+{-# ANN module "HLint: ignore Redundant do" #-} -instance Arbitrary BS.ByteString where- shrink bs = if BS.null bs then [] else BS.inits bs- arbitrary = fromABS <$> arbitrary+boxPK, boxSK :: Int+boxPK = 32+boxSK = 32 -- | Ensure that the hostname has a chance of being valid. filterHost :: C.Options -> C.Options@@ -34,21 +24,21 @@ hostChars = ".-_" ++ ['0'..'9'] ++ ['a'..'z'] ++ ['A'..'Z'] instance Arbitrary C.Options where- shrink = map filterHost . genericShrink- arbitrary = fmap filterHost $ C.Options- <$> arbitrary- <*> arbitrary- <*> arbitrary- <*> arbitrary- <*> arbitrary- <*> arbitrary- <*> arbitrary- <*> arbitrary- <*> arbitrary- <*> arbitrary+ shrink = map filterHost . genericShrink+ arbitrary = fmap filterHost $ C.Options+ <$> arbitrary+ <*> arbitrary+ <*> arbitrary+ <*> arbitrary+ <*> arbitrary+ <*> arbitrary+ <*> arbitrary+ <*> arbitrary+ <*> arbitrary+ <*> arbitrary -getRight :: (Monad m, Show a) => Either a b -> m b+getRight :: (MonadFail m, Show a) => Either a b -> m b getRight (Left l) = fail $ show l getRight (Right r) = return r @@ -57,63 +47,68 @@ must = (getRight =<<) +shouldBeBetween :: (Show a, Ord a) => a -> (a, a) -> IO ()+shouldBeBetween v (lo, hi) = do+ when (v < lo || v > hi) $+ expectationFailure $ "value " <> show v <> " should be between " <> show lo <> " and " <> show hi++ spec :: Spec spec = do- describe "tox_version_is_compatible" $- it "is compatible with the major/minor/patch of the linked library" $- C.tox_version_is_compatible- C.tox_version_major- C.tox_version_minor- C.tox_version_patch- `shouldBe` True+ describe "tox_version_is_compatible" $ do+ it "is compatible with the major/minor/patch of the linked library" $ do+ C.tox_version_is_compatible+ C.tox_version_major+ C.tox_version_minor+ C.tox_version_patch+ `shouldBe` True - describe "Constants" $- it "has constants equal to the hstox expected key size" $ do- fromIntegral C.tox_public_key_size `shouldBe` Sodium.boxPK- fromIntegral C.tox_secret_key_size `shouldBe` Sodium.boxSK- C.tox_address_size `shouldBe` C.tox_public_key_size + 6- C.tox_max_name_length `shouldBe` 128- C.tox_max_status_message_length `shouldBe` 1007- C.tox_max_friend_request_length `shouldBe` 1016- C.tox_max_message_length `shouldBe` C.tox_max_custom_packet_size - 1- C.tox_max_custom_packet_size `shouldBe` 1373- C.tox_max_filename_length `shouldBe` 255- C.tox_hash_length `shouldBe` C.tox_file_id_length+ describe "Constants" $ do+ it "has constants equal to the hstox expected key size" $ do+ fromIntegral C.tox_public_key_size `shouldBe` boxPK+ fromIntegral C.tox_secret_key_size `shouldBe` boxSK+ C.tox_address_size `shouldBe` C.tox_public_key_size + 6+ C.tox_max_name_length `shouldBeBetween` (100, 200)+ C.tox_max_status_message_length `shouldBeBetween` (500, 1400)+ C.tox_max_friend_request_length `shouldBeBetween` (500, 1400)+ C.tox_max_message_length `shouldBe` C.tox_max_custom_packet_size - 1+ C.tox_max_custom_packet_size `shouldBeBetween` (500, 1400)+ C.tox_max_filename_length `shouldBeBetween` (100, 255)+ C.tox_hash_length `shouldBe` C.tox_file_id_length - describe "Options" $ do- it "can be marshalled to C and back" $- property $ \options -> do- res <- C.withOptions options C.peekToxOptions- res `shouldBe` Right options+ describe "Options" $ do+ it "can be marshalled to C and back" $ do+ property $ \options -> do+ res <- C.withOptions options C.peekToxOptions+ res `shouldBe` Right options - it "is saved correctly by pokeToxOptions" $- property $ \options0 options1 -> do- res <- C.withOptions options0 $ \ptr -> do- C.pokeToxOptions options1 ptr (return ())- C.peekToxOptions ptr- res `shouldBe` Right options0+ it "has a 'def' that is equivalent to the C default options" $ do+ res <- C.withToxOptions C.peekToxOptions+ res `shouldBe` Right C.defaultOptions - it "has a 'def' that is equivalent to the C default options" $ do- res <- C.withToxOptions C.peekToxOptions- res `shouldBe` Right def+ describe "nospam" $ do+ it "can be retrieved after being set" $ do+ property $ \nospam ->+ must $ C.withTox C.defaultOptions $ \tox -> do+ C.toxSelfSetNospam tox nospam+ nospam' <- C.toxSelfGetNospam tox+ nospam' `shouldBe` nospam - describe "nospam" $- it "can be retrieved after being set" $- property $ \nospam ->- must $ C.withDefaultTox $ \tox -> do- C.tox_self_set_nospam tox nospam- nospam' <- C.tox_self_get_nospam tox- nospam' `shouldBe` nospam+ describe "public key" $ do+ it "is a prefix of the address" $ do+ must $ C.withTox C.defaultOptions $ \tox -> do+ pk <- C.toxSelfGetPublicKey tox+ addr <- C.toxSelfGetAddress tox+ BS.unpack addr `shouldStartWith` BS.unpack pk - describe "public key" $ do- it "is a prefix of the address" $- must $ C.withDefaultTox $ \tox -> do- pk <- C.toxSelfGetPublicKey tox- addr <- C.toxSelfGetAddress tox- BS.unpack addr `shouldStartWith` BS.unpack pk+ it "is not equal to the secret key" $ do+ must $ C.withTox C.defaultOptions $ \tox -> do+ pk <- C.toxSelfGetPublicKey tox+ sk <- C.toxSelfGetSecretKey tox+ pk `shouldNotBe` sk - it "is not equal to the secret key" $- must $ C.withDefaultTox $ \tox -> do- pk <- C.toxSelfGetPublicKey tox- sk <- C.toxSelfGetSecretKey tox- pk `shouldNotBe` sk+ describe "error code enum" $ do+ it "is correctly translated to Haskell" $ do+ must $ C.withTox C.defaultOptions $ \tox -> do+ err <- C.toxFriendSendMessage tox 0 C.MessageTypeNormal $ BS.pack [1, 2, 3]+ err `shouldBe` Left C.ErrFriendSendMessageFriendNotFound
− test/Network/Tox/CSpec.hs
@@ -1,96 +0,0 @@-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE Trustworthy #-}-module Network.Tox.CSpec where--import Control.Applicative ((<$>))-import Control.Concurrent (threadDelay)-import Control.Concurrent.MVar (MVar, newMVar, readMVar)-import Control.Exception (bracket)-import Control.Monad (when)-import qualified Data.ByteString as BS-import qualified Data.ByteString.Base16 as Base16-import Data.String (fromString)-import Foreign.StablePtr (StablePtr, freeStablePtr,- newStablePtr)-import Foreign.Storable (Storable (..))-import Test.Hspec--import qualified Network.Tox.C as C---bootstrapKey :: BS.ByteString-bootstrapKey =- fst . Base16.decode . fromString $- "1C5293AEF2114717547B39DA8EA6F1E331E5E358B35F9B6B5F19317911C5F976"--bootstrapHost :: String-bootstrapHost = "tox.verdict.gg"---options :: C.Options-options = C.Options- { C.ipv6Enabled = True- , C.udpEnabled = True- , C.proxyType = C.ProxyTypeNone- , C.proxyHost = ""- , C.proxyPort = 0- , C.startPort = 33445- , C.endPort = 33545- , C.tcpPort = 3128- , C.savedataType = C.SavedataTypeNone- , C.savedataData = BS.empty- }---while :: IO Bool -> IO () -> IO ()-while cond io = do- continue <- cond- when continue $ io >> while cond io---getRight :: (Monad m, Show a) => Either a b -> m b-getRight (Left l) = fail $ show l-getRight (Right r) = return r---must :: Show a => IO (Either a b) -> IO b-must = (getRight =<<)---newtype UserData = UserData Int- deriving (Eq, Storable, Read, Show)--instance C.CHandler UserData where- cSelfConnectionStatus _ conn ud = do- print conn- print ud- return $ UserData 4321---withStablePtr :: a -> (StablePtr a -> IO b) -> IO b-withStablePtr x = bracket (newStablePtr x) freeStablePtr---toxIterate :: MVar a -> C.Tox a -> IO ()-toxIterate ud tox =- withStablePtr ud (C.tox_iterate tox)---spec :: Spec-spec =- describe "toxcore" $- it "can bootstrap" $- must $ C.withOptions options $ \optPtr ->- must $ C.withTox optPtr $ \tox -> do- must $ C.toxBootstrap tox bootstrapHost 33445 bootstrapKey- must $ C.toxAddTcpRelay tox bootstrapHost 33445 bootstrapKey-- C.withCHandler tox $ do- ud <- newMVar (UserData 1234)- while ((/= UserData 4321) <$> readMVar ud) $ do- toxIterate ud tox- putStrLn "tox_iterate"- interval <- C.tox_iteration_interval tox- threadDelay $ fromIntegral $ interval * 10000- putStrLn "done"
+ test/Network/Tox/Types/EventsSpec.hs view
@@ -0,0 +1,74 @@+{-# LANGUAGE StrictData #-}+{-# LANGUAGE Trustworthy #-}+module Network.Tox.Types.EventsSpec where++import Control.Concurrent (threadDelay)+import Control.Monad (forM)+--import Data.List (sort)+--import Data.MessagePack (Object (..))+--import qualified Data.MessagePack as MP+--import qualified Data.Vector as V+import Test.Hspec+--import Test.QuickCheck++import qualified Network.Tox.C as C+import Network.Tox.Types.Events+++getRight :: (MonadFail m, Show a) => Either a b -> m b+getRight (Left l) = fail $ show l+getRight (Right r) = return r+++must :: Show a => IO (Either a b) -> IO b+must = (getRight =<<)+++processEvent :: Event -> IO Bool+processEvent SelfConnectionStatus{} = return True+processEvent _ = return False+++toxIterate :: Int -> [C.ToxPtr] -> IO ()+toxIterate 0 _ =+ expectationFailure "could not bootstrap"+toxIterate countdown toxes = do+ interval <- foldr max 0 <$> mapM C.toxIterationInterval toxes+ threadDelay $ fromIntegral $ interval * 10000++ connected <- fmap and . forM toxes $ \tox -> do+ events <- must $ C.toxEventsIterate tox+ or <$> mapM processEvent events++ if connected+ then putStrLn "connected"+ else toxIterate (countdown - 1) toxes+++spec :: Spec+spec = do++{- TODO(iphydf): re-enable once the c-toxcore system PR is in.+ describe "event serialisation format" $ do+ it "is linear encoding" $+ MP.toObject MP.defaultConfig (FileChunkRequest 1 2 3 4)+ `shouldBe` ObjectArray (V.fromList+ [ ObjectWord 11+ , ObjectArray (V.fromList+ [ObjectWord 1,ObjectWord 2,ObjectWord 3,ObjectWord 4])])++ it "can round-trip through toxcore" $+ property $ \(sort -> events) -> do+ events' <- C.toxEventsToPtr events >>= C.toxEventsFromPtr+ sort <$> events' `shouldBe` Right events+-}++ describe "toxcore" $+ it "can bootstrap" $ do+ must $ C.withTox C.defaultOptions $ \tox1 ->+ must $ C.withTox C.defaultOptions $ \tox2 -> do+ bootstrapPort <- must $ C.toxSelfGetUdpPort tox1+ bootstrapKey <- C.toxSelfGetDhtId tox1+ _ <- must $ C.toxBootstrap tox2 "127.0.0.1" bootstrapPort bootstrapKey++ toxIterate 100 [tox1, tox2]
+ tools/groupbot.hs view
@@ -0,0 +1,169 @@+{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE StrictData #-}+module Main (main) where++import Control.Concurrent (threadDelay)+import Control.Exception (AsyncException (UserInterrupt),+ catch, throwIO)+import Control.Monad (foldM, void, when)+import qualified Data.ByteString.Base16 as Base16+import qualified Data.ByteString.Char8 as BS+import Data.String (fromString)+import qualified Data.Text.Encoding as Text+import qualified Data.Text.IO as Text+import Data.Word (Word32)+import System.Directory (doesFileExist)+import System.Exit (exitSuccess)++import qualified Network.Tox.C as C+import Network.Tox.Types.Events+++bootstrapKey, masterKey :: BS.ByteString+Right bootstrapKey =+ Base16.decode . fromString $+ "3F0A45A268367C1BEA652F258C85F4A66DA76BCAA667A49E770BCC4917AB6A25"+Right masterKey =+ Base16.decode . fromString $+ "13117C65771C5A05409F532A7809D238E38E94312C870FE7970C5B65B1215E20"++isMasterKey :: BS.ByteString -> Bool+isMasterKey = (masterKey ==)++botName :: BS.ByteString+botName = fromString "groupbot"++bootstrapHost :: String+bootstrapHost = "tox.initramfs.io"++savedataFilename :: String+savedataFilename = "groupbot.tox"++doInvite :: Bool+doInvite = False++save :: C.ToxPtr -> IO ()+save tox = do+ savedSavedata <- C.toxGetSavedata tox+ BS.writeFile savedataFilename savedSavedata+++options :: BS.ByteString -> C.Options+options savedata = C.Options+ { C.ipv6Enabled = True+ , C.udpEnabled = True+ , C.proxyType = C.ProxyTypeNone+ , C.proxyHost = ""+ , C.proxyPort = 0+ , C.startPort = 33445+ , C.endPort = 33545+ , C.tcpPort = 3128+ , C.savedataType = if savedata == BS.empty then C.SavedataTypeNone else C.SavedataTypeToxSave+ , C.savedataData = savedata+ }+++getRight :: (MonadFail m, Show a) => Either a b -> m b+getRight (Left l) = fail $ show l+getRight (Right r) = return r+++must :: Show a => IO (Either a b) -> IO b+must = (getRight =<<)+++newtype UserData = UserData { groupNumber :: Word32 }+ deriving (Read, Show)++handleEvent :: C.ToxPtr -> UserData -> Event -> IO UserData+handleEvent tox ud@(UserData gn) = \case+ SelfConnectionStatus{ connectionStatus } -> do+ putStrLn "SelfConnectionStatusCb"+ print connectionStatus+ return ud++ FriendRequest{ publicKey = C.FixedByteString pk, message } -> do+ putStrLn "FriendRequestCb"+ Right fn <- C.toxFriendAddNorequest tox pk+ putStrLn $ (BS.unpack . Base16.encode) pk+ Text.putStrLn $ Text.decodeUtf8 message+ print fn+ save tox+ return ud++ FriendConnectionStatus friendNumber status -> do+ putStrLn "FriendConnectionStatusCb"+ print friendNumber+ print status+ if doInvite && status /= C.ConnectionNone+ then do+ putStrLn "Inviting!"+ _ <- C.toxConferenceInvite tox friendNumber gn+ return ()+ else+ putStrLn "Friend offline"+ return ud++ FriendMessage{ friendNumber, messageType, message } -> do+ putStrLn "FriendMessage"+ print friendNumber+ print messageType+ Text.putStrLn $ Text.decodeUtf8 message+ _ <- C.toxFriendSendMessage tox friendNumber messageType (message <> "\0" <> message)+ return ud++ ConferenceInvite{ friendNumber, cookie } -> do+ putStrLn "ConferenceInvite"+ print friendNumber+ pk <- getRight =<< C.toxFriendGetPublicKey tox friendNumber+ if isMasterKey pk+ then do+ putStrLn "Joining!"+ newGn <- getRight =<< C.toxConferenceJoin tox friendNumber cookie+ save tox+ return $ UserData newGn+ else do+ putStrLn "Not master!"+ return ud++ ConferenceMessage{ conferenceNumber, peerNumber, message, messageType } -> do+ when (peerNumber /= 0 && botName `BS.isPrefixOf` message) $ do+ putStrLn "ConferenceMessage"+ print message+ void $ C.toxConferenceSendMessage tox conferenceNumber messageType (message <> "\0" <> message)+ return ud++ _ -> return ud+++loop :: C.ToxPtr -> UserData -> IO ()+loop tox ud = do+ interval <- C.toxIterationInterval tox+ threadDelay $ fromIntegral $ interval * 10000+ events <- C.toxEventsIterate tox+ case events of+ Left err -> fail $ show err+ Right ok -> foldM (handleEvent tox) ud ok >>= loop tox+++main :: IO ()+main = do+ exists <- doesFileExist savedataFilename+ loadedSavedata <- if exists then BS.readFile savedataFilename else return BS.empty+ must $ C.withTox (options loadedSavedata) $ \tox -> do+ _ <- must $ C.toxBootstrap tox bootstrapHost 33445 bootstrapKey++ adr <- C.toxSelfGetAddress tox+ putStrLn $ (BS.unpack . Base16.encode) adr+ _ <- C.toxSelfSetName tox botName+ gn <- getRight =<< C.toxConferenceNew tox+ catch (loop tox (UserData gn)) $ \case+ e@UserInterrupt -> do+ save tox+ throwIO e+ _ -> do+ save tox+ exitSuccess
− tools/groupbot/Main.hs
@@ -1,143 +0,0 @@-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE LambdaCase #-}-module Main (main) where--import Control.Concurrent (threadDelay)-import Control.Concurrent.MVar (MVar, newMVar)-import Control.Exception (AsyncException (UserInterrupt), catch,- throwIO)-import Control.Monad (forever)-import qualified Data.ByteString.Base16 as Base16-import qualified Data.ByteString.Char8 as BS-import Data.String (fromString)-import Data.Word (Word32)-import Foreign.Storable (Storable (..))-import System.Directory (doesFileExist)-import System.Exit (exitSuccess)--import qualified Network.Tox.C as C---bootstrapKey :: BS.ByteString-bootstrapKey =- fst . Base16.decode . fromString $- "15E9C309CFCB79FDDF0EBA057DABB49FE15F3803B1BFF06536AE2E5BA5E4690E"--isMasterKey :: BS.ByteString -> Bool-isMasterKey key =- (key ==) . fst . Base16.decode . fromString $- "040F75B5C8995F9525F9A8692A6C355286BBD3CF248C984560733421274F0365"--botName :: String-botName = "groupbot"--bootstrapHost :: String-bootstrapHost = "tox.ngc.zone"--savedataFilename :: String-savedataFilename = "groupbot.tox"--options :: BS.ByteString -> C.Options-options savedata = C.Options- { C.ipv6Enabled = True- , C.udpEnabled = True- , C.proxyType = C.ProxyTypeNone- , C.proxyHost = ""- , C.proxyPort = 0- , C.startPort = 33445- , C.endPort = 33545- , C.tcpPort = 3128- , C.savedataType = if savedata == BS.empty then C.SavedataTypeNone else C.SavedataTypeToxSave- , C.savedataData = savedata- }---getRight :: (Monad m, Show a) => Either a b -> m b-getRight (Left l) = fail $ show l-getRight (Right r) = return r---must :: Show a => IO (Either a b) -> IO b-must = (getRight =<<)---newtype UserData = UserData Word32- deriving (Eq, Storable, Read, Show)--instance C.CHandler UserData where- cSelfConnectionStatus _ conn ud = do- putStrLn "SelfConnectionStatusCb"- print conn- return ud-- cFriendRequest tox pk msg ud = do- putStrLn "FriendRequestCb"- Right fn <- C.toxFriendAddNorequest tox pk- putStrLn $ (BS.unpack . Base16.encode) pk- putStrLn msg- print fn- return ud-- cFriendConnectionStatus tox fn status ud@(UserData gn) = do- putStrLn "FriendConnectionStatusCb"- print fn- print status- if status /= C.ConnectionNone- then do- putStrLn "Inviting!"- _ <- C.toxConferenceInvite tox fn gn- return ()- else- putStrLn "Friend offline"- return ud-- cFriendMessage tox fn msgType msg ud = do- putStrLn "FriendMessage"- print fn- print msgType- putStrLn msg- _ <- C.toxFriendSendMessage tox fn msgType msg- return ud-- cConferenceInvite tox fn _confType cookie ud = do- putStrLn "ConferenceInvite"- print fn- pk <- getRight =<< C.toxFriendGetPublicKey tox fn- if isMasterKey pk- then do- putStrLn "Joining!"- gn <- getRight =<< C.toxConferenceJoin tox fn cookie- return $ UserData gn- else do- putStrLn "Not master!"- return ud---loop :: MVar ud -> C.Tox ud -> IO a-loop ud tox =- forever $ do- C.toxIterate tox ud- interval <- C.tox_iteration_interval tox- threadDelay $ fromIntegral $ interval * 10000---main :: IO ()-main = do- exists <- doesFileExist savedataFilename- loadedSavedata <- if exists then BS.readFile savedataFilename else return BS.empty- must $ C.withOptions (options loadedSavedata) $ \optPtr ->- must $ C.withTox optPtr $ \tox -> do- must $ C.toxBootstrap tox bootstrapHost 33445 bootstrapKey-- C.withCHandler tox $ do- adr <- C.toxSelfGetAddress tox- putStrLn $ (BS.unpack . Base16.encode) adr- _ <- C.toxSelfSetName tox botName- gn <- getRight =<< C.toxConferenceNew tox- ud <- newMVar (UserData gn)- catch (loop ud tox) $ \case- e@UserInterrupt -> throwIO e- _ -> do- savedSavedata <- C.toxGetSavedata tox- BS.writeFile savedataFilename savedSavedata- exitSuccess
toxcore-c.cabal view
@@ -1,80 +1,80 @@-name: toxcore-c-synopsis: Haskell bindings to the C reference implementation of Tox-version: 0.2.11-cabal-version: >= 1.10-license: GPL-3-license-file: LICENSE-build-type: Simple-author: iphy-maintainer: iphy-copyright: © 2016-2020 The TokTok Team-homepage: https://toktok.github.io-category: Network+name: toxcore-c+synopsis: Haskell bindings to the C reference implementation of Tox+version: 0.2.19+cabal-version: >=1.10+license: GPL-3+license-file: LICENSE+build-type: Simple+author: iphy+maintainer: iphy+copyright: Copyright (c) 2016-2020 The TokTok Team+homepage: https://toktok.github.io+category: Network description: Haskell bindings to the C reference implementation of Tox. . See <https://github.com/TokTok/c-toxcore>. source-repository head- type: git+ type: git location: https://github.com/TokTok/hs-toxcore-c library default-language: Haskell2010- hs-source-dirs:- src- ghc-options:- -Wall- extra-libraries: toxcore+ hs-source-dirs: src+ ghc-options: -Wall+ extra-libraries: toxcore exposed-modules:- Network.Tox.C- Network.Tox.C.CEnum- Network.Tox.C.Callbacks- Network.Tox.C.Constants- Network.Tox.C.Options- Network.Tox.C.Tox- Network.Tox.C.Type- Network.Tox.C.Version+ FFI.Tox.Tox+ Foreign.C.Enum+ Network.Tox.C+ Network.Tox.C.Constants+ Network.Tox.C.Options+ Network.Tox.C.Tox+ Network.Tox.C.Type+ Network.Tox.C.Version+ Network.Tox.Types.Events+ build-depends:- base < 5+ base <5 , bytestring- , data-default-class+ , generic-arbitrary <2+ , msgpack-binary >=0.0.16+ , QuickCheck+ , quickcheck-instances executable groupbot default-language: Haskell2010- hs-source-dirs:- tools/groupbot- ghc-options:- -Wall- -fno-warn-unused-imports- extra-libraries: toxcore- main-is: Main.hs+ hs-source-dirs: tools+ ghc-options: -Wall -Wno-unused-imports+ extra-libraries: toxcore+ main-is: groupbot.hs build-depends:- base < 5- , base16-bytestring+ base <5+ , base16-bytestring >=1 , bytestring , directory+ , text , toxcore-c test-suite testsuite default-language: Haskell2010- type: exitcode-stdio-1.0- hs-source-dirs:- test- ghc-options:- -Wall- -fno-warn-unused-imports- main-is: testsuite.hs+ type: exitcode-stdio-1.0+ hs-source-dirs: test+ ghc-options: -Wall -Wno-unused-imports+ main-is: testsuite.hs other-modules:- Network.Tox.C.ToxSpec- Network.Tox.CSpec+ Network.Tox.C.ToxSpec+ Network.Tox.Types.EventsSpec+ build-depends:- base < 5- , QuickCheck >= 2.9.1+ base <5 , base16-bytestring , bytestring- , bytestring-arbitrary- , data-default-class+ , cryptohash , hspec+ , msgpack-binary+ , QuickCheck >=2.9.1 , saltine , toxcore-c+ , vector