{-# LANGUAGE ApplicativeDo #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}

module Simplex.Chat.Options
  ( ChatOpts (..),
    CoreChatOpts (..),
    CreateBotOpts (..),
    ChatCmdLog (..),
    chatOptsP,
    coreChatOptsP,
    getChatOpts,
    protocolServersP,
    defaultHostMode,
    printDbOpts,
  )
where

import Control.Logger.Simple (LogLevel (..))
import qualified Data.Attoparsec.ByteString.Char8 as A
import qualified Data.ByteString.Char8 as B
import Data.Maybe (fromMaybe)
import Data.Text (Text)
import qualified Data.Text as T
import Data.Text.Encoding (encodeUtf8)
import Numeric.Natural (Natural)
import Options.Applicative
import Simplex.Chat.Controller (ChatLogLevel (..), SimpleNetCfg (..), versionNumber, versionString)
import Simplex.FileTransfer.Description (mb)
import Simplex.Messaging.Client (HostMode (..), SMPWebPortServers (..), SocksMode (..), textToHostMode)
import Simplex.Messaging.Encoding.String
import Simplex.Messaging.Parsers (parseAll)
import Simplex.Messaging.Protocol (ProtoServerWithAuth, ProtocolTypeI, SMPServerWithAuth, XFTPServerWithAuth)
import Simplex.Messaging.Transport.Client (SocksProxyWithAuth (..), SocksAuth (..), defaultSocksProxyWithAuth)
import Simplex.Chat.Options.DB

data ChatOpts = ChatOpts
  { ChatOpts -> CoreChatOpts
coreOptions :: CoreChatOpts,
    ChatOpts -> String
chatCmd :: String,
    ChatOpts -> Int
chatCmdDelay :: Int,
    ChatOpts -> ChatCmdLog
chatCmdLog :: ChatCmdLog,
    ChatOpts -> Maybe String
chatServerPort :: Maybe String,
    ChatOpts -> Maybe String
optFilesFolder :: Maybe FilePath,
    ChatOpts -> Maybe String
optTempDirectory :: Maybe FilePath,
    ChatOpts -> Bool
showReactions :: Bool,
    ChatOpts -> Bool
allowInstantFiles :: Bool,
    ChatOpts -> Integer
autoAcceptFileSize :: Integer,
    ChatOpts -> Bool
muteNotifications :: Bool,
    ChatOpts -> Bool
markRead :: Bool,
    ChatOpts -> Maybe CreateBotOpts
createBot :: Maybe CreateBotOpts,
    ChatOpts -> Bool
maintenance :: Bool
  }

data CoreChatOpts = CoreChatOpts
  { CoreChatOpts -> ChatDbOpts
dbOptions :: ChatDbOpts,
    CoreChatOpts -> [ProtoServerWithAuth 'PSMP]
smpServers :: [SMPServerWithAuth],
    CoreChatOpts -> [ProtoServerWithAuth 'PXFTP]
xftpServers :: [XFTPServerWithAuth],
    CoreChatOpts -> SimpleNetCfg
simpleNetCfg :: SimpleNetCfg,
    CoreChatOpts -> ChatLogLevel
logLevel :: ChatLogLevel,
    CoreChatOpts -> Bool
logConnections :: Bool,
    CoreChatOpts -> Bool
logServerHosts :: Bool,
    CoreChatOpts -> Maybe LogLevel
logAgent :: Maybe LogLevel,
    CoreChatOpts -> Maybe String
logFile :: Maybe FilePath,
    CoreChatOpts -> Natural
tbqSize :: Natural,
    CoreChatOpts -> Maybe Text
deviceName :: Maybe Text,
    CoreChatOpts -> Bool
highlyAvailable :: Bool,
    CoreChatOpts -> Bool
yesToUpMigrations :: Bool,
    CoreChatOpts -> Maybe String
migrationBackupPath :: Maybe FilePath
  }

data CreateBotOpts = CreateBotOpts
  { CreateBotOpts -> Text
botDisplayName :: Text,
    CreateBotOpts -> Bool
allowFiles :: Bool
  }

data ChatCmdLog = CCLAll | CCLMessages | CCLNone
  deriving (ChatCmdLog -> ChatCmdLog -> Bool
(ChatCmdLog -> ChatCmdLog -> Bool)
-> (ChatCmdLog -> ChatCmdLog -> Bool) -> Eq ChatCmdLog
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: ChatCmdLog -> ChatCmdLog -> Bool
== :: ChatCmdLog -> ChatCmdLog -> Bool
$c/= :: ChatCmdLog -> ChatCmdLog -> Bool
/= :: ChatCmdLog -> ChatCmdLog -> Bool
Eq)

agentLogLevel :: ChatLogLevel -> LogLevel
agentLogLevel :: ChatLogLevel -> LogLevel
agentLogLevel = \case
  ChatLogLevel
CLLDebug -> LogLevel
LogDebug
  ChatLogLevel
CLLInfo -> LogLevel
LogInfo
  ChatLogLevel
CLLWarning -> LogLevel
LogWarn
  ChatLogLevel
CLLError -> LogLevel
LogError
  ChatLogLevel
CLLImportant -> LogLevel
LogInfo

coreChatOptsP :: FilePath -> FilePath -> Parser CoreChatOpts
coreChatOptsP :: String -> String -> Parser CoreChatOpts
coreChatOptsP String
appDir String
defaultDbName = do
  ChatDbOpts
dbOptions <- String -> String -> Parser ChatDbOpts
chatDbOptsP String
appDir String
defaultDbName
  [ProtoServerWithAuth 'PSMP]
smpServers <-
    ReadM [ProtoServerWithAuth 'PSMP]
-> Mod OptionFields [ProtoServerWithAuth 'PSMP]
-> Parser [ProtoServerWithAuth 'PSMP]
forall a. ReadM a -> Mod OptionFields a -> Parser a
option
      ReadM [ProtoServerWithAuth 'PSMP]
forall (p :: ProtocolType).
ProtocolTypeI p =>
ReadM [ProtoServerWithAuth p]
parseProtocolServers
      ( String -> Mod OptionFields [ProtoServerWithAuth 'PSMP]
forall (f :: * -> *) a. HasName f => String -> Mod f a
long String
"server"
          Mod OptionFields [ProtoServerWithAuth 'PSMP]
-> Mod OptionFields [ProtoServerWithAuth 'PSMP]
-> Mod OptionFields [ProtoServerWithAuth 'PSMP]
forall a. Semigroup a => a -> a -> a
<> Char -> Mod OptionFields [ProtoServerWithAuth 'PSMP]
forall (f :: * -> *) a. HasName f => Char -> Mod f a
short Char
's'
          Mod OptionFields [ProtoServerWithAuth 'PSMP]
-> Mod OptionFields [ProtoServerWithAuth 'PSMP]
-> Mod OptionFields [ProtoServerWithAuth 'PSMP]
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields [ProtoServerWithAuth 'PSMP]
forall (f :: * -> *) a. HasMetavar f => String -> Mod f a
metavar String
"SERVER"
          Mod OptionFields [ProtoServerWithAuth 'PSMP]
-> Mod OptionFields [ProtoServerWithAuth 'PSMP]
-> Mod OptionFields [ProtoServerWithAuth 'PSMP]
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields [ProtoServerWithAuth 'PSMP]
forall (f :: * -> *) a. String -> Mod f a
help
            ( (String
"Space-separated list of SMP server(s) to use (each server can have more than one hostname)." String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
"\n")
                String -> String -> String
forall a. Semigroup a => a -> a -> a
<> (String
"If you pass multiple servers, surround the entire list in quotes." String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
"\n")
                String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
"Examples: smp1.example.com, \"smp1.example.com smp2.example.com smp3.example.com\""
            )
          Mod OptionFields [ProtoServerWithAuth 'PSMP]
-> Mod OptionFields [ProtoServerWithAuth 'PSMP]
-> Mod OptionFields [ProtoServerWithAuth 'PSMP]
forall a. Semigroup a => a -> a -> a
<> [ProtoServerWithAuth 'PSMP]
-> Mod OptionFields [ProtoServerWithAuth 'PSMP]
forall (f :: * -> *) a. HasValue f => a -> Mod f a
value []
      )
  [ProtoServerWithAuth 'PXFTP]
xftpServers <-
    ReadM [ProtoServerWithAuth 'PXFTP]
-> Mod OptionFields [ProtoServerWithAuth 'PXFTP]
-> Parser [ProtoServerWithAuth 'PXFTP]
forall a. ReadM a -> Mod OptionFields a -> Parser a
option
      ReadM [ProtoServerWithAuth 'PXFTP]
forall (p :: ProtocolType).
ProtocolTypeI p =>
ReadM [ProtoServerWithAuth p]
parseProtocolServers
      ( String -> Mod OptionFields [ProtoServerWithAuth 'PXFTP]
forall (f :: * -> *) a. HasName f => String -> Mod f a
long String
"xftp-server"
          Mod OptionFields [ProtoServerWithAuth 'PXFTP]
-> Mod OptionFields [ProtoServerWithAuth 'PXFTP]
-> Mod OptionFields [ProtoServerWithAuth 'PXFTP]
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields [ProtoServerWithAuth 'PXFTP]
forall (f :: * -> *) a. HasMetavar f => String -> Mod f a
metavar String
"SERVER"
          Mod OptionFields [ProtoServerWithAuth 'PXFTP]
-> Mod OptionFields [ProtoServerWithAuth 'PXFTP]
-> Mod OptionFields [ProtoServerWithAuth 'PXFTP]
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields [ProtoServerWithAuth 'PXFTP]
forall (f :: * -> *) a. String -> Mod f a
help
            ( (String
"Space-separated list of XFTP server(s) to use (each server can have more than one hostname)." String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
"\n")
                String -> String -> String
forall a. Semigroup a => a -> a -> a
<> (String
"If you pass multiple servers, surround the entire list in quotes." String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
"\n")
                String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
"Examples: xftp1.example.com, \"xftp1.example.com xftp2.example.com xftp3.example.com\""
            )
          Mod OptionFields [ProtoServerWithAuth 'PXFTP]
-> Mod OptionFields [ProtoServerWithAuth 'PXFTP]
-> Mod OptionFields [ProtoServerWithAuth 'PXFTP]
forall a. Semigroup a => a -> a -> a
<> [ProtoServerWithAuth 'PXFTP]
-> Mod OptionFields [ProtoServerWithAuth 'PXFTP]
forall (f :: * -> *) a. HasValue f => a -> Mod f a
value []
      )
  Maybe SocksProxyWithAuth
socksProxy <-
    Maybe SocksProxyWithAuth
-> Mod FlagFields (Maybe SocksProxyWithAuth)
-> Parser (Maybe SocksProxyWithAuth)
forall a. a -> Mod FlagFields a -> Parser a
flag' (SocksProxyWithAuth -> Maybe SocksProxyWithAuth
forall a. a -> Maybe a
Just SocksProxyWithAuth
defaultSocksProxyWithAuth) (Char -> Mod FlagFields (Maybe SocksProxyWithAuth)
forall (f :: * -> *) a. HasName f => Char -> Mod f a
short Char
'x' Mod FlagFields (Maybe SocksProxyWithAuth)
-> Mod FlagFields (Maybe SocksProxyWithAuth)
-> Mod FlagFields (Maybe SocksProxyWithAuth)
forall a. Semigroup a => a -> a -> a
<> String -> Mod FlagFields (Maybe SocksProxyWithAuth)
forall (f :: * -> *) a. String -> Mod f a
help String
"Use local SOCKS5 proxy at :9050")
      Parser (Maybe SocksProxyWithAuth)
-> Parser (Maybe SocksProxyWithAuth)
-> Parser (Maybe SocksProxyWithAuth)
forall a. Parser a -> Parser a -> Parser a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> ReadM (Maybe SocksProxyWithAuth)
-> Mod OptionFields (Maybe SocksProxyWithAuth)
-> Parser (Maybe SocksProxyWithAuth)
forall a. ReadM a -> Mod OptionFields a -> Parser a
option
        ReadM (Maybe SocksProxyWithAuth)
forall a. StrEncoding a => ReadM a
strParse
        ( String -> Mod OptionFields (Maybe SocksProxyWithAuth)
forall (f :: * -> *) a. HasName f => String -> Mod f a
long String
"socks-proxy"
            Mod OptionFields (Maybe SocksProxyWithAuth)
-> Mod OptionFields (Maybe SocksProxyWithAuth)
-> Mod OptionFields (Maybe SocksProxyWithAuth)
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields (Maybe SocksProxyWithAuth)
forall (f :: * -> *) a. HasMetavar f => String -> Mod f a
metavar String
"SOCKS5"
            Mod OptionFields (Maybe SocksProxyWithAuth)
-> Mod OptionFields (Maybe SocksProxyWithAuth)
-> Mod OptionFields (Maybe SocksProxyWithAuth)
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields (Maybe SocksProxyWithAuth)
forall (f :: * -> *) a. String -> Mod f a
help String
"Use SOCKS5 proxy at `ipv4:port` or `:port`"
            Mod OptionFields (Maybe SocksProxyWithAuth)
-> Mod OptionFields (Maybe SocksProxyWithAuth)
-> Mod OptionFields (Maybe SocksProxyWithAuth)
forall a. Semigroup a => a -> a -> a
<> Maybe SocksProxyWithAuth
-> Mod OptionFields (Maybe SocksProxyWithAuth)
forall (f :: * -> *) a. HasValue f => a -> Mod f a
value Maybe SocksProxyWithAuth
forall a. Maybe a
Nothing
        )
  SocksMode
socksMode <-
    ReadM SocksMode -> Mod OptionFields SocksMode -> Parser SocksMode
forall a. ReadM a -> Mod OptionFields a -> Parser a
option
      ReadM SocksMode
forall a. StrEncoding a => ReadM a
strParse
      ( String -> Mod OptionFields SocksMode
forall (f :: * -> *) a. HasName f => String -> Mod f a
long String
"socks-mode"
          Mod OptionFields SocksMode
-> Mod OptionFields SocksMode -> Mod OptionFields SocksMode
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields SocksMode
forall (f :: * -> *) a. HasMetavar f => String -> Mod f a
metavar String
"SOCKS_MODE"
          Mod OptionFields SocksMode
-> Mod OptionFields SocksMode -> Mod OptionFields SocksMode
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields SocksMode
forall (f :: * -> *) a. String -> Mod f a
help String
"Use SOCKS5 proxy: always (default), onion (with onion-only relays)"
          Mod OptionFields SocksMode
-> Mod OptionFields SocksMode -> Mod OptionFields SocksMode
forall a. Semigroup a => a -> a -> a
<> SocksMode -> Mod OptionFields SocksMode
forall (f :: * -> *) a. HasValue f => a -> Mod f a
value SocksMode
SMAlways
      )
  Maybe HostMode
hostMode_ <-
    Parser HostMode -> Parser (Maybe HostMode)
forall (f :: * -> *) a. Alternative f => f a -> f (Maybe a)
optional (Parser HostMode -> Parser (Maybe HostMode))
-> Parser HostMode -> Parser (Maybe HostMode)
forall a b. (a -> b) -> a -> b
$
      ReadM HostMode -> Mod OptionFields HostMode -> Parser HostMode
forall a. ReadM a -> Mod OptionFields a -> Parser a
option
        ReadM HostMode
parseHostMode
        ( String -> Mod OptionFields HostMode
forall (f :: * -> *) a. HasName f => String -> Mod f a
long String
"host-mode"
            Mod OptionFields HostMode
-> Mod OptionFields HostMode -> Mod OptionFields HostMode
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields HostMode
forall (f :: * -> *) a. HasMetavar f => String -> Mod f a
metavar String
"HOST_MODE"
            Mod OptionFields HostMode
-> Mod OptionFields HostMode -> Mod OptionFields HostMode
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields HostMode
forall (f :: * -> *) a. String -> Mod f a
help String
"Preferred server host type: onion (when SOCKS proxy with isolate-by-auth is used), public"
        )
  Bool
requiredHostMode <-
    Mod FlagFields Bool -> Parser Bool
switch
      ( String -> Mod FlagFields Bool
forall (f :: * -> *) a. HasName f => String -> Mod f a
long String
"required-host-mode"
          Mod FlagFields Bool -> Mod FlagFields Bool -> Mod FlagFields Bool
forall a. Semigroup a => a -> a -> a
<> String -> Mod FlagFields Bool
forall (f :: * -> *) a. String -> Mod f a
help String
"Refuse connection if preferred server host type is not available"
      )
  Maybe SMPProxyMode
smpProxyMode_ <-
    Parser SMPProxyMode -> Parser (Maybe SMPProxyMode)
forall (f :: * -> *) a. Alternative f => f a -> f (Maybe a)
optional (Parser SMPProxyMode -> Parser (Maybe SMPProxyMode))
-> Parser SMPProxyMode -> Parser (Maybe SMPProxyMode)
forall a b. (a -> b) -> a -> b
$
      ReadM SMPProxyMode
-> Mod OptionFields SMPProxyMode -> Parser SMPProxyMode
forall a. ReadM a -> Mod OptionFields a -> Parser a
option
        ReadM SMPProxyMode
forall a. StrEncoding a => ReadM a
strParse
        ( String -> Mod OptionFields SMPProxyMode
forall (f :: * -> *) a. HasName f => String -> Mod f a
long String
"smp-proxy"
            Mod OptionFields SMPProxyMode
-> Mod OptionFields SMPProxyMode -> Mod OptionFields SMPProxyMode
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields SMPProxyMode
forall (f :: * -> *) a. HasMetavar f => String -> Mod f a
metavar String
"SMP_PROXY_MODE"
            Mod OptionFields SMPProxyMode
-> Mod OptionFields SMPProxyMode -> Mod OptionFields SMPProxyMode
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields SMPProxyMode
forall (f :: * -> *) a. String -> Mod f a
help String
"Use private message routing: always, unknown (default), unprotected, never"
        )
  Maybe SMPProxyFallback
smpProxyFallback_ <-
    Parser SMPProxyFallback -> Parser (Maybe SMPProxyFallback)
forall (f :: * -> *) a. Alternative f => f a -> f (Maybe a)
optional (Parser SMPProxyFallback -> Parser (Maybe SMPProxyFallback))
-> Parser SMPProxyFallback -> Parser (Maybe SMPProxyFallback)
forall a b. (a -> b) -> a -> b
$
      ReadM SMPProxyFallback
-> Mod OptionFields SMPProxyFallback -> Parser SMPProxyFallback
forall a. ReadM a -> Mod OptionFields a -> Parser a
option
        ReadM SMPProxyFallback
forall a. StrEncoding a => ReadM a
strParse
        ( String -> Mod OptionFields SMPProxyFallback
forall (f :: * -> *) a. HasName f => String -> Mod f a
long String
"smp-proxy-fallback"
            Mod OptionFields SMPProxyFallback
-> Mod OptionFields SMPProxyFallback
-> Mod OptionFields SMPProxyFallback
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields SMPProxyFallback
forall (f :: * -> *) a. HasMetavar f => String -> Mod f a
metavar String
"SMP_PROXY_FALLBACK_MODE"
            Mod OptionFields SMPProxyFallback
-> Mod OptionFields SMPProxyFallback
-> Mod OptionFields SMPProxyFallback
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields SMPProxyFallback
forall (f :: * -> *) a. String -> Mod f a
help String
"Allow downgrade and connect directly: no, [when IP address is] protected (default), yes"
        )
  SMPWebPortServers
smpWebPortServers <-
    SMPWebPortServers
-> Mod FlagFields SMPWebPortServers -> Parser SMPWebPortServers
forall a. a -> Mod FlagFields a -> Parser a
flag' SMPWebPortServers
SWPAll
      ( String -> Mod FlagFields SMPWebPortServers
forall (f :: * -> *) a. HasName f => String -> Mod f a
long String
"smp-web-port"
          Mod FlagFields SMPWebPortServers
-> Mod FlagFields SMPWebPortServers
-> Mod FlagFields SMPWebPortServers
forall a. Semigroup a => a -> a -> a
<> String -> Mod FlagFields SMPWebPortServers
forall (f :: * -> *) a. String -> Mod f a
help String
"Use port 443 with SMP servers when not specified"
      )
      Parser SMPWebPortServers
-> Parser SMPWebPortServers -> Parser SMPWebPortServers
forall a. Parser a -> Parser a -> Parser a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> ReadM SMPWebPortServers
-> Mod OptionFields SMPWebPortServers -> Parser SMPWebPortServers
forall a. ReadM a -> Mod OptionFields a -> Parser a
option
        ReadM SMPWebPortServers
forall a. StrEncoding a => ReadM a
strParse
          ( String -> Mod OptionFields SMPWebPortServers
forall (f :: * -> *) a. HasName f => String -> Mod f a
long String
"smp-web-port-servers"
              Mod OptionFields SMPWebPortServers
-> Mod OptionFields SMPWebPortServers
-> Mod OptionFields SMPWebPortServers
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields SMPWebPortServers
forall (f :: * -> *) a. String -> Mod f a
help String
"Use port 443 with SMP servers when not specified: all, preset (default), off"
              Mod OptionFields SMPWebPortServers
-> Mod OptionFields SMPWebPortServers
-> Mod OptionFields SMPWebPortServers
forall a. Semigroup a => a -> a -> a
<> SMPWebPortServers -> Mod OptionFields SMPWebPortServers
forall (f :: * -> *) a. HasValue f => a -> Mod f a
value SMPWebPortServers
SWPPreset
          )
  Int
t <-
    ReadM Int -> Mod OptionFields Int -> Parser Int
forall a. ReadM a -> Mod OptionFields a -> Parser a
option
      ReadM Int
forall a. Read a => ReadM a
auto
      ( String -> Mod OptionFields Int
forall (f :: * -> *) a. HasName f => String -> Mod f a
long String
"tcp-timeout"
          Mod OptionFields Int
-> Mod OptionFields Int -> Mod OptionFields Int
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields Int
forall (f :: * -> *) a. HasMetavar f => String -> Mod f a
metavar String
"TIMEOUT"
          Mod OptionFields Int
-> Mod OptionFields Int -> Mod OptionFields Int
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields Int
forall (f :: * -> *) a. String -> Mod f a
help String
"TCP timeout, seconds (default: 7/15 without/with SOCKS5 proxy)"
          Mod OptionFields Int
-> Mod OptionFields Int -> Mod OptionFields Int
forall a. Semigroup a => a -> a -> a
<> Int -> Mod OptionFields Int
forall (f :: * -> *) a. HasValue f => a -> Mod f a
value Int
0
      )
  ChatLogLevel
logLevel <-
    ReadM ChatLogLevel
-> Mod OptionFields ChatLogLevel -> Parser ChatLogLevel
forall a. ReadM a -> Mod OptionFields a -> Parser a
option
      ReadM ChatLogLevel
parseLogLevel
      ( String -> Mod OptionFields ChatLogLevel
forall (f :: * -> *) a. HasName f => String -> Mod f a
long String
"log-level"
          Mod OptionFields ChatLogLevel
-> Mod OptionFields ChatLogLevel -> Mod OptionFields ChatLogLevel
forall a. Semigroup a => a -> a -> a
<> Char -> Mod OptionFields ChatLogLevel
forall (f :: * -> *) a. HasName f => Char -> Mod f a
short Char
'l'
          Mod OptionFields ChatLogLevel
-> Mod OptionFields ChatLogLevel -> Mod OptionFields ChatLogLevel
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields ChatLogLevel
forall (f :: * -> *) a. HasMetavar f => String -> Mod f a
metavar String
"LEVEL"
          Mod OptionFields ChatLogLevel
-> Mod OptionFields ChatLogLevel -> Mod OptionFields ChatLogLevel
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields ChatLogLevel
forall (f :: * -> *) a. String -> Mod f a
help String
"Log level: debug, info, warn, error, important (default)"
          Mod OptionFields ChatLogLevel
-> Mod OptionFields ChatLogLevel -> Mod OptionFields ChatLogLevel
forall a. Semigroup a => a -> a -> a
<> ChatLogLevel -> Mod OptionFields ChatLogLevel
forall (f :: * -> *) a. HasValue f => a -> Mod f a
value ChatLogLevel
CLLImportant
      )
  Bool
logTLSErrors <-
    Mod FlagFields Bool -> Parser Bool
switch
      ( String -> Mod FlagFields Bool
forall (f :: * -> *) a. HasName f => String -> Mod f a
long String
"log-tls-errors"
          Mod FlagFields Bool -> Mod FlagFields Bool -> Mod FlagFields Bool
forall a. Semigroup a => a -> a -> a
<> String -> Mod FlagFields Bool
forall (f :: * -> *) a. String -> Mod f a
help String
"Log TLS errors"
      )
  Bool
logConnections <-
    Mod FlagFields Bool -> Parser Bool
switch
      ( String -> Mod FlagFields Bool
forall (f :: * -> *) a. HasName f => String -> Mod f a
long String
"connections"
          Mod FlagFields Bool -> Mod FlagFields Bool -> Mod FlagFields Bool
forall a. Semigroup a => a -> a -> a
<> Char -> Mod FlagFields Bool
forall (f :: * -> *) a. HasName f => Char -> Mod f a
short Char
'c'
          Mod FlagFields Bool -> Mod FlagFields Bool -> Mod FlagFields Bool
forall a. Semigroup a => a -> a -> a
<> String -> Mod FlagFields Bool
forall (f :: * -> *) a. String -> Mod f a
help String
"Log connections subscription errors on start (also with `-l info`)"
      )
  Bool
logServerHosts <-
    Mod FlagFields Bool -> Parser Bool
switch
      ( String -> Mod FlagFields Bool
forall (f :: * -> *) a. HasName f => String -> Mod f a
long String
"log-hosts"
          Mod FlagFields Bool -> Mod FlagFields Bool -> Mod FlagFields Bool
forall a. Semigroup a => a -> a -> a
<> String -> Mod FlagFields Bool
forall (f :: * -> *) a. String -> Mod f a
help String
"Log connections to servers (also with `-l info`)"
      )
  Bool
logAgent <-
    Mod FlagFields Bool -> Parser Bool
switch
      ( String -> Mod FlagFields Bool
forall (f :: * -> *) a. HasName f => String -> Mod f a
long String
"log-agent"
          Mod FlagFields Bool -> Mod FlagFields Bool -> Mod FlagFields Bool
forall a. Semigroup a => a -> a -> a
<> String -> Mod FlagFields Bool
forall (f :: * -> *) a. String -> Mod f a
help String
"Enable logs from SMP agent (also with `-l debug`)"
      )
  Maybe String
logFile <-
    Parser String -> Parser (Maybe String)
forall (f :: * -> *) a. Alternative f => f a -> f (Maybe a)
optional (Parser String -> Parser (Maybe String))
-> Parser String -> Parser (Maybe String)
forall a b. (a -> b) -> a -> b
$
      Mod OptionFields String -> Parser String
forall s. IsString s => Mod OptionFields s -> Parser s
strOption
        ( String -> Mod OptionFields String
forall (f :: * -> *) a. HasName f => String -> Mod f a
long String
"log-file"
            Mod OptionFields String
-> Mod OptionFields String -> Mod OptionFields String
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields String
forall (f :: * -> *) a. String -> Mod f a
help String
"Log to specified file / device"
        )
  Natural
tbqSize <-
    ReadM Natural -> Mod OptionFields Natural -> Parser Natural
forall a. ReadM a -> Mod OptionFields a -> Parser a
option
      ReadM Natural
forall a. Read a => ReadM a
auto
      ( String -> Mod OptionFields Natural
forall (f :: * -> *) a. HasName f => String -> Mod f a
long String
"queue-size"
          Mod OptionFields Natural
-> Mod OptionFields Natural -> Mod OptionFields Natural
forall a. Semigroup a => a -> a -> a
<> Char -> Mod OptionFields Natural
forall (f :: * -> *) a. HasName f => Char -> Mod f a
short Char
'q'
          Mod OptionFields Natural
-> Mod OptionFields Natural -> Mod OptionFields Natural
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields Natural
forall (f :: * -> *) a. HasMetavar f => String -> Mod f a
metavar String
"SIZE"
          Mod OptionFields Natural
-> Mod OptionFields Natural -> Mod OptionFields Natural
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields Natural
forall (f :: * -> *) a. String -> Mod f a
help String
"Internal queue size"
          Mod OptionFields Natural
-> Mod OptionFields Natural -> Mod OptionFields Natural
forall a. Semigroup a => a -> a -> a
<> Natural -> Mod OptionFields Natural
forall (f :: * -> *) a. HasValue f => a -> Mod f a
value Natural
1024
          Mod OptionFields Natural
-> Mod OptionFields Natural -> Mod OptionFields Natural
forall a. Semigroup a => a -> a -> a
<> Mod OptionFields Natural
forall a (f :: * -> *). Show a => Mod f a
showDefault
      )
  Maybe Text
deviceName <-
    Parser Text -> Parser (Maybe Text)
forall (f :: * -> *) a. Alternative f => f a -> f (Maybe a)
optional (Parser Text -> Parser (Maybe Text))
-> Parser Text -> Parser (Maybe Text)
forall a b. (a -> b) -> a -> b
$
      Mod OptionFields Text -> Parser Text
forall s. IsString s => Mod OptionFields s -> Parser s
strOption
        ( String -> Mod OptionFields Text
forall (f :: * -> *) a. HasName f => String -> Mod f a
long String
"device-name"
            Mod OptionFields Text
-> Mod OptionFields Text -> Mod OptionFields Text
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields Text
forall (f :: * -> *) a. HasMetavar f => String -> Mod f a
metavar String
"DEVICE"
            Mod OptionFields Text
-> Mod OptionFields Text -> Mod OptionFields Text
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields Text
forall (f :: * -> *) a. String -> Mod f a
help String
"Device name to use in connections with remote hosts and controller"
        )
  Bool
highlyAvailable <-
    Mod FlagFields Bool -> Parser Bool
switch
      ( String -> Mod FlagFields Bool
forall (f :: * -> *) a. HasName f => String -> Mod f a
long String
"ha"
          Mod FlagFields Bool -> Mod FlagFields Bool -> Mod FlagFields Bool
forall a. Semigroup a => a -> a -> a
<> String -> Mod FlagFields Bool
forall (f :: * -> *) a. String -> Mod f a
help String
"Run as a highly available client (this may increase traffic in groups)"
      )
  Bool
yesToUpMigrations <-
    Mod FlagFields Bool -> Parser Bool
switch
      ( String -> Mod FlagFields Bool
forall (f :: * -> *) a. HasName f => String -> Mod f a
long String
"yes-migrate"
          Mod FlagFields Bool -> Mod FlagFields Bool -> Mod FlagFields Bool
forall a. Semigroup a => a -> a -> a
<> Char -> Mod FlagFields Bool
forall (f :: * -> *) a. HasName f => Char -> Mod f a
short Char
'y'
          Mod FlagFields Bool -> Mod FlagFields Bool -> Mod FlagFields Bool
forall a. Semigroup a => a -> a -> a
<> String -> Mod FlagFields Bool
forall (f :: * -> *) a. String -> Mod f a
help String
"Automatically confirm \"up\" database migrations"
      )
  Maybe String
migrationBackupPath <- Parser (Maybe String)
migrationBackupPathP
  pure
    CoreChatOpts
      { ChatDbOpts
dbOptions :: ChatDbOpts
dbOptions :: ChatDbOpts
dbOptions,
        [ProtoServerWithAuth 'PSMP]
smpServers :: [ProtoServerWithAuth 'PSMP]
smpServers :: [ProtoServerWithAuth 'PSMP]
smpServers,
        [ProtoServerWithAuth 'PXFTP]
xftpServers :: [ProtoServerWithAuth 'PXFTP]
xftpServers :: [ProtoServerWithAuth 'PXFTP]
xftpServers,
        simpleNetCfg :: SimpleNetCfg
simpleNetCfg =
          SimpleNetCfg
            { Maybe SocksProxyWithAuth
socksProxy :: Maybe SocksProxyWithAuth
socksProxy :: Maybe SocksProxyWithAuth
socksProxy,
              SocksMode
socksMode :: SocksMode
socksMode :: SocksMode
socksMode,
              hostMode :: HostMode
hostMode = HostMode -> Maybe HostMode -> HostMode
forall a. a -> Maybe a -> a
fromMaybe (Maybe SocksProxyWithAuth -> HostMode
defaultHostMode Maybe SocksProxyWithAuth
socksProxy) Maybe HostMode
hostMode_,
              Bool
requiredHostMode :: Bool
requiredHostMode :: Bool
requiredHostMode,
              Maybe SMPProxyMode
smpProxyMode_ :: Maybe SMPProxyMode
smpProxyMode_ :: Maybe SMPProxyMode
smpProxyMode_,
              Maybe SMPProxyFallback
smpProxyFallback_ :: Maybe SMPProxyFallback
smpProxyFallback_ :: Maybe SMPProxyFallback
smpProxyFallback_,
              SMPWebPortServers
smpWebPortServers :: SMPWebPortServers
smpWebPortServers :: SMPWebPortServers
smpWebPortServers,
              tcpTimeout_ :: Maybe Int
tcpTimeout_ = Int -> Maybe Int
forall a. a -> Maybe a
Just (Int -> Maybe Int) -> Int -> Maybe Int
forall a b. (a -> b) -> a -> b
$ Maybe SocksProxyWithAuth -> Int -> Int
forall {a} {a}. (Num a, Ord a) => Maybe a -> a -> a
useTcpTimeout Maybe SocksProxyWithAuth
socksProxy Int
t,
              Bool
logTLSErrors :: Bool
logTLSErrors :: Bool
logTLSErrors
            },
        ChatLogLevel
logLevel :: ChatLogLevel
logLevel :: ChatLogLevel
logLevel,
        logConnections :: Bool
logConnections = Bool
logConnections Bool -> Bool -> Bool
|| ChatLogLevel
logLevel ChatLogLevel -> ChatLogLevel -> Bool
forall a. Ord a => a -> a -> Bool
<= ChatLogLevel
CLLInfo,
        logServerHosts :: Bool
logServerHosts = Bool
logServerHosts Bool -> Bool -> Bool
|| ChatLogLevel
logLevel ChatLogLevel -> ChatLogLevel -> Bool
forall a. Ord a => a -> a -> Bool
<= ChatLogLevel
CLLInfo,
        logAgent :: Maybe LogLevel
logAgent = if Bool
logAgent Bool -> Bool -> Bool
|| ChatLogLevel
logLevel ChatLogLevel -> ChatLogLevel -> Bool
forall a. Eq a => a -> a -> Bool
== ChatLogLevel
CLLDebug then LogLevel -> Maybe LogLevel
forall a. a -> Maybe a
Just (LogLevel -> Maybe LogLevel) -> LogLevel -> Maybe LogLevel
forall a b. (a -> b) -> a -> b
$ ChatLogLevel -> LogLevel
agentLogLevel ChatLogLevel
logLevel else Maybe LogLevel
forall a. Maybe a
Nothing,
        Maybe String
logFile :: Maybe String
logFile :: Maybe String
logFile,
        Natural
tbqSize :: Natural
tbqSize :: Natural
tbqSize,
        Maybe Text
deviceName :: Maybe Text
deviceName :: Maybe Text
deviceName,
        Bool
highlyAvailable :: Bool
highlyAvailable :: Bool
highlyAvailable,
        Bool
yesToUpMigrations :: Bool
yesToUpMigrations :: Bool
yesToUpMigrations,
        Maybe String
migrationBackupPath :: Maybe String
migrationBackupPath :: Maybe String
migrationBackupPath
      }
  where
    useTcpTimeout :: Maybe a -> a -> a
useTcpTimeout Maybe a
p a
t = a
1000000 a -> a -> a
forall a. Num a => a -> a -> a
* if a
t a -> a -> Bool
forall a. Ord a => a -> a -> Bool
> a
0 then a
t else a -> (a -> a) -> Maybe a -> a
forall b a. b -> (a -> b) -> Maybe a -> b
maybe a
7 (a -> a -> a
forall a b. a -> b -> a
const a
15) Maybe a
p

defaultHostMode :: Maybe SocksProxyWithAuth -> HostMode
defaultHostMode :: Maybe SocksProxyWithAuth -> HostMode
defaultHostMode = \case
  Just (SocksProxyWithAuth SocksAuth
SocksIsolateByAuth SocksProxy
_) -> HostMode
HMOnionViaSocks;
  Maybe SocksProxyWithAuth
_ -> HostMode
HMPublic

chatOptsP :: FilePath -> FilePath -> Parser ChatOpts
chatOptsP :: String -> String -> Parser ChatOpts
chatOptsP String
appDir String
defaultDbName = do
  CoreChatOpts
coreOptions <- String -> String -> Parser CoreChatOpts
coreChatOptsP String
appDir String
defaultDbName
  String
chatCmd <-
    Mod OptionFields String -> Parser String
forall s. IsString s => Mod OptionFields s -> Parser s
strOption
      ( String -> Mod OptionFields String
forall (f :: * -> *) a. HasName f => String -> Mod f a
long String
"execute"
          Mod OptionFields String
-> Mod OptionFields String -> Mod OptionFields String
forall a. Semigroup a => a -> a -> a
<> Char -> Mod OptionFields String
forall (f :: * -> *) a. HasName f => Char -> Mod f a
short Char
'e'
          Mod OptionFields String
-> Mod OptionFields String -> Mod OptionFields String
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields String
forall (f :: * -> *) a. HasMetavar f => String -> Mod f a
metavar String
"COMMAND"
          Mod OptionFields String
-> Mod OptionFields String -> Mod OptionFields String
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields String
forall (f :: * -> *) a. String -> Mod f a
help String
"Execute chat command (received messages won't be logged) and exit"
          Mod OptionFields String
-> Mod OptionFields String -> Mod OptionFields String
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields String
forall (f :: * -> *) a. HasValue f => a -> Mod f a
value String
""
      )
  Int
chatCmdDelay <-
    ReadM Int -> Mod OptionFields Int -> Parser Int
forall a. ReadM a -> Mod OptionFields a -> Parser a
option
      ReadM Int
forall a. Read a => ReadM a
auto
      ( String -> Mod OptionFields Int
forall (f :: * -> *) a. HasName f => String -> Mod f a
long String
"time"
          Mod OptionFields Int
-> Mod OptionFields Int -> Mod OptionFields Int
forall a. Semigroup a => a -> a -> a
<> Char -> Mod OptionFields Int
forall (f :: * -> *) a. HasName f => Char -> Mod f a
short Char
't'
          Mod OptionFields Int
-> Mod OptionFields Int -> Mod OptionFields Int
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields Int
forall (f :: * -> *) a. HasMetavar f => String -> Mod f a
metavar String
"TIME"
          Mod OptionFields Int
-> Mod OptionFields Int -> Mod OptionFields Int
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields Int
forall (f :: * -> *) a. String -> Mod f a
help String
"Time to wait after sending chat command before exiting, seconds"
          Mod OptionFields Int
-> Mod OptionFields Int -> Mod OptionFields Int
forall a. Semigroup a => a -> a -> a
<> Int -> Mod OptionFields Int
forall (f :: * -> *) a. HasValue f => a -> Mod f a
value Int
3
          Mod OptionFields Int
-> Mod OptionFields Int -> Mod OptionFields Int
forall a. Semigroup a => a -> a -> a
<> Mod OptionFields Int
forall a (f :: * -> *). Show a => Mod f a
showDefault
      )
  ChatCmdLog
chatCmdLog <-
    ReadM ChatCmdLog
-> Mod OptionFields ChatCmdLog -> Parser ChatCmdLog
forall a. ReadM a -> Mod OptionFields a -> Parser a
option
      ReadM ChatCmdLog
parseChatCmdLog
      ( String -> Mod OptionFields ChatCmdLog
forall (f :: * -> *) a. HasName f => String -> Mod f a
long String
"execute-log"
          Mod OptionFields ChatCmdLog
-> Mod OptionFields ChatCmdLog -> Mod OptionFields ChatCmdLog
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields ChatCmdLog
forall (f :: * -> *) a. HasMetavar f => String -> Mod f a
metavar String
"EXEC_LOG"
          Mod OptionFields ChatCmdLog
-> Mod OptionFields ChatCmdLog -> Mod OptionFields ChatCmdLog
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields ChatCmdLog
forall (f :: * -> *) a. String -> Mod f a
help String
"Log during command execution: all, messages, none (default)"
          Mod OptionFields ChatCmdLog
-> Mod OptionFields ChatCmdLog -> Mod OptionFields ChatCmdLog
forall a. Semigroup a => a -> a -> a
<> ChatCmdLog -> Mod OptionFields ChatCmdLog
forall (f :: * -> *) a. HasValue f => a -> Mod f a
value ChatCmdLog
CCLNone
      )
  Maybe String
chatServerPort <-
    ReadM (Maybe String)
-> Mod OptionFields (Maybe String) -> Parser (Maybe String)
forall a. ReadM a -> Mod OptionFields a -> Parser a
option
      ReadM (Maybe String)
parseServerPort
      ( String -> Mod OptionFields (Maybe String)
forall (f :: * -> *) a. HasName f => String -> Mod f a
long String
"chat-server-port"
          Mod OptionFields (Maybe String)
-> Mod OptionFields (Maybe String)
-> Mod OptionFields (Maybe String)
forall a. Semigroup a => a -> a -> a
<> Char -> Mod OptionFields (Maybe String)
forall (f :: * -> *) a. HasName f => Char -> Mod f a
short Char
'p'
          Mod OptionFields (Maybe String)
-> Mod OptionFields (Maybe String)
-> Mod OptionFields (Maybe String)
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields (Maybe String)
forall (f :: * -> *) a. HasMetavar f => String -> Mod f a
metavar String
"PORT"
          Mod OptionFields (Maybe String)
-> Mod OptionFields (Maybe String)
-> Mod OptionFields (Maybe String)
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields (Maybe String)
forall (f :: * -> *) a. String -> Mod f a
help String
"Run chat server on specified port"
          Mod OptionFields (Maybe String)
-> Mod OptionFields (Maybe String)
-> Mod OptionFields (Maybe String)
forall a. Semigroup a => a -> a -> a
<> Maybe String -> Mod OptionFields (Maybe String)
forall (f :: * -> *) a. HasValue f => a -> Mod f a
value Maybe String
forall a. Maybe a
Nothing
      )
  Maybe String
optFilesFolder <-
    Parser String -> Parser (Maybe String)
forall (f :: * -> *) a. Alternative f => f a -> f (Maybe a)
optional (Parser String -> Parser (Maybe String))
-> Parser String -> Parser (Maybe String)
forall a b. (a -> b) -> a -> b
$
      Mod OptionFields String -> Parser String
forall s. IsString s => Mod OptionFields s -> Parser s
strOption
        ( String -> Mod OptionFields String
forall (f :: * -> *) a. HasName f => String -> Mod f a
long String
"files-folder"
            Mod OptionFields String
-> Mod OptionFields String -> Mod OptionFields String
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields String
forall (f :: * -> *) a. HasMetavar f => String -> Mod f a
metavar String
"FOLDER"
            Mod OptionFields String
-> Mod OptionFields String -> Mod OptionFields String
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields String
forall (f :: * -> *) a. String -> Mod f a
help String
"Folder to use for sent and received files"
        )
  Maybe String
optTempDirectory <-
    Parser String -> Parser (Maybe String)
forall (f :: * -> *) a. Alternative f => f a -> f (Maybe a)
optional (Parser String -> Parser (Maybe String))
-> Parser String -> Parser (Maybe String)
forall a b. (a -> b) -> a -> b
$
      Mod OptionFields String -> Parser String
forall s. IsString s => Mod OptionFields s -> Parser s
strOption
        ( String -> Mod OptionFields String
forall (f :: * -> *) a. HasName f => String -> Mod f a
long String
"temp-folder"
            Mod OptionFields String
-> Mod OptionFields String -> Mod OptionFields String
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields String
forall (f :: * -> *) a. HasMetavar f => String -> Mod f a
metavar String
"FOLDER"
            Mod OptionFields String
-> Mod OptionFields String -> Mod OptionFields String
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields String
forall (f :: * -> *) a. String -> Mod f a
help String
"Folder for temporary encrypted files (default: system temp directory)"
        )
  Bool
showReactions <-
    Mod FlagFields Bool -> Parser Bool
switch
      ( String -> Mod FlagFields Bool
forall (f :: * -> *) a. HasName f => String -> Mod f a
long String
"reactions"
          Mod FlagFields Bool -> Mod FlagFields Bool -> Mod FlagFields Bool
forall a. Semigroup a => a -> a -> a
<> String -> Mod FlagFields Bool
forall (f :: * -> *) a. String -> Mod f a
help String
"Show message reactions"
      )
  Bool
allowInstantFiles <-
    Mod FlagFields Bool -> Parser Bool
switch
      ( String -> Mod FlagFields Bool
forall (f :: * -> *) a. HasName f => String -> Mod f a
long String
"allow-instant-files"
          Mod FlagFields Bool -> Mod FlagFields Bool -> Mod FlagFields Bool
forall a. Semigroup a => a -> a -> a
<> Char -> Mod FlagFields Bool
forall (f :: * -> *) a. HasName f => Char -> Mod f a
short Char
'f'
          Mod FlagFields Bool -> Mod FlagFields Bool -> Mod FlagFields Bool
forall a. Semigroup a => a -> a -> a
<> String -> Mod FlagFields Bool
forall (f :: * -> *) a. String -> Mod f a
help String
"Send and receive instant files without acceptance"
      )
  Integer
autoAcceptFileSize <-
    Integer -> Mod FlagFields Integer -> Parser Integer
forall a. a -> Mod FlagFields a -> Parser a
flag' (Integer -> Integer
forall a. Integral a => a -> a
mb Integer
1) (Char -> Mod FlagFields Integer
forall (f :: * -> *) a. HasName f => Char -> Mod f a
short Char
'a' Mod FlagFields Integer
-> Mod FlagFields Integer -> Mod FlagFields Integer
forall a. Semigroup a => a -> a -> a
<> String -> Mod FlagFields Integer
forall (f :: * -> *) a. String -> Mod f a
help String
"Automatically accept files up to 1MB")
      Parser Integer -> Parser Integer -> Parser Integer
forall a. Parser a -> Parser a -> Parser a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> ReadM Integer -> Mod OptionFields Integer -> Parser Integer
forall a. ReadM a -> Mod OptionFields a -> Parser a
option
        ReadM Integer
forall a. Read a => ReadM a
auto
        ( String -> Mod OptionFields Integer
forall (f :: * -> *) a. HasName f => String -> Mod f a
long String
"auto-accept-files"
            Mod OptionFields Integer
-> Mod OptionFields Integer -> Mod OptionFields Integer
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields Integer
forall (f :: * -> *) a. HasMetavar f => String -> Mod f a
metavar String
"FILE_SIZE"
            Mod OptionFields Integer
-> Mod OptionFields Integer -> Mod OptionFields Integer
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields Integer
forall (f :: * -> *) a. String -> Mod f a
help String
"Automatically accept files up to specified size"
            Mod OptionFields Integer
-> Mod OptionFields Integer -> Mod OptionFields Integer
forall a. Semigroup a => a -> a -> a
<> Integer -> Mod OptionFields Integer
forall (f :: * -> *) a. HasValue f => a -> Mod f a
value Integer
0
        )
  Bool
muteNotifications <-
    Mod FlagFields Bool -> Parser Bool
switch
      ( String -> Mod FlagFields Bool
forall (f :: * -> *) a. HasName f => String -> Mod f a
long String
"mute"
          Mod FlagFields Bool -> Mod FlagFields Bool -> Mod FlagFields Bool
forall a. Semigroup a => a -> a -> a
<> String -> Mod FlagFields Bool
forall (f :: * -> *) a. String -> Mod f a
help String
"Mute notifications"
      )
  Bool
markRead <-
    Mod FlagFields Bool -> Parser Bool
switch
      ( String -> Mod FlagFields Bool
forall (f :: * -> *) a. HasName f => String -> Mod f a
long String
"mark-read"
          Mod FlagFields Bool -> Mod FlagFields Bool -> Mod FlagFields Bool
forall a. Semigroup a => a -> a -> a
<> Char -> Mod FlagFields Bool
forall (f :: * -> *) a. HasName f => Char -> Mod f a
short Char
'r'
          Mod FlagFields Bool -> Mod FlagFields Bool -> Mod FlagFields Bool
forall a. Semigroup a => a -> a -> a
<> String -> Mod FlagFields Bool
forall (f :: * -> *) a. String -> Mod f a
help String
"Mark shown messages as read"
      )
  Maybe Text
createBotDisplayName <-
    Parser Text -> Parser (Maybe Text)
forall (f :: * -> *) a. Alternative f => f a -> f (Maybe a)
optional (Parser Text -> Parser (Maybe Text))
-> Parser Text -> Parser (Maybe Text)
forall a b. (a -> b) -> a -> b
$
      Mod OptionFields Text -> Parser Text
forall s. IsString s => Mod OptionFields s -> Parser s
strOption
        ( String -> Mod OptionFields Text
forall (f :: * -> *) a. HasName f => String -> Mod f a
long String
"create-bot-display-name"
            Mod OptionFields Text
-> Mod OptionFields Text -> Mod OptionFields Text
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields Text
forall (f :: * -> *) a. HasMetavar f => String -> Mod f a
metavar String
"BOT_NAME"
            Mod OptionFields Text
-> Mod OptionFields Text -> Mod OptionFields Text
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields Text
forall (f :: * -> *) a. String -> Mod f a
help String
"Create new bot user on the first start with the passed display name"
        )
  Bool
createBotAllowFiles <-
    Mod FlagFields Bool -> Parser Bool
switch
      ( String -> Mod FlagFields Bool
forall (f :: * -> *) a. HasName f => String -> Mod f a
long String
"create-bot-allow-files"
          Mod FlagFields Bool -> Mod FlagFields Bool -> Mod FlagFields Bool
forall a. Semigroup a => a -> a -> a
<> String -> Mod FlagFields Bool
forall (f :: * -> *) a. String -> Mod f a
help String
"Flag for created bot to allow files (only allowed together with --create-bot option)"
      )
  Bool
maintenance <-
    Mod FlagFields Bool -> Parser Bool
switch
      ( String -> Mod FlagFields Bool
forall (f :: * -> *) a. HasName f => String -> Mod f a
long String
"maintenance"
          Mod FlagFields Bool -> Mod FlagFields Bool -> Mod FlagFields Bool
forall a. Semigroup a => a -> a -> a
<> Char -> Mod FlagFields Bool
forall (f :: * -> *) a. HasName f => Char -> Mod f a
short Char
'm'
          Mod FlagFields Bool -> Mod FlagFields Bool -> Mod FlagFields Bool
forall a. Semigroup a => a -> a -> a
<> String -> Mod FlagFields Bool
forall (f :: * -> *) a. String -> Mod f a
help String
"Run in maintenance mode (/_start to start chat)"
      )
  pure
    ChatOpts
      { CoreChatOpts
coreOptions :: CoreChatOpts
coreOptions :: CoreChatOpts
coreOptions,
        String
chatCmd :: String
chatCmd :: String
chatCmd,
        Int
chatCmdDelay :: Int
chatCmdDelay :: Int
chatCmdDelay,
        ChatCmdLog
chatCmdLog :: ChatCmdLog
chatCmdLog :: ChatCmdLog
chatCmdLog,
        Maybe String
chatServerPort :: Maybe String
chatServerPort :: Maybe String
chatServerPort,
        Maybe String
optFilesFolder :: Maybe String
optFilesFolder :: Maybe String
optFilesFolder,
        Maybe String
optTempDirectory :: Maybe String
optTempDirectory :: Maybe String
optTempDirectory,
        Bool
showReactions :: Bool
showReactions :: Bool
showReactions,
        Bool
allowInstantFiles :: Bool
allowInstantFiles :: Bool
allowInstantFiles,
        Integer
autoAcceptFileSize :: Integer
autoAcceptFileSize :: Integer
autoAcceptFileSize,
        Bool
muteNotifications :: Bool
muteNotifications :: Bool
muteNotifications,
        Bool
markRead :: Bool
markRead :: Bool
markRead,
        createBot :: Maybe CreateBotOpts
createBot = case Maybe Text
createBotDisplayName of
          Just Text
botDisplayName -> CreateBotOpts -> Maybe CreateBotOpts
forall a. a -> Maybe a
Just CreateBotOpts {Text
botDisplayName :: Text
botDisplayName :: Text
botDisplayName, allowFiles :: Bool
allowFiles = Bool
createBotAllowFiles}
          Maybe Text
Nothing
            | Bool
createBotAllowFiles -> String -> Maybe CreateBotOpts
forall a. HasCallStack => String -> a
error String
"--create-bot-allow-files option requires --create-bot-name option"
            | Bool
otherwise -> Maybe CreateBotOpts
forall a. Maybe a
Nothing,
        Bool
maintenance :: Bool
maintenance :: Bool
maintenance
      }

parseProtocolServers :: ProtocolTypeI p => ReadM [ProtoServerWithAuth p]
parseProtocolServers :: forall (p :: ProtocolType).
ProtocolTypeI p =>
ReadM [ProtoServerWithAuth p]
parseProtocolServers = (String -> Either String [ProtoServerWithAuth p])
-> ReadM [ProtoServerWithAuth p]
forall a. (String -> Either String a) -> ReadM a
eitherReader ((String -> Either String [ProtoServerWithAuth p])
 -> ReadM [ProtoServerWithAuth p])
-> (String -> Either String [ProtoServerWithAuth p])
-> ReadM [ProtoServerWithAuth p]
forall a b. (a -> b) -> a -> b
$ Parser [ProtoServerWithAuth p]
-> ByteString -> Either String [ProtoServerWithAuth p]
forall a. Parser a -> ByteString -> Either String a
parseAll Parser [ProtoServerWithAuth p]
forall (p :: ProtocolType).
ProtocolTypeI p =>
Parser [ProtoServerWithAuth p]
protocolServersP (ByteString -> Either String [ProtoServerWithAuth p])
-> (String -> ByteString)
-> String
-> Either String [ProtoServerWithAuth p]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> ByteString
B.pack

strParse :: StrEncoding a => ReadM a
strParse :: forall a. StrEncoding a => ReadM a
strParse = (String -> Either String a) -> ReadM a
forall a. (String -> Either String a) -> ReadM a
eitherReader ((String -> Either String a) -> ReadM a)
-> (String -> Either String a) -> ReadM a
forall a b. (a -> b) -> a -> b
$ Parser a -> ByteString -> Either String a
forall a. Parser a -> ByteString -> Either String a
parseAll Parser a
forall a. StrEncoding a => Parser a
strP (ByteString -> Either String a)
-> (String -> ByteString) -> String -> Either String a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> ByteString
encodeUtf8 (Text -> ByteString) -> (String -> Text) -> String -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
T.pack

parseHostMode :: ReadM HostMode
parseHostMode :: ReadM HostMode
parseHostMode = (String -> Either String HostMode) -> ReadM HostMode
forall a. (String -> Either String a) -> ReadM a
eitherReader ((String -> Either String HostMode) -> ReadM HostMode)
-> (String -> Either String HostMode) -> ReadM HostMode
forall a b. (a -> b) -> a -> b
$ Text -> Either String HostMode
textToHostMode (Text -> Either String HostMode)
-> (String -> Text) -> String -> Either String HostMode
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
T.pack

parseServerPort :: ReadM (Maybe String)
parseServerPort :: ReadM (Maybe String)
parseServerPort = (String -> Either String (Maybe String)) -> ReadM (Maybe String)
forall a. (String -> Either String a) -> ReadM a
eitherReader ((String -> Either String (Maybe String)) -> ReadM (Maybe String))
-> (String -> Either String (Maybe String)) -> ReadM (Maybe String)
forall a b. (a -> b) -> a -> b
$ Parser (Maybe String) -> ByteString -> Either String (Maybe String)
forall a. Parser a -> ByteString -> Either String a
parseAll Parser (Maybe String)
serverPortP (ByteString -> Either String (Maybe String))
-> (String -> ByteString) -> String -> Either String (Maybe String)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> ByteString
B.pack

serverPortP :: A.Parser (Maybe String)
serverPortP :: Parser (Maybe String)
serverPortP = String -> Maybe String
forall a. a -> Maybe a
Just (String -> Maybe String)
-> (ByteString -> String) -> ByteString -> Maybe String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> String
B.unpack (ByteString -> Maybe String)
-> Parser ByteString ByteString -> Parser (Maybe String)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Char -> Bool) -> Parser ByteString ByteString
A.takeWhile Char -> Bool
A.isDigit

protocolServersP :: ProtocolTypeI p => A.Parser [ProtoServerWithAuth p]
protocolServersP :: forall (p :: ProtocolType).
ProtocolTypeI p =>
Parser [ProtoServerWithAuth p]
protocolServersP = Parser (ProtoServerWithAuth p)
forall a. StrEncoding a => Parser a
strP Parser (ProtoServerWithAuth p)
-> Parser ByteString Char
-> Parser ByteString [ProtoServerWithAuth p]
forall (f :: * -> *) a s. Alternative f => f a -> f s -> f [a]
`A.sepBy1` Char -> Parser ByteString Char
A.char Char
' '

parseLogLevel :: ReadM ChatLogLevel
parseLogLevel :: ReadM ChatLogLevel
parseLogLevel = (String -> Either String ChatLogLevel) -> ReadM ChatLogLevel
forall a. (String -> Either String a) -> ReadM a
eitherReader ((String -> Either String ChatLogLevel) -> ReadM ChatLogLevel)
-> (String -> Either String ChatLogLevel) -> ReadM ChatLogLevel
forall a b. (a -> b) -> a -> b
$ \case
  String
"debug" -> ChatLogLevel -> Either String ChatLogLevel
forall a b. b -> Either a b
Right ChatLogLevel
CLLDebug
  String
"info" -> ChatLogLevel -> Either String ChatLogLevel
forall a b. b -> Either a b
Right ChatLogLevel
CLLInfo
  String
"warn" -> ChatLogLevel -> Either String ChatLogLevel
forall a b. b -> Either a b
Right ChatLogLevel
CLLWarning
  String
"error" -> ChatLogLevel -> Either String ChatLogLevel
forall a b. b -> Either a b
Right ChatLogLevel
CLLError
  String
"important" -> ChatLogLevel -> Either String ChatLogLevel
forall a b. b -> Either a b
Right ChatLogLevel
CLLImportant
  String
_ -> String -> Either String ChatLogLevel
forall a b. a -> Either a b
Left String
"Invalid log level"

parseChatCmdLog :: ReadM ChatCmdLog
parseChatCmdLog :: ReadM ChatCmdLog
parseChatCmdLog = (String -> Either String ChatCmdLog) -> ReadM ChatCmdLog
forall a. (String -> Either String a) -> ReadM a
eitherReader ((String -> Either String ChatCmdLog) -> ReadM ChatCmdLog)
-> (String -> Either String ChatCmdLog) -> ReadM ChatCmdLog
forall a b. (a -> b) -> a -> b
$ \case
  String
"all" -> ChatCmdLog -> Either String ChatCmdLog
forall a b. b -> Either a b
Right ChatCmdLog
CCLAll
  String
"messages" -> ChatCmdLog -> Either String ChatCmdLog
forall a b. b -> Either a b
Right ChatCmdLog
CCLMessages
  String
"none" -> ChatCmdLog -> Either String ChatCmdLog
forall a b. b -> Either a b
Right ChatCmdLog
CCLNone
  String
_ -> String -> Either String ChatCmdLog
forall a b. a -> Either a b
Left String
"Invalid chat command log level"

getChatOpts :: FilePath -> FilePath -> IO ChatOpts
getChatOpts :: String -> String -> IO ChatOpts
getChatOpts String
appDir String
defaultDbName =
  ParserInfo ChatOpts -> IO ChatOpts
forall a. ParserInfo a -> IO a
execParser (ParserInfo ChatOpts -> IO ChatOpts)
-> ParserInfo ChatOpts -> IO ChatOpts
forall a b. (a -> b) -> a -> b
$
    Parser ChatOpts -> InfoMod ChatOpts -> ParserInfo ChatOpts
forall a. Parser a -> InfoMod a -> ParserInfo a
info
      (Parser ((ChatOpts -> ChatOpts) -> ChatOpts -> ChatOpts)
forall a. Parser (a -> a)
helper Parser ((ChatOpts -> ChatOpts) -> ChatOpts -> ChatOpts)
-> Parser (ChatOpts -> ChatOpts) -> Parser (ChatOpts -> ChatOpts)
forall a b. Parser (a -> b) -> Parser a -> Parser b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Parser (ChatOpts -> ChatOpts)
forall a. Parser (a -> a)
versionOption Parser (ChatOpts -> ChatOpts) -> Parser ChatOpts -> Parser ChatOpts
forall a b. Parser (a -> b) -> Parser a -> Parser b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> String -> String -> Parser ChatOpts
chatOptsP String
appDir String
defaultDbName)
      (String -> InfoMod ChatOpts
forall a. String -> InfoMod a
header String
versionStr InfoMod ChatOpts -> InfoMod ChatOpts -> InfoMod ChatOpts
forall a. Semigroup a => a -> a -> a
<> InfoMod ChatOpts
forall a. InfoMod a
fullDesc InfoMod ChatOpts -> InfoMod ChatOpts -> InfoMod ChatOpts
forall a. Semigroup a => a -> a -> a
<> String -> InfoMod ChatOpts
forall a. String -> InfoMod a
progDesc String
"Start chat with DB_FILE file and use SERVER as SMP server")
  where
    versionOption :: Parser (a -> a)
versionOption = String -> Mod OptionFields (a -> a) -> Parser (a -> a)
forall a. String -> Mod OptionFields (a -> a) -> Parser (a -> a)
infoOption String
versionStr (String -> Mod OptionFields (a -> a)
forall (f :: * -> *) a. HasName f => String -> Mod f a
long String
"version" Mod OptionFields (a -> a)
-> Mod OptionFields (a -> a) -> Mod OptionFields (a -> a)
forall a. Semigroup a => a -> a -> a
<> Char -> Mod OptionFields (a -> a)
forall (f :: * -> *) a. HasName f => Char -> Mod f a
short Char
'v' Mod OptionFields (a -> a)
-> Mod OptionFields (a -> a) -> Mod OptionFields (a -> a)
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields (a -> a)
forall (f :: * -> *) a. String -> Mod f a
help String
"Show version")
    versionStr :: String
versionStr = String -> String
versionString String
versionNumber

printDbOpts :: CoreChatOpts -> IO ()
printDbOpts :: CoreChatOpts -> IO ()
printDbOpts CoreChatOpts
opts = String -> IO ()
putStrLn (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
"db: " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> ChatDbOpts -> String
dbString (CoreChatOpts -> ChatDbOpts
dbOptions CoreChatOpts
opts)