2021-06-25 18:18:24 +01:00
|
|
|
{-# LANGUAGE ConstraintKinds #-}
|
2022-01-28 10:41:09 +00:00
|
|
|
{-# LANGUAGE DataKinds #-}
|
2021-06-25 18:18:24 +01:00
|
|
|
{-# LANGUAGE DeriveAnyClass #-}
|
2022-01-26 21:20:08 +00:00
|
|
|
{-# LANGUAGE DeriveGeneric #-}
|
2021-07-05 19:54:44 +01:00
|
|
|
{-# LANGUAGE DuplicateRecordFields #-}
|
2021-06-25 18:18:24 +01:00
|
|
|
{-# LANGUAGE FlexibleContexts #-}
|
2022-06-25 17:02:16 +01:00
|
|
|
{-# LANGUAGE NamedFieldPuns #-}
|
2021-07-05 19:54:44 +01:00
|
|
|
{-# LANGUAGE OverloadedStrings #-}
|
2021-06-25 18:18:24 +01:00
|
|
|
|
|
|
|
|
module Simplex.Chat.Controller where
|
|
|
|
|
|
2022-02-06 16:18:01 +00:00
|
|
|
import Control.Concurrent.Async (Async)
|
2021-06-25 18:18:24 +01:00
|
|
|
import Control.Exception
|
|
|
|
|
import Control.Monad.Except
|
|
|
|
|
import Control.Monad.IO.Unlift
|
|
|
|
|
import Control.Monad.Reader
|
2021-07-12 19:00:03 +01:00
|
|
|
import Crypto.Random (ChaChaDRG)
|
2022-05-05 14:04:03 +01:00
|
|
|
import Data.Aeson (FromJSON, ToJSON)
|
2022-01-26 21:20:08 +00:00
|
|
|
import qualified Data.Aeson as J
|
2022-09-05 14:54:39 +01:00
|
|
|
import qualified Data.Attoparsec.ByteString.Char8 as A
|
2022-01-24 16:07:17 +00:00
|
|
|
import Data.ByteString.Char8 (ByteString)
|
2022-09-05 14:54:39 +01:00
|
|
|
import qualified Data.ByteString.Char8 as B
|
|
|
|
|
import Data.Char (ord)
|
2021-09-04 07:32:56 +01:00
|
|
|
import Data.Int (Int64)
|
|
|
|
|
import Data.Map.Strict (Map)
|
2022-09-05 14:54:39 +01:00
|
|
|
import Data.String
|
2022-01-24 16:07:17 +00:00
|
|
|
import Data.Text (Text)
|
2022-03-29 08:53:30 +01:00
|
|
|
import Data.Time (ZonedTime)
|
2022-05-27 06:30:01 +01:00
|
|
|
import Data.Time.Clock (UTCTime)
|
2022-03-19 09:04:53 +00:00
|
|
|
import Data.Version (showVersion)
|
2022-01-26 21:20:08 +00:00
|
|
|
import GHC.Generics (Generic)
|
2021-09-04 07:32:56 +01:00
|
|
|
import Numeric.Natural
|
2022-03-19 09:04:53 +00:00
|
|
|
import qualified Paths_simplex_chat as SC
|
2022-05-02 17:06:49 +01:00
|
|
|
import Simplex.Chat.Call
|
2022-04-04 19:51:49 +01:00
|
|
|
import Simplex.Chat.Markdown (MarkdownList)
|
2022-01-24 16:07:17 +00:00
|
|
|
import Simplex.Chat.Messages
|
2022-01-30 10:49:13 +00:00
|
|
|
import Simplex.Chat.Protocol
|
2021-07-05 20:05:07 +01:00
|
|
|
import Simplex.Chat.Store (StoreError)
|
2021-07-04 18:42:24 +01:00
|
|
|
import Simplex.Chat.Types
|
2021-06-25 18:18:24 +01:00
|
|
|
import Simplex.Messaging.Agent (AgentClient)
|
2022-07-25 14:04:27 +01:00
|
|
|
import Simplex.Messaging.Agent.Env.SQLite (AgentConfig, InitialAgentServers, NetworkConfig)
|
2022-01-24 16:07:17 +00:00
|
|
|
import Simplex.Messaging.Agent.Protocol
|
2021-07-04 18:42:24 +01:00
|
|
|
import Simplex.Messaging.Agent.Store.SQLite (SQLiteStore)
|
2022-04-21 20:04:22 +01:00
|
|
|
import qualified Simplex.Messaging.Crypto as C
|
2022-09-05 14:54:39 +01:00
|
|
|
import Simplex.Messaging.Encoding.String
|
2022-04-22 20:32:19 +01:00
|
|
|
import Simplex.Messaging.Notifications.Protocol (DeviceToken (..), NtfTknStatus)
|
2022-09-05 14:54:39 +01:00
|
|
|
import Simplex.Messaging.Parsers (dropPrefix, enumJSON, parseAll, parseString, sumTypeJSON)
|
2022-08-13 14:18:12 +01:00
|
|
|
import Simplex.Messaging.Protocol (AProtocolType, CorrId, MsgFlags)
|
2022-05-04 13:31:00 +01:00
|
|
|
import Simplex.Messaging.TMap (TMap)
|
2022-08-13 14:18:12 +01:00
|
|
|
import Simplex.Messaging.Transport.Client (TransportHost)
|
2021-09-04 07:32:56 +01:00
|
|
|
import System.IO (Handle)
|
2021-06-25 18:18:24 +01:00
|
|
|
import UnliftIO.STM
|
|
|
|
|
|
2021-11-07 21:57:05 +00:00
|
|
|
versionNumber :: String
|
2022-03-19 09:04:53 +00:00
|
|
|
versionNumber = showVersion SC.version
|
2022-01-11 21:23:57 +00:00
|
|
|
|
|
|
|
|
versionStr :: String
|
|
|
|
|
versionStr = "SimpleX Chat v" <> versionNumber
|
|
|
|
|
|
|
|
|
|
updateStr :: String
|
|
|
|
|
updateStr = "To update run: curl -o- https://raw.githubusercontent.com/simplex-chat/simplex-chat/master/install.sh | bash"
|
2021-11-07 21:57:05 +00:00
|
|
|
|
2021-09-04 07:32:56 +01:00
|
|
|
data ChatConfig = ChatConfig
|
|
|
|
|
{ agentConfig :: AgentConfig,
|
2022-02-07 15:19:34 +04:00
|
|
|
yesToMigrations :: Bool,
|
2022-05-11 16:52:08 +01:00
|
|
|
defaultServers :: InitialAgentServers,
|
2021-09-04 07:32:56 +01:00
|
|
|
tbqSize :: Natural,
|
2022-02-09 20:58:02 +04:00
|
|
|
fileChunkSize :: Integer,
|
2022-02-26 10:04:25 +00:00
|
|
|
subscriptionConcurrency :: Int,
|
2022-02-25 16:29:36 +04:00
|
|
|
subscriptionEvents :: Bool,
|
2022-08-13 14:18:12 +01:00
|
|
|
hostEvents :: Bool,
|
2022-02-09 20:58:02 +04:00
|
|
|
testView :: Bool
|
2021-09-04 07:32:56 +01:00
|
|
|
}
|
|
|
|
|
|
2022-01-21 11:09:33 +00:00
|
|
|
data ActiveTo = ActiveNone | ActiveC ContactName | ActiveG GroupName
|
|
|
|
|
deriving (Eq)
|
|
|
|
|
|
2022-09-23 19:22:56 +01:00
|
|
|
data ChatDatabase = ChatDatabase {chatStore :: SQLiteStore, agentStore :: SQLiteStore}
|
|
|
|
|
|
2021-06-25 18:18:24 +01:00
|
|
|
data ChatController = ChatController
|
2022-02-06 16:18:01 +00:00
|
|
|
{ currentUser :: TVar (Maybe User),
|
2022-01-21 11:09:33 +00:00
|
|
|
activeTo :: TVar ActiveTo,
|
2021-12-13 12:05:57 +00:00
|
|
|
firstTime :: Bool,
|
2021-07-04 18:42:24 +01:00
|
|
|
smpAgent :: AgentClient,
|
2022-07-02 10:13:06 +01:00
|
|
|
agentAsync :: TVar (Maybe (Async (), Maybe (Async ()))),
|
2021-07-04 18:42:24 +01:00
|
|
|
chatStore :: SQLiteStore,
|
2022-06-06 16:23:47 +01:00
|
|
|
chatStoreChanged :: TVar Bool, -- if True, chat should be fully restarted
|
2021-07-12 19:00:03 +01:00
|
|
|
idsDrg :: TVar ChaChaDRG,
|
2022-01-24 16:07:17 +00:00
|
|
|
inputQ :: TBQueue String,
|
2022-01-26 21:20:08 +00:00
|
|
|
outputQ :: TBQueue (Maybe CorrId, ChatResponse),
|
2021-06-26 20:20:33 +01:00
|
|
|
notifyQ :: TBQueue Notification,
|
2021-08-05 20:51:48 +01:00
|
|
|
sendNotification :: Notification -> IO (),
|
2021-09-04 07:32:56 +01:00
|
|
|
chatLock :: TMVar (),
|
|
|
|
|
sndFiles :: TVar (Map Int64 Handle),
|
|
|
|
|
rcvFiles :: TVar (Map Int64 Handle),
|
2022-05-04 13:31:00 +01:00
|
|
|
currentCalls :: TMap ContactId Call,
|
2022-04-15 09:36:38 +04:00
|
|
|
config :: ChatConfig,
|
2022-08-18 11:35:31 +04:00
|
|
|
filesFolder :: TVar (Maybe FilePath), -- path to files folder for mobile apps,
|
|
|
|
|
incognitoMode :: TVar Bool
|
2021-06-25 18:18:24 +01:00
|
|
|
}
|
|
|
|
|
|
2022-07-26 07:29:28 +01:00
|
|
|
data HelpSection = HSMain | HSFiles | HSGroups | HSMyAddress | HSMarkdown | HSMessages | HSSettings
|
2022-01-26 21:20:08 +00:00
|
|
|
deriving (Show, Generic)
|
|
|
|
|
|
|
|
|
|
instance ToJSON HelpSection where
|
2022-01-27 22:01:15 +00:00
|
|
|
toJSON = J.genericToJSON . enumJSON $ dropPrefix "HS"
|
|
|
|
|
toEncoding = J.genericToEncoding . enumJSON $ dropPrefix "HS"
|
2022-01-24 16:07:17 +00:00
|
|
|
|
|
|
|
|
data ChatCommand
|
2022-02-06 16:18:01 +00:00
|
|
|
= ShowActiveUser
|
|
|
|
|
| CreateActiveUser Profile
|
2022-06-21 11:25:12 +01:00
|
|
|
| StartChat {subscribeConnections :: Bool}
|
2022-06-06 16:23:47 +01:00
|
|
|
| APIStopChat
|
2022-06-26 15:04:44 +01:00
|
|
|
| APIActivateChat
|
|
|
|
|
| APISuspendChat {suspendTimeout :: Int}
|
2022-04-30 12:47:50 +01:00
|
|
|
| ResubscribeAllConnections
|
2022-04-15 09:36:38 +04:00
|
|
|
| SetFilesFolder FilePath
|
2022-08-18 11:35:31 +04:00
|
|
|
| SetIncognito Bool
|
2022-06-06 16:23:47 +01:00
|
|
|
| APIExportArchive ArchiveConfig
|
|
|
|
|
| APIImportArchive ArchiveConfig
|
|
|
|
|
| APIDeleteStorage
|
2022-09-05 14:54:39 +01:00
|
|
|
| APIStorageEncryption DBEncryptionConfig
|
2022-09-17 16:06:27 +01:00
|
|
|
| ExecChatStoreSQL Text
|
|
|
|
|
| ExecAgentStoreSQL Text
|
2022-04-23 17:32:40 +01:00
|
|
|
| APIGetChats {pendingConnections :: Bool}
|
2022-08-08 22:48:42 +04:00
|
|
|
| APIGetChat ChatRef ChatPagination (Maybe String)
|
2022-01-28 10:41:09 +00:00
|
|
|
| APIGetChatItems Int
|
2022-05-05 14:04:03 +01:00
|
|
|
| APISendMessage ChatRef ComposedMessage
|
2022-04-28 08:34:21 +01:00
|
|
|
| APIUpdateChatItem ChatRef ChatItemId MsgContent
|
|
|
|
|
| APIDeleteChatItem ChatRef ChatItemId CIDeleteMode
|
2022-05-13 09:38:14 +01:00
|
|
|
| APIChatRead ChatRef (Maybe (ChatItemId, ChatItemId))
|
2022-04-28 08:34:21 +01:00
|
|
|
| APIDeleteChat ChatRef
|
2022-05-17 11:22:09 +04:00
|
|
|
| APIClearChat ChatRef
|
2022-01-31 21:53:53 +04:00
|
|
|
| APIAcceptContact Int64
|
2022-02-01 05:31:34 +00:00
|
|
|
| APIRejectContact Int64
|
2022-05-04 13:31:00 +01:00
|
|
|
| APISendCallInvitation ContactId CallType
|
2022-05-17 08:37:00 +01:00
|
|
|
| SendCallInvitation ContactName CallType
|
2022-05-04 13:31:00 +01:00
|
|
|
| APIRejectCall ContactId
|
|
|
|
|
| APISendCallOffer ContactId WebRTCCallOffer
|
|
|
|
|
| APISendCallAnswer ContactId WebRTCSession
|
|
|
|
|
| APISendCallExtraInfo ContactId WebRTCExtraInfo
|
|
|
|
|
| APIEndCall ContactId
|
2022-07-04 11:15:25 +01:00
|
|
|
| APIGetCallInvitations
|
2022-05-04 13:31:00 +01:00
|
|
|
| APICallStatus ContactId WebRTCCallStatus
|
2022-03-23 20:52:00 +00:00
|
|
|
| APIUpdateProfile Profile
|
2022-08-24 19:03:43 +04:00
|
|
|
| APISetContactAlias ContactId LocalAlias
|
2022-04-04 19:51:49 +01:00
|
|
|
| APIParseMarkdown Text
|
2022-06-25 17:02:16 +01:00
|
|
|
| APIGetNtfToken
|
|
|
|
|
| APIRegisterToken DeviceToken NotificationsMode
|
2022-06-27 23:03:27 +01:00
|
|
|
| APIVerifyToken DeviceToken C.CbNonce ByteString
|
2022-04-21 20:04:22 +01:00
|
|
|
| APIDeleteToken DeviceToken
|
2022-06-19 14:44:13 +01:00
|
|
|
| APIGetNtfMessage {nonce :: C.CbNonce, encNtfInfo :: ByteString}
|
2022-07-12 19:20:56 +04:00
|
|
|
| APIAddMember GroupId ContactId GroupMemberRole
|
|
|
|
|
| APIJoinGroup GroupId
|
|
|
|
|
| APIMemberRole GroupId GroupMemberId GroupMemberRole
|
|
|
|
|
| APIRemoveMember GroupId GroupMemberId
|
|
|
|
|
| APILeaveGroup GroupId
|
|
|
|
|
| APIListMembers GroupId
|
2022-07-29 19:04:32 +01:00
|
|
|
| APIUpdateGroupProfile GroupId GroupProfile
|
2022-03-10 15:45:40 +04:00
|
|
|
| GetUserSMPServers
|
|
|
|
|
| SetUserSMPServers [SMPServer]
|
2022-07-25 14:04:27 +01:00
|
|
|
| APISetNetworkConfig NetworkConfig
|
|
|
|
|
| APIGetNetworkConfig
|
2022-08-19 15:17:05 +01:00
|
|
|
| APISetChatSettings ChatRef ChatSettings
|
2022-07-20 14:57:16 +01:00
|
|
|
| APIContactInfo ContactId
|
|
|
|
|
| APIGroupMemberInfo GroupId GroupMemberId
|
2022-09-05 15:23:38 +01:00
|
|
|
| ShowMessages ChatName Bool
|
2022-07-20 14:57:16 +01:00
|
|
|
| ContactInfo ContactName
|
|
|
|
|
| GroupMemberInfo GroupName ContactName
|
2022-01-28 10:41:09 +00:00
|
|
|
| ChatHelp HelpSection
|
2022-01-24 16:07:17 +00:00
|
|
|
| Welcome
|
|
|
|
|
| AddContact
|
|
|
|
|
| Connect (Maybe AConnectionRequestUri)
|
2022-03-29 08:53:30 +01:00
|
|
|
| ConnectSimplex
|
2022-01-24 16:07:17 +00:00
|
|
|
| DeleteContact ContactName
|
2022-05-17 11:22:09 +04:00
|
|
|
| ClearContact ContactName
|
2022-01-24 16:07:17 +00:00
|
|
|
| ListContacts
|
|
|
|
|
| CreateMyAddress
|
|
|
|
|
| DeleteMyAddress
|
|
|
|
|
| ShowMyAddress
|
2022-06-27 19:41:25 +01:00
|
|
|
| AddressAutoAccept Bool (Maybe MsgContent)
|
2022-01-24 16:07:17 +00:00
|
|
|
| AcceptContact ContactName
|
|
|
|
|
| RejectContact ContactName
|
2022-04-28 08:34:21 +01:00
|
|
|
| SendMessage ChatName ByteString
|
2022-03-13 19:34:03 +00:00
|
|
|
| SendMessageQuote {contactName :: ContactName, msgDir :: AMsgDirection, quotedMsg :: ByteString, message :: ByteString}
|
2022-03-29 08:53:30 +01:00
|
|
|
| SendMessageBroadcast ByteString
|
2022-04-28 08:34:21 +01:00
|
|
|
| DeleteMessage ChatName ByteString
|
|
|
|
|
| EditMessage {chatName :: ChatName, editedMsg :: ByteString, message :: ByteString}
|
2022-01-24 16:07:17 +00:00
|
|
|
| NewGroup GroupProfile
|
|
|
|
|
| AddMember GroupName ContactName GroupMemberRole
|
|
|
|
|
| JoinGroup GroupName
|
|
|
|
|
| MemberRole GroupName ContactName GroupMemberRole
|
2022-07-12 19:20:56 +04:00
|
|
|
| RemoveMember GroupName ContactName
|
2022-01-24 16:07:17 +00:00
|
|
|
| LeaveGroup GroupName
|
|
|
|
|
| DeleteGroup GroupName
|
2022-05-17 11:22:09 +04:00
|
|
|
| ClearGroup GroupName
|
2022-01-24 16:07:17 +00:00
|
|
|
| ListMembers GroupName
|
|
|
|
|
| ListGroups
|
2022-07-29 19:04:32 +01:00
|
|
|
| UpdateGroupProfile GroupName GroupProfile
|
2022-03-19 09:04:53 +00:00
|
|
|
| SendGroupMessageQuote {groupName :: GroupName, contactName_ :: Maybe ContactName, quotedMsg :: ByteString, message :: ByteString}
|
2022-04-28 07:26:43 +01:00
|
|
|
| LastMessages (Maybe ChatName) Int
|
2022-04-30 19:18:46 +04:00
|
|
|
| SendFile ChatName FilePath
|
2022-05-21 18:17:15 +04:00
|
|
|
| SendImage ChatName FilePath
|
|
|
|
|
| ForwardFile ChatName FileTransferId
|
|
|
|
|
| ForwardImage ChatName FileTransferId
|
2022-01-26 21:20:08 +00:00
|
|
|
| ReceiveFile FileTransferId (Maybe FilePath)
|
|
|
|
|
| CancelFile FileTransferId
|
|
|
|
|
| FileStatus FileTransferId
|
2022-01-24 16:07:17 +00:00
|
|
|
| ShowProfile
|
2022-03-10 15:45:40 +04:00
|
|
|
| UpdateProfile ContactName Text
|
2022-04-04 19:51:49 +01:00
|
|
|
| UpdateProfileImage (Maybe ImageData)
|
2022-01-24 16:07:17 +00:00
|
|
|
| QuitChat
|
|
|
|
|
| ShowVersion
|
|
|
|
|
deriving (Show)
|
|
|
|
|
|
|
|
|
|
data ChatResponse
|
2022-02-06 16:18:01 +00:00
|
|
|
= CRActiveUser {user :: User}
|
|
|
|
|
| CRChatStarted
|
2022-02-26 20:21:32 +00:00
|
|
|
| CRChatRunning
|
2022-06-06 16:23:47 +01:00
|
|
|
| CRChatStopped
|
2022-06-26 15:04:44 +01:00
|
|
|
| CRChatSuspended
|
2022-02-06 16:18:01 +00:00
|
|
|
| CRApiChats {chats :: [AChat]}
|
2022-01-30 10:49:13 +00:00
|
|
|
| CRApiChat {chat :: AChat}
|
2022-04-28 07:26:43 +01:00
|
|
|
| CRLastMessages {chatItems :: [AChatItem]}
|
2022-04-04 19:51:49 +01:00
|
|
|
| CRApiParsedMarkdown {formattedText :: Maybe MarkdownList}
|
2022-03-10 15:45:40 +04:00
|
|
|
| CRUserSMPServers {smpServers :: [SMPServer]}
|
2022-07-25 14:04:27 +01:00
|
|
|
| CRNetworkConfig {networkConfig :: NetworkConfig}
|
2022-08-18 11:35:31 +04:00
|
|
|
| CRContactInfo {contact :: Contact, connectionStats :: ConnectionStats, customUserProfile :: Maybe Profile}
|
2022-08-27 19:56:03 +04:00
|
|
|
| CRGroupMemberInfo {groupInfo :: GroupInfo, member :: GroupMember, connectionStats_ :: Maybe ConnectionStats}
|
2022-01-28 10:41:09 +00:00
|
|
|
| CRNewChatItem {chatItem :: AChatItem}
|
2022-03-23 11:37:51 +00:00
|
|
|
| CRChatItemStatusUpdated {chatItem :: AChatItem}
|
2022-02-07 15:19:34 +04:00
|
|
|
| CRChatItemUpdated {chatItem :: AChatItem}
|
2022-03-28 20:35:57 +04:00
|
|
|
| CRChatItemDeleted {deletedChatItem :: AChatItem, toChatItem :: AChatItem}
|
2022-05-17 11:22:09 +04:00
|
|
|
| CRChatItemDeletedNotFound {contact :: Contact, sharedMsgId :: SharedMsgId}
|
2022-03-29 08:53:30 +01:00
|
|
|
| CRBroadcastSent MsgContent Int ZonedTime
|
2022-05-28 19:13:07 +01:00
|
|
|
| CRMsgIntegrityError {msgError :: MsgErrorType}
|
2022-01-26 21:20:08 +00:00
|
|
|
| CRCmdAccepted {corr :: CorrId}
|
2022-02-08 17:27:43 +04:00
|
|
|
| CRCmdOk
|
2022-01-27 22:01:15 +00:00
|
|
|
| CRChatHelp {helpSection :: HelpSection}
|
|
|
|
|
| CRWelcome {user :: User}
|
2022-08-27 19:56:03 +04:00
|
|
|
| CRGroupCreated {groupInfo :: GroupInfo}
|
2022-01-26 21:20:08 +00:00
|
|
|
| CRGroupMembers {group :: Group}
|
|
|
|
|
| CRContactsList {contacts :: [Contact]}
|
2022-06-27 19:41:25 +01:00
|
|
|
| CRUserContactLink {connReqContact :: ConnReqContact, autoAccept :: Bool, autoReply :: Maybe MsgContent}
|
|
|
|
|
| CRUserContactLinkUpdated {connReqContact :: ConnReqContact, autoAccept :: Bool, autoReply :: Maybe MsgContent}
|
2022-01-31 21:53:53 +04:00
|
|
|
| CRContactRequestRejected {contactRequest :: UserContactRequest}
|
2022-01-26 21:20:08 +00:00
|
|
|
| CRUserAcceptedGroupSent {groupInfo :: GroupInfo}
|
|
|
|
|
| CRUserDeletedMember {groupInfo :: GroupInfo, member :: GroupMember}
|
|
|
|
|
| CRGroupsList {groups :: [GroupInfo]}
|
2022-08-27 19:56:03 +04:00
|
|
|
| CRSentGroupInvitation {groupInfo :: GroupInfo, contact :: Contact, member :: GroupMember}
|
2022-01-26 21:20:08 +00:00
|
|
|
| CRFileTransferStatus (FileTransfer, [Integer]) -- TODO refactor this type to FileTransferStatus
|
|
|
|
|
| CRUserProfile {profile :: Profile}
|
2022-01-24 16:07:17 +00:00
|
|
|
| CRUserProfileNoChange
|
2022-02-14 17:51:50 +00:00
|
|
|
| CRVersionInfo {version :: String}
|
2022-01-26 21:20:08 +00:00
|
|
|
| CRInvitation {connReqInvitation :: ConnReqInvitation}
|
2022-01-24 16:07:17 +00:00
|
|
|
| CRSentConfirmation
|
2022-08-18 11:35:31 +04:00
|
|
|
| CRSentInvitation {customUserProfile :: Maybe Profile}
|
2022-01-24 16:07:17 +00:00
|
|
|
| CRContactUpdated {fromContact :: Contact, toContact :: Contact}
|
|
|
|
|
| CRContactsMerged {intoContact :: Contact, mergedContact :: Contact}
|
2022-01-31 15:14:56 +04:00
|
|
|
| CRContactDeleted {contact :: Contact}
|
2022-05-17 11:22:09 +04:00
|
|
|
| CRChatCleared {chatInfo :: AChatInfo}
|
2022-01-26 21:20:08 +00:00
|
|
|
| CRUserContactLinkCreated {connReqContact :: ConnReqContact}
|
2022-01-24 16:07:17 +00:00
|
|
|
| CRUserContactLinkDeleted
|
2022-01-31 21:53:53 +04:00
|
|
|
| CRReceivedContactRequest {contactRequest :: UserContactRequest}
|
2022-02-01 17:04:44 +04:00
|
|
|
| CRAcceptingContactRequest {contact :: Contact}
|
2022-02-13 13:19:24 +04:00
|
|
|
| CRContactAlreadyExists {contact :: Contact}
|
|
|
|
|
| CRContactRequestAlreadyAccepted {contact :: Contact}
|
2022-01-26 21:20:08 +00:00
|
|
|
| CRLeftMemberUser {groupInfo :: GroupInfo}
|
|
|
|
|
| CRGroupDeletedUser {groupInfo :: GroupInfo}
|
2022-04-29 15:56:56 +04:00
|
|
|
| CRRcvFileAccepted {chatItem :: AChatItem}
|
2022-01-26 21:20:08 +00:00
|
|
|
| CRRcvFileAcceptedSndCancelled {rcvFileTransfer :: RcvFileTransfer}
|
2022-04-29 15:56:56 +04:00
|
|
|
| CRRcvFileStart {chatItem :: AChatItem}
|
2022-04-15 09:36:38 +04:00
|
|
|
| CRRcvFileComplete {chatItem :: AChatItem}
|
2022-01-26 21:20:08 +00:00
|
|
|
| CRRcvFileCancelled {rcvFileTransfer :: RcvFileTransfer}
|
|
|
|
|
| CRRcvFileSndCancelled {rcvFileTransfer :: RcvFileTransfer}
|
2022-05-05 10:37:53 +01:00
|
|
|
| CRSndFileStart {chatItem :: AChatItem, sndFileTransfer :: SndFileTransfer}
|
|
|
|
|
| CRSndFileComplete {chatItem :: AChatItem, sndFileTransfer :: SndFileTransfer}
|
|
|
|
|
| CRSndFileCancelled {chatItem :: AChatItem, sndFileTransfer :: SndFileTransfer}
|
|
|
|
|
| CRSndFileRcvCancelled {chatItem :: AChatItem, sndFileTransfer :: SndFileTransfer}
|
|
|
|
|
| CRSndGroupFileCancelled {chatItem :: AChatItem, fileTransferMeta :: FileTransferMeta, sndFileTransfers :: [SndFileTransfer]}
|
2022-01-24 16:07:17 +00:00
|
|
|
| CRUserProfileUpdated {fromProfile :: Profile, toProfile :: Profile}
|
2022-08-24 19:03:43 +04:00
|
|
|
| CRContactAliasUpdated {toContact :: Contact}
|
2022-02-08 13:04:17 +04:00
|
|
|
| CRContactConnecting {contact :: Contact}
|
2022-08-18 11:35:31 +04:00
|
|
|
| CRContactConnected {contact :: Contact, userCustomProfile :: Maybe Profile}
|
2022-01-26 21:20:08 +00:00
|
|
|
| CRContactAnotherClient {contact :: Contact}
|
2022-04-25 09:17:12 +01:00
|
|
|
| CRContactsDisconnected {server :: SMPServer, contactRefs :: [ContactRef]}
|
|
|
|
|
| CRContactsSubscribed {server :: SMPServer, contactRefs :: [ContactRef]}
|
2022-01-26 21:20:08 +00:00
|
|
|
| CRContactSubError {contact :: Contact, chatError :: ChatError}
|
2022-02-25 16:29:36 +04:00
|
|
|
| CRContactSubSummary {contactSubscriptions :: [ContactSubStatus]}
|
2022-08-13 14:18:12 +01:00
|
|
|
| CRHostConnected {protocol :: AProtocolType, transportHost :: TransportHost}
|
|
|
|
|
| CRHostDisconnected {protocol :: AProtocolType, transportHost :: TransportHost}
|
2022-01-26 21:20:08 +00:00
|
|
|
| CRGroupInvitation {groupInfo :: GroupInfo}
|
2022-08-27 19:56:03 +04:00
|
|
|
| CRReceivedGroupInvitation {groupInfo :: GroupInfo, contact :: Contact, memberRole :: GroupMemberRole}
|
|
|
|
|
| CRUserJoinedGroup {groupInfo :: GroupInfo, hostMember :: GroupMember}
|
|
|
|
|
| CRJoinedGroupMember {groupInfo :: GroupInfo, member :: GroupMember}
|
2022-01-26 21:20:08 +00:00
|
|
|
| CRJoinedGroupMemberConnecting {groupInfo :: GroupInfo, hostMember :: GroupMember, member :: GroupMember}
|
|
|
|
|
| CRConnectedToGroupMember {groupInfo :: GroupInfo, member :: GroupMember}
|
|
|
|
|
| CRDeletedMember {groupInfo :: GroupInfo, byMember :: GroupMember, deletedMember :: GroupMember}
|
|
|
|
|
| CRDeletedMemberUser {groupInfo :: GroupInfo, member :: GroupMember}
|
|
|
|
|
| CRLeftMember {groupInfo :: GroupInfo, member :: GroupMember}
|
|
|
|
|
| CRGroupEmpty {groupInfo :: GroupInfo}
|
|
|
|
|
| CRGroupRemoved {groupInfo :: GroupInfo}
|
|
|
|
|
| CRGroupDeleted {groupInfo :: GroupInfo, member :: GroupMember}
|
2022-07-29 19:04:32 +01:00
|
|
|
| CRGroupUpdated {fromGroup :: GroupInfo, toGroup :: GroupInfo, member_ :: Maybe GroupMember}
|
2022-07-17 15:51:17 +01:00
|
|
|
| CRMemberSubError {groupInfo :: GroupInfo, member :: GroupMember, chatError :: ChatError}
|
|
|
|
|
| CRMemberSubSummary {memberSubscriptions :: [MemberSubStatus]}
|
2022-01-26 21:20:08 +00:00
|
|
|
| CRGroupSubscribed {groupInfo :: GroupInfo}
|
2022-07-17 15:51:17 +01:00
|
|
|
| CRPendingSubSummary {pendingSubscriptions :: [PendingSubStatus]}
|
2022-01-26 21:20:08 +00:00
|
|
|
| CRSndFileSubError {sndFileTransfer :: SndFileTransfer, chatError :: ChatError}
|
|
|
|
|
| CRRcvFileSubError {rcvFileTransfer :: RcvFileTransfer, chatError :: ChatError}
|
2022-07-04 11:15:25 +01:00
|
|
|
| CRCallInvitation {callInvitation :: RcvCallInvitation}
|
2022-05-03 10:22:35 +01:00
|
|
|
| CRCallOffer {contact :: Contact, callType :: CallType, offer :: WebRTCSession, sharedKey :: Maybe C.Key, askConfirmation :: Bool}
|
2022-05-02 17:06:49 +01:00
|
|
|
| CRCallAnswer {contact :: Contact, answer :: WebRTCSession}
|
|
|
|
|
| CRCallExtraInfo {contact :: Contact, extraInfo :: WebRTCExtraInfo}
|
|
|
|
|
| CRCallEnded {contact :: Contact}
|
2022-07-04 11:15:25 +01:00
|
|
|
| CRCallInvitations {callInvitations :: [RcvCallInvitation]}
|
2022-01-24 16:07:17 +00:00
|
|
|
| CRUserContactLinkSubscribed
|
2022-01-26 21:20:08 +00:00
|
|
|
| CRUserContactLinkSubError {chatError :: ChatError}
|
2022-04-22 20:32:19 +01:00
|
|
|
| CRNtfTokenStatus {status :: NtfTknStatus}
|
2022-06-25 17:02:16 +01:00
|
|
|
| CRNtfToken {token :: DeviceToken, status :: NtfTknStatus, ntfMode :: NotificationsMode}
|
2022-06-19 14:44:13 +01:00
|
|
|
| CRNtfMessages {connEntity :: Maybe ConnectionEntity, msgTs :: Maybe UTCTime, ntfMessages :: [NtfMsgInfo]}
|
2022-04-23 17:32:40 +01:00
|
|
|
| CRNewContactConnection {connection :: PendingContactConnection}
|
|
|
|
|
| CRContactConnectionDeleted {connection :: PendingContactConnection}
|
2022-09-17 16:06:27 +01:00
|
|
|
| CRSQLResult {rows :: [Text]}
|
2022-01-26 21:20:08 +00:00
|
|
|
| CRMessageError {severity :: Text, errorMessage :: Text}
|
|
|
|
|
| CRChatCmdError {chatError :: ChatError}
|
|
|
|
|
| CRChatError {chatError :: ChatError}
|
|
|
|
|
deriving (Show, Generic)
|
|
|
|
|
|
|
|
|
|
instance ToJSON ChatResponse where
|
2022-01-29 20:21:37 +00:00
|
|
|
toJSON = J.genericToJSON . sumTypeJSON $ dropPrefix "CR"
|
|
|
|
|
toEncoding = J.genericToEncoding . sumTypeJSON $ dropPrefix "CR"
|
2021-06-25 18:18:24 +01:00
|
|
|
|
2022-07-06 21:45:29 +04:00
|
|
|
data ArchiveConfig = ArchiveConfig {archivePath :: FilePath, disableCompression :: Maybe Bool, parentTempDirectory :: Maybe FilePath}
|
2022-06-06 16:23:47 +01:00
|
|
|
deriving (Show, Generic, FromJSON)
|
|
|
|
|
|
2022-09-05 14:54:39 +01:00
|
|
|
data DBEncryptionConfig = DBEncryptionConfig {currentKey :: DBEncryptionKey, newKey :: DBEncryptionKey}
|
|
|
|
|
deriving (Show, Generic, FromJSON)
|
|
|
|
|
|
|
|
|
|
newtype DBEncryptionKey = DBEncryptionKey String
|
|
|
|
|
deriving (Show)
|
|
|
|
|
|
|
|
|
|
instance IsString DBEncryptionKey where fromString = parseString $ parseAll strP
|
|
|
|
|
|
|
|
|
|
instance StrEncoding DBEncryptionKey where
|
|
|
|
|
strEncode (DBEncryptionKey s) = B.pack s
|
|
|
|
|
strP = DBEncryptionKey . B.unpack <$> A.takeWhile (\c -> c /= ' ' && ord c >= 0x21 && ord c <= 0x7E)
|
|
|
|
|
|
|
|
|
|
instance FromJSON DBEncryptionKey where
|
|
|
|
|
parseJSON = strParseJSON "DBEncryptionKey"
|
|
|
|
|
|
2022-02-25 16:29:36 +04:00
|
|
|
data ContactSubStatus = ContactSubStatus
|
|
|
|
|
{ contact :: Contact,
|
|
|
|
|
contactError :: Maybe ChatError
|
|
|
|
|
}
|
|
|
|
|
deriving (Show, Generic)
|
|
|
|
|
|
|
|
|
|
instance ToJSON ContactSubStatus where
|
|
|
|
|
toJSON = J.genericToJSON J.defaultOptions {J.omitNothingFields = True}
|
|
|
|
|
toEncoding = J.genericToEncoding J.defaultOptions {J.omitNothingFields = True}
|
|
|
|
|
|
2022-07-17 15:51:17 +01:00
|
|
|
data MemberSubStatus = MemberSubStatus
|
2022-02-25 16:29:36 +04:00
|
|
|
{ member :: GroupMember,
|
2022-07-17 15:51:17 +01:00
|
|
|
memberError :: Maybe ChatError
|
2022-02-25 16:29:36 +04:00
|
|
|
}
|
|
|
|
|
deriving (Show, Generic)
|
|
|
|
|
|
2022-07-17 15:51:17 +01:00
|
|
|
instance ToJSON MemberSubStatus where
|
|
|
|
|
toJSON = J.genericToJSON J.defaultOptions {J.omitNothingFields = True}
|
|
|
|
|
toEncoding = J.genericToEncoding J.defaultOptions {J.omitNothingFields = True}
|
2022-02-25 16:29:36 +04:00
|
|
|
|
2022-02-26 20:21:32 +00:00
|
|
|
data PendingSubStatus = PendingSubStatus
|
2022-07-17 15:51:17 +01:00
|
|
|
{ connection :: PendingContactConnection,
|
2022-02-26 20:21:32 +00:00
|
|
|
connError :: Maybe ChatError
|
|
|
|
|
}
|
|
|
|
|
deriving (Show, Generic)
|
|
|
|
|
|
|
|
|
|
instance ToJSON PendingSubStatus where
|
|
|
|
|
toJSON = J.genericToJSON J.defaultOptions {J.omitNothingFields = True}
|
|
|
|
|
toEncoding = J.genericToEncoding J.defaultOptions {J.omitNothingFields = True}
|
|
|
|
|
|
2022-05-05 14:04:03 +01:00
|
|
|
data ComposedMessage = ComposedMessage
|
|
|
|
|
{ filePath :: Maybe FilePath,
|
|
|
|
|
quotedItemId :: Maybe ChatItemId,
|
|
|
|
|
msgContent :: MsgContent
|
|
|
|
|
}
|
|
|
|
|
deriving (Show, Generic, FromJSON)
|
|
|
|
|
|
2022-06-19 14:44:13 +01:00
|
|
|
data NtfMsgInfo = NtfMsgInfo {msgTs :: UTCTime, msgFlags :: MsgFlags}
|
|
|
|
|
deriving (Show, Generic)
|
|
|
|
|
|
|
|
|
|
instance ToJSON NtfMsgInfo where toEncoding = J.genericToEncoding J.defaultOptions
|
|
|
|
|
|
2022-06-25 17:02:16 +01:00
|
|
|
crNtfToken :: (DeviceToken, NtfTknStatus, NotificationsMode) -> ChatResponse
|
|
|
|
|
crNtfToken (token, status, ntfMode) = CRNtfToken {token, status, ntfMode}
|
|
|
|
|
|
2021-07-04 18:42:24 +01:00
|
|
|
data ChatError
|
2022-01-27 22:01:15 +00:00
|
|
|
= ChatError {errorType :: ChatErrorType}
|
|
|
|
|
| ChatErrorAgent {agentError :: AgentErrorType}
|
|
|
|
|
| ChatErrorStore {storeError :: StoreError}
|
2022-09-06 23:14:58 +01:00
|
|
|
| ChatErrorDatabase {databaseError :: DatabaseError}
|
2022-01-26 21:20:08 +00:00
|
|
|
deriving (Show, Exception, Generic)
|
|
|
|
|
|
|
|
|
|
instance ToJSON ChatError where
|
2022-01-29 20:21:37 +00:00
|
|
|
toJSON = J.genericToJSON . sumTypeJSON $ dropPrefix "Chat"
|
|
|
|
|
toEncoding = J.genericToEncoding . sumTypeJSON $ dropPrefix "Chat"
|
2021-07-04 18:42:24 +01:00
|
|
|
|
2021-07-16 07:40:55 +01:00
|
|
|
data ChatErrorType
|
2022-02-06 16:18:01 +00:00
|
|
|
= CENoActiveUser
|
|
|
|
|
| CEActiveUserExists
|
|
|
|
|
| CEChatNotStarted
|
2022-06-06 16:23:47 +01:00
|
|
|
| CEChatNotStopped
|
|
|
|
|
| CEChatStoreChanged
|
2022-01-24 16:07:17 +00:00
|
|
|
| CEInvalidConnReq
|
2022-02-06 16:18:01 +00:00
|
|
|
| CEInvalidChatMessage {message :: String}
|
2022-02-14 18:49:42 +04:00
|
|
|
| CEContactNotReady {contact :: Contact}
|
2022-01-31 15:14:56 +04:00
|
|
|
| CEContactGroups {contact :: Contact, groupNames :: [GroupName]}
|
2022-02-06 16:18:01 +00:00
|
|
|
| CEGroupUserRole
|
2022-08-27 19:56:03 +04:00
|
|
|
| CEContactIncognitoCantInvite
|
|
|
|
|
| CEGroupIncognitoCantInvite
|
2022-01-26 21:20:08 +00:00
|
|
|
| CEGroupContactRole {contactName :: ContactName}
|
|
|
|
|
| CEGroupDuplicateMember {contactName :: ContactName}
|
2021-07-16 07:40:55 +01:00
|
|
|
| CEGroupDuplicateMemberId
|
2022-01-26 21:20:08 +00:00
|
|
|
| CEGroupNotJoined {groupInfo :: GroupInfo}
|
2021-07-24 10:26:28 +01:00
|
|
|
| CEGroupMemberNotActive
|
2021-08-02 20:10:24 +01:00
|
|
|
| CEGroupMemberUserRemoved
|
2022-07-12 19:20:56 +04:00
|
|
|
| CEGroupMemberNotFound
|
2022-01-26 21:20:08 +00:00
|
|
|
| CEGroupMemberIntroNotFound {contactName :: ContactName}
|
|
|
|
|
| CEGroupCantResendInvitation {groupInfo :: GroupInfo, contactName :: ContactName}
|
|
|
|
|
| CEGroupInternal {message :: String}
|
|
|
|
|
| CEFileNotFound {message :: String}
|
|
|
|
|
| CEFileAlreadyReceiving {message :: String}
|
2022-05-11 16:18:28 +04:00
|
|
|
| CEFileCancelled {message :: String}
|
2022-01-26 21:20:08 +00:00
|
|
|
| CEFileAlreadyExists {filePath :: FilePath}
|
|
|
|
|
| CEFileRead {filePath :: FilePath, message :: String}
|
|
|
|
|
| CEFileWrite {filePath :: FilePath, message :: String}
|
|
|
|
|
| CEFileSend {fileId :: FileTransferId, agentError :: AgentErrorType}
|
|
|
|
|
| CEFileRcvChunk {message :: String}
|
|
|
|
|
| CEFileInternal {message :: String}
|
2022-05-21 18:17:15 +04:00
|
|
|
| CEFileImageType {filePath :: FilePath}
|
|
|
|
|
| CEFileImageSize {filePath :: FilePath}
|
|
|
|
|
| CEFileNotReceived {fileId :: FileTransferId}
|
2022-03-13 19:34:03 +00:00
|
|
|
| CEInvalidQuote
|
2022-03-28 20:35:57 +04:00
|
|
|
| CEInvalidChatItemUpdate
|
|
|
|
|
| CEInvalidChatItemDelete
|
2022-05-03 10:22:35 +01:00
|
|
|
| CEHasCurrentCall
|
|
|
|
|
| CENoCurrentCall
|
|
|
|
|
| CECallContact {contactId :: Int64}
|
|
|
|
|
| CECallState {currentCallState :: CallStateTag}
|
2022-01-11 08:50:44 +00:00
|
|
|
| CEAgentVersion
|
2022-07-17 15:51:17 +01:00
|
|
|
| CEAgentNoSubResult {agentConnId :: AgentConnId}
|
2022-01-26 21:20:08 +00:00
|
|
|
| CECommandError {message :: String}
|
2022-09-14 19:45:21 +04:00
|
|
|
| CEAgentCommandError {message :: String}
|
2022-01-26 21:20:08 +00:00
|
|
|
deriving (Show, Exception, Generic)
|
|
|
|
|
|
|
|
|
|
instance ToJSON ChatErrorType where
|
2022-01-29 20:21:37 +00:00
|
|
|
toJSON = J.genericToJSON . sumTypeJSON $ dropPrefix "CE"
|
|
|
|
|
toEncoding = J.genericToEncoding . sumTypeJSON $ dropPrefix "CE"
|
2021-06-25 18:18:24 +01:00
|
|
|
|
2022-08-31 18:07:34 +01:00
|
|
|
data DatabaseError
|
2022-09-05 14:54:39 +01:00
|
|
|
= DBErrorEncrypted
|
|
|
|
|
| DBErrorPlaintext
|
|
|
|
|
| DBErrorNoFile {dbFile :: String}
|
2022-09-06 23:14:58 +01:00
|
|
|
| DBErrorExport {sqliteError :: SQLiteError}
|
|
|
|
|
| DBErrorOpen {sqliteError :: SQLiteError}
|
2022-08-31 18:07:34 +01:00
|
|
|
deriving (Show, Exception, Generic)
|
|
|
|
|
|
|
|
|
|
instance ToJSON DatabaseError where
|
2022-09-06 23:14:58 +01:00
|
|
|
toJSON = J.genericToJSON . sumTypeJSON $ dropPrefix "DB"
|
|
|
|
|
toEncoding = J.genericToEncoding . sumTypeJSON $ dropPrefix "DB"
|
|
|
|
|
|
|
|
|
|
data SQLiteError = SQLiteErrorNotADatabase | SQLiteError String
|
|
|
|
|
deriving (Show, Exception, Generic)
|
|
|
|
|
|
|
|
|
|
instance ToJSON SQLiteError where
|
|
|
|
|
toJSON = J.genericToJSON . sumTypeJSON $ dropPrefix "SQLite"
|
|
|
|
|
toEncoding = J.genericToEncoding . sumTypeJSON $ dropPrefix "SQLite"
|
2022-08-31 18:07:34 +01:00
|
|
|
|
|
|
|
|
throwDBError :: ChatMonad m => DatabaseError -> m ()
|
|
|
|
|
throwDBError = throwError . ChatErrorDatabase
|
|
|
|
|
|
2022-01-24 16:07:17 +00:00
|
|
|
type ChatMonad m = (MonadUnliftIO m, MonadReader ChatController m, MonadError ChatError m)
|
2021-06-25 18:18:24 +01:00
|
|
|
|
2022-02-06 16:18:01 +00:00
|
|
|
chatCmdError :: String -> ChatResponse
|
|
|
|
|
chatCmdError = CRChatCmdError . ChatError . CECommandError
|
|
|
|
|
|
2021-07-04 18:42:24 +01:00
|
|
|
setActive :: (MonadUnliftIO m, MonadReader ChatController m) => ActiveTo -> m ()
|
2022-01-21 11:09:33 +00:00
|
|
|
setActive to = asks activeTo >>= atomically . (`writeTVar` to)
|
2021-06-25 18:18:24 +01:00
|
|
|
|
2021-07-04 18:42:24 +01:00
|
|
|
unsetActive :: (MonadUnliftIO m, MonadReader ChatController m) => ActiveTo -> m ()
|
2022-01-21 11:09:33 +00:00
|
|
|
unsetActive a = asks activeTo >>= atomically . (`modifyTVar` unset)
|
2021-06-25 18:18:24 +01:00
|
|
|
where
|
|
|
|
|
unset a' = if a == a' then ActiveNone else a'
|