mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2024-12-17 17:20:21 +01:00
Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 87fffeb698 | |||
| f9cba3f8e0 | |||
| 3655971aec | |||
| dea45e3228 | |||
| 4f2102ac6e | |||
| 17bcdaf6c4 | |||
| 1a2fad070e | |||
| 6101be5657 | |||
| a10dd81a1d | |||
| 289130832a | |||
| 224cfe9e02 | |||
| 0679d023e2 | |||
| 6d5869e974 | |||
| f0974af03a | |||
| da70aa30b6 |
@@ -927,19 +927,14 @@ func standaloneFileInfo(url: String, ctrl: chat_ctrl? = nil) async -> MigrationF
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func receiveFile(user: any UserLike, fileId: Int64, userApprovedRelays: Bool = false, auto: Bool = false) async {
|
func receiveFile(user: any UserLike, fileId: Int64, auto: Bool = false) async {
|
||||||
if let chatItem = await apiReceiveFile(
|
if let chatItem = await apiReceiveFile(fileId: fileId, encrypted: privacyEncryptLocalFilesGroupDefault.get(), auto: auto) {
|
||||||
fileId: fileId,
|
|
||||||
userApprovedRelays: userApprovedRelays || !privacyAskToApproveRelaysGroupDefault.get(),
|
|
||||||
encrypted: privacyEncryptLocalFilesGroupDefault.get(),
|
|
||||||
auto: auto
|
|
||||||
) {
|
|
||||||
await chatItemSimpleUpdate(user, chatItem)
|
await chatItemSimpleUpdate(user, chatItem)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func apiReceiveFile(fileId: Int64, userApprovedRelays: Bool, encrypted: Bool, inline: Bool? = nil, auto: Bool = false) async -> AChatItem? {
|
func apiReceiveFile(fileId: Int64, encrypted: Bool, inline: Bool? = nil, auto: Bool = false) async -> AChatItem? {
|
||||||
let r = await chatSendCmd(.receiveFile(fileId: fileId, userApprovedRelays: userApprovedRelays, encrypted: encrypted, inline: inline))
|
let r = await chatSendCmd(.receiveFile(fileId: fileId, encrypted: encrypted, inline: inline))
|
||||||
let am = AlertManager.shared
|
let am = AlertManager.shared
|
||||||
if case let .rcvFileAccepted(_, chatItem) = r { return chatItem }
|
if case let .rcvFileAccepted(_, chatItem) = r { return chatItem }
|
||||||
if case .rcvFileAcceptedSndCancelled = r {
|
if case .rcvFileAcceptedSndCancelled = r {
|
||||||
@@ -952,52 +947,21 @@ func apiReceiveFile(fileId: Int64, userApprovedRelays: Bool, encrypted: Bool, in
|
|||||||
}
|
}
|
||||||
} else if let networkErrorAlert = networkErrorAlert(r) {
|
} else if let networkErrorAlert = networkErrorAlert(r) {
|
||||||
logger.error("apiReceiveFile network error: \(String(describing: r))")
|
logger.error("apiReceiveFile network error: \(String(describing: r))")
|
||||||
if !auto {
|
|
||||||
am.showAlert(networkErrorAlert)
|
am.showAlert(networkErrorAlert)
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
switch chatError(r) {
|
switch chatError(r) {
|
||||||
case .fileCancelled:
|
case .fileCancelled:
|
||||||
logger.debug("apiReceiveFile ignoring fileCancelled error")
|
logger.debug("apiReceiveFile ignoring fileCancelled error")
|
||||||
case .fileAlreadyReceiving:
|
case .fileAlreadyReceiving:
|
||||||
logger.debug("apiReceiveFile ignoring fileAlreadyReceiving error")
|
logger.debug("apiReceiveFile ignoring fileAlreadyReceiving error")
|
||||||
case let .fileNotApproved(fileId, unknownServers):
|
|
||||||
logger.debug("apiReceiveFile fileNotApproved error")
|
|
||||||
if !auto {
|
|
||||||
let srvs = unknownServers.map { s in
|
|
||||||
if let srv = parseServerAddress(s), !srv.hostnames.isEmpty {
|
|
||||||
srv.hostnames[0]
|
|
||||||
} else {
|
|
||||||
serverHost(s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
am.showAlert(Alert(
|
|
||||||
title: Text("Unknown servers!"),
|
|
||||||
message: Text("Without Tor or VPN, your IP address will be visible to these XFTP relays: \(srvs.sorted().joined(separator: ", "))."),
|
|
||||||
primaryButton: .default(
|
|
||||||
Text("Download"),
|
|
||||||
action: {
|
|
||||||
Task {
|
|
||||||
logger.debug("apiReceiveFile fileNotApproved alert - in Task")
|
|
||||||
if let user = ChatModel.shared.currentUser {
|
|
||||||
await receiveFile(user: user, fileId: fileId, userApprovedRelays: true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
),
|
|
||||||
secondaryButton: .cancel()
|
|
||||||
))
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
logger.error("apiReceiveFile error: \(String(describing: r))")
|
logger.error("apiReceiveFile error: \(String(describing: r))")
|
||||||
if !auto {
|
|
||||||
am.showAlertMsg(
|
am.showAlertMsg(
|
||||||
title: "Error receiving file",
|
title: "Error receiving file",
|
||||||
message: "Error: \(String(describing: r))"
|
message: "Error: \(String(describing: r))"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ func localizedInfoRow(_ title: LocalizedStringKey, _ value: LocalizedStringKey)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func serverHost(_ s: String) -> String {
|
private func serverHost(_ s: String) -> String {
|
||||||
if let i = s.range(of: "@")?.lowerBound {
|
if let i = s.range(of: "@")?.lowerBound {
|
||||||
return String(s[i...].dropFirst())
|
return String(s[i...].dropFirst())
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -60,7 +60,6 @@ struct CIFileView: View {
|
|||||||
case .rcvInvitation: return true
|
case .rcvInvitation: return true
|
||||||
case .rcvAccepted: return true
|
case .rcvAccepted: return true
|
||||||
case .rcvTransfer: return false
|
case .rcvTransfer: return false
|
||||||
case .rcvAborted: return true
|
|
||||||
case .rcvComplete: return true
|
case .rcvComplete: return true
|
||||||
case .rcvCancelled: return false
|
case .rcvCancelled: return false
|
||||||
case .rcvError: return false
|
case .rcvError: return false
|
||||||
@@ -74,10 +73,10 @@ struct CIFileView: View {
|
|||||||
logger.debug("CIFileView fileAction")
|
logger.debug("CIFileView fileAction")
|
||||||
if let file = file {
|
if let file = file {
|
||||||
switch (file.fileStatus) {
|
switch (file.fileStatus) {
|
||||||
case .rcvInvitation, .rcvAborted:
|
case .rcvInvitation:
|
||||||
if fileSizeValid(file) {
|
if fileSizeValid(file) {
|
||||||
Task {
|
Task {
|
||||||
logger.debug("CIFileView fileAction - in .rcvInvitation, .rcvAborted, in Task")
|
logger.debug("CIFileView fileAction - in .rcvInvitation, in Task")
|
||||||
if let user = m.currentUser {
|
if let user = m.currentUser {
|
||||||
await receiveFile(user: user, fileId: file.fileId)
|
await receiveFile(user: user, fileId: file.fileId)
|
||||||
}
|
}
|
||||||
@@ -149,8 +148,6 @@ struct CIFileView: View {
|
|||||||
} else {
|
} else {
|
||||||
progressView()
|
progressView()
|
||||||
}
|
}
|
||||||
case .rcvAborted:
|
|
||||||
fileIcon("doc.fill", color: .accentColor, innerIcon: "exclamationmark.arrow.circlepath", innerIconSize: 12)
|
|
||||||
case .rcvComplete: fileIcon("doc.fill")
|
case .rcvComplete: fileIcon("doc.fill")
|
||||||
case .rcvCancelled: fileIcon("doc.fill", innerIcon: "xmark", innerIconSize: 10)
|
case .rcvCancelled: fileIcon("doc.fill", innerIcon: "xmark", innerIconSize: 10)
|
||||||
case .rcvError: fileIcon("doc.fill", innerIcon: "xmark", innerIconSize: 10)
|
case .rcvError: fileIcon("doc.fill", innerIcon: "xmark", innerIconSize: 10)
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ struct CIImageView: View {
|
|||||||
let maxWidth: CGFloat
|
let maxWidth: CGFloat
|
||||||
@Binding var imgWidth: CGFloat?
|
@Binding var imgWidth: CGFloat?
|
||||||
@State var scrollProxy: ScrollViewProxy?
|
@State var scrollProxy: ScrollViewProxy?
|
||||||
|
@State var metaColor: Color
|
||||||
@State private var showFullScreenImage = false
|
@State private var showFullScreenImage = false
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
@@ -37,7 +38,7 @@ struct CIImageView: View {
|
|||||||
.onTapGesture {
|
.onTapGesture {
|
||||||
if let file = file {
|
if let file = file {
|
||||||
switch file.fileStatus {
|
switch file.fileStatus {
|
||||||
case .rcvInvitation, .rcvAborted:
|
case .rcvInvitation:
|
||||||
Task {
|
Task {
|
||||||
if let user = m.currentUser {
|
if let user = m.currentUser {
|
||||||
await receiveFile(user: user, fileId: file.fileId)
|
await receiveFile(user: user, fileId: file.fileId)
|
||||||
@@ -102,7 +103,6 @@ struct CIImageView: View {
|
|||||||
case .rcvInvitation: fileIcon("arrow.down", 10, 13)
|
case .rcvInvitation: fileIcon("arrow.down", 10, 13)
|
||||||
case .rcvAccepted: fileIcon("ellipsis", 14, 11)
|
case .rcvAccepted: fileIcon("ellipsis", 14, 11)
|
||||||
case .rcvTransfer: progressView()
|
case .rcvTransfer: progressView()
|
||||||
case .rcvAborted: fileIcon("exclamationmark.arrow.circlepath", 14, 11)
|
|
||||||
case .rcvCancelled: fileIcon("xmark", 10, 13)
|
case .rcvCancelled: fileIcon("xmark", 10, 13)
|
||||||
case .rcvError: fileIcon("xmark", 10, 13)
|
case .rcvError: fileIcon("xmark", 10, 13)
|
||||||
case .invalid: fileIcon("questionmark", 10, 13)
|
case .invalid: fileIcon("questionmark", 10, 13)
|
||||||
@@ -116,7 +116,7 @@ struct CIImageView: View {
|
|||||||
.resizable()
|
.resizable()
|
||||||
.aspectRatio(contentMode: .fit)
|
.aspectRatio(contentMode: .fit)
|
||||||
.frame(width: size, height: size)
|
.frame(width: size, height: size)
|
||||||
.foregroundColor(.white)
|
.foregroundColor(metaColor)
|
||||||
.padding(padding)
|
.padding(padding)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ struct CIVideoView: View {
|
|||||||
.onTapGesture {
|
.onTapGesture {
|
||||||
if let file = file {
|
if let file = file {
|
||||||
switch file.fileStatus {
|
switch file.fileStatus {
|
||||||
case .rcvInvitation, .rcvAborted:
|
case .rcvInvitation:
|
||||||
receiveFileIfValidSize(file: file, receiveFile: receiveFile)
|
receiveFileIfValidSize(file: file, receiveFile: receiveFile)
|
||||||
case .rcvAccepted:
|
case .rcvAccepted:
|
||||||
switch file.fileProtocol {
|
switch file.fileProtocol {
|
||||||
@@ -95,7 +95,7 @@ struct CIVideoView: View {
|
|||||||
}
|
}
|
||||||
durationProgress()
|
durationProgress()
|
||||||
}
|
}
|
||||||
if let file = file, showDownloadButton(file.fileStatus) {
|
if let file = file, case .rcvInvitation = file.fileStatus {
|
||||||
Button {
|
Button {
|
||||||
receiveFileIfValidSize(file: file, receiveFile: receiveFile)
|
receiveFileIfValidSize(file: file, receiveFile: receiveFile)
|
||||||
} label: {
|
} label: {
|
||||||
@@ -105,14 +105,6 @@ struct CIVideoView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func showDownloadButton(_ fileStatus: CIFileStatus) -> Bool {
|
|
||||||
switch fileStatus {
|
|
||||||
case .rcvInvitation: true
|
|
||||||
case .rcvAborted: true
|
|
||||||
default: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func videoViewEncrypted(_ file: CIFile, _ defaultPreview: UIImage, _ duration: Int) -> some View {
|
private func videoViewEncrypted(_ file: CIFile, _ defaultPreview: UIImage, _ duration: Int) -> some View {
|
||||||
return ZStack(alignment: .topTrailing) {
|
return ZStack(alignment: .topTrailing) {
|
||||||
ZStack(alignment: .center) {
|
ZStack(alignment: .center) {
|
||||||
@@ -288,7 +280,6 @@ struct CIVideoView: View {
|
|||||||
} else {
|
} else {
|
||||||
progressView()
|
progressView()
|
||||||
}
|
}
|
||||||
case .rcvAborted: fileIcon("exclamationmark.arrow.circlepath", 14, 11)
|
|
||||||
case .rcvCancelled: fileIcon("xmark", 10, 13)
|
case .rcvCancelled: fileIcon("xmark", 10, 13)
|
||||||
case .rcvError: fileIcon("xmark", 10, 13)
|
case .rcvError: fileIcon("xmark", 10, 13)
|
||||||
case .invalid: fileIcon("questionmark", 10, 13)
|
case .invalid: fileIcon("questionmark", 10, 13)
|
||||||
@@ -327,10 +318,10 @@ struct CIVideoView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO encrypt: where file size is checked?
|
// TODO encrypt: where file size is checked?
|
||||||
private func receiveFileIfValidSize(file: CIFile, receiveFile: @escaping (User, Int64, Bool, Bool) async -> Void) {
|
private func receiveFileIfValidSize(file: CIFile, receiveFile: @escaping (User, Int64, Bool) async -> Void) {
|
||||||
Task {
|
Task {
|
||||||
if let user = m.currentUser {
|
if let user = m.currentUser {
|
||||||
await receiveFile(user, file.fileId, false, false)
|
await receiveFile(user, file.fileId, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -139,10 +139,9 @@ struct VoiceMessagePlayer: View {
|
|||||||
case .sndComplete: playbackButton()
|
case .sndComplete: playbackButton()
|
||||||
case .sndCancelled: playbackButton()
|
case .sndCancelled: playbackButton()
|
||||||
case .sndError: playbackButton()
|
case .sndError: playbackButton()
|
||||||
case .rcvInvitation: downloadButton(recordingFile, "play.fill")
|
case .rcvInvitation: downloadButton(recordingFile)
|
||||||
case .rcvAccepted: loadingIcon()
|
case .rcvAccepted: loadingIcon()
|
||||||
case .rcvTransfer: loadingIcon()
|
case .rcvTransfer: loadingIcon()
|
||||||
case .rcvAborted: downloadButton(recordingFile, "exclamationmark.arrow.circlepath")
|
|
||||||
case .rcvComplete: playbackButton()
|
case .rcvComplete: playbackButton()
|
||||||
case .rcvCancelled: playPauseIcon("play.fill", Color(uiColor: .tertiaryLabel))
|
case .rcvCancelled: playPauseIcon("play.fill", Color(uiColor: .tertiaryLabel))
|
||||||
case .rcvError: playPauseIcon("play.fill", Color(uiColor: .tertiaryLabel))
|
case .rcvError: playPauseIcon("play.fill", Color(uiColor: .tertiaryLabel))
|
||||||
@@ -218,7 +217,7 @@ struct VoiceMessagePlayer: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func downloadButton(_ recordingFile: CIFile, _ icon: String) -> some View {
|
private func downloadButton(_ recordingFile: CIFile) -> some View {
|
||||||
Button {
|
Button {
|
||||||
Task {
|
Task {
|
||||||
if let user = chatModel.currentUser {
|
if let user = chatModel.currentUser {
|
||||||
@@ -226,7 +225,7 @@ struct VoiceMessagePlayer: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} label: {
|
} label: {
|
||||||
playPauseIcon(icon)
|
playPauseIcon("play.fill")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ struct FramedItemView: View {
|
|||||||
} else {
|
} else {
|
||||||
switch (chatItem.content.msgContent) {
|
switch (chatItem.content.msgContent) {
|
||||||
case let .image(text, image):
|
case let .image(text, image):
|
||||||
CIImageView(chatItem: chatItem, image: image, maxWidth: maxWidth, imgWidth: $imgWidth, scrollProxy: scrollProxy)
|
CIImageView(chatItem: chatItem, image: image, maxWidth: maxWidth, imgWidth: $imgWidth, scrollProxy: scrollProxy, metaColor: metaColor)
|
||||||
.overlay(DetermineWidth())
|
.overlay(DetermineWidth())
|
||||||
if text == "" && !chatItem.meta.isLive {
|
if text == "" && !chatItem.meta.isLive {
|
||||||
Color.clear
|
Color.clear
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ extension AppSettings {
|
|||||||
setNetCfg(val)
|
setNetCfg(val)
|
||||||
}
|
}
|
||||||
if let val = privacyEncryptLocalFiles { privacyEncryptLocalFilesGroupDefault.set(val) }
|
if let val = privacyEncryptLocalFiles { privacyEncryptLocalFilesGroupDefault.set(val) }
|
||||||
if let val = privacyAskToApproveRelays { privacyAskToApproveRelaysGroupDefault.set(val) }
|
|
||||||
if let val = privacyAcceptImages {
|
if let val = privacyAcceptImages {
|
||||||
privacyAcceptImagesGroupDefault.set(val)
|
privacyAcceptImagesGroupDefault.set(val)
|
||||||
def.setValue(val, forKey: DEFAULT_PRIVACY_ACCEPT_IMAGES)
|
def.setValue(val, forKey: DEFAULT_PRIVACY_ACCEPT_IMAGES)
|
||||||
@@ -51,7 +50,6 @@ extension AppSettings {
|
|||||||
var c = AppSettings.defaults
|
var c = AppSettings.defaults
|
||||||
c.networkConfig = getNetCfg()
|
c.networkConfig = getNetCfg()
|
||||||
c.privacyEncryptLocalFiles = privacyEncryptLocalFilesGroupDefault.get()
|
c.privacyEncryptLocalFiles = privacyEncryptLocalFilesGroupDefault.get()
|
||||||
c.privacyAskToApproveRelays = privacyAskToApproveRelaysGroupDefault.get()
|
|
||||||
c.privacyAcceptImages = privacyAcceptImagesGroupDefault.get()
|
c.privacyAcceptImages = privacyAcceptImagesGroupDefault.get()
|
||||||
c.privacyLinkPreviews = def.bool(forKey: DEFAULT_PRIVACY_LINK_PREVIEWS)
|
c.privacyLinkPreviews = def.bool(forKey: DEFAULT_PRIVACY_LINK_PREVIEWS)
|
||||||
c.privacyShowChatPreviews = def.bool(forKey: DEFAULT_PRIVACY_SHOW_CHAT_PREVIEWS)
|
c.privacyShowChatPreviews = def.bool(forKey: DEFAULT_PRIVACY_SHOW_CHAT_PREVIEWS)
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ struct PrivacySettings: View {
|
|||||||
@AppStorage(DEFAULT_PRIVACY_SHOW_CHAT_PREVIEWS) private var showChatPreviews = true
|
@AppStorage(DEFAULT_PRIVACY_SHOW_CHAT_PREVIEWS) private var showChatPreviews = true
|
||||||
@AppStorage(DEFAULT_PRIVACY_SAVE_LAST_DRAFT) private var saveLastDraft = true
|
@AppStorage(DEFAULT_PRIVACY_SAVE_LAST_DRAFT) private var saveLastDraft = true
|
||||||
@AppStorage(GROUP_DEFAULT_PRIVACY_ENCRYPT_LOCAL_FILES, store: groupDefaults) private var encryptLocalFiles = true
|
@AppStorage(GROUP_DEFAULT_PRIVACY_ENCRYPT_LOCAL_FILES, store: groupDefaults) private var encryptLocalFiles = true
|
||||||
@AppStorage(GROUP_DEFAULT_PRIVACY_ASK_TO_APPROVE_RELAYS, store: groupDefaults) private var askToApproveRelays = true
|
|
||||||
@State private var simplexLinkMode = privacySimplexLinkModeDefault.get()
|
@State private var simplexLinkMode = privacySimplexLinkModeDefault.get()
|
||||||
@AppStorage(DEFAULT_PRIVACY_PROTECT_SCREEN) private var protectScreen = false
|
@AppStorage(DEFAULT_PRIVACY_PROTECT_SCREEN) private var protectScreen = false
|
||||||
@AppStorage(DEFAULT_PERFORM_LA) private var prefPerformLA = false
|
@AppStorage(DEFAULT_PERFORM_LA) private var prefPerformLA = false
|
||||||
@@ -65,6 +64,18 @@ struct PrivacySettings: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Section {
|
Section {
|
||||||
|
settingsRow("lock.doc") {
|
||||||
|
Toggle("Encrypt local files", isOn: $encryptLocalFiles)
|
||||||
|
.onChange(of: encryptLocalFiles) {
|
||||||
|
setEncryptLocalFiles($0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
settingsRow("photo") {
|
||||||
|
Toggle("Auto-accept images", isOn: $autoAcceptImages)
|
||||||
|
.onChange(of: autoAcceptImages) {
|
||||||
|
privacyAcceptImagesGroupDefault.set($0)
|
||||||
|
}
|
||||||
|
}
|
||||||
settingsRow("network") {
|
settingsRow("network") {
|
||||||
Toggle("Send link previews", isOn: $useLinkPreviews)
|
Toggle("Send link previews", isOn: $useLinkPreviews)
|
||||||
}
|
}
|
||||||
@@ -97,32 +108,6 @@ struct PrivacySettings: View {
|
|||||||
Text("Chats")
|
Text("Chats")
|
||||||
}
|
}
|
||||||
|
|
||||||
Section {
|
|
||||||
settingsRow("lock.doc") {
|
|
||||||
Toggle("Encrypt local files", isOn: $encryptLocalFiles)
|
|
||||||
.onChange(of: encryptLocalFiles) {
|
|
||||||
setEncryptLocalFiles($0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
settingsRow("photo") {
|
|
||||||
Toggle("Auto-accept images", isOn: $autoAcceptImages)
|
|
||||||
.onChange(of: autoAcceptImages) {
|
|
||||||
privacyAcceptImagesGroupDefault.set($0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
settingsRow("network.badge.shield.half.filled") {
|
|
||||||
Toggle("Protect IP address", isOn: $askToApproveRelays)
|
|
||||||
}
|
|
||||||
} header: {
|
|
||||||
Text("Files")
|
|
||||||
} footer: {
|
|
||||||
if askToApproveRelays {
|
|
||||||
Text("The app will ask to confirm downloads from unknown file servers (except .onion).")
|
|
||||||
} else {
|
|
||||||
Text("Without Tor or VPN, your IP address will be visible to file servers.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Section {
|
Section {
|
||||||
settingsRow("person") {
|
settingsRow("person") {
|
||||||
Toggle("Contacts", isOn: $contactReceipts)
|
Toggle("Contacts", isOn: $contactReceipts)
|
||||||
|
|||||||
@@ -696,16 +696,14 @@ func apiGetNtfMessage(nonce: String, encNtfInfo: String) -> NtfMessages? {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func apiReceiveFile(fileId: Int64, encrypted: Bool, inline: Bool? = nil) -> AChatItem? {
|
func apiReceiveFile(fileId: Int64, encrypted: Bool, inline: Bool? = nil) -> AChatItem? {
|
||||||
let userApprovedRelays = !privacyAskToApproveRelaysGroupDefault.get()
|
let r = sendSimpleXCmd(.receiveFile(fileId: fileId, encrypted: encrypted, inline: inline))
|
||||||
let r = sendSimpleXCmd(.receiveFile(fileId: fileId, userApprovedRelays: userApprovedRelays, encrypted: encrypted, inline: inline))
|
|
||||||
if case let .rcvFileAccepted(_, chatItem) = r { return chatItem }
|
if case let .rcvFileAccepted(_, chatItem) = r { return chatItem }
|
||||||
logger.error("receiveFile error: \(responseError(r))")
|
logger.error("receiveFile error: \(responseError(r))")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func apiSetFileToReceive(fileId: Int64, encrypted: Bool) {
|
func apiSetFileToReceive(fileId: Int64, encrypted: Bool) {
|
||||||
let userApprovedRelays = !privacyAskToApproveRelaysGroupDefault.get()
|
let r = sendSimpleXCmd(.setFileToReceive(fileId: fileId, encrypted: encrypted))
|
||||||
let r = sendSimpleXCmd(.setFileToReceive(fileId: fileId, userApprovedRelays: userApprovedRelays, encrypted: encrypted))
|
|
||||||
if case .cmdOk = r { return }
|
if case .cmdOk = r { return }
|
||||||
logger.error("setFileToReceive error: \(responseError(r))")
|
logger.error("setFileToReceive error: \(responseError(r))")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,11 +76,6 @@
|
|||||||
5C9CC7AD28C55D7800BEF955 /* DatabaseEncryptionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C9CC7AC28C55D7800BEF955 /* DatabaseEncryptionView.swift */; };
|
5C9CC7AD28C55D7800BEF955 /* DatabaseEncryptionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C9CC7AC28C55D7800BEF955 /* DatabaseEncryptionView.swift */; };
|
||||||
5C9D13A3282187BB00AB8B43 /* WebRTC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C9D13A2282187BB00AB8B43 /* WebRTC.swift */; };
|
5C9D13A3282187BB00AB8B43 /* WebRTC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C9D13A2282187BB00AB8B43 /* WebRTC.swift */; };
|
||||||
5C9D811A2AA8727A001D49FD /* CryptoFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C9D81182AA7A4F1001D49FD /* CryptoFile.swift */; };
|
5C9D811A2AA8727A001D49FD /* CryptoFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C9D81182AA7A4F1001D49FD /* CryptoFile.swift */; };
|
||||||
5C9F3DD62BFBCDD90003B86B /* libHSsimplex-chat-5.8.0.2-8RkLdmy05dJBsgWrGV50Uf-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C9F3DD12BFBCDD80003B86B /* libHSsimplex-chat-5.8.0.2-8RkLdmy05dJBsgWrGV50Uf-ghc9.6.3.a */; };
|
|
||||||
5C9F3DD72BFBCDD90003B86B /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C9F3DD22BFBCDD80003B86B /* libffi.a */; };
|
|
||||||
5C9F3DD82BFBCDD90003B86B /* libHSsimplex-chat-5.8.0.2-8RkLdmy05dJBsgWrGV50Uf.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C9F3DD32BFBCDD80003B86B /* libHSsimplex-chat-5.8.0.2-8RkLdmy05dJBsgWrGV50Uf.a */; };
|
|
||||||
5C9F3DD92BFBCDD90003B86B /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C9F3DD42BFBCDD90003B86B /* libgmpxx.a */; };
|
|
||||||
5C9F3DDA2BFBCDD90003B86B /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C9F3DD52BFBCDD90003B86B /* libgmp.a */; };
|
|
||||||
5C9FD96E27A5D6ED0075386C /* SendMessageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C9FD96D27A5D6ED0075386C /* SendMessageView.swift */; };
|
5C9FD96E27A5D6ED0075386C /* SendMessageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C9FD96D27A5D6ED0075386C /* SendMessageView.swift */; };
|
||||||
5CA059DC279559F40002BEB4 /* Tests_iOS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CA059DB279559F40002BEB4 /* Tests_iOS.swift */; };
|
5CA059DC279559F40002BEB4 /* Tests_iOS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CA059DB279559F40002BEB4 /* Tests_iOS.swift */; };
|
||||||
5CA059DE279559F40002BEB4 /* Tests_iOSLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CA059DD279559F40002BEB4 /* Tests_iOSLaunchTests.swift */; };
|
5CA059DE279559F40002BEB4 /* Tests_iOSLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CA059DD279559F40002BEB4 /* Tests_iOSLaunchTests.swift */; };
|
||||||
@@ -120,6 +115,11 @@
|
|||||||
5CD67B8F2B0E858A00C510B1 /* hs_init.h in Headers */ = {isa = PBXBuildFile; fileRef = 5CD67B8D2B0E858A00C510B1 /* hs_init.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
5CD67B8F2B0E858A00C510B1 /* hs_init.h in Headers */ = {isa = PBXBuildFile; fileRef = 5CD67B8D2B0E858A00C510B1 /* hs_init.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||||
5CD67B902B0E858A00C510B1 /* hs_init.c in Sources */ = {isa = PBXBuildFile; fileRef = 5CD67B8E2B0E858A00C510B1 /* hs_init.c */; };
|
5CD67B902B0E858A00C510B1 /* hs_init.c in Sources */ = {isa = PBXBuildFile; fileRef = 5CD67B8E2B0E858A00C510B1 /* hs_init.c */; };
|
||||||
5CDCAD482818589900503DA2 /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CDCAD472818589900503DA2 /* NotificationService.swift */; };
|
5CDCAD482818589900503DA2 /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CDCAD472818589900503DA2 /* NotificationService.swift */; };
|
||||||
|
5CE0E8B52BF2B9ED008D6E06 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CE0E8B02BF2B9ED008D6E06 /* libgmp.a */; };
|
||||||
|
5CE0E8B62BF2B9ED008D6E06 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CE0E8B12BF2B9ED008D6E06 /* libgmpxx.a */; };
|
||||||
|
5CE0E8B72BF2B9ED008D6E06 /* libHSsimplex-chat-5.8.0.0-4rkacYU1Nfn5xrDMCOexv9-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CE0E8B22BF2B9ED008D6E06 /* libHSsimplex-chat-5.8.0.0-4rkacYU1Nfn5xrDMCOexv9-ghc9.6.3.a */; };
|
||||||
|
5CE0E8B82BF2B9ED008D6E06 /* libHSsimplex-chat-5.8.0.0-4rkacYU1Nfn5xrDMCOexv9.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CE0E8B32BF2B9ED008D6E06 /* libHSsimplex-chat-5.8.0.0-4rkacYU1Nfn5xrDMCOexv9.a */; };
|
||||||
|
5CE0E8B92BF2B9ED008D6E06 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CE0E8B42BF2B9ED008D6E06 /* libffi.a */; };
|
||||||
5CE2BA702845308900EC33A6 /* SimpleXChat.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CE2BA682845308900EC33A6 /* SimpleXChat.framework */; };
|
5CE2BA702845308900EC33A6 /* SimpleXChat.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CE2BA682845308900EC33A6 /* SimpleXChat.framework */; };
|
||||||
5CE2BA712845308900EC33A6 /* SimpleXChat.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 5CE2BA682845308900EC33A6 /* SimpleXChat.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
5CE2BA712845308900EC33A6 /* SimpleXChat.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 5CE2BA682845308900EC33A6 /* SimpleXChat.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||||
5CE2BA77284530BF00EC33A6 /* SimpleXChat.h in Headers */ = {isa = PBXBuildFile; fileRef = 5CE2BA76284530BF00EC33A6 /* SimpleXChat.h */; };
|
5CE2BA77284530BF00EC33A6 /* SimpleXChat.h in Headers */ = {isa = PBXBuildFile; fileRef = 5CE2BA76284530BF00EC33A6 /* SimpleXChat.h */; };
|
||||||
@@ -354,11 +354,6 @@
|
|||||||
5C9CC7AC28C55D7800BEF955 /* DatabaseEncryptionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DatabaseEncryptionView.swift; sourceTree = "<group>"; };
|
5C9CC7AC28C55D7800BEF955 /* DatabaseEncryptionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DatabaseEncryptionView.swift; sourceTree = "<group>"; };
|
||||||
5C9D13A2282187BB00AB8B43 /* WebRTC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebRTC.swift; sourceTree = "<group>"; };
|
5C9D13A2282187BB00AB8B43 /* WebRTC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebRTC.swift; sourceTree = "<group>"; };
|
||||||
5C9D81182AA7A4F1001D49FD /* CryptoFile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CryptoFile.swift; sourceTree = "<group>"; };
|
5C9D81182AA7A4F1001D49FD /* CryptoFile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CryptoFile.swift; sourceTree = "<group>"; };
|
||||||
5C9F3DD12BFBCDD80003B86B /* libHSsimplex-chat-5.8.0.2-8RkLdmy05dJBsgWrGV50Uf-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.8.0.2-8RkLdmy05dJBsgWrGV50Uf-ghc9.6.3.a"; sourceTree = "<group>"; };
|
|
||||||
5C9F3DD22BFBCDD80003B86B /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = "<group>"; };
|
|
||||||
5C9F3DD32BFBCDD80003B86B /* libHSsimplex-chat-5.8.0.2-8RkLdmy05dJBsgWrGV50Uf.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.8.0.2-8RkLdmy05dJBsgWrGV50Uf.a"; sourceTree = "<group>"; };
|
|
||||||
5C9F3DD42BFBCDD90003B86B /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = "<group>"; };
|
|
||||||
5C9F3DD52BFBCDD90003B86B /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = "<group>"; };
|
|
||||||
5C9FD96A27A56D4D0075386C /* JSON.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSON.swift; sourceTree = "<group>"; };
|
5C9FD96A27A56D4D0075386C /* JSON.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSON.swift; sourceTree = "<group>"; };
|
||||||
5C9FD96D27A5D6ED0075386C /* SendMessageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SendMessageView.swift; sourceTree = "<group>"; };
|
5C9FD96D27A5D6ED0075386C /* SendMessageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SendMessageView.swift; sourceTree = "<group>"; };
|
||||||
5CA059C3279559F40002BEB4 /* SimpleXApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimpleXApp.swift; sourceTree = "<group>"; };
|
5CA059C3279559F40002BEB4 /* SimpleXApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimpleXApp.swift; sourceTree = "<group>"; };
|
||||||
@@ -425,6 +420,11 @@
|
|||||||
5CDCAD7428188D2900503DA2 /* APITypes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = APITypes.swift; sourceTree = "<group>"; };
|
5CDCAD7428188D2900503DA2 /* APITypes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = APITypes.swift; sourceTree = "<group>"; };
|
||||||
5CDCAD7D2818941F00503DA2 /* API.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = API.swift; sourceTree = "<group>"; };
|
5CDCAD7D2818941F00503DA2 /* API.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = API.swift; sourceTree = "<group>"; };
|
||||||
5CDCAD80281A7E2700503DA2 /* Notifications.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Notifications.swift; sourceTree = "<group>"; };
|
5CDCAD80281A7E2700503DA2 /* Notifications.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Notifications.swift; sourceTree = "<group>"; };
|
||||||
|
5CE0E8B02BF2B9ED008D6E06 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = "<group>"; };
|
||||||
|
5CE0E8B12BF2B9ED008D6E06 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = "<group>"; };
|
||||||
|
5CE0E8B22BF2B9ED008D6E06 /* libHSsimplex-chat-5.8.0.0-4rkacYU1Nfn5xrDMCOexv9-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.8.0.0-4rkacYU1Nfn5xrDMCOexv9-ghc9.6.3.a"; sourceTree = "<group>"; };
|
||||||
|
5CE0E8B32BF2B9ED008D6E06 /* libHSsimplex-chat-5.8.0.0-4rkacYU1Nfn5xrDMCOexv9.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.8.0.0-4rkacYU1Nfn5xrDMCOexv9.a"; sourceTree = "<group>"; };
|
||||||
|
5CE0E8B42BF2B9ED008D6E06 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = "<group>"; };
|
||||||
5CE1330328E118CC00FFFD8C /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = "de.lproj/SimpleX--iOS--InfoPlist.strings"; sourceTree = "<group>"; };
|
5CE1330328E118CC00FFFD8C /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = "de.lproj/SimpleX--iOS--InfoPlist.strings"; sourceTree = "<group>"; };
|
||||||
5CE1330428E118CC00FFFD8C /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
5CE1330428E118CC00FFFD8C /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||||
5CE2BA682845308900EC33A6 /* SimpleXChat.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SimpleXChat.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
5CE2BA682845308900EC33A6 /* SimpleXChat.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SimpleXChat.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
@@ -529,13 +529,13 @@
|
|||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
5C9F3DD92BFBCDD90003B86B /* libgmpxx.a in Frameworks */,
|
5CE0E8B72BF2B9ED008D6E06 /* libHSsimplex-chat-5.8.0.0-4rkacYU1Nfn5xrDMCOexv9-ghc9.6.3.a in Frameworks */,
|
||||||
5C9F3DDA2BFBCDD90003B86B /* libgmp.a in Frameworks */,
|
5CE0E8B62BF2B9ED008D6E06 /* libgmpxx.a in Frameworks */,
|
||||||
5C9F3DD82BFBCDD90003B86B /* libHSsimplex-chat-5.8.0.2-8RkLdmy05dJBsgWrGV50Uf.a in Frameworks */,
|
|
||||||
5CE2BA93284534B000EC33A6 /* libiconv.tbd in Frameworks */,
|
5CE2BA93284534B000EC33A6 /* libiconv.tbd in Frameworks */,
|
||||||
5C9F3DD62BFBCDD90003B86B /* libHSsimplex-chat-5.8.0.2-8RkLdmy05dJBsgWrGV50Uf-ghc9.6.3.a in Frameworks */,
|
5CE0E8B52BF2B9ED008D6E06 /* libgmp.a in Frameworks */,
|
||||||
|
5CE0E8B92BF2B9ED008D6E06 /* libffi.a in Frameworks */,
|
||||||
5CE2BA94284534BB00EC33A6 /* libz.tbd in Frameworks */,
|
5CE2BA94284534BB00EC33A6 /* libz.tbd in Frameworks */,
|
||||||
5C9F3DD72BFBCDD90003B86B /* libffi.a in Frameworks */,
|
5CE0E8B82BF2B9ED008D6E06 /* libHSsimplex-chat-5.8.0.0-4rkacYU1Nfn5xrDMCOexv9.a in Frameworks */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@@ -601,11 +601,11 @@
|
|||||||
5C764E5C279C70B7000C6508 /* Libraries */ = {
|
5C764E5C279C70B7000C6508 /* Libraries */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
5C9F3DD22BFBCDD80003B86B /* libffi.a */,
|
5CE0E8B42BF2B9ED008D6E06 /* libffi.a */,
|
||||||
5C9F3DD52BFBCDD90003B86B /* libgmp.a */,
|
5CE0E8B02BF2B9ED008D6E06 /* libgmp.a */,
|
||||||
5C9F3DD42BFBCDD90003B86B /* libgmpxx.a */,
|
5CE0E8B12BF2B9ED008D6E06 /* libgmpxx.a */,
|
||||||
5C9F3DD12BFBCDD80003B86B /* libHSsimplex-chat-5.8.0.2-8RkLdmy05dJBsgWrGV50Uf-ghc9.6.3.a */,
|
5CE0E8B22BF2B9ED008D6E06 /* libHSsimplex-chat-5.8.0.0-4rkacYU1Nfn5xrDMCOexv9-ghc9.6.3.a */,
|
||||||
5C9F3DD32BFBCDD80003B86B /* libHSsimplex-chat-5.8.0.2-8RkLdmy05dJBsgWrGV50Uf.a */,
|
5CE0E8B32BF2B9ED008D6E06 /* libHSsimplex-chat-5.8.0.0-4rkacYU1Nfn5xrDMCOexv9.a */,
|
||||||
);
|
);
|
||||||
path = Libraries;
|
path = Libraries;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -1552,7 +1552,7 @@
|
|||||||
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
|
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
|
||||||
CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements";
|
CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 218;
|
CURRENT_PROJECT_VERSION = 216;
|
||||||
DEAD_CODE_STRIPPING = YES;
|
DEAD_CODE_STRIPPING = YES;
|
||||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
@@ -1601,7 +1601,7 @@
|
|||||||
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
|
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
|
||||||
CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements";
|
CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 218;
|
CURRENT_PROJECT_VERSION = 216;
|
||||||
DEAD_CODE_STRIPPING = YES;
|
DEAD_CODE_STRIPPING = YES;
|
||||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
@@ -1687,7 +1687,7 @@
|
|||||||
CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements";
|
CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements";
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 218;
|
CURRENT_PROJECT_VERSION = 216;
|
||||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
GCC_OPTIMIZATION_LEVEL = s;
|
GCC_OPTIMIZATION_LEVEL = s;
|
||||||
@@ -1724,7 +1724,7 @@
|
|||||||
CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements";
|
CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements";
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 218;
|
CURRENT_PROJECT_VERSION = 216;
|
||||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
ENABLE_CODE_COVERAGE = NO;
|
ENABLE_CODE_COVERAGE = NO;
|
||||||
@@ -1761,7 +1761,7 @@
|
|||||||
CLANG_TIDY_BUGPRONE_REDUNDANT_BRANCH_CONDITION = YES;
|
CLANG_TIDY_BUGPRONE_REDUNDANT_BRANCH_CONDITION = YES;
|
||||||
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
|
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 218;
|
CURRENT_PROJECT_VERSION = 216;
|
||||||
DEFINES_MODULE = YES;
|
DEFINES_MODULE = YES;
|
||||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||||
@@ -1812,7 +1812,7 @@
|
|||||||
CLANG_TIDY_BUGPRONE_REDUNDANT_BRANCH_CONDITION = YES;
|
CLANG_TIDY_BUGPRONE_REDUNDANT_BRANCH_CONDITION = YES;
|
||||||
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
|
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 218;
|
CURRENT_PROJECT_VERSION = 216;
|
||||||
DEFINES_MODULE = YES;
|
DEFINES_MODULE = YES;
|
||||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||||
|
|||||||
@@ -123,8 +123,8 @@ public enum ChatCommand {
|
|||||||
case apiGetNetworkStatuses
|
case apiGetNetworkStatuses
|
||||||
case apiChatRead(type: ChatType, id: Int64, itemRange: (Int64, Int64))
|
case apiChatRead(type: ChatType, id: Int64, itemRange: (Int64, Int64))
|
||||||
case apiChatUnread(type: ChatType, id: Int64, unreadChat: Bool)
|
case apiChatUnread(type: ChatType, id: Int64, unreadChat: Bool)
|
||||||
case receiveFile(fileId: Int64, userApprovedRelays: Bool, encrypted: Bool?, inline: Bool?)
|
case receiveFile(fileId: Int64, encrypted: Bool?, inline: Bool?)
|
||||||
case setFileToReceive(fileId: Int64, userApprovedRelays: Bool, encrypted: Bool?)
|
case setFileToReceive(fileId: Int64, encrypted: Bool?)
|
||||||
case cancelFile(fileId: Int64)
|
case cancelFile(fileId: Int64)
|
||||||
// remote desktop commands
|
// remote desktop commands
|
||||||
case setLocalDeviceName(displayName: String)
|
case setLocalDeviceName(displayName: String)
|
||||||
@@ -282,8 +282,8 @@ public enum ChatCommand {
|
|||||||
case .apiGetNetworkStatuses: return "/_network_statuses"
|
case .apiGetNetworkStatuses: return "/_network_statuses"
|
||||||
case let .apiChatRead(type, id, itemRange: (from, to)): return "/_read chat \(ref(type, id)) from=\(from) to=\(to)"
|
case let .apiChatRead(type, id, itemRange: (from, to)): return "/_read chat \(ref(type, id)) from=\(from) to=\(to)"
|
||||||
case let .apiChatUnread(type, id, unreadChat): return "/_unread chat \(ref(type, id)) \(onOff(unreadChat))"
|
case let .apiChatUnread(type, id, unreadChat): return "/_unread chat \(ref(type, id)) \(onOff(unreadChat))"
|
||||||
case let .receiveFile(fileId, userApprovedRelays, encrypt, inline): return "/freceive \(fileId)\(onOffParam("approved_relays", userApprovedRelays))\(onOffParam("encrypt", encrypt))\(onOffParam("inline", inline))"
|
case let .receiveFile(fileId, encrypt, inline): return "/freceive \(fileId)\(onOffParam("encrypt", encrypt))\(onOffParam("inline", inline))"
|
||||||
case let .setFileToReceive(fileId, userApprovedRelays, encrypt): return "/_set_file_to_receive \(fileId)\(onOffParam("approved_relays", userApprovedRelays))\(onOffParam("encrypt", encrypt))"
|
case let .setFileToReceive(fileId, encrypt): return "/_set_file_to_receive \(fileId)\(onOffParam("encrypt", encrypt))"
|
||||||
case let .cancelFile(fileId): return "/fcancel \(fileId)"
|
case let .cancelFile(fileId): return "/fcancel \(fileId)"
|
||||||
case let .setLocalDeviceName(displayName): return "/set device name \(displayName)"
|
case let .setLocalDeviceName(displayName): return "/set device name \(displayName)"
|
||||||
case let .connectRemoteCtrl(xrcpInv): return "/connect remote ctrl \(xrcpInv)"
|
case let .connectRemoteCtrl(xrcpInv): return "/connect remote ctrl \(xrcpInv)"
|
||||||
@@ -1760,7 +1760,6 @@ public enum ChatErrorType: Decodable {
|
|||||||
case fileImageType(filePath: String)
|
case fileImageType(filePath: String)
|
||||||
case fileImageSize(filePath: String)
|
case fileImageSize(filePath: String)
|
||||||
case fileNotReceived(fileId: Int64)
|
case fileNotReceived(fileId: Int64)
|
||||||
case fileNotApproved(fileId: Int64, unknownServers: [String])
|
|
||||||
// case xFTPRcvFile
|
// case xFTPRcvFile
|
||||||
// case xFTPSndFile
|
// case xFTPSndFile
|
||||||
case fallbackToSMPProhibited(fileId: Int64)
|
case fallbackToSMPProhibited(fileId: Int64)
|
||||||
@@ -2039,7 +2038,6 @@ public struct MigrationFileLinkData: Codable {
|
|||||||
public struct AppSettings: Codable, Equatable {
|
public struct AppSettings: Codable, Equatable {
|
||||||
public var networkConfig: NetCfg? = nil
|
public var networkConfig: NetCfg? = nil
|
||||||
public var privacyEncryptLocalFiles: Bool? = nil
|
public var privacyEncryptLocalFiles: Bool? = nil
|
||||||
public var privacyAskToApproveRelays: Bool? = nil
|
|
||||||
public var privacyAcceptImages: Bool? = nil
|
public var privacyAcceptImages: Bool? = nil
|
||||||
public var privacyLinkPreviews: Bool? = nil
|
public var privacyLinkPreviews: Bool? = nil
|
||||||
public var privacyShowChatPreviews: Bool? = nil
|
public var privacyShowChatPreviews: Bool? = nil
|
||||||
@@ -2063,7 +2061,6 @@ public struct AppSettings: Codable, Equatable {
|
|||||||
let def = AppSettings.defaults
|
let def = AppSettings.defaults
|
||||||
if networkConfig != def.networkConfig { empty.networkConfig = networkConfig }
|
if networkConfig != def.networkConfig { empty.networkConfig = networkConfig }
|
||||||
if privacyEncryptLocalFiles != def.privacyEncryptLocalFiles { empty.privacyEncryptLocalFiles = privacyEncryptLocalFiles }
|
if privacyEncryptLocalFiles != def.privacyEncryptLocalFiles { empty.privacyEncryptLocalFiles = privacyEncryptLocalFiles }
|
||||||
if privacyAskToApproveRelays != def.privacyAskToApproveRelays { empty.privacyAskToApproveRelays = privacyAskToApproveRelays }
|
|
||||||
if privacyAcceptImages != def.privacyAcceptImages { empty.privacyAcceptImages = privacyAcceptImages }
|
if privacyAcceptImages != def.privacyAcceptImages { empty.privacyAcceptImages = privacyAcceptImages }
|
||||||
if privacyLinkPreviews != def.privacyLinkPreviews { empty.privacyLinkPreviews = privacyLinkPreviews }
|
if privacyLinkPreviews != def.privacyLinkPreviews { empty.privacyLinkPreviews = privacyLinkPreviews }
|
||||||
if privacyShowChatPreviews != def.privacyShowChatPreviews { empty.privacyShowChatPreviews = privacyShowChatPreviews }
|
if privacyShowChatPreviews != def.privacyShowChatPreviews { empty.privacyShowChatPreviews = privacyShowChatPreviews }
|
||||||
@@ -2088,7 +2085,6 @@ public struct AppSettings: Codable, Equatable {
|
|||||||
AppSettings (
|
AppSettings (
|
||||||
networkConfig: NetCfg.defaults,
|
networkConfig: NetCfg.defaults,
|
||||||
privacyEncryptLocalFiles: true,
|
privacyEncryptLocalFiles: true,
|
||||||
privacyAskToApproveRelays: true,
|
|
||||||
privacyAcceptImages: true,
|
privacyAcceptImages: true,
|
||||||
privacyLinkPreviews: true,
|
privacyLinkPreviews: true,
|
||||||
privacyShowChatPreviews: true,
|
privacyShowChatPreviews: true,
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ public let GROUP_DEFAULT_NTF_ENABLE_PERIODIC = "ntfEnablePeriodic" // no longer
|
|||||||
let GROUP_DEFAULT_PRIVACY_ACCEPT_IMAGES = "privacyAcceptImages"
|
let GROUP_DEFAULT_PRIVACY_ACCEPT_IMAGES = "privacyAcceptImages"
|
||||||
public let GROUP_DEFAULT_PRIVACY_TRANSFER_IMAGES_INLINE = "privacyTransferImagesInline" // no longer used
|
public let GROUP_DEFAULT_PRIVACY_TRANSFER_IMAGES_INLINE = "privacyTransferImagesInline" // no longer used
|
||||||
public let GROUP_DEFAULT_PRIVACY_ENCRYPT_LOCAL_FILES = "privacyEncryptLocalFiles"
|
public let GROUP_DEFAULT_PRIVACY_ENCRYPT_LOCAL_FILES = "privacyEncryptLocalFiles"
|
||||||
public let GROUP_DEFAULT_PRIVACY_ASK_TO_APPROVE_RELAYS = "privacyAskToApproveRelays"
|
|
||||||
let GROUP_DEFAULT_NTF_BADGE_COUNT = "ntgBadgeCount"
|
let GROUP_DEFAULT_NTF_BADGE_COUNT = "ntgBadgeCount"
|
||||||
let GROUP_DEFAULT_NETWORK_USE_ONION_HOSTS = "networkUseOnionHosts"
|
let GROUP_DEFAULT_NETWORK_USE_ONION_HOSTS = "networkUseOnionHosts"
|
||||||
let GROUP_DEFAULT_NETWORK_SESSION_MODE = "networkSessionMode"
|
let GROUP_DEFAULT_NETWORK_SESSION_MODE = "networkSessionMode"
|
||||||
@@ -74,7 +73,6 @@ public func registerGroupDefaults() {
|
|||||||
GROUP_DEFAULT_PRIVACY_ACCEPT_IMAGES: true,
|
GROUP_DEFAULT_PRIVACY_ACCEPT_IMAGES: true,
|
||||||
GROUP_DEFAULT_PRIVACY_TRANSFER_IMAGES_INLINE: false,
|
GROUP_DEFAULT_PRIVACY_TRANSFER_IMAGES_INLINE: false,
|
||||||
GROUP_DEFAULT_PRIVACY_ENCRYPT_LOCAL_FILES: true,
|
GROUP_DEFAULT_PRIVACY_ENCRYPT_LOCAL_FILES: true,
|
||||||
GROUP_DEFAULT_PRIVACY_ASK_TO_APPROVE_RELAYS: true,
|
|
||||||
GROUP_DEFAULT_CONFIRM_DB_UPGRADES: false,
|
GROUP_DEFAULT_CONFIRM_DB_UPGRADES: false,
|
||||||
GROUP_DEFAULT_CALL_KIT_ENABLED: true,
|
GROUP_DEFAULT_CALL_KIT_ENABLED: true,
|
||||||
GROUP_DEFAULT_PQ_EXPERIMENTAL_ENABLED: false,
|
GROUP_DEFAULT_PQ_EXPERIMENTAL_ENABLED: false,
|
||||||
@@ -183,8 +181,6 @@ public let privacyAcceptImagesGroupDefault = BoolDefault(defaults: groupDefaults
|
|||||||
|
|
||||||
public let privacyEncryptLocalFilesGroupDefault = BoolDefault(defaults: groupDefaults, forKey: GROUP_DEFAULT_PRIVACY_ENCRYPT_LOCAL_FILES)
|
public let privacyEncryptLocalFilesGroupDefault = BoolDefault(defaults: groupDefaults, forKey: GROUP_DEFAULT_PRIVACY_ENCRYPT_LOCAL_FILES)
|
||||||
|
|
||||||
public let privacyAskToApproveRelaysGroupDefault = BoolDefault(defaults: groupDefaults, forKey: GROUP_DEFAULT_PRIVACY_ASK_TO_APPROVE_RELAYS)
|
|
||||||
|
|
||||||
public let ntfBadgeCountGroupDefault = IntDefault(defaults: groupDefaults, forKey: GROUP_DEFAULT_NTF_BADGE_COUNT)
|
public let ntfBadgeCountGroupDefault = IntDefault(defaults: groupDefaults, forKey: GROUP_DEFAULT_NTF_BADGE_COUNT)
|
||||||
|
|
||||||
public let networkUseOnionHostsGroupDefault = EnumDefault<OnionHosts>(
|
public let networkUseOnionHostsGroupDefault = EnumDefault<OnionHosts>(
|
||||||
|
|||||||
@@ -3174,7 +3174,6 @@ public struct CIFile: Decodable {
|
|||||||
case .rcvInvitation: return false
|
case .rcvInvitation: return false
|
||||||
case .rcvAccepted: return false
|
case .rcvAccepted: return false
|
||||||
case .rcvTransfer: return false
|
case .rcvTransfer: return false
|
||||||
case .rcvAborted: return false
|
|
||||||
case .rcvCancelled: return false
|
case .rcvCancelled: return false
|
||||||
case .rcvComplete: return true
|
case .rcvComplete: return true
|
||||||
case .rcvError: return false
|
case .rcvError: return false
|
||||||
@@ -3199,7 +3198,6 @@ public struct CIFile: Decodable {
|
|||||||
case .rcvInvitation: return nil
|
case .rcvInvitation: return nil
|
||||||
case .rcvAccepted: return rcvCancelAction
|
case .rcvAccepted: return rcvCancelAction
|
||||||
case .rcvTransfer: return rcvCancelAction
|
case .rcvTransfer: return rcvCancelAction
|
||||||
case .rcvAborted: return nil
|
|
||||||
case .rcvCancelled: return nil
|
case .rcvCancelled: return nil
|
||||||
case .rcvComplete: return nil
|
case .rcvComplete: return nil
|
||||||
case .rcvError: return nil
|
case .rcvError: return nil
|
||||||
@@ -3314,7 +3312,6 @@ public enum CIFileStatus: Decodable, Equatable {
|
|||||||
case rcvInvitation
|
case rcvInvitation
|
||||||
case rcvAccepted
|
case rcvAccepted
|
||||||
case rcvTransfer(rcvProgress: Int64, rcvTotal: Int64)
|
case rcvTransfer(rcvProgress: Int64, rcvTotal: Int64)
|
||||||
case rcvAborted
|
|
||||||
case rcvComplete
|
case rcvComplete
|
||||||
case rcvCancelled
|
case rcvCancelled
|
||||||
case rcvError
|
case rcvError
|
||||||
@@ -3330,7 +3327,6 @@ public enum CIFileStatus: Decodable, Equatable {
|
|||||||
case .rcvInvitation: return "rcvInvitation"
|
case .rcvInvitation: return "rcvInvitation"
|
||||||
case .rcvAccepted: return "rcvAccepted"
|
case .rcvAccepted: return "rcvAccepted"
|
||||||
case let .rcvTransfer(rcvProgress, rcvTotal): return "rcvTransfer \(rcvProgress) \(rcvTotal)"
|
case let .rcvTransfer(rcvProgress, rcvTotal): return "rcvTransfer \(rcvProgress) \(rcvTotal)"
|
||||||
case .rcvAborted: return "rcvAborted"
|
|
||||||
case .rcvComplete: return "rcvComplete"
|
case .rcvComplete: return "rcvComplete"
|
||||||
case .rcvCancelled: return "rcvCancelled"
|
case .rcvCancelled: return "rcvCancelled"
|
||||||
case .rcvError: return "rcvError"
|
case .rcvError: return "rcvError"
|
||||||
|
|||||||
@@ -2644,7 +2644,6 @@ data class CIFile(
|
|||||||
is CIFileStatus.RcvInvitation -> false
|
is CIFileStatus.RcvInvitation -> false
|
||||||
is CIFileStatus.RcvAccepted -> false
|
is CIFileStatus.RcvAccepted -> false
|
||||||
is CIFileStatus.RcvTransfer -> false
|
is CIFileStatus.RcvTransfer -> false
|
||||||
is CIFileStatus.RcvAborted -> false
|
|
||||||
is CIFileStatus.RcvCancelled -> false
|
is CIFileStatus.RcvCancelled -> false
|
||||||
is CIFileStatus.RcvComplete -> true
|
is CIFileStatus.RcvComplete -> true
|
||||||
is CIFileStatus.RcvError -> false
|
is CIFileStatus.RcvError -> false
|
||||||
@@ -2666,7 +2665,6 @@ data class CIFile(
|
|||||||
is CIFileStatus.RcvInvitation -> null
|
is CIFileStatus.RcvInvitation -> null
|
||||||
is CIFileStatus.RcvAccepted -> rcvCancelAction
|
is CIFileStatus.RcvAccepted -> rcvCancelAction
|
||||||
is CIFileStatus.RcvTransfer -> rcvCancelAction
|
is CIFileStatus.RcvTransfer -> rcvCancelAction
|
||||||
is CIFileStatus.RcvAborted -> null
|
|
||||||
is CIFileStatus.RcvCancelled -> null
|
is CIFileStatus.RcvCancelled -> null
|
||||||
is CIFileStatus.RcvComplete -> null
|
is CIFileStatus.RcvComplete -> null
|
||||||
is CIFileStatus.RcvError -> null
|
is CIFileStatus.RcvError -> null
|
||||||
@@ -2847,7 +2845,6 @@ sealed class CIFileStatus {
|
|||||||
@Serializable @SerialName("rcvInvitation") object RcvInvitation: CIFileStatus()
|
@Serializable @SerialName("rcvInvitation") object RcvInvitation: CIFileStatus()
|
||||||
@Serializable @SerialName("rcvAccepted") object RcvAccepted: CIFileStatus()
|
@Serializable @SerialName("rcvAccepted") object RcvAccepted: CIFileStatus()
|
||||||
@Serializable @SerialName("rcvTransfer") class RcvTransfer(val rcvProgress: Long, val rcvTotal: Long): CIFileStatus()
|
@Serializable @SerialName("rcvTransfer") class RcvTransfer(val rcvProgress: Long, val rcvTotal: Long): CIFileStatus()
|
||||||
@Serializable @SerialName("rcvAborted") object RcvAborted: CIFileStatus()
|
|
||||||
@Serializable @SerialName("rcvComplete") object RcvComplete: CIFileStatus()
|
@Serializable @SerialName("rcvComplete") object RcvComplete: CIFileStatus()
|
||||||
@Serializable @SerialName("rcvCancelled") object RcvCancelled: CIFileStatus()
|
@Serializable @SerialName("rcvCancelled") object RcvCancelled: CIFileStatus()
|
||||||
@Serializable @SerialName("rcvError") object RcvError: CIFileStatus()
|
@Serializable @SerialName("rcvError") object RcvError: CIFileStatus()
|
||||||
@@ -2862,7 +2859,6 @@ sealed class CIFileStatus {
|
|||||||
is RcvInvitation -> false
|
is RcvInvitation -> false
|
||||||
is RcvAccepted -> false
|
is RcvAccepted -> false
|
||||||
is RcvTransfer -> false
|
is RcvTransfer -> false
|
||||||
is RcvAborted -> false
|
|
||||||
is RcvComplete -> false
|
is RcvComplete -> false
|
||||||
is RcvCancelled -> false
|
is RcvCancelled -> false
|
||||||
is RcvError -> false
|
is RcvError -> false
|
||||||
|
|||||||
+8
-40
@@ -12,7 +12,6 @@ import dev.icerock.moko.resources.compose.painterResource
|
|||||||
import chat.simplex.common.platform.*
|
import chat.simplex.common.platform.*
|
||||||
import chat.simplex.common.ui.theme.*
|
import chat.simplex.common.ui.theme.*
|
||||||
import chat.simplex.common.views.call.*
|
import chat.simplex.common.views.call.*
|
||||||
import chat.simplex.common.views.chat.group.toggleShowMemberMessages
|
|
||||||
import chat.simplex.common.views.migration.MigrationFileLinkData
|
import chat.simplex.common.views.migration.MigrationFileLinkData
|
||||||
import chat.simplex.common.views.onboarding.OnboardingStage
|
import chat.simplex.common.views.onboarding.OnboardingStage
|
||||||
import chat.simplex.common.views.usersettings.*
|
import chat.simplex.common.views.usersettings.*
|
||||||
@@ -107,7 +106,6 @@ class AppPreferences {
|
|||||||
val privacySaveLastDraft = mkBoolPreference(SHARED_PREFS_PRIVACY_SAVE_LAST_DRAFT, true)
|
val privacySaveLastDraft = mkBoolPreference(SHARED_PREFS_PRIVACY_SAVE_LAST_DRAFT, true)
|
||||||
val privacyDeliveryReceiptsSet = mkBoolPreference(SHARED_PREFS_PRIVACY_DELIVERY_RECEIPTS_SET, false)
|
val privacyDeliveryReceiptsSet = mkBoolPreference(SHARED_PREFS_PRIVACY_DELIVERY_RECEIPTS_SET, false)
|
||||||
val privacyEncryptLocalFiles = mkBoolPreference(SHARED_PREFS_PRIVACY_ENCRYPT_LOCAL_FILES, true)
|
val privacyEncryptLocalFiles = mkBoolPreference(SHARED_PREFS_PRIVACY_ENCRYPT_LOCAL_FILES, true)
|
||||||
val privacyAskToApproveRelays = mkBoolPreference(SHARED_PREFS_PRIVACY_ASK_TO_APPROVE_RELAYS, true)
|
|
||||||
val experimentalCalls = mkBoolPreference(SHARED_PREFS_EXPERIMENTAL_CALLS, false)
|
val experimentalCalls = mkBoolPreference(SHARED_PREFS_EXPERIMENTAL_CALLS, false)
|
||||||
val showUnreadAndFavorites = mkBoolPreference(SHARED_PREFS_SHOW_UNREAD_AND_FAVORITES, false)
|
val showUnreadAndFavorites = mkBoolPreference(SHARED_PREFS_SHOW_UNREAD_AND_FAVORITES, false)
|
||||||
val chatArchiveName = mkStrPreference(SHARED_PREFS_CHAT_ARCHIVE_NAME, null)
|
val chatArchiveName = mkStrPreference(SHARED_PREFS_CHAT_ARCHIVE_NAME, null)
|
||||||
@@ -294,7 +292,6 @@ class AppPreferences {
|
|||||||
private const val SHARED_PREFS_PRIVACY_SAVE_LAST_DRAFT = "PrivacySaveLastDraft"
|
private const val SHARED_PREFS_PRIVACY_SAVE_LAST_DRAFT = "PrivacySaveLastDraft"
|
||||||
private const val SHARED_PREFS_PRIVACY_DELIVERY_RECEIPTS_SET = "PrivacyDeliveryReceiptsSet"
|
private const val SHARED_PREFS_PRIVACY_DELIVERY_RECEIPTS_SET = "PrivacyDeliveryReceiptsSet"
|
||||||
private const val SHARED_PREFS_PRIVACY_ENCRYPT_LOCAL_FILES = "PrivacyEncryptLocalFiles"
|
private const val SHARED_PREFS_PRIVACY_ENCRYPT_LOCAL_FILES = "PrivacyEncryptLocalFiles"
|
||||||
private const val SHARED_PREFS_PRIVACY_ASK_TO_APPROVE_RELAYS = "PrivacyAskToApproveRelays"
|
|
||||||
const val SHARED_PREFS_PRIVACY_FULL_BACKUP = "FullBackup"
|
const val SHARED_PREFS_PRIVACY_FULL_BACKUP = "FullBackup"
|
||||||
private const val SHARED_PREFS_EXPERIMENTAL_CALLS = "ExperimentalCalls"
|
private const val SHARED_PREFS_EXPERIMENTAL_CALLS = "ExperimentalCalls"
|
||||||
private const val SHARED_PREFS_SHOW_UNREAD_AND_FAVORITES = "ShowUnreadAndFavorites"
|
private const val SHARED_PREFS_SHOW_UNREAD_AND_FAVORITES = "ShowUnreadAndFavorites"
|
||||||
@@ -1340,9 +1337,9 @@ object ChatController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun apiReceiveFile(rh: Long?, fileId: Long, userApprovedRelays: Boolean, encrypted: Boolean, inline: Boolean? = null, auto: Boolean = false): AChatItem? {
|
suspend fun apiReceiveFile(rh: Long?, fileId: Long, encrypted: Boolean, inline: Boolean? = null, auto: Boolean = false): AChatItem? {
|
||||||
// -1 here is to override default behavior of providing current remote host id because file can be asked by local device while remote is connected
|
// -1 here is to override default behavior of providing current remote host id because file can be asked by local device while remote is connected
|
||||||
val r = sendCmd(rh, CC.ReceiveFile(fileId, userApprovedRelays = userApprovedRelays, encrypt = encrypted, inline = inline))
|
val r = sendCmd(rh, CC.ReceiveFile(fileId, encrypted, inline))
|
||||||
return when (r) {
|
return when (r) {
|
||||||
is CR.RcvFileAccepted -> r.chatItem
|
is CR.RcvFileAccepted -> r.chatItem
|
||||||
is CR.RcvFileAcceptedSndCancelled -> {
|
is CR.RcvFileAcceptedSndCancelled -> {
|
||||||
@@ -1361,23 +1358,7 @@ object ChatController {
|
|||||||
val maybeChatError = chatError(r)
|
val maybeChatError = chatError(r)
|
||||||
if (maybeChatError is ChatErrorType.FileCancelled || maybeChatError is ChatErrorType.FileAlreadyReceiving) {
|
if (maybeChatError is ChatErrorType.FileCancelled || maybeChatError is ChatErrorType.FileAlreadyReceiving) {
|
||||||
Log.d(TAG, "apiReceiveFile ignoring FileCancelled or FileAlreadyReceiving error")
|
Log.d(TAG, "apiReceiveFile ignoring FileCancelled or FileAlreadyReceiving error")
|
||||||
} else if (maybeChatError is ChatErrorType.FileNotApproved) {
|
} else {
|
||||||
Log.d(TAG, "apiReceiveFile FileNotApproved error")
|
|
||||||
if (!auto) {
|
|
||||||
val srvs = maybeChatError.unknownServers.map{ serverHostname(it) }
|
|
||||||
AlertManager.shared.showAlertDialog(
|
|
||||||
title = generalGetString(MR.strings.file_not_approved_title),
|
|
||||||
text = generalGetString(MR.strings.file_not_approved_descr).format(srvs.sorted().joinToString(separator = ", ")),
|
|
||||||
confirmText = generalGetString(MR.strings.download_file),
|
|
||||||
onConfirm = {
|
|
||||||
val user = chatModel.currentUser.value
|
|
||||||
if (user != null) {
|
|
||||||
withBGApi { chatModel.controller.receiveFile(rh, user, fileId, userApprovedRelays = true) }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} else if (!auto) {
|
|
||||||
apiErrorAlert("apiReceiveFile", generalGetString(MR.strings.error_receiving_file), r)
|
apiErrorAlert("apiReceiveFile", generalGetString(MR.strings.error_receiving_file), r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2235,14 +2216,9 @@ object ChatController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun receiveFile(rhId: Long?, user: UserLike, fileId: Long, userApprovedRelays: Boolean = false, auto: Boolean = false) {
|
suspend fun receiveFile(rhId: Long?, user: UserLike, fileId: Long, auto: Boolean = false) {
|
||||||
val chatItem = apiReceiveFile(
|
val encrypted = appPrefs.privacyEncryptLocalFiles.get()
|
||||||
rhId,
|
val chatItem = apiReceiveFile(rhId, fileId, encrypted = encrypted, auto = auto)
|
||||||
fileId,
|
|
||||||
userApprovedRelays = userApprovedRelays || !appPrefs.privacyAskToApproveRelays.get(),
|
|
||||||
encrypted = appPrefs.privacyEncryptLocalFiles.get(),
|
|
||||||
auto = auto
|
|
||||||
)
|
|
||||||
if (chatItem != null) {
|
if (chatItem != null) {
|
||||||
chatItemSimpleUpdate(rhId, user, chatItem)
|
chatItemSimpleUpdate(rhId, user, chatItem)
|
||||||
}
|
}
|
||||||
@@ -2525,7 +2501,7 @@ sealed class CC {
|
|||||||
class ApiRejectContact(val contactReqId: Long): CC()
|
class ApiRejectContact(val contactReqId: Long): CC()
|
||||||
class ApiChatRead(val type: ChatType, val id: Long, val range: ItemRange): CC()
|
class ApiChatRead(val type: ChatType, val id: Long, val range: ItemRange): CC()
|
||||||
class ApiChatUnread(val type: ChatType, val id: Long, val unreadChat: Boolean): CC()
|
class ApiChatUnread(val type: ChatType, val id: Long, val unreadChat: Boolean): CC()
|
||||||
class ReceiveFile(val fileId: Long, val userApprovedRelays: Boolean, val encrypt: Boolean, val inline: Boolean?): CC()
|
class ReceiveFile(val fileId: Long, val encrypt: Boolean, val inline: Boolean?): CC()
|
||||||
class CancelFile(val fileId: Long): CC()
|
class CancelFile(val fileId: Long): CC()
|
||||||
// Remote control
|
// Remote control
|
||||||
class SetLocalDeviceName(val displayName: String): CC()
|
class SetLocalDeviceName(val displayName: String): CC()
|
||||||
@@ -2676,7 +2652,6 @@ sealed class CC {
|
|||||||
is ApiChatUnread -> "/_unread chat ${chatRef(type, id)} ${onOff(unreadChat)}"
|
is ApiChatUnread -> "/_unread chat ${chatRef(type, id)} ${onOff(unreadChat)}"
|
||||||
is ReceiveFile ->
|
is ReceiveFile ->
|
||||||
"/freceive $fileId" +
|
"/freceive $fileId" +
|
||||||
(" approved_relays=${onOff(userApprovedRelays)}") +
|
|
||||||
(if (encrypt == null) "" else " encrypt=${onOff(encrypt)}") +
|
(if (encrypt == null) "" else " encrypt=${onOff(encrypt)}") +
|
||||||
(if (inline == null) "" else " inline=${onOff(inline)}")
|
(if (inline == null) "" else " inline=${onOff(inline)}")
|
||||||
is CancelFile -> "/fcancel $fileId"
|
is CancelFile -> "/fcancel $fileId"
|
||||||
@@ -4917,14 +4892,13 @@ sealed class ChatErrorType {
|
|||||||
is FileCancel -> "fileCancel"
|
is FileCancel -> "fileCancel"
|
||||||
is FileAlreadyExists -> "fileAlreadyExists"
|
is FileAlreadyExists -> "fileAlreadyExists"
|
||||||
is FileRead -> "fileRead"
|
is FileRead -> "fileRead"
|
||||||
is FileWrite -> "fileWrite $message"
|
is FileWrite -> "fileWrite"
|
||||||
is FileSend -> "fileSend"
|
is FileSend -> "fileSend"
|
||||||
is FileRcvChunk -> "fileRcvChunk"
|
is FileRcvChunk -> "fileRcvChunk"
|
||||||
is FileInternal -> "fileInternal"
|
is FileInternal -> "fileInternal"
|
||||||
is FileImageType -> "fileImageType"
|
is FileImageType -> "fileImageType"
|
||||||
is FileImageSize -> "fileImageSize"
|
is FileImageSize -> "fileImageSize"
|
||||||
is FileNotReceived -> "fileNotReceived"
|
is FileNotReceived -> "fileNotReceived"
|
||||||
is FileNotApproved -> "fileNotApproved"
|
|
||||||
// is XFTPRcvFile -> "xftpRcvFile"
|
// is XFTPRcvFile -> "xftpRcvFile"
|
||||||
// is XFTPSndFile -> "xftpSndFile"
|
// is XFTPSndFile -> "xftpSndFile"
|
||||||
is FallbackToSMPProhibited -> "fallbackToSMPProhibited"
|
is FallbackToSMPProhibited -> "fallbackToSMPProhibited"
|
||||||
@@ -5004,7 +4978,6 @@ sealed class ChatErrorType {
|
|||||||
@Serializable @SerialName("fileImageType") class FileImageType(val filePath: String): ChatErrorType()
|
@Serializable @SerialName("fileImageType") class FileImageType(val filePath: String): ChatErrorType()
|
||||||
@Serializable @SerialName("fileImageSize") class FileImageSize(val filePath: String): ChatErrorType()
|
@Serializable @SerialName("fileImageSize") class FileImageSize(val filePath: String): ChatErrorType()
|
||||||
@Serializable @SerialName("fileNotReceived") class FileNotReceived(val fileId: Long): ChatErrorType()
|
@Serializable @SerialName("fileNotReceived") class FileNotReceived(val fileId: Long): ChatErrorType()
|
||||||
@Serializable @SerialName("fileNotApproved") class FileNotApproved(val fileId: Long, val unknownServers: List<String>): ChatErrorType()
|
|
||||||
// @Serializable @SerialName("xFTPRcvFile") object XFTPRcvFile: ChatErrorType()
|
// @Serializable @SerialName("xFTPRcvFile") object XFTPRcvFile: ChatErrorType()
|
||||||
// @Serializable @SerialName("xFTPSndFile") object XFTPSndFile: ChatErrorType()
|
// @Serializable @SerialName("xFTPSndFile") object XFTPSndFile: ChatErrorType()
|
||||||
@Serializable @SerialName("fallbackToSMPProhibited") class FallbackToSMPProhibited(val fileId: Long): ChatErrorType()
|
@Serializable @SerialName("fallbackToSMPProhibited") class FallbackToSMPProhibited(val fileId: Long): ChatErrorType()
|
||||||
@@ -5503,7 +5476,6 @@ enum class NotificationsMode() {
|
|||||||
data class AppSettings(
|
data class AppSettings(
|
||||||
var networkConfig: NetCfg? = null,
|
var networkConfig: NetCfg? = null,
|
||||||
var privacyEncryptLocalFiles: Boolean? = null,
|
var privacyEncryptLocalFiles: Boolean? = null,
|
||||||
var privacyAskToApproveRelays: Boolean? = null,
|
|
||||||
var privacyAcceptImages: Boolean? = null,
|
var privacyAcceptImages: Boolean? = null,
|
||||||
var privacyLinkPreviews: Boolean? = null,
|
var privacyLinkPreviews: Boolean? = null,
|
||||||
var privacyShowChatPreviews: Boolean? = null,
|
var privacyShowChatPreviews: Boolean? = null,
|
||||||
@@ -5527,7 +5499,6 @@ data class AppSettings(
|
|||||||
val def = defaults
|
val def = defaults
|
||||||
if (networkConfig != def.networkConfig) { empty.networkConfig = networkConfig }
|
if (networkConfig != def.networkConfig) { empty.networkConfig = networkConfig }
|
||||||
if (privacyEncryptLocalFiles != def.privacyEncryptLocalFiles) { empty.privacyEncryptLocalFiles = privacyEncryptLocalFiles }
|
if (privacyEncryptLocalFiles != def.privacyEncryptLocalFiles) { empty.privacyEncryptLocalFiles = privacyEncryptLocalFiles }
|
||||||
if (privacyAskToApproveRelays != def.privacyAskToApproveRelays) { empty.privacyAskToApproveRelays = privacyAskToApproveRelays }
|
|
||||||
if (privacyAcceptImages != def.privacyAcceptImages) { empty.privacyAcceptImages = privacyAcceptImages }
|
if (privacyAcceptImages != def.privacyAcceptImages) { empty.privacyAcceptImages = privacyAcceptImages }
|
||||||
if (privacyLinkPreviews != def.privacyLinkPreviews) { empty.privacyLinkPreviews = privacyLinkPreviews }
|
if (privacyLinkPreviews != def.privacyLinkPreviews) { empty.privacyLinkPreviews = privacyLinkPreviews }
|
||||||
if (privacyShowChatPreviews != def.privacyShowChatPreviews) { empty.privacyShowChatPreviews = privacyShowChatPreviews }
|
if (privacyShowChatPreviews != def.privacyShowChatPreviews) { empty.privacyShowChatPreviews = privacyShowChatPreviews }
|
||||||
@@ -5559,7 +5530,6 @@ data class AppSettings(
|
|||||||
setNetCfg(net)
|
setNetCfg(net)
|
||||||
}
|
}
|
||||||
privacyEncryptLocalFiles?.let { def.privacyEncryptLocalFiles.set(it) }
|
privacyEncryptLocalFiles?.let { def.privacyEncryptLocalFiles.set(it) }
|
||||||
privacyAskToApproveRelays?.let { def.privacyAskToApproveRelays.set(it) }
|
|
||||||
privacyAcceptImages?.let { def.privacyAcceptImages.set(it) }
|
privacyAcceptImages?.let { def.privacyAcceptImages.set(it) }
|
||||||
privacyLinkPreviews?.let { def.privacyLinkPreviews.set(it) }
|
privacyLinkPreviews?.let { def.privacyLinkPreviews.set(it) }
|
||||||
privacyShowChatPreviews?.let { def.privacyShowChatPreviews.set(it) }
|
privacyShowChatPreviews?.let { def.privacyShowChatPreviews.set(it) }
|
||||||
@@ -5584,7 +5554,6 @@ data class AppSettings(
|
|||||||
get() = AppSettings(
|
get() = AppSettings(
|
||||||
networkConfig = NetCfg.defaults,
|
networkConfig = NetCfg.defaults,
|
||||||
privacyEncryptLocalFiles = true,
|
privacyEncryptLocalFiles = true,
|
||||||
privacyAskToApproveRelays = true,
|
|
||||||
privacyAcceptImages = true,
|
privacyAcceptImages = true,
|
||||||
privacyLinkPreviews = true,
|
privacyLinkPreviews = true,
|
||||||
privacyShowChatPreviews = true,
|
privacyShowChatPreviews = true,
|
||||||
@@ -5610,7 +5579,6 @@ data class AppSettings(
|
|||||||
return defaults.copy(
|
return defaults.copy(
|
||||||
networkConfig = getNetCfg(),
|
networkConfig = getNetCfg(),
|
||||||
privacyEncryptLocalFiles = def.privacyEncryptLocalFiles.get(),
|
privacyEncryptLocalFiles = def.privacyEncryptLocalFiles.get(),
|
||||||
privacyAskToApproveRelays = def.privacyAskToApproveRelays.get(),
|
|
||||||
privacyAcceptImages = def.privacyAcceptImages.get(),
|
privacyAcceptImages = def.privacyAcceptImages.get(),
|
||||||
privacyLinkPreviews = def.privacyLinkPreviews.get(),
|
privacyLinkPreviews = def.privacyLinkPreviews.get(),
|
||||||
privacyShowChatPreviews = def.privacyShowChatPreviews.get(),
|
privacyShowChatPreviews = def.privacyShowChatPreviews.get(),
|
||||||
|
|||||||
+2
-3
@@ -1,5 +1,6 @@
|
|||||||
package chat.simplex.common.views.chat.item
|
package chat.simplex.common.views.chat.item
|
||||||
|
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.combinedClickable
|
import androidx.compose.foundation.combinedClickable
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.shape.CornerSize
|
import androidx.compose.foundation.shape.CornerSize
|
||||||
@@ -63,7 +64,7 @@ fun CIFileView(
|
|||||||
fun fileAction() {
|
fun fileAction() {
|
||||||
if (file != null) {
|
if (file != null) {
|
||||||
when {
|
when {
|
||||||
file.fileStatus is CIFileStatus.RcvInvitation || file.fileStatus is CIFileStatus.RcvAborted -> {
|
file.fileStatus is CIFileStatus.RcvInvitation -> {
|
||||||
if (fileSizeValid(file)) {
|
if (fileSizeValid(file)) {
|
||||||
receiveFile(file.fileId)
|
receiveFile(file.fileId)
|
||||||
} else {
|
} else {
|
||||||
@@ -175,8 +176,6 @@ fun CIFileView(
|
|||||||
} else {
|
} else {
|
||||||
progressIndicator()
|
progressIndicator()
|
||||||
}
|
}
|
||||||
is CIFileStatus.RcvAborted ->
|
|
||||||
fileIcon(innerIcon = painterResource(MR.images.ic_sync_problem), color = MaterialTheme.colors.primary)
|
|
||||||
is CIFileStatus.RcvComplete -> fileIcon()
|
is CIFileStatus.RcvComplete -> fileIcon()
|
||||||
is CIFileStatus.RcvCancelled -> fileIcon(innerIcon = painterResource(MR.images.ic_close))
|
is CIFileStatus.RcvCancelled -> fileIcon(innerIcon = painterResource(MR.images.ic_close))
|
||||||
is CIFileStatus.RcvError -> fileIcon(innerIcon = painterResource(MR.images.ic_close))
|
is CIFileStatus.RcvError -> fileIcon(innerIcon = painterResource(MR.images.ic_close))
|
||||||
|
|||||||
+7
-3
@@ -21,12 +21,17 @@ import chat.simplex.common.platform.*
|
|||||||
import chat.simplex.common.ui.theme.DEFAULT_MAX_IMAGE_WIDTH
|
import chat.simplex.common.ui.theme.DEFAULT_MAX_IMAGE_WIDTH
|
||||||
import chat.simplex.res.MR
|
import chat.simplex.res.MR
|
||||||
import dev.icerock.moko.resources.StringResource
|
import dev.icerock.moko.resources.StringResource
|
||||||
|
import kotlinx.coroutines.flow.collect
|
||||||
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import java.io.File
|
||||||
|
import java.net.URI
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun CIImageView(
|
fun CIImageView(
|
||||||
image: String,
|
image: String,
|
||||||
file: CIFile?,
|
file: CIFile?,
|
||||||
|
metaColor: Color,
|
||||||
imageProvider: () -> ImageGalleryProvider,
|
imageProvider: () -> ImageGalleryProvider,
|
||||||
showMenu: MutableState<Boolean>,
|
showMenu: MutableState<Boolean>,
|
||||||
receiveFile: (Long) -> Unit
|
receiveFile: (Long) -> Unit
|
||||||
@@ -46,7 +51,7 @@ fun CIImageView(
|
|||||||
icon,
|
icon,
|
||||||
stringResource(stringId),
|
stringResource(stringId),
|
||||||
Modifier.fillMaxSize(),
|
Modifier.fillMaxSize(),
|
||||||
tint = Color.White
|
tint = metaColor
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,7 +78,6 @@ fun CIImageView(
|
|||||||
is CIFileStatus.RcvInvitation -> fileIcon(painterResource(MR.images.ic_arrow_downward), MR.strings.icon_descr_asked_to_receive)
|
is CIFileStatus.RcvInvitation -> fileIcon(painterResource(MR.images.ic_arrow_downward), MR.strings.icon_descr_asked_to_receive)
|
||||||
is CIFileStatus.RcvAccepted -> fileIcon(painterResource(MR.images.ic_more_horiz), MR.strings.icon_descr_waiting_for_image)
|
is CIFileStatus.RcvAccepted -> fileIcon(painterResource(MR.images.ic_more_horiz), MR.strings.icon_descr_waiting_for_image)
|
||||||
is CIFileStatus.RcvTransfer -> progressIndicator()
|
is CIFileStatus.RcvTransfer -> progressIndicator()
|
||||||
is CIFileStatus.RcvAborted -> fileIcon(painterResource(MR.images.ic_sync_problem), MR.strings.icon_descr_file)
|
|
||||||
is CIFileStatus.RcvCancelled -> fileIcon(painterResource(MR.images.ic_close), MR.strings.icon_descr_file)
|
is CIFileStatus.RcvCancelled -> fileIcon(painterResource(MR.images.ic_close), MR.strings.icon_descr_file)
|
||||||
is CIFileStatus.RcvError -> fileIcon(painterResource(MR.images.ic_close), MR.strings.icon_descr_file)
|
is CIFileStatus.RcvError -> fileIcon(painterResource(MR.images.ic_close), MR.strings.icon_descr_file)
|
||||||
is CIFileStatus.Invalid -> fileIcon(painterResource(MR.images.ic_question_mark), MR.strings.icon_descr_file)
|
is CIFileStatus.Invalid -> fileIcon(painterResource(MR.images.ic_question_mark), MR.strings.icon_descr_file)
|
||||||
@@ -202,7 +206,7 @@ fun CIImageView(
|
|||||||
imageView(base64ToBitmap(image), onClick = {
|
imageView(base64ToBitmap(image), onClick = {
|
||||||
if (file != null) {
|
if (file != null) {
|
||||||
when (file.fileStatus) {
|
when (file.fileStatus) {
|
||||||
CIFileStatus.RcvInvitation, CIFileStatus.RcvAborted ->
|
CIFileStatus.RcvInvitation ->
|
||||||
if (fileSizeValid()) {
|
if (fileSizeValid()) {
|
||||||
receiveFile(file.fileId)
|
receiveFile(file.fileId)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
+2
-3
@@ -73,7 +73,7 @@ fun CIVideoView(
|
|||||||
VideoPreviewImageView(preview, onClick = {
|
VideoPreviewImageView(preview, onClick = {
|
||||||
if (file != null) {
|
if (file != null) {
|
||||||
when (file.fileStatus) {
|
when (file.fileStatus) {
|
||||||
CIFileStatus.RcvInvitation, CIFileStatus.RcvAborted ->
|
CIFileStatus.RcvInvitation ->
|
||||||
receiveFileIfValidSize(file, receiveFile)
|
receiveFileIfValidSize(file, receiveFile)
|
||||||
CIFileStatus.RcvAccepted ->
|
CIFileStatus.RcvAccepted ->
|
||||||
when (file.fileProtocol) {
|
when (file.fileProtocol) {
|
||||||
@@ -102,7 +102,7 @@ fun CIVideoView(
|
|||||||
if (file != null) {
|
if (file != null) {
|
||||||
DurationProgress(file, remember { mutableStateOf(false) }, remember { mutableStateOf(duration * 1000L) }, remember { mutableStateOf(0L) }/*, soundEnabled*/)
|
DurationProgress(file, remember { mutableStateOf(false) }, remember { mutableStateOf(duration * 1000L) }, remember { mutableStateOf(0L) }/*, soundEnabled*/)
|
||||||
}
|
}
|
||||||
if (file?.fileStatus is CIFileStatus.RcvInvitation || file?.fileStatus is CIFileStatus.RcvAborted) {
|
if (file?.fileStatus is CIFileStatus.RcvInvitation) {
|
||||||
PlayButton(error = false, { showMenu.value = true }) { receiveFileIfValidSize(file, receiveFile) }
|
PlayButton(error = false, { showMenu.value = true }) { receiveFileIfValidSize(file, receiveFile) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -396,7 +396,6 @@ private fun loadingIndicator(file: CIFile?) {
|
|||||||
} else {
|
} else {
|
||||||
progressIndicator()
|
progressIndicator()
|
||||||
}
|
}
|
||||||
is CIFileStatus.RcvAborted -> fileIcon(painterResource(MR.images.ic_sync_problem), MR.strings.icon_descr_file)
|
|
||||||
is CIFileStatus.RcvCancelled -> fileIcon(painterResource(MR.images.ic_close), MR.strings.icon_descr_file)
|
is CIFileStatus.RcvCancelled -> fileIcon(painterResource(MR.images.ic_close), MR.strings.icon_descr_file)
|
||||||
is CIFileStatus.RcvError -> fileIcon(painterResource(MR.images.ic_close), MR.strings.icon_descr_file)
|
is CIFileStatus.RcvError -> fileIcon(painterResource(MR.images.ic_close), MR.strings.icon_descr_file)
|
||||||
is CIFileStatus.Invalid -> fileIcon(painterResource(MR.images.ic_question_mark), MR.strings.icon_descr_file)
|
is CIFileStatus.Invalid -> fileIcon(painterResource(MR.images.ic_question_mark), MR.strings.icon_descr_file)
|
||||||
|
|||||||
+2
-6
@@ -22,7 +22,6 @@ import chat.simplex.common.views.helpers.*
|
|||||||
import chat.simplex.common.model.*
|
import chat.simplex.common.model.*
|
||||||
import chat.simplex.common.platform.*
|
import chat.simplex.common.platform.*
|
||||||
import chat.simplex.res.MR
|
import chat.simplex.res.MR
|
||||||
import dev.icerock.moko.resources.ImageResource
|
|
||||||
import kotlinx.coroutines.flow.*
|
import kotlinx.coroutines.flow.*
|
||||||
|
|
||||||
// TODO refactor https://github.com/simplex-chat/simplex-chat/pull/1451#discussion_r1033429901
|
// TODO refactor https://github.com/simplex-chat/simplex-chat/pull/1451#discussion_r1033429901
|
||||||
@@ -221,8 +220,7 @@ private fun PlayPauseButton(
|
|||||||
error: Boolean,
|
error: Boolean,
|
||||||
play: () -> Unit,
|
play: () -> Unit,
|
||||||
pause: () -> Unit,
|
pause: () -> Unit,
|
||||||
longClick: () -> Unit,
|
longClick: () -> Unit
|
||||||
icon: ImageResource = MR.images.ic_play_arrow_filled,
|
|
||||||
) {
|
) {
|
||||||
val sentColor = CurrentColors.collectAsState().value.appColors.sentMessage
|
val sentColor = CurrentColors.collectAsState().value.appColors.sentMessage
|
||||||
val receivedColor = CurrentColors.collectAsState().value.appColors.receivedMessage
|
val receivedColor = CurrentColors.collectAsState().value.appColors.receivedMessage
|
||||||
@@ -243,7 +241,7 @@ private fun PlayPauseButton(
|
|||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
if (audioPlaying) painterResource(MR.images.ic_pause_filled) else painterResource(icon),
|
if (audioPlaying) painterResource(MR.images.ic_pause_filled) else painterResource(MR.images.ic_play_arrow_filled),
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
Modifier.size(36.dp),
|
Modifier.size(36.dp),
|
||||||
tint = if (error) WarningOrange else if (!enabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary
|
tint = if (error) WarningOrange else if (!enabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary
|
||||||
@@ -296,8 +294,6 @@ private fun VoiceMsgIndicator(
|
|||||||
) {
|
) {
|
||||||
ProgressIndicator()
|
ProgressIndicator()
|
||||||
}
|
}
|
||||||
} else if (file?.fileStatus is CIFileStatus.RcvAborted) {
|
|
||||||
PlayPauseButton(audioPlaying, sent, 0f, strokeWidth, strokeColor, true, error, { receiveFile(file.fileId) }, {}, longClick = longClick, icon = MR.images.ic_sync_problem)
|
|
||||||
} else {
|
} else {
|
||||||
PlayPauseButton(audioPlaying, sent, 0f, strokeWidth, strokeColor, false, false, {}, {}, longClick)
|
PlayPauseButton(audioPlaying, sent, 0f, strokeWidth, strokeColor, false, false, {}, {}, longClick)
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -241,7 +241,7 @@ fun FramedItemView(
|
|||||||
} else {
|
} else {
|
||||||
when (val mc = ci.content.msgContent) {
|
when (val mc = ci.content.msgContent) {
|
||||||
is MsgContent.MCImage -> {
|
is MsgContent.MCImage -> {
|
||||||
CIImageView(image = mc.image, file = ci.file, imageProvider ?: return@PriorityLayout, showMenu, receiveFile)
|
CIImageView(image = mc.image, file = ci.file, metaColor = metaColor, imageProvider ?: return@PriorityLayout, showMenu, receiveFile)
|
||||||
if (mc.text == "" && !ci.meta.isLive) {
|
if (mc.text == "" && !ci.meta.isLive) {
|
||||||
metaColor = Color.White
|
metaColor = Color.White
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
+5
-18
@@ -1,7 +1,6 @@
|
|||||||
package chat.simplex.common.views.usersettings
|
package chat.simplex.common.views.usersettings
|
||||||
|
|
||||||
import SectionBottomSpacer
|
import SectionBottomSpacer
|
||||||
import SectionCustomFooter
|
|
||||||
import SectionDividerSpaced
|
import SectionDividerSpaced
|
||||||
import SectionItemView
|
import SectionItemView
|
||||||
import SectionTextFooter
|
import SectionTextFooter
|
||||||
@@ -64,6 +63,10 @@ fun PrivacySettingsView(
|
|||||||
SectionDividerSpaced()
|
SectionDividerSpaced()
|
||||||
|
|
||||||
SectionView(stringResource(MR.strings.settings_section_title_chats)) {
|
SectionView(stringResource(MR.strings.settings_section_title_chats)) {
|
||||||
|
SettingsPreferenceItem(painterResource(MR.images.ic_lock), stringResource(MR.strings.encrypt_local_files), chatModel.controller.appPrefs.privacyEncryptLocalFiles, onChange = { enable ->
|
||||||
|
withBGApi { chatModel.controller.apiSetEncryptLocalFiles(enable) }
|
||||||
|
})
|
||||||
|
SettingsPreferenceItem(painterResource(MR.images.ic_image), stringResource(MR.strings.auto_accept_images), chatModel.controller.appPrefs.privacyAcceptImages)
|
||||||
SettingsPreferenceItem(painterResource(MR.images.ic_travel_explore), stringResource(MR.strings.send_link_previews), chatModel.controller.appPrefs.privacyLinkPreviews)
|
SettingsPreferenceItem(painterResource(MR.images.ic_travel_explore), stringResource(MR.strings.send_link_previews), chatModel.controller.appPrefs.privacyLinkPreviews)
|
||||||
SettingsPreferenceItem(
|
SettingsPreferenceItem(
|
||||||
painterResource(MR.images.ic_chat_bubble),
|
painterResource(MR.images.ic_chat_bubble),
|
||||||
@@ -88,22 +91,6 @@ fun PrivacySettingsView(
|
|||||||
chatModel.simplexLinkMode.value = it
|
chatModel.simplexLinkMode.value = it
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
SectionDividerSpaced()
|
|
||||||
|
|
||||||
SectionView(stringResource(MR.strings.settings_section_title_files)) {
|
|
||||||
SettingsPreferenceItem(painterResource(MR.images.ic_lock), stringResource(MR.strings.encrypt_local_files), chatModel.controller.appPrefs.privacyEncryptLocalFiles, onChange = { enable ->
|
|
||||||
withBGApi { chatModel.controller.apiSetEncryptLocalFiles(enable) }
|
|
||||||
})
|
|
||||||
SettingsPreferenceItem(painterResource(MR.images.ic_image), stringResource(MR.strings.auto_accept_images), chatModel.controller.appPrefs.privacyAcceptImages)
|
|
||||||
SettingsPreferenceItem(painterResource(MR.images.ic_security), stringResource(MR.strings.protect_ip_address), chatModel.controller.appPrefs.privacyAskToApproveRelays)
|
|
||||||
}
|
|
||||||
SectionCustomFooter {
|
|
||||||
if (chatModel.controller.appPrefs.privacyAskToApproveRelays.state.value) {
|
|
||||||
Text(stringResource(MR.strings.app_will_ask_to_confirm_unknown_file_servers))
|
|
||||||
} else {
|
|
||||||
Text(stringResource(MR.strings.without_tor_or_vpn_ip_address_will_be_visible_to_file_servers))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val currentUser = chatModel.currentUser.value
|
val currentUser = chatModel.currentUser.value
|
||||||
if (currentUser != null) {
|
if (currentUser != null) {
|
||||||
@@ -154,7 +141,7 @@ fun PrivacySettingsView(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!chatModel.desktopNoUserNoRemote) {
|
if (!chatModel.desktopNoUserNoRemote) {
|
||||||
SectionDividerSpaced(maxTopPadding = true)
|
SectionDividerSpaced()
|
||||||
DeliveryReceiptsSection(
|
DeliveryReceiptsSection(
|
||||||
currentUser = currentUser,
|
currentUser = currentUser,
|
||||||
setOrAskSendReceiptsContacts = { enable ->
|
setOrAskSendReceiptsContacts = { enable ->
|
||||||
|
|||||||
@@ -119,8 +119,6 @@
|
|||||||
<string name="error_joining_group">Error joining group</string>
|
<string name="error_joining_group">Error joining group</string>
|
||||||
<string name="cannot_receive_file">Cannot receive file</string>
|
<string name="cannot_receive_file">Cannot receive file</string>
|
||||||
<string name="sender_cancelled_file_transfer">Sender cancelled file transfer.</string>
|
<string name="sender_cancelled_file_transfer">Sender cancelled file transfer.</string>
|
||||||
<string name="file_not_approved_title">Unknown servers!</string>
|
|
||||||
<string name="file_not_approved_descr">Without Tor or VPN, your IP address will be visible to these XFTP relays:\n%1$s.</string>
|
|
||||||
<string name="error_receiving_file">Error receiving file</string>
|
<string name="error_receiving_file">Error receiving file</string>
|
||||||
<string name="error_creating_address">Error creating address</string>
|
<string name="error_creating_address">Error creating address</string>
|
||||||
<string name="contact_already_exists">Contact already exists</string>
|
<string name="contact_already_exists">Contact already exists</string>
|
||||||
@@ -994,9 +992,6 @@
|
|||||||
<string name="protect_app_screen">Protect app screen</string>
|
<string name="protect_app_screen">Protect app screen</string>
|
||||||
<string name="encrypt_local_files">Encrypt local files</string>
|
<string name="encrypt_local_files">Encrypt local files</string>
|
||||||
<string name="auto_accept_images">Auto-accept images</string>
|
<string name="auto_accept_images">Auto-accept images</string>
|
||||||
<string name="protect_ip_address">Protect IP address</string>
|
|
||||||
<string name="app_will_ask_to_confirm_unknown_file_servers">The app will ask to confirm downloads from unknown file servers (except .onion or when SOCKS proxy is enabled).</string>
|
|
||||||
<string name="without_tor_or_vpn_ip_address_will_be_visible_to_file_servers">Without Tor or VPN, your IP address will be visible to file servers.</string>
|
|
||||||
<string name="send_link_previews">Send link previews</string>
|
<string name="send_link_previews">Send link previews</string>
|
||||||
<string name="privacy_show_last_messages">Show last messages</string>
|
<string name="privacy_show_last_messages">Show last messages</string>
|
||||||
<string name="privacy_message_draft">Message draft</string>
|
<string name="privacy_message_draft">Message draft</string>
|
||||||
@@ -1061,7 +1056,6 @@
|
|||||||
<string name="settings_section_title_app">APP</string>
|
<string name="settings_section_title_app">APP</string>
|
||||||
<string name="settings_section_title_device">DEVICE</string>
|
<string name="settings_section_title_device">DEVICE</string>
|
||||||
<string name="settings_section_title_chats">CHATS</string>
|
<string name="settings_section_title_chats">CHATS</string>
|
||||||
<string name="settings_section_title_files">FILES</string>
|
|
||||||
<string name="settings_section_title_delivery_receipts">SEND DELIVERY RECEIPTS TO</string>
|
<string name="settings_section_title_delivery_receipts">SEND DELIVERY RECEIPTS TO</string>
|
||||||
<string name="settings_restart_app">Restart</string>
|
<string name="settings_restart_app">Restart</string>
|
||||||
<string name="settings_shutdown">Shutdown</string>
|
<string name="settings_shutdown">Shutdown</string>
|
||||||
|
|||||||
@@ -26,11 +26,11 @@ android.enableJetifier=true
|
|||||||
kotlin.mpp.androidSourceSetLayoutVersion=2
|
kotlin.mpp.androidSourceSetLayoutVersion=2
|
||||||
kotlin.jvm.target=11
|
kotlin.jvm.target=11
|
||||||
|
|
||||||
android.version_name=5.8-beta.2
|
android.version_name=5.8-beta.0
|
||||||
android.version_code=210
|
android.version_code=208
|
||||||
|
|
||||||
desktop.version_name=5.8-beta.2
|
desktop.version_name=5.8-beta.0
|
||||||
desktop.version_code=47
|
desktop.version_code=45
|
||||||
|
|
||||||
kotlin.version=1.9.23
|
kotlin.version=1.9.23
|
||||||
gradle.plugin.version=8.2.0
|
gradle.plugin.version=8.2.0
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ layout: layouts/article.html
|
|||||||
title: "SimpleX: Redefining Privacy by Making Hard Choices"
|
title: "SimpleX: Redefining Privacy by Making Hard Choices"
|
||||||
date: 2024-05-16
|
date: 2024-05-16
|
||||||
previewBody: blog_previews/20240516.html
|
previewBody: blog_previews/20240516.html
|
||||||
image: images/simplex-explained.png
|
image: images/simplex-explained.svg
|
||||||
imageWide: true
|
imageWide: true
|
||||||
permalink: "/blog/20240516-simplex-redefining-privacy-hard-choices.html"
|
permalink: "/blog/20240516-simplex-redefining-privacy-hard-choices.html"
|
||||||
---
|
---
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 65 KiB |
+1
-1
@@ -12,7 +12,7 @@ constraints: zip +disable-bzip2 +disable-zstd
|
|||||||
source-repository-package
|
source-repository-package
|
||||||
type: git
|
type: git
|
||||||
location: https://github.com/simplex-chat/simplexmq.git
|
location: https://github.com/simplex-chat/simplexmq.git
|
||||||
tag: e3f5d244c1a435593e33adc023bf1f920f379f8d
|
tag: 7d30eb6548e81df197931e755b8b6853774d622a
|
||||||
|
|
||||||
source-repository-package
|
source-repository-package
|
||||||
type: git
|
type: git
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
name: simplex-chat
|
name: simplex-chat
|
||||||
version: 5.8.0.2
|
version: 5.8.0.0
|
||||||
#synopsis:
|
#synopsis:
|
||||||
#description:
|
#description:
|
||||||
homepage: https://github.com/simplex-chat/simplex-chat#readme
|
homepage: https://github.com/simplex-chat/simplex-chat#readme
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"https://github.com/simplex-chat/simplexmq.git"."e3f5d244c1a435593e33adc023bf1f920f379f8d" = "1klin78kgvgzdvf64nahn3280m7hw5f8wzrca43cmyajm2qp3wfs";
|
"https://github.com/simplex-chat/simplexmq.git"."7d30eb6548e81df197931e755b8b6853774d622a" = "07fs1y6mamkiz6cxv94n2palismxc0yi5mjwb03jla6hfvqdrmxp";
|
||||||
"https://github.com/simplex-chat/hs-socks.git"."a30cc7a79a08d8108316094f8f2f82a0c5e1ac51" = "0yasvnr7g91k76mjkamvzab2kvlb1g5pspjyjn2fr6v83swjhj38";
|
"https://github.com/simplex-chat/hs-socks.git"."a30cc7a79a08d8108316094f8f2f82a0c5e1ac51" = "0yasvnr7g91k76mjkamvzab2kvlb1g5pspjyjn2fr6v83swjhj38";
|
||||||
"https://github.com/simplex-chat/direct-sqlcipher.git"."f814ee68b16a9447fbb467ccc8f29bdd3546bfd9" = "1ql13f4kfwkbaq7nygkxgw84213i0zm7c1a8hwvramayxl38dq5d";
|
"https://github.com/simplex-chat/direct-sqlcipher.git"."f814ee68b16a9447fbb467ccc8f29bdd3546bfd9" = "1ql13f4kfwkbaq7nygkxgw84213i0zm7c1a8hwvramayxl38dq5d";
|
||||||
"https://github.com/simplex-chat/sqlcipher-simple.git"."a46bd361a19376c5211f1058908fc0ae6bf42446" = "1z0r78d8f0812kxbgsm735qf6xx8lvaz27k1a0b4a2m0sshpd5gl";
|
"https://github.com/simplex-chat/sqlcipher-simple.git"."a46bd361a19376c5211f1058908fc0ae6bf42446" = "1z0r78d8f0812kxbgsm735qf6xx8lvaz27k1a0b4a2m0sshpd5gl";
|
||||||
|
|||||||
+1
-2
@@ -5,7 +5,7 @@ cabal-version: 1.12
|
|||||||
-- see: https://github.com/sol/hpack
|
-- see: https://github.com/sol/hpack
|
||||||
|
|
||||||
name: simplex-chat
|
name: simplex-chat
|
||||||
version: 5.8.0.2
|
version: 5.8.0.0
|
||||||
category: Web, System, Services, Cryptography
|
category: Web, System, Services, Cryptography
|
||||||
homepage: https://github.com/simplex-chat/simplex-chat#readme
|
homepage: https://github.com/simplex-chat/simplex-chat#readme
|
||||||
author: simplex.chat
|
author: simplex.chat
|
||||||
@@ -144,7 +144,6 @@ library
|
|||||||
Simplex.Chat.Migrations.M20240430_ui_theme
|
Simplex.Chat.Migrations.M20240430_ui_theme
|
||||||
Simplex.Chat.Migrations.M20240501_chat_deleted
|
Simplex.Chat.Migrations.M20240501_chat_deleted
|
||||||
Simplex.Chat.Migrations.M20240510_chat_items_via_proxy
|
Simplex.Chat.Migrations.M20240510_chat_items_via_proxy
|
||||||
Simplex.Chat.Migrations.M20240515_rcv_files_user_approved_relays
|
|
||||||
Simplex.Chat.Mobile
|
Simplex.Chat.Mobile
|
||||||
Simplex.Chat.Mobile.File
|
Simplex.Chat.Mobile.File
|
||||||
Simplex.Chat.Mobile.Shared
|
Simplex.Chat.Mobile.Shared
|
||||||
|
|||||||
+35
-92
@@ -47,7 +47,6 @@ import Data.Map.Strict (Map)
|
|||||||
import qualified Data.Map.Strict as M
|
import qualified Data.Map.Strict as M
|
||||||
import Data.Maybe (catMaybes, fromMaybe, isJust, isNothing, listToMaybe, mapMaybe, maybeToList)
|
import Data.Maybe (catMaybes, fromMaybe, isJust, isNothing, listToMaybe, mapMaybe, maybeToList)
|
||||||
import Data.Ord (Down (..))
|
import Data.Ord (Down (..))
|
||||||
import qualified Data.Set as S
|
|
||||||
import Data.Text (Text)
|
import Data.Text (Text)
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
import Data.Text.Encoding (decodeLatin1, encodeUtf8)
|
import Data.Text.Encoding (decodeLatin1, encodeUtf8)
|
||||||
@@ -91,9 +90,8 @@ import Simplex.FileTransfer.Client.Presets (defaultXFTPServers)
|
|||||||
import Simplex.FileTransfer.Description (FileDescriptionURI (..), ValidFileDescription)
|
import Simplex.FileTransfer.Description (FileDescriptionURI (..), ValidFileDescription)
|
||||||
import qualified Simplex.FileTransfer.Description as FD
|
import qualified Simplex.FileTransfer.Description as FD
|
||||||
import Simplex.FileTransfer.Protocol (FileParty (..), FilePartyI)
|
import Simplex.FileTransfer.Protocol (FileParty (..), FilePartyI)
|
||||||
import qualified Simplex.FileTransfer.Transport as XFTP
|
|
||||||
import Simplex.Messaging.Agent as Agent
|
import Simplex.Messaging.Agent as Agent
|
||||||
import Simplex.Messaging.Agent.Client (AgentStatsKey (..), SubInfo (..), agentClientStore, getAgentWorkersDetails, getAgentWorkersSummary, ipAddressProtected, temporaryAgentError, withLockMap)
|
import Simplex.Messaging.Agent.Client (AgentStatsKey (..), agentClientStore, getAgentWorkersDetails, getAgentWorkersSummary, temporaryAgentError, withLockMap)
|
||||||
import Simplex.Messaging.Agent.Env.SQLite (AgentConfig (..), InitialAgentServers (..), createAgentStore, defaultAgentConfig)
|
import Simplex.Messaging.Agent.Env.SQLite (AgentConfig (..), InitialAgentServers (..), createAgentStore, defaultAgentConfig)
|
||||||
import Simplex.Messaging.Agent.Lock (withLock)
|
import Simplex.Messaging.Agent.Lock (withLock)
|
||||||
import Simplex.Messaging.Agent.Protocol
|
import Simplex.Messaging.Agent.Protocol
|
||||||
@@ -111,7 +109,7 @@ import qualified Simplex.Messaging.Crypto.Ratchet as CR
|
|||||||
import Simplex.Messaging.Encoding
|
import Simplex.Messaging.Encoding
|
||||||
import Simplex.Messaging.Encoding.String
|
import Simplex.Messaging.Encoding.String
|
||||||
import Simplex.Messaging.Parsers (base64P)
|
import Simplex.Messaging.Parsers (base64P)
|
||||||
import Simplex.Messaging.Protocol (AProtoServerWithAuth (..), AProtocolType (..), EntityId, ErrorType (..), MsgBody, MsgFlags (..), NtfServer, ProtoServerWithAuth (..), ProtocolTypeI, SProtocolType (..), SubscriptionMode (..), UserProtocol, XFTPServer, userProtocol)
|
import Simplex.Messaging.Protocol (AProtoServerWithAuth (..), AProtocolType (..), EntityId, ErrorType (..), MsgBody, MsgFlags (..), NtfServer, ProtoServerWithAuth, ProtocolTypeI, SProtocolType (..), SubscriptionMode (..), UserProtocol, userProtocol)
|
||||||
import qualified Simplex.Messaging.Protocol as SMP
|
import qualified Simplex.Messaging.Protocol as SMP
|
||||||
import Simplex.Messaging.ServiceScheme (ServiceScheme (..))
|
import Simplex.Messaging.ServiceScheme (ServiceScheme (..))
|
||||||
import qualified Simplex.Messaging.TMap as TM
|
import qualified Simplex.Messaging.TMap as TM
|
||||||
@@ -429,7 +427,7 @@ startReceiveUserFiles user = do
|
|||||||
filesToReceive <- withStore' (`getRcvFilesToReceive` user)
|
filesToReceive <- withStore' (`getRcvFilesToReceive` user)
|
||||||
forM_ filesToReceive $ \ft ->
|
forM_ filesToReceive $ \ft ->
|
||||||
flip catchChatError (toView . CRChatError (Just user)) $
|
flip catchChatError (toView . CRChatError (Just user)) $
|
||||||
toView =<< receiveFile' user ft False Nothing Nothing
|
toView =<< receiveFile' user ft Nothing Nothing
|
||||||
|
|
||||||
restoreCalls :: CM' ()
|
restoreCalls :: CM' ()
|
||||||
restoreCalls = do
|
restoreCalls = do
|
||||||
@@ -2057,17 +2055,17 @@ processChatCommand' vr = \case
|
|||||||
ForwardFile chatName fileId -> forwardFile chatName fileId SendFile
|
ForwardFile chatName fileId -> forwardFile chatName fileId SendFile
|
||||||
ForwardImage chatName fileId -> forwardFile chatName fileId SendImage
|
ForwardImage chatName fileId -> forwardFile chatName fileId SendImage
|
||||||
SendFileDescription _chatName _f -> pure $ chatCmdError Nothing "TODO"
|
SendFileDescription _chatName _f -> pure $ chatCmdError Nothing "TODO"
|
||||||
ReceiveFile fileId userApprovedRelays encrypted_ rcvInline_ filePath_ -> withUser $ \_ ->
|
ReceiveFile fileId encrypted_ rcvInline_ filePath_ -> withUser $ \_ ->
|
||||||
withFileLock "receiveFile" fileId . procCmd $ do
|
withFileLock "receiveFile" fileId . procCmd $ do
|
||||||
(user, ft@RcvFileTransfer {fileStatus}) <- withStore (`getRcvFileTransferById` fileId)
|
(user, ft@RcvFileTransfer {fileStatus}) <- withStore (`getRcvFileTransferById` fileId)
|
||||||
encrypt <- (`fromMaybe` encrypted_) <$> chatReadVar encryptLocalFiles
|
encrypt <- (`fromMaybe` encrypted_) <$> chatReadVar encryptLocalFiles
|
||||||
ft' <- (if encrypt && fileStatus == RFSNew then setFileToEncrypt else pure) ft
|
ft' <- (if encrypt && fileStatus == RFSNew then setFileToEncrypt else pure) ft
|
||||||
receiveFile' user ft' userApprovedRelays rcvInline_ filePath_
|
receiveFile' user ft' rcvInline_ filePath_
|
||||||
SetFileToReceive fileId userApprovedRelays encrypted_ -> withUser $ \_ -> do
|
SetFileToReceive fileId encrypted_ -> withUser $ \_ -> do
|
||||||
withFileLock "setFileToReceive" fileId . procCmd $ do
|
withFileLock "setFileToReceive" fileId . procCmd $ do
|
||||||
encrypt <- (`fromMaybe` encrypted_) <$> chatReadVar encryptLocalFiles
|
encrypt <- (`fromMaybe` encrypted_) <$> chatReadVar encryptLocalFiles
|
||||||
cfArgs <- if encrypt then Just <$> (atomically . CF.randomArgs =<< asks random) else pure Nothing
|
cfArgs <- if encrypt then Just <$> (atomically . CF.randomArgs =<< asks random) else pure Nothing
|
||||||
withStore' $ \db -> setRcvFileToReceive db fileId userApprovedRelays cfArgs
|
withStore' $ \db -> setRcvFileToReceive db fileId cfArgs
|
||||||
ok_
|
ok_
|
||||||
CancelFile fileId -> withUser $ \user@User {userId} ->
|
CancelFile fileId -> withUser $ \user@User {userId} ->
|
||||||
withFileLock "cancelFile" fileId . procCmd $
|
withFileLock "cancelFile" fileId . procCmd $
|
||||||
@@ -2107,8 +2105,13 @@ processChatCommand' vr = \case
|
|||||||
liftIO $ removeFile fsFilePath `catchAll_` pure ()
|
liftIO $ removeFile fsFilePath `catchAll_` pure ()
|
||||||
lift . forM_ agentRcvFileId $ \(AgentRcvFileId aFileId) ->
|
lift . forM_ agentRcvFileId $ \(AgentRcvFileId aFileId) ->
|
||||||
withAgent' (`xftpDeleteRcvFile` aFileId)
|
withAgent' (`xftpDeleteRcvFile` aFileId)
|
||||||
aci_ <- resetRcvCIFileStatus user fileId CIFSRcvInvitation
|
ci <- withStore $ \db -> do
|
||||||
pure $ CRRcvFileCancelled user aci_ ftr
|
liftIO $ do
|
||||||
|
updateCIFileStatus db user fileId CIFSRcvInvitation
|
||||||
|
updateRcvFileStatus db fileId FSNew
|
||||||
|
updateRcvFileAgentId db fileId Nothing
|
||||||
|
lookupChatItemByFileId db vr user fileId
|
||||||
|
pure $ CRRcvFileCancelled user ci ftr
|
||||||
FileStatus fileId -> withUser $ \user -> do
|
FileStatus fileId -> withUser $ \user -> do
|
||||||
withStore (\db -> lookupChatItemByFileId db vr user fileId) >>= \case
|
withStore (\db -> lookupChatItemByFileId db vr user fileId) >>= \case
|
||||||
Nothing -> do
|
Nothing -> do
|
||||||
@@ -2222,20 +2225,9 @@ processChatCommand' vr = \case
|
|||||||
counts <- map (first decodeLatin1) <$> withAgent' getMsgCounts
|
counts <- map (first decodeLatin1) <$> withAgent' getMsgCounts
|
||||||
let allMsgs = foldl' (\(ts, ds) (_, (t, d)) -> (ts + t, ds + d)) (0, 0) counts
|
let allMsgs = foldl' (\(ts, ds) (_, (t, d)) -> (ts + t, ds + d)) (0, 0) counts
|
||||||
pure CRAgentMsgCounts {msgCounts = ("all", allMsgs) : sortOn (Down . snd) (filter (\(_, (_, d)) -> d /= 0) counts)}
|
pure CRAgentMsgCounts {msgCounts = ("all", allMsgs) : sortOn (Down . snd) (filter (\(_, (_, d)) -> d /= 0) counts)}
|
||||||
GetAgentSubs -> lift $ summary <$> withAgent' getAgentSubscriptions
|
GetAgentUserNetworkState ->
|
||||||
where
|
CRAgentUserNetworkState <$> (readTVarIO =<< asks (userNetworkState . smpAgent))
|
||||||
summary SubscriptionsInfo {activeSubscriptions, pendingSubscriptions, removedSubscriptions} =
|
GetAgentSubs diff -> withUser $ \User {userId} -> lift $ CRAgentSubs <$> withAgent' (\a -> getAgentSubscriptions a diff (Just userId))
|
||||||
CRAgentSubs
|
|
||||||
{ activeSubs = foldl' countSubs M.empty activeSubscriptions,
|
|
||||||
pendingSubs = foldl' countSubs M.empty pendingSubscriptions,
|
|
||||||
removedSubs = foldl' accSubErrors M.empty removedSubscriptions
|
|
||||||
}
|
|
||||||
where
|
|
||||||
countSubs m SubInfo {server} = M.alter (Just . maybe 1 (+ 1)) server m
|
|
||||||
accSubErrors m = \case
|
|
||||||
SubInfo {server, subError = Just e} -> M.alter (Just . maybe [e] (e :)) server m
|
|
||||||
_ -> m
|
|
||||||
GetAgentSubsDetails -> lift $ CRAgentSubsDetails <$> withAgent' getAgentSubscriptions
|
|
||||||
-- CustomChatCommand is unsupported, it can be processed in preCmdHook
|
-- CustomChatCommand is unsupported, it can be processed in preCmdHook
|
||||||
-- in a modified CLI app or core - the hook should return Either ChatResponse ChatCommand
|
-- in a modified CLI app or core - the hook should return Either ChatResponse ChatCommand
|
||||||
CustomChatCommand _cmd -> withUser $ \user -> pure $ chatCmdError (Just user) "not supported"
|
CustomChatCommand _cmd -> withUser $ \user -> pure $ chatCmdError (Just user) "not supported"
|
||||||
@@ -3049,9 +3041,9 @@ setFileToEncrypt ft@RcvFileTransfer {fileId} = do
|
|||||||
withStore' $ \db -> setFileCryptoArgs db fileId cfArgs
|
withStore' $ \db -> setFileCryptoArgs db fileId cfArgs
|
||||||
pure (ft :: RcvFileTransfer) {cryptoArgs = Just cfArgs}
|
pure (ft :: RcvFileTransfer) {cryptoArgs = Just cfArgs}
|
||||||
|
|
||||||
receiveFile' :: User -> RcvFileTransfer -> Bool -> Maybe Bool -> Maybe FilePath -> CM ChatResponse
|
receiveFile' :: User -> RcvFileTransfer -> Maybe Bool -> Maybe FilePath -> CM ChatResponse
|
||||||
receiveFile' user ft userApprovedRelays rcvInline_ filePath_ = do
|
receiveFile' user ft rcvInline_ filePath_ = do
|
||||||
(CRRcvFileAccepted user <$> acceptFileReceive user ft userApprovedRelays rcvInline_ filePath_) `catchChatError` processError
|
(CRRcvFileAccepted user <$> acceptFileReceive user ft rcvInline_ filePath_) `catchChatError` processError
|
||||||
where
|
where
|
||||||
processError = \case
|
processError = \case
|
||||||
-- TODO AChatItem in Cancelled events
|
-- TODO AChatItem in Cancelled events
|
||||||
@@ -3059,8 +3051,8 @@ receiveFile' user ft userApprovedRelays rcvInline_ filePath_ = do
|
|||||||
ChatErrorAgent (CONN DUPLICATE) _ -> pure $ CRRcvFileAcceptedSndCancelled user ft
|
ChatErrorAgent (CONN DUPLICATE) _ -> pure $ CRRcvFileAcceptedSndCancelled user ft
|
||||||
e -> throwError e
|
e -> throwError e
|
||||||
|
|
||||||
acceptFileReceive :: User -> RcvFileTransfer -> Bool -> Maybe Bool -> Maybe FilePath -> CM AChatItem
|
acceptFileReceive :: User -> RcvFileTransfer -> Maybe Bool -> Maybe FilePath -> CM AChatItem
|
||||||
acceptFileReceive user@User {userId} RcvFileTransfer {fileId, xftpRcvFile, fileInvitation = FileInvitation {fileName = fName, fileConnReq, fileInline, fileSize}, fileStatus, grpMemberId, cryptoArgs} userApprovedRelays rcvInline_ filePath_ = do
|
acceptFileReceive user@User {userId} RcvFileTransfer {fileId, xftpRcvFile, fileInvitation = FileInvitation {fileName = fName, fileConnReq, fileInline, fileSize}, fileStatus, grpMemberId, cryptoArgs} rcvInline_ filePath_ = do
|
||||||
unless (fileStatus == RFSNew) $ case fileStatus of
|
unless (fileStatus == RFSNew) $ case fileStatus of
|
||||||
RFSCancelled _ -> throwChatError $ CEFileCancelled fName
|
RFSCancelled _ -> throwChatError $ CEFileCancelled fName
|
||||||
_ -> throwChatError $ CEFileAlreadyReceiving fName
|
_ -> throwChatError $ CEFileAlreadyReceiving fName
|
||||||
@@ -3074,16 +3066,15 @@ acceptFileReceive user@User {userId} RcvFileTransfer {fileId, xftpRcvFile, fileI
|
|||||||
filePath <- getRcvFilePath fileId filePath_ fName True
|
filePath <- getRcvFilePath fileId filePath_ fName True
|
||||||
withStore $ \db -> acceptRcvFileTransfer db vr user fileId connIds ConnJoined filePath subMode
|
withStore $ \db -> acceptRcvFileTransfer db vr user fileId connIds ConnJoined filePath subMode
|
||||||
-- XFTP
|
-- XFTP
|
||||||
(Just XFTPRcvFile {userApprovedRelays = approvedBeforeReady}, _) -> do
|
(Just XFTPRcvFile {}, _) -> do
|
||||||
let userApproved = approvedBeforeReady || userApprovedRelays
|
|
||||||
filePath <- getRcvFilePath fileId filePath_ fName False
|
filePath <- getRcvFilePath fileId filePath_ fName False
|
||||||
(ci, rfd) <- withStore $ \db -> do
|
(ci, rfd) <- withStore $ \db -> do
|
||||||
-- marking file as accepted and reading description in the same transaction
|
-- marking file as accepted and reading description in the same transaction
|
||||||
-- to prevent race condition with appending description
|
-- to prevent race condition with appending description
|
||||||
ci <- xftpAcceptRcvFT db vr user fileId filePath userApproved
|
ci <- xftpAcceptRcvFT db vr user fileId filePath
|
||||||
rfd <- getRcvFileDescrByRcvFileId db fileId
|
rfd <- getRcvFileDescrByRcvFileId db fileId
|
||||||
pure (ci, rfd)
|
pure (ci, rfd)
|
||||||
receiveViaCompleteFD user fileId rfd userApproved cryptoArgs
|
receiveViaCompleteFD user fileId rfd cryptoArgs
|
||||||
pure ci
|
pure ci
|
||||||
-- group & direct file protocol
|
-- group & direct file protocol
|
||||||
_ -> do
|
_ -> do
|
||||||
@@ -3128,61 +3119,18 @@ acceptFileReceive user@User {userId} RcvFileTransfer {fileId, xftpRcvFile, fileI
|
|||||||
|| (rcvInline_ == Just True && fileSize <= fileChunkSize * offerChunks)
|
|| (rcvInline_ == Just True && fileSize <= fileChunkSize * offerChunks)
|
||||||
)
|
)
|
||||||
|
|
||||||
receiveViaCompleteFD :: User -> FileTransferId -> RcvFileDescr -> Bool -> Maybe CryptoFileArgs -> CM ()
|
receiveViaCompleteFD :: User -> FileTransferId -> RcvFileDescr -> Maybe CryptoFileArgs -> CM ()
|
||||||
receiveViaCompleteFD user fileId RcvFileDescr {fileDescrText, fileDescrComplete} userApprovedRelays cfArgs =
|
receiveViaCompleteFD user fileId RcvFileDescr {fileDescrText, fileDescrComplete} cfArgs =
|
||||||
when fileDescrComplete $ do
|
when fileDescrComplete $ do
|
||||||
rd <- parseFileDescription fileDescrText
|
rd <- parseFileDescription fileDescrText
|
||||||
if userApprovedRelays
|
aFileId <- withAgent $ \a -> xftpReceiveFile a (aUserId user) rd cfArgs
|
||||||
then receive' rd True
|
|
||||||
else do
|
|
||||||
let srvs = fileServers rd
|
|
||||||
unknownSrvs <- getUnknownSrvs srvs
|
|
||||||
let approved = null unknownSrvs
|
|
||||||
ifM
|
|
||||||
((approved ||) <$> ipProtectedForSrvs srvs)
|
|
||||||
(receive' rd approved)
|
|
||||||
(relaysNotApproved unknownSrvs)
|
|
||||||
where
|
|
||||||
receive' :: ValidFileDescription 'FRecipient -> Bool -> CM ()
|
|
||||||
receive' rd approved = do
|
|
||||||
aFileId <- withAgent $ \a -> xftpReceiveFile a (aUserId user) rd cfArgs approved
|
|
||||||
startReceivingFile user fileId
|
startReceivingFile user fileId
|
||||||
withStore' $ \db -> updateRcvFileAgentId db fileId (Just $ AgentRcvFileId aFileId)
|
withStore' $ \db -> updateRcvFileAgentId db fileId (Just $ AgentRcvFileId aFileId)
|
||||||
fileServers :: ValidFileDescription 'FRecipient -> [XFTPServer]
|
|
||||||
fileServers (FD.ValidFileDescription FD.FileDescription {chunks}) =
|
|
||||||
S.toList $ S.fromList $ concatMap (\FD.FileChunk {replicas} -> map (\FD.FileChunkReplica {server} -> server) replicas) chunks
|
|
||||||
getUnknownSrvs :: [XFTPServer] -> CM [XFTPServer]
|
|
||||||
getUnknownSrvs srvs = do
|
|
||||||
ChatConfig {defaultServers = DefaultAgentServers {xftp = defXftp}} <- asks config
|
|
||||||
storedSrvs <- map (\ServerCfg {server} -> protoServer server) <$> withStore' (`getProtocolServers` user)
|
|
||||||
let defXftp' = L.map protoServer defXftp
|
|
||||||
knownSrvs = fromMaybe defXftp' $ nonEmpty storedSrvs
|
|
||||||
pure $ filter (`notElem` knownSrvs) srvs
|
|
||||||
ipProtectedForSrvs :: [XFTPServer] -> CM Bool
|
|
||||||
ipProtectedForSrvs srvs = do
|
|
||||||
netCfg <- lift $ withAgent' getNetworkConfig
|
|
||||||
pure $ all (ipAddressProtected netCfg) srvs
|
|
||||||
relaysNotApproved :: [XFTPServer] -> CM ()
|
|
||||||
relaysNotApproved unknownSrvs = do
|
|
||||||
aci_ <- resetRcvCIFileStatus user fileId CIFSRcvInvitation
|
|
||||||
forM_ aci_ $ \aci -> toView $ CRChatItemUpdated user aci
|
|
||||||
throwChatError $ CEFileNotApproved fileId unknownSrvs
|
|
||||||
|
|
||||||
resetRcvCIFileStatus :: User -> FileTransferId -> CIFileStatus 'MDRcv -> CM (Maybe AChatItem)
|
|
||||||
resetRcvCIFileStatus user fileId ciFileStatus = do
|
|
||||||
vr <- chatVersionRange
|
|
||||||
withStore $ \db -> do
|
|
||||||
liftIO $ do
|
|
||||||
updateCIFileStatus db user fileId ciFileStatus
|
|
||||||
updateRcvFileStatus db fileId FSNew
|
|
||||||
updateRcvFileAgentId db fileId Nothing
|
|
||||||
lookupChatItemByFileId db vr user fileId
|
|
||||||
|
|
||||||
receiveViaURI :: User -> FileDescriptionURI -> CryptoFile -> CM RcvFileTransfer
|
receiveViaURI :: User -> FileDescriptionURI -> CryptoFile -> CM RcvFileTransfer
|
||||||
receiveViaURI user@User {userId} FileDescriptionURI {description} cf@CryptoFile {cryptoArgs} = do
|
receiveViaURI user@User {userId} FileDescriptionURI {description} cf@CryptoFile {cryptoArgs} = do
|
||||||
fileId <- withStore $ \db -> createRcvStandaloneFileTransfer db userId cf fileSize chunkSize
|
fileId <- withStore $ \db -> createRcvStandaloneFileTransfer db userId cf fileSize chunkSize
|
||||||
-- currently the only use case is user migrating via their configured servers, so we pass approvedRelays = True
|
aFileId <- withAgent $ \a -> xftpReceiveFile a (aUserId user) description cryptoArgs
|
||||||
aFileId <- withAgent $ \a -> xftpReceiveFile a (aUserId user) description cryptoArgs True
|
|
||||||
withStore $ \db -> do
|
withStore $ \db -> do
|
||||||
liftIO $ do
|
liftIO $ do
|
||||||
updateRcvFileStatus db fileId FSConnected
|
updateRcvFileStatus db fileId FSConnected
|
||||||
@@ -3852,10 +3800,6 @@ processAgentMsgRcvFile _corrId aFileId msg = do
|
|||||||
RFERR e
|
RFERR e
|
||||||
| temporaryAgentError e ->
|
| temporaryAgentError e ->
|
||||||
throwChatError $ CEXFTPRcvFile fileId (AgentRcvFileId aFileId) e
|
throwChatError $ CEXFTPRcvFile fileId (AgentRcvFileId aFileId) e
|
||||||
| e == XFTP "" XFTP.NOT_APPROVED -> do
|
|
||||||
aci_ <- resetRcvCIFileStatus user fileId CIFSRcvAborted
|
|
||||||
agentXFTPDeleteRcvFile aFileId fileId
|
|
||||||
forM_ aci_ $ \aci -> toView $ CRChatItemUpdated user aci
|
|
||||||
| otherwise -> do
|
| otherwise -> do
|
||||||
ci <- withStore $ \db -> do
|
ci <- withStore $ \db -> do
|
||||||
liftIO $ updateFileCancelled db user fileId CIFSRcvError
|
liftIO $ updateFileCancelled db user fileId CIFSRcvError
|
||||||
@@ -4907,9 +4851,8 @@ processAgentMessageConn vr user@User {userId} corrId agentConnId agentMessage =
|
|||||||
|
|
||||||
autoAcceptFile :: Maybe (RcvFileTransfer, CIFile 'MDRcv) -> CM ()
|
autoAcceptFile :: Maybe (RcvFileTransfer, CIFile 'MDRcv) -> CM ()
|
||||||
autoAcceptFile = mapM_ $ \(ft, CIFile {fileSize}) -> do
|
autoAcceptFile = mapM_ $ \(ft, CIFile {fileSize}) -> do
|
||||||
-- ! autoAcceptFileSize is only used in tests
|
|
||||||
ChatConfig {autoAcceptFileSize = sz} <- asks config
|
ChatConfig {autoAcceptFileSize = sz} <- asks config
|
||||||
when (sz > fileSize) $ receiveFile' user ft False Nothing Nothing >>= toView
|
when (sz > fileSize) $ receiveFile' user ft Nothing Nothing >>= toView
|
||||||
|
|
||||||
messageFileDescription :: Contact -> SharedMsgId -> FileDescr -> CM ()
|
messageFileDescription :: Contact -> SharedMsgId -> FileDescr -> CM ()
|
||||||
messageFileDescription ct@Contact {contactId} sharedMsgId fileDescr = do
|
messageFileDescription ct@Contact {contactId} sharedMsgId fileDescr = do
|
||||||
@@ -4935,7 +4878,7 @@ processAgentMessageConn vr user@User {userId} corrId agentConnId agentMessage =
|
|||||||
ci <- withStore $ \db -> getAChatItemBySharedMsgId db user cd sharedMsgId
|
ci <- withStore $ \db -> getAChatItemBySharedMsgId db user cd sharedMsgId
|
||||||
toView $ CRRcvFileDescrReady user ci ft' rfd
|
toView $ CRRcvFileDescrReady user ci ft' rfd
|
||||||
case (fileStatus, xftpRcvFile) of
|
case (fileStatus, xftpRcvFile) of
|
||||||
(RFSAccepted _, Just XFTPRcvFile {userApprovedRelays}) -> receiveViaCompleteFD user fileId rfd userApprovedRelays cryptoArgs
|
(RFSAccepted _, Just XFTPRcvFile {}) -> receiveViaCompleteFD user fileId rfd cryptoArgs
|
||||||
_ -> pure ()
|
_ -> pure ()
|
||||||
|
|
||||||
processFileInvitation :: Maybe FileInvitation -> MsgContent -> (DB.Connection -> FileInvitation -> Maybe InlineFileMode -> Integer -> ExceptT StoreError IO RcvFileTransfer) -> CM (Maybe (RcvFileTransfer, CIFile 'MDRcv))
|
processFileInvitation :: Maybe FileInvitation -> MsgContent -> (DB.Connection -> FileInvitation -> Maybe InlineFileMode -> Integer -> ExceptT StoreError IO RcvFileTransfer) -> CM (Maybe (RcvFileTransfer, CIFile 'MDRcv))
|
||||||
@@ -7361,8 +7304,8 @@ chatCommandP =
|
|||||||
("/fforward " <|> "/ff ") *> (ForwardFile <$> chatNameP' <* A.space <*> A.decimal),
|
("/fforward " <|> "/ff ") *> (ForwardFile <$> chatNameP' <* A.space <*> A.decimal),
|
||||||
("/image_forward " <|> "/imgf ") *> (ForwardImage <$> chatNameP' <* A.space <*> A.decimal),
|
("/image_forward " <|> "/imgf ") *> (ForwardImage <$> chatNameP' <* A.space <*> A.decimal),
|
||||||
("/fdescription " <|> "/fd") *> (SendFileDescription <$> chatNameP' <* A.space <*> filePath),
|
("/fdescription " <|> "/fd") *> (SendFileDescription <$> chatNameP' <* A.space <*> filePath),
|
||||||
("/freceive " <|> "/fr ") *> (ReceiveFile <$> A.decimal <*> (" approved_relays=" *> onOffP <|> pure False) <*> optional (" encrypt=" *> onOffP) <*> optional (" inline=" *> onOffP) <*> optional (A.space *> filePath)),
|
("/freceive " <|> "/fr ") *> (ReceiveFile <$> A.decimal <*> optional (" encrypt=" *> onOffP) <*> optional (" inline=" *> onOffP) <*> optional (A.space *> filePath)),
|
||||||
"/_set_file_to_receive " *> (SetFileToReceive <$> A.decimal <*> (" approved_relays=" *> onOffP <|> pure False) <*> optional (" encrypt=" *> onOffP)),
|
"/_set_file_to_receive " *> (SetFileToReceive <$> A.decimal <*> optional (" encrypt=" *> onOffP)),
|
||||||
("/fcancel " <|> "/fc ") *> (CancelFile <$> A.decimal),
|
("/fcancel " <|> "/fc ") *> (CancelFile <$> A.decimal),
|
||||||
("/fstatus " <|> "/fs ") *> (FileStatus <$> A.decimal),
|
("/fstatus " <|> "/fs ") *> (FileStatus <$> A.decimal),
|
||||||
"/_connect contact " *> (APIConnectContactViaAddress <$> A.decimal <*> incognitoOnOffP <* A.space <*> A.decimal),
|
"/_connect contact " *> (APIConnectContactViaAddress <$> A.decimal <*> incognitoOnOffP <* A.space <*> A.decimal),
|
||||||
@@ -7427,11 +7370,11 @@ chatCommandP =
|
|||||||
"/debug event " *> (DebugEvent <$> jsonP),
|
"/debug event " *> (DebugEvent <$> jsonP),
|
||||||
"/get stats" $> GetAgentStats,
|
"/get stats" $> GetAgentStats,
|
||||||
"/reset stats" $> ResetAgentStats,
|
"/reset stats" $> ResetAgentStats,
|
||||||
"/get subs" $> GetAgentSubs,
|
"/get subs" *> (GetAgentSubs <$> (" diff" $> True <|> pure False)),
|
||||||
"/get subs details" $> GetAgentSubsDetails,
|
|
||||||
"/get workers" $> GetAgentWorkers,
|
"/get workers" $> GetAgentWorkers,
|
||||||
"/get workers details" $> GetAgentWorkersDetails,
|
"/get workers details" $> GetAgentWorkersDetails,
|
||||||
"/get msgs" $> GetAgentMsgCounts,
|
"/get msgs" $> GetAgentMsgCounts,
|
||||||
|
"/debug net" $> GetAgentUserNetworkState,
|
||||||
"//" *> (CustomChatCommand <$> A.takeByteString)
|
"//" *> (CustomChatCommand <$> A.takeByteString)
|
||||||
]
|
]
|
||||||
where
|
where
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ data AppSettings = AppSettings
|
|||||||
{ appPlatform :: Maybe AppPlatform,
|
{ appPlatform :: Maybe AppPlatform,
|
||||||
networkConfig :: Maybe NetworkConfig,
|
networkConfig :: Maybe NetworkConfig,
|
||||||
privacyEncryptLocalFiles :: Maybe Bool,
|
privacyEncryptLocalFiles :: Maybe Bool,
|
||||||
privacyAskToApproveRelays :: Maybe Bool,
|
|
||||||
privacyAcceptImages :: Maybe Bool,
|
privacyAcceptImages :: Maybe Bool,
|
||||||
privacyLinkPreviews :: Maybe Bool,
|
privacyLinkPreviews :: Maybe Bool,
|
||||||
privacyShowChatPreviews :: Maybe Bool,
|
privacyShowChatPreviews :: Maybe Bool,
|
||||||
@@ -62,7 +61,6 @@ defaultAppSettings =
|
|||||||
{ appPlatform = Nothing,
|
{ appPlatform = Nothing,
|
||||||
networkConfig = Just defaultNetworkConfig,
|
networkConfig = Just defaultNetworkConfig,
|
||||||
privacyEncryptLocalFiles = Just True,
|
privacyEncryptLocalFiles = Just True,
|
||||||
privacyAskToApproveRelays = Just True,
|
|
||||||
privacyAcceptImages = Just True,
|
privacyAcceptImages = Just True,
|
||||||
privacyLinkPreviews = Just True,
|
privacyLinkPreviews = Just True,
|
||||||
privacyShowChatPreviews = Just True,
|
privacyShowChatPreviews = Just True,
|
||||||
@@ -94,7 +92,6 @@ defaultParseAppSettings =
|
|||||||
{ appPlatform = Nothing,
|
{ appPlatform = Nothing,
|
||||||
networkConfig = Nothing,
|
networkConfig = Nothing,
|
||||||
privacyEncryptLocalFiles = Nothing,
|
privacyEncryptLocalFiles = Nothing,
|
||||||
privacyAskToApproveRelays = Nothing,
|
|
||||||
privacyAcceptImages = Nothing,
|
privacyAcceptImages = Nothing,
|
||||||
privacyLinkPreviews = Nothing,
|
privacyLinkPreviews = Nothing,
|
||||||
privacyShowChatPreviews = Nothing,
|
privacyShowChatPreviews = Nothing,
|
||||||
@@ -126,7 +123,6 @@ combineAppSettings platformDefaults storedSettings =
|
|||||||
{ appPlatform = p appPlatform,
|
{ appPlatform = p appPlatform,
|
||||||
networkConfig = p networkConfig,
|
networkConfig = p networkConfig,
|
||||||
privacyEncryptLocalFiles = p privacyEncryptLocalFiles,
|
privacyEncryptLocalFiles = p privacyEncryptLocalFiles,
|
||||||
privacyAskToApproveRelays = p privacyAskToApproveRelays,
|
|
||||||
privacyAcceptImages = p privacyAcceptImages,
|
privacyAcceptImages = p privacyAcceptImages,
|
||||||
privacyLinkPreviews = p privacyLinkPreviews,
|
privacyLinkPreviews = p privacyLinkPreviews,
|
||||||
privacyShowChatPreviews = p privacyShowChatPreviews,
|
privacyShowChatPreviews = p privacyShowChatPreviews,
|
||||||
@@ -170,7 +166,6 @@ instance FromJSON AppSettings where
|
|||||||
appPlatform <- p "appPlatform"
|
appPlatform <- p "appPlatform"
|
||||||
networkConfig <- p "networkConfig"
|
networkConfig <- p "networkConfig"
|
||||||
privacyEncryptLocalFiles <- p "privacyEncryptLocalFiles"
|
privacyEncryptLocalFiles <- p "privacyEncryptLocalFiles"
|
||||||
privacyAskToApproveRelays <- p "privacyAskToApproveRelays"
|
|
||||||
privacyAcceptImages <- p "privacyAcceptImages"
|
privacyAcceptImages <- p "privacyAcceptImages"
|
||||||
privacyLinkPreviews <- p "privacyLinkPreviews"
|
privacyLinkPreviews <- p "privacyLinkPreviews"
|
||||||
privacyShowChatPreviews <- p "privacyShowChatPreviews"
|
privacyShowChatPreviews <- p "privacyShowChatPreviews"
|
||||||
@@ -199,7 +194,6 @@ instance FromJSON AppSettings where
|
|||||||
{ appPlatform,
|
{ appPlatform,
|
||||||
networkConfig,
|
networkConfig,
|
||||||
privacyEncryptLocalFiles,
|
privacyEncryptLocalFiles,
|
||||||
privacyAskToApproveRelays,
|
|
||||||
privacyAcceptImages,
|
privacyAcceptImages,
|
||||||
privacyLinkPreviews,
|
privacyLinkPreviews,
|
||||||
privacyShowChatPreviews,
|
privacyShowChatPreviews,
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ import Simplex.Chat.Types.UITheme
|
|||||||
import Simplex.Chat.Util (liftIOEither)
|
import Simplex.Chat.Util (liftIOEither)
|
||||||
import Simplex.FileTransfer.Description (FileDescriptionURI)
|
import Simplex.FileTransfer.Description (FileDescriptionURI)
|
||||||
import Simplex.Messaging.Agent (AgentClient, SubscriptionsInfo)
|
import Simplex.Messaging.Agent (AgentClient, SubscriptionsInfo)
|
||||||
import Simplex.Messaging.Agent.Client (AgentLocks, AgentWorkersDetails (..), AgentWorkersSummary (..), ProtocolTestFailure, UserNetworkInfo)
|
import Simplex.Messaging.Agent.Client (AgentLocks, AgentWorkersDetails (..), AgentWorkersSummary (..), ProtocolTestFailure, UserNetworkInfo, UNSOffline, UserNetworkState)
|
||||||
import Simplex.Messaging.Agent.Env.SQLite (AgentConfig, NetworkConfig)
|
import Simplex.Messaging.Agent.Env.SQLite (AgentConfig, NetworkConfig)
|
||||||
import Simplex.Messaging.Agent.Lock
|
import Simplex.Messaging.Agent.Lock
|
||||||
import Simplex.Messaging.Agent.Protocol
|
import Simplex.Messaging.Agent.Protocol
|
||||||
@@ -81,7 +81,7 @@ import Simplex.Messaging.Crypto.Ratchet (PQEncryption)
|
|||||||
import Simplex.Messaging.Encoding.String
|
import Simplex.Messaging.Encoding.String
|
||||||
import Simplex.Messaging.Notifications.Protocol (DeviceToken (..), NtfTknStatus)
|
import Simplex.Messaging.Notifications.Protocol (DeviceToken (..), NtfTknStatus)
|
||||||
import Simplex.Messaging.Parsers (defaultJSON, dropPrefix, enumJSON, parseAll, parseString, sumTypeJSON)
|
import Simplex.Messaging.Parsers (defaultJSON, dropPrefix, enumJSON, parseAll, parseString, sumTypeJSON)
|
||||||
import Simplex.Messaging.Protocol (AProtoServerWithAuth, AProtocolType (..), CorrId, NtfServer, ProtoServerWithAuth, ProtocolTypeI, QueueId, SMPMsgMeta (..), SProtocolType, SubscriptionMode (..), UserProtocol, XFTPServer, XFTPServerWithAuth, userProtocol)
|
import Simplex.Messaging.Protocol (AProtoServerWithAuth, AProtocolType (..), CorrId, NtfServer, ProtoServerWithAuth, ProtocolTypeI, QueueId, SMPMsgMeta (..), SProtocolType, SubscriptionMode (..), UserProtocol, XFTPServerWithAuth, userProtocol)
|
||||||
import Simplex.Messaging.TMap (TMap)
|
import Simplex.Messaging.TMap (TMap)
|
||||||
import Simplex.Messaging.Transport (TLS, simplexMQVersion)
|
import Simplex.Messaging.Transport (TLS, simplexMQVersion)
|
||||||
import Simplex.Messaging.Transport.Client (TransportHost)
|
import Simplex.Messaging.Transport.Client (TransportHost)
|
||||||
@@ -458,8 +458,8 @@ data ChatCommand
|
|||||||
| ForwardFile ChatName FileTransferId
|
| ForwardFile ChatName FileTransferId
|
||||||
| ForwardImage ChatName FileTransferId
|
| ForwardImage ChatName FileTransferId
|
||||||
| SendFileDescription ChatName FilePath
|
| SendFileDescription ChatName FilePath
|
||||||
| ReceiveFile {fileId :: FileTransferId, userApprovedRelays :: Bool, storeEncrypted :: Maybe Bool, fileInline :: Maybe Bool, filePath :: Maybe FilePath}
|
| ReceiveFile {fileId :: FileTransferId, storeEncrypted :: Maybe Bool, fileInline :: Maybe Bool, filePath :: Maybe FilePath}
|
||||||
| SetFileToReceive {fileId :: FileTransferId, userApprovedRelays :: Bool, storeEncrypted :: Maybe Bool}
|
| SetFileToReceive {fileId :: FileTransferId, storeEncrypted :: Maybe Bool}
|
||||||
| CancelFile FileTransferId
|
| CancelFile FileTransferId
|
||||||
| FileStatus FileTransferId
|
| FileStatus FileTransferId
|
||||||
| ShowProfile -- UserId (not used in UI)
|
| ShowProfile -- UserId (not used in UI)
|
||||||
@@ -497,11 +497,11 @@ data ChatCommand
|
|||||||
| DebugEvent ChatResponse
|
| DebugEvent ChatResponse
|
||||||
| GetAgentStats
|
| GetAgentStats
|
||||||
| ResetAgentStats
|
| ResetAgentStats
|
||||||
| GetAgentSubs
|
| GetAgentSubs {diffOnly :: Bool}
|
||||||
| GetAgentSubsDetails
|
|
||||||
| GetAgentWorkers
|
| GetAgentWorkers
|
||||||
| GetAgentWorkersDetails
|
| GetAgentWorkersDetails
|
||||||
| GetAgentMsgCounts
|
| GetAgentMsgCounts
|
||||||
|
| GetAgentUserNetworkState
|
||||||
| -- The parser will return this command for strings that start from "//".
|
| -- The parser will return this command for strings that start from "//".
|
||||||
-- This command should be processed in preCmdHook
|
-- This command should be processed in preCmdHook
|
||||||
CustomChatCommand ByteString
|
CustomChatCommand ByteString
|
||||||
@@ -745,9 +745,9 @@ data ChatResponse
|
|||||||
| CRAgentStats {agentStats :: [[String]]}
|
| CRAgentStats {agentStats :: [[String]]}
|
||||||
| CRAgentWorkersDetails {agentWorkersDetails :: AgentWorkersDetails}
|
| CRAgentWorkersDetails {agentWorkersDetails :: AgentWorkersDetails}
|
||||||
| CRAgentWorkersSummary {agentWorkersSummary :: AgentWorkersSummary}
|
| CRAgentWorkersSummary {agentWorkersSummary :: AgentWorkersSummary}
|
||||||
| CRAgentSubs {activeSubs :: Map Text Int, pendingSubs :: Map Text Int, removedSubs :: Map Text [String]}
|
| CRAgentSubs {agentSubs :: SubscriptionsInfo}
|
||||||
| CRAgentSubsDetails {agentSubs :: SubscriptionsInfo}
|
|
||||||
| CRAgentMsgCounts {msgCounts :: [(Text, (Int, Int))]}
|
| CRAgentMsgCounts {msgCounts :: [(Text, (Int, Int))]}
|
||||||
|
| CRAgentUserNetworkState {networkState :: UserNetworkState}
|
||||||
| CRContactDisabled {user :: User, contact :: Contact}
|
| CRContactDisabled {user :: User, contact :: Contact}
|
||||||
| CRConnectionDisabled {connectionEntity :: ConnectionEntity}
|
| CRConnectionDisabled {connectionEntity :: ConnectionEntity}
|
||||||
| CRAgentRcvQueueDeleted {agentConnId :: AgentConnId, server :: SMPServer, agentQueueId :: AgentQueueId, agentError_ :: Maybe AgentErrorType}
|
| CRAgentRcvQueueDeleted {agentConnId :: AgentConnId, server :: SMPServer, agentQueueId :: AgentQueueId, agentError_ :: Maybe AgentErrorType}
|
||||||
@@ -1132,7 +1132,6 @@ data ChatErrorType
|
|||||||
| CEFileImageType {filePath :: FilePath}
|
| CEFileImageType {filePath :: FilePath}
|
||||||
| CEFileImageSize {filePath :: FilePath}
|
| CEFileImageSize {filePath :: FilePath}
|
||||||
| CEFileNotReceived {fileId :: FileTransferId}
|
| CEFileNotReceived {fileId :: FileTransferId}
|
||||||
| CEFileNotApproved {fileId :: FileTransferId, unknownServers :: [XFTPServer]}
|
|
||||||
| CEXFTPRcvFile {fileId :: FileTransferId, agentRcvFileId :: AgentRcvFileId, agentError :: AgentErrorType}
|
| CEXFTPRcvFile {fileId :: FileTransferId, agentRcvFileId :: AgentRcvFileId, agentError :: AgentErrorType}
|
||||||
| CEXFTPSndFile {fileId :: FileTransferId, agentSndFileId :: AgentSndFileId, agentError :: AgentErrorType}
|
| CEXFTPSndFile {fileId :: FileTransferId, agentSndFileId :: AgentSndFileId, agentError :: AgentErrorType}
|
||||||
| CEFallbackToSMPProhibited {fileId :: FileTransferId}
|
| CEFallbackToSMPProhibited {fileId :: FileTransferId}
|
||||||
@@ -1481,6 +1480,10 @@ $(JQ.deriveJSON (sumTypeJSON $ dropPrefix "RCSR") ''RemoteCtrlStopReason)
|
|||||||
|
|
||||||
$(JQ.deriveJSON (sumTypeJSON $ dropPrefix "RHSR") ''RemoteHostStopReason)
|
$(JQ.deriveJSON (sumTypeJSON $ dropPrefix "RHSR") ''RemoteHostStopReason)
|
||||||
|
|
||||||
|
$(JQ.deriveJSON defaultJSON ''UNSOffline)
|
||||||
|
|
||||||
|
$(JQ.deriveJSON defaultJSON ''UserNetworkState)
|
||||||
|
|
||||||
$(JQ.deriveJSON (sumTypeJSON $ dropPrefix "CR") ''ChatResponse)
|
$(JQ.deriveJSON (sumTypeJSON $ dropPrefix "CR") ''ChatResponse)
|
||||||
|
|
||||||
$(JQ.deriveFromJSON defaultJSON ''ArchiveConfig)
|
$(JQ.deriveFromJSON defaultJSON ''ArchiveConfig)
|
||||||
|
|||||||
@@ -539,7 +539,6 @@ data CIFileStatus (d :: MsgDirection) where
|
|||||||
CIFSRcvInvitation :: CIFileStatus 'MDRcv
|
CIFSRcvInvitation :: CIFileStatus 'MDRcv
|
||||||
CIFSRcvAccepted :: CIFileStatus 'MDRcv
|
CIFSRcvAccepted :: CIFileStatus 'MDRcv
|
||||||
CIFSRcvTransfer :: {rcvProgress :: Int64, rcvTotal :: Int64} -> CIFileStatus 'MDRcv
|
CIFSRcvTransfer :: {rcvProgress :: Int64, rcvTotal :: Int64} -> CIFileStatus 'MDRcv
|
||||||
CIFSRcvAborted :: CIFileStatus 'MDRcv
|
|
||||||
CIFSRcvComplete :: CIFileStatus 'MDRcv
|
CIFSRcvComplete :: CIFileStatus 'MDRcv
|
||||||
CIFSRcvCancelled :: CIFileStatus 'MDRcv
|
CIFSRcvCancelled :: CIFileStatus 'MDRcv
|
||||||
CIFSRcvError :: CIFileStatus 'MDRcv
|
CIFSRcvError :: CIFileStatus 'MDRcv
|
||||||
@@ -559,7 +558,6 @@ ciFileEnded = \case
|
|||||||
CIFSRcvInvitation -> False
|
CIFSRcvInvitation -> False
|
||||||
CIFSRcvAccepted -> False
|
CIFSRcvAccepted -> False
|
||||||
CIFSRcvTransfer {} -> False
|
CIFSRcvTransfer {} -> False
|
||||||
CIFSRcvAborted -> True
|
|
||||||
CIFSRcvCancelled -> True
|
CIFSRcvCancelled -> True
|
||||||
CIFSRcvComplete -> True
|
CIFSRcvComplete -> True
|
||||||
CIFSRcvError -> True
|
CIFSRcvError -> True
|
||||||
@@ -575,7 +573,6 @@ ciFileLoaded = \case
|
|||||||
CIFSRcvInvitation -> False
|
CIFSRcvInvitation -> False
|
||||||
CIFSRcvAccepted -> False
|
CIFSRcvAccepted -> False
|
||||||
CIFSRcvTransfer {} -> False
|
CIFSRcvTransfer {} -> False
|
||||||
CIFSRcvAborted -> False
|
|
||||||
CIFSRcvCancelled -> False
|
CIFSRcvCancelled -> False
|
||||||
CIFSRcvComplete -> True
|
CIFSRcvComplete -> True
|
||||||
CIFSRcvError -> False
|
CIFSRcvError -> False
|
||||||
@@ -595,7 +592,6 @@ instance MsgDirectionI d => StrEncoding (CIFileStatus d) where
|
|||||||
CIFSRcvInvitation -> "rcv_invitation"
|
CIFSRcvInvitation -> "rcv_invitation"
|
||||||
CIFSRcvAccepted -> "rcv_accepted"
|
CIFSRcvAccepted -> "rcv_accepted"
|
||||||
CIFSRcvTransfer rcvd total -> strEncode (Str "rcv_transfer", rcvd, total)
|
CIFSRcvTransfer rcvd total -> strEncode (Str "rcv_transfer", rcvd, total)
|
||||||
CIFSRcvAborted -> "rcv_aborted"
|
|
||||||
CIFSRcvComplete -> "rcv_complete"
|
CIFSRcvComplete -> "rcv_complete"
|
||||||
CIFSRcvCancelled -> "rcv_cancelled"
|
CIFSRcvCancelled -> "rcv_cancelled"
|
||||||
CIFSRcvError -> "rcv_error"
|
CIFSRcvError -> "rcv_error"
|
||||||
@@ -618,7 +614,6 @@ instance StrEncoding ACIFileStatus where
|
|||||||
"rcv_invitation" -> pure $ AFS SMDRcv CIFSRcvInvitation
|
"rcv_invitation" -> pure $ AFS SMDRcv CIFSRcvInvitation
|
||||||
"rcv_accepted" -> pure $ AFS SMDRcv CIFSRcvAccepted
|
"rcv_accepted" -> pure $ AFS SMDRcv CIFSRcvAccepted
|
||||||
"rcv_transfer" -> AFS SMDRcv <$> progress CIFSRcvTransfer
|
"rcv_transfer" -> AFS SMDRcv <$> progress CIFSRcvTransfer
|
||||||
"rcv_aborted" -> pure $ AFS SMDRcv CIFSRcvAborted
|
|
||||||
"rcv_complete" -> pure $ AFS SMDRcv CIFSRcvComplete
|
"rcv_complete" -> pure $ AFS SMDRcv CIFSRcvComplete
|
||||||
"rcv_cancelled" -> pure $ AFS SMDRcv CIFSRcvCancelled
|
"rcv_cancelled" -> pure $ AFS SMDRcv CIFSRcvCancelled
|
||||||
"rcv_error" -> pure $ AFS SMDRcv CIFSRcvError
|
"rcv_error" -> pure $ AFS SMDRcv CIFSRcvError
|
||||||
@@ -636,7 +631,6 @@ data JSONCIFileStatus
|
|||||||
| JCIFSRcvInvitation
|
| JCIFSRcvInvitation
|
||||||
| JCIFSRcvAccepted
|
| JCIFSRcvAccepted
|
||||||
| JCIFSRcvTransfer {rcvProgress :: Int64, rcvTotal :: Int64}
|
| JCIFSRcvTransfer {rcvProgress :: Int64, rcvTotal :: Int64}
|
||||||
| JCIFSRcvAborted
|
|
||||||
| JCIFSRcvComplete
|
| JCIFSRcvComplete
|
||||||
| JCIFSRcvCancelled
|
| JCIFSRcvCancelled
|
||||||
| JCIFSRcvError
|
| JCIFSRcvError
|
||||||
@@ -652,7 +646,6 @@ jsonCIFileStatus = \case
|
|||||||
CIFSRcvInvitation -> JCIFSRcvInvitation
|
CIFSRcvInvitation -> JCIFSRcvInvitation
|
||||||
CIFSRcvAccepted -> JCIFSRcvAccepted
|
CIFSRcvAccepted -> JCIFSRcvAccepted
|
||||||
CIFSRcvTransfer rcvd total -> JCIFSRcvTransfer rcvd total
|
CIFSRcvTransfer rcvd total -> JCIFSRcvTransfer rcvd total
|
||||||
CIFSRcvAborted -> JCIFSRcvAborted
|
|
||||||
CIFSRcvComplete -> JCIFSRcvComplete
|
CIFSRcvComplete -> JCIFSRcvComplete
|
||||||
CIFSRcvCancelled -> JCIFSRcvCancelled
|
CIFSRcvCancelled -> JCIFSRcvCancelled
|
||||||
CIFSRcvError -> JCIFSRcvError
|
CIFSRcvError -> JCIFSRcvError
|
||||||
@@ -668,7 +661,6 @@ aciFileStatusJSON = \case
|
|||||||
JCIFSRcvInvitation -> AFS SMDRcv CIFSRcvInvitation
|
JCIFSRcvInvitation -> AFS SMDRcv CIFSRcvInvitation
|
||||||
JCIFSRcvAccepted -> AFS SMDRcv CIFSRcvAccepted
|
JCIFSRcvAccepted -> AFS SMDRcv CIFSRcvAccepted
|
||||||
JCIFSRcvTransfer rcvd total -> AFS SMDRcv $ CIFSRcvTransfer rcvd total
|
JCIFSRcvTransfer rcvd total -> AFS SMDRcv $ CIFSRcvTransfer rcvd total
|
||||||
JCIFSRcvAborted -> AFS SMDRcv CIFSRcvAborted
|
|
||||||
JCIFSRcvComplete -> AFS SMDRcv CIFSRcvComplete
|
JCIFSRcvComplete -> AFS SMDRcv CIFSRcvComplete
|
||||||
JCIFSRcvCancelled -> AFS SMDRcv CIFSRcvCancelled
|
JCIFSRcvCancelled -> AFS SMDRcv CIFSRcvCancelled
|
||||||
JCIFSRcvError -> AFS SMDRcv CIFSRcvError
|
JCIFSRcvError -> AFS SMDRcv CIFSRcvError
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
{-# LANGUAGE QuasiQuotes #-}
|
|
||||||
|
|
||||||
module Simplex.Chat.Migrations.M20240515_rcv_files_user_approved_relays where
|
|
||||||
|
|
||||||
import Database.SQLite.Simple (Query)
|
|
||||||
import Database.SQLite.Simple.QQ (sql)
|
|
||||||
|
|
||||||
m20240515_rcv_files_user_approved_relays :: Query
|
|
||||||
m20240515_rcv_files_user_approved_relays =
|
|
||||||
[sql|
|
|
||||||
ALTER TABLE rcv_files ADD COLUMN user_approved_relays INTEGER NOT NULL DEFAULT 0;
|
|
||||||
|]
|
|
||||||
|
|
||||||
down_m20240515_rcv_files_user_approved_relays :: Query
|
|
||||||
down_m20240515_rcv_files_user_approved_relays =
|
|
||||||
[sql|
|
|
||||||
ALTER TABLE rcv_files DROP COLUMN user_approved_relays;
|
|
||||||
|]
|
|
||||||
@@ -229,8 +229,7 @@ CREATE TABLE rcv_files(
|
|||||||
REFERENCES xftp_file_descriptions ON DELETE SET NULL,
|
REFERENCES xftp_file_descriptions ON DELETE SET NULL,
|
||||||
agent_rcv_file_id BLOB NULL,
|
agent_rcv_file_id BLOB NULL,
|
||||||
agent_rcv_file_deleted INTEGER DEFAULT 0 CHECK(agent_rcv_file_deleted NOT NULL),
|
agent_rcv_file_deleted INTEGER DEFAULT 0 CHECK(agent_rcv_file_deleted NOT NULL),
|
||||||
to_receive INTEGER,
|
to_receive INTEGER
|
||||||
user_approved_relays INTEGER NOT NULL DEFAULT 0
|
|
||||||
);
|
);
|
||||||
CREATE TABLE snd_file_chunks(
|
CREATE TABLE snd_file_chunks(
|
||||||
file_id INTEGER NOT NULL,
|
file_id INTEGER NOT NULL,
|
||||||
|
|||||||
@@ -514,7 +514,7 @@ createRcvFileTransfer db userId Contact {contactId, localDisplayName = c} f@File
|
|||||||
rfd_ <- mapM (createRcvFD_ db userId currentTs) fileDescr
|
rfd_ <- mapM (createRcvFD_ db userId currentTs) fileDescr
|
||||||
let rfdId = (\RcvFileDescr {fileDescrId} -> fileDescrId) <$> rfd_
|
let rfdId = (\RcvFileDescr {fileDescrId} -> fileDescrId) <$> rfd_
|
||||||
-- cryptoArgs = Nothing here, the decision to encrypt is made when receiving it
|
-- cryptoArgs = Nothing here, the decision to encrypt is made when receiving it
|
||||||
xftpRcvFile = (\rfd -> XFTPRcvFile {rcvFileDescription = rfd, agentRcvFileId = Nothing, agentRcvFileDeleted = False, userApprovedRelays = False}) <$> rfd_
|
xftpRcvFile = (\rfd -> XFTPRcvFile {rcvFileDescription = rfd, agentRcvFileId = Nothing, agentRcvFileDeleted = False}) <$> rfd_
|
||||||
fileProtocol = if isJust rfd_ then FPXFTP else FPSMP
|
fileProtocol = if isJust rfd_ then FPXFTP else FPSMP
|
||||||
fileId <- liftIO $ do
|
fileId <- liftIO $ do
|
||||||
DB.execute
|
DB.execute
|
||||||
@@ -535,7 +535,7 @@ createRcvGroupFileTransfer db userId GroupMember {groupId, groupMemberId, localD
|
|||||||
rfd_ <- mapM (createRcvFD_ db userId currentTs) fileDescr
|
rfd_ <- mapM (createRcvFD_ db userId currentTs) fileDescr
|
||||||
let rfdId = (\RcvFileDescr {fileDescrId} -> fileDescrId) <$> rfd_
|
let rfdId = (\RcvFileDescr {fileDescrId} -> fileDescrId) <$> rfd_
|
||||||
-- cryptoArgs = Nothing here, the decision to encrypt is made when receiving it
|
-- cryptoArgs = Nothing here, the decision to encrypt is made when receiving it
|
||||||
xftpRcvFile = (\rfd -> XFTPRcvFile {rcvFileDescription = rfd, agentRcvFileId = Nothing, agentRcvFileDeleted = False, userApprovedRelays = False}) <$> rfd_
|
xftpRcvFile = (\rfd -> XFTPRcvFile {rcvFileDescription = rfd, agentRcvFileId = Nothing, agentRcvFileDeleted = False}) <$> rfd_
|
||||||
fileProtocol = if isJust rfd_ then FPXFTP else FPSMP
|
fileProtocol = if isJust rfd_ then FPXFTP else FPSMP
|
||||||
fileId <- liftIO $ do
|
fileId <- liftIO $ do
|
||||||
DB.execute
|
DB.execute
|
||||||
@@ -676,9 +676,7 @@ getRcvFileTransfer_ db userId fileId = do
|
|||||||
[sql|
|
[sql|
|
||||||
SELECT r.file_status, r.file_queue_info, r.group_member_id, f.file_name,
|
SELECT r.file_status, r.file_queue_info, r.group_member_id, f.file_name,
|
||||||
f.file_size, f.chunk_size, f.cancelled, cs.local_display_name, m.local_display_name,
|
f.file_size, f.chunk_size, f.cancelled, cs.local_display_name, m.local_display_name,
|
||||||
f.file_path, f.file_crypto_key, f.file_crypto_nonce, r.file_inline, r.rcv_file_inline,
|
f.file_path, f.file_crypto_key, f.file_crypto_nonce, r.file_inline, r.rcv_file_inline, r.agent_rcv_file_id, r.agent_rcv_file_deleted, c.connection_id, c.agent_conn_id
|
||||||
r.agent_rcv_file_id, r.agent_rcv_file_deleted, r.user_approved_relays,
|
|
||||||
c.connection_id, c.agent_conn_id
|
|
||||||
FROM rcv_files r
|
FROM rcv_files r
|
||||||
JOIN files f USING (file_id)
|
JOIN files f USING (file_id)
|
||||||
LEFT JOIN connections c ON r.file_id = c.rcv_file_id
|
LEFT JOIN connections c ON r.file_id = c.rcv_file_id
|
||||||
@@ -692,9 +690,9 @@ getRcvFileTransfer_ db userId fileId = do
|
|||||||
where
|
where
|
||||||
rcvFileTransfer ::
|
rcvFileTransfer ::
|
||||||
Maybe RcvFileDescr ->
|
Maybe RcvFileDescr ->
|
||||||
(FileStatus, Maybe ConnReqInvitation, Maybe Int64, String, Integer, Integer, Maybe Bool) :. (Maybe ContactName, Maybe ContactName, Maybe FilePath, Maybe C.SbKey, Maybe C.CbNonce, Maybe InlineFileMode, Maybe InlineFileMode, Maybe AgentRcvFileId, Bool, Bool) :. (Maybe Int64, Maybe AgentConnId) ->
|
(FileStatus, Maybe ConnReqInvitation, Maybe Int64, String, Integer, Integer, Maybe Bool) :. (Maybe ContactName, Maybe ContactName, Maybe FilePath, Maybe C.SbKey, Maybe C.CbNonce, Maybe InlineFileMode, Maybe InlineFileMode, Maybe AgentRcvFileId, Bool) :. (Maybe Int64, Maybe AgentConnId) ->
|
||||||
ExceptT StoreError IO RcvFileTransfer
|
ExceptT StoreError IO RcvFileTransfer
|
||||||
rcvFileTransfer rfd_ ((fileStatus', fileConnReq, grpMemberId, fileName, fileSize, chunkSize, cancelled_) :. (contactName_, memberName_, filePath_, fileKey, fileNonce, fileInline, rcvFileInline, agentRcvFileId, agentRcvFileDeleted, userApprovedRelays) :. (connId_, agentConnId_)) =
|
rcvFileTransfer rfd_ ((fileStatus', fileConnReq, grpMemberId, fileName, fileSize, chunkSize, cancelled_) :. (contactName_, memberName_, filePath_, fileKey, fileNonce, fileInline, rcvFileInline, agentRcvFileId, agentRcvFileDeleted) :. (connId_, agentConnId_)) =
|
||||||
case contactName_ <|> memberName_ <|> standaloneName_ of
|
case contactName_ <|> memberName_ <|> standaloneName_ of
|
||||||
Nothing -> throwError $ SERcvFileInvalid fileId
|
Nothing -> throwError $ SERcvFileInvalid fileId
|
||||||
Just name ->
|
Just name ->
|
||||||
@@ -711,7 +709,7 @@ getRcvFileTransfer_ db userId fileId = do
|
|||||||
ft senderDisplayName fileStatus =
|
ft senderDisplayName fileStatus =
|
||||||
let fileInvitation = FileInvitation {fileName, fileSize, fileDigest = Nothing, fileConnReq, fileInline, fileDescr = Nothing}
|
let fileInvitation = FileInvitation {fileName, fileSize, fileDigest = Nothing, fileConnReq, fileInline, fileDescr = Nothing}
|
||||||
cryptoArgs = CFArgs <$> fileKey <*> fileNonce
|
cryptoArgs = CFArgs <$> fileKey <*> fileNonce
|
||||||
xftpRcvFile = (\rfd -> XFTPRcvFile {rcvFileDescription = rfd, agentRcvFileId, agentRcvFileDeleted, userApprovedRelays}) <$> rfd_
|
xftpRcvFile = (\rfd -> XFTPRcvFile {rcvFileDescription = rfd, agentRcvFileId, agentRcvFileDeleted}) <$> rfd_
|
||||||
in RcvFileTransfer {fileId, xftpRcvFile, fileInvitation, fileStatus, rcvFileInline, senderDisplayName, chunkSize, cancelled, grpMemberId, cryptoArgs}
|
in RcvFileTransfer {fileId, xftpRcvFile, fileInvitation, fileStatus, rcvFileInline, senderDisplayName, chunkSize, cancelled, grpMemberId, cryptoArgs}
|
||||||
rfi = maybe (throwError $ SERcvFileInvalid fileId) pure =<< rfi_
|
rfi = maybe (throwError $ SERcvFileInvalid fileId) pure =<< rfi_
|
||||||
rfi_ = case (filePath_, connId_, agentConnId_) of
|
rfi_ = case (filePath_, connId_, agentConnId_) of
|
||||||
@@ -722,7 +720,7 @@ getRcvFileTransfer_ db userId fileId = do
|
|||||||
acceptRcvFileTransfer :: DB.Connection -> VersionRangeChat -> User -> Int64 -> (CommandId, ConnId) -> ConnStatus -> FilePath -> SubscriptionMode -> ExceptT StoreError IO AChatItem
|
acceptRcvFileTransfer :: DB.Connection -> VersionRangeChat -> User -> Int64 -> (CommandId, ConnId) -> ConnStatus -> FilePath -> SubscriptionMode -> ExceptT StoreError IO AChatItem
|
||||||
acceptRcvFileTransfer db vr user@User {userId} fileId (cmdId, acId) connStatus filePath subMode = ExceptT $ do
|
acceptRcvFileTransfer db vr user@User {userId} fileId (cmdId, acId) connStatus filePath subMode = ExceptT $ do
|
||||||
currentTs <- getCurrentTime
|
currentTs <- getCurrentTime
|
||||||
acceptRcvFT_ db user fileId filePath False Nothing currentTs
|
acceptRcvFT_ db user fileId filePath Nothing currentTs
|
||||||
DB.execute
|
DB.execute
|
||||||
db
|
db
|
||||||
"INSERT INTO connections (agent_conn_id, conn_status, conn_type, rcv_file_id, user_id, created_at, updated_at, to_subscribe) VALUES (?,?,?,?,?,?,?,?)"
|
"INSERT INTO connections (agent_conn_id, conn_status, conn_type, rcv_file_id, user_id, created_at, updated_at, to_subscribe) VALUES (?,?,?,?,?,?,?,?)"
|
||||||
@@ -742,40 +740,33 @@ getContactByFileId db vr user@User {userId} fileId = do
|
|||||||
|
|
||||||
acceptRcvInlineFT :: DB.Connection -> VersionRangeChat -> User -> FileTransferId -> FilePath -> ExceptT StoreError IO AChatItem
|
acceptRcvInlineFT :: DB.Connection -> VersionRangeChat -> User -> FileTransferId -> FilePath -> ExceptT StoreError IO AChatItem
|
||||||
acceptRcvInlineFT db vr user fileId filePath = do
|
acceptRcvInlineFT db vr user fileId filePath = do
|
||||||
liftIO $ acceptRcvFT_ db user fileId filePath False (Just IFMOffer) =<< getCurrentTime
|
liftIO $ acceptRcvFT_ db user fileId filePath (Just IFMOffer) =<< getCurrentTime
|
||||||
getChatItemByFileId db vr user fileId
|
getChatItemByFileId db vr user fileId
|
||||||
|
|
||||||
startRcvInlineFT :: DB.Connection -> User -> RcvFileTransfer -> FilePath -> Maybe InlineFileMode -> IO ()
|
startRcvInlineFT :: DB.Connection -> User -> RcvFileTransfer -> FilePath -> Maybe InlineFileMode -> IO ()
|
||||||
startRcvInlineFT db user RcvFileTransfer {fileId} filePath rcvFileInline =
|
startRcvInlineFT db user RcvFileTransfer {fileId} filePath rcvFileInline =
|
||||||
acceptRcvFT_ db user fileId filePath False rcvFileInline =<< getCurrentTime
|
acceptRcvFT_ db user fileId filePath rcvFileInline =<< getCurrentTime
|
||||||
|
|
||||||
xftpAcceptRcvFT :: DB.Connection -> VersionRangeChat -> User -> FileTransferId -> FilePath -> Bool -> ExceptT StoreError IO AChatItem
|
xftpAcceptRcvFT :: DB.Connection -> VersionRangeChat -> User -> FileTransferId -> FilePath -> ExceptT StoreError IO AChatItem
|
||||||
xftpAcceptRcvFT db vr user fileId filePath userApprovedRelays = do
|
xftpAcceptRcvFT db vr user fileId filePath = do
|
||||||
liftIO $ acceptRcvFT_ db user fileId filePath userApprovedRelays Nothing =<< getCurrentTime
|
liftIO $ acceptRcvFT_ db user fileId filePath Nothing =<< getCurrentTime
|
||||||
getChatItemByFileId db vr user fileId
|
getChatItemByFileId db vr user fileId
|
||||||
|
|
||||||
acceptRcvFT_ :: DB.Connection -> User -> FileTransferId -> FilePath -> Bool -> Maybe InlineFileMode -> UTCTime -> IO ()
|
acceptRcvFT_ :: DB.Connection -> User -> FileTransferId -> FilePath -> Maybe InlineFileMode -> UTCTime -> IO ()
|
||||||
acceptRcvFT_ db User {userId} fileId filePath userApprovedRelays rcvFileInline currentTs = do
|
acceptRcvFT_ db User {userId} fileId filePath rcvFileInline currentTs = do
|
||||||
DB.execute
|
DB.execute
|
||||||
db
|
db
|
||||||
"UPDATE files SET file_path = ?, ci_file_status = ?, updated_at = ? WHERE user_id = ? AND file_id = ?"
|
"UPDATE files SET file_path = ?, ci_file_status = ?, updated_at = ? WHERE user_id = ? AND file_id = ?"
|
||||||
(filePath, CIFSRcvAccepted, currentTs, userId, fileId)
|
(filePath, CIFSRcvAccepted, currentTs, userId, fileId)
|
||||||
DB.execute
|
DB.execute
|
||||||
db
|
db
|
||||||
"UPDATE rcv_files SET user_approved_relays = ?, rcv_file_inline = ?, file_status = ?, updated_at = ? WHERE file_id = ?"
|
"UPDATE rcv_files SET rcv_file_inline = ?, file_status = ?, updated_at = ? WHERE file_id = ?"
|
||||||
(userApprovedRelays, rcvFileInline, FSAccepted, currentTs, fileId)
|
(rcvFileInline, FSAccepted, currentTs, fileId)
|
||||||
|
|
||||||
setRcvFileToReceive :: DB.Connection -> FileTransferId -> Bool -> Maybe CryptoFileArgs -> IO ()
|
setRcvFileToReceive :: DB.Connection -> FileTransferId -> Maybe CryptoFileArgs -> IO ()
|
||||||
setRcvFileToReceive db fileId userApprovedRelays cfArgs_ = do
|
setRcvFileToReceive db fileId cfArgs_ = do
|
||||||
currentTs <- getCurrentTime
|
currentTs <- getCurrentTime
|
||||||
DB.execute
|
DB.execute db "UPDATE rcv_files SET to_receive = 1, updated_at = ? WHERE file_id = ?" (currentTs, fileId)
|
||||||
db
|
|
||||||
[sql|
|
|
||||||
UPDATE rcv_files
|
|
||||||
SET to_receive = 1, user_approved_relays = ?, updated_at = ?
|
|
||||||
WHERE file_id = ?
|
|
||||||
|]
|
|
||||||
(userApprovedRelays, currentTs, fileId)
|
|
||||||
forM_ cfArgs_ $ \cfArgs -> setFileCryptoArgs_ db fileId cfArgs currentTs
|
forM_ cfArgs_ $ \cfArgs -> setFileCryptoArgs_ db fileId cfArgs currentTs
|
||||||
|
|
||||||
setFileCryptoArgs :: DB.Connection -> FileTransferId -> CryptoFileArgs -> IO ()
|
setFileCryptoArgs :: DB.Connection -> FileTransferId -> CryptoFileArgs -> IO ()
|
||||||
|
|||||||
@@ -108,7 +108,6 @@ import Simplex.Chat.Migrations.M20240402_item_forwarded
|
|||||||
import Simplex.Chat.Migrations.M20240430_ui_theme
|
import Simplex.Chat.Migrations.M20240430_ui_theme
|
||||||
import Simplex.Chat.Migrations.M20240501_chat_deleted
|
import Simplex.Chat.Migrations.M20240501_chat_deleted
|
||||||
import Simplex.Chat.Migrations.M20240510_chat_items_via_proxy
|
import Simplex.Chat.Migrations.M20240510_chat_items_via_proxy
|
||||||
import Simplex.Chat.Migrations.M20240515_rcv_files_user_approved_relays
|
|
||||||
import Simplex.Messaging.Agent.Store.SQLite.Migrations (Migration (..))
|
import Simplex.Messaging.Agent.Store.SQLite.Migrations (Migration (..))
|
||||||
|
|
||||||
schemaMigrations :: [(String, Query, Maybe Query)]
|
schemaMigrations :: [(String, Query, Maybe Query)]
|
||||||
@@ -216,8 +215,7 @@ schemaMigrations =
|
|||||||
("20240402_item_forwarded", m20240402_item_forwarded, Just down_m20240402_item_forwarded),
|
("20240402_item_forwarded", m20240402_item_forwarded, Just down_m20240402_item_forwarded),
|
||||||
("20240430_ui_theme", m20240430_ui_theme, Just down_m20240430_ui_theme),
|
("20240430_ui_theme", m20240430_ui_theme, Just down_m20240430_ui_theme),
|
||||||
("20240501_chat_deleted", m20240501_chat_deleted, Just down_m20240501_chat_deleted),
|
("20240501_chat_deleted", m20240501_chat_deleted, Just down_m20240501_chat_deleted),
|
||||||
("20240510_chat_items_via_proxy", m20240510_chat_items_via_proxy, Just down_m20240510_chat_items_via_proxy),
|
("20240510_chat_items_via_proxy", m20240510_chat_items_via_proxy, Just down_m20240510_chat_items_via_proxy)
|
||||||
("20240515_rcv_files_user_approved_relays", m20240515_rcv_files_user_approved_relays, Just down_m20240515_rcv_files_user_approved_relays)
|
|
||||||
]
|
]
|
||||||
|
|
||||||
-- | The list of migrations in ascending order by date
|
-- | The list of migrations in ascending order by date
|
||||||
|
|||||||
@@ -1072,8 +1072,7 @@ data RcvFileTransfer = RcvFileTransfer
|
|||||||
data XFTPRcvFile = XFTPRcvFile
|
data XFTPRcvFile = XFTPRcvFile
|
||||||
{ rcvFileDescription :: RcvFileDescr,
|
{ rcvFileDescription :: RcvFileDescr,
|
||||||
agentRcvFileId :: Maybe AgentRcvFileId,
|
agentRcvFileId :: Maybe AgentRcvFileId,
|
||||||
agentRcvFileDeleted :: Bool,
|
agentRcvFileDeleted :: Bool
|
||||||
userApprovedRelays :: Bool
|
|
||||||
}
|
}
|
||||||
deriving (Eq, Show)
|
deriving (Eq, Show)
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ import Data.Int (Int64)
|
|||||||
import Data.List (groupBy, intercalate, intersperse, partition, sortOn)
|
import Data.List (groupBy, intercalate, intersperse, partition, sortOn)
|
||||||
import Data.List.NonEmpty (NonEmpty (..))
|
import Data.List.NonEmpty (NonEmpty (..))
|
||||||
import qualified Data.List.NonEmpty as L
|
import qualified Data.List.NonEmpty as L
|
||||||
import Data.Map.Strict (Map)
|
|
||||||
import qualified Data.Map.Strict as M
|
import qualified Data.Map.Strict as M
|
||||||
import Data.Maybe (fromMaybe, isJust, isNothing, mapMaybe)
|
import Data.Maybe (fromMaybe, isJust, isNothing, mapMaybe)
|
||||||
import Data.Text (Text)
|
import Data.Text (Text)
|
||||||
@@ -52,7 +51,7 @@ import Simplex.Chat.Types.Preferences
|
|||||||
import Simplex.Chat.Types.Shared
|
import Simplex.Chat.Types.Shared
|
||||||
import Simplex.Chat.Types.UITheme
|
import Simplex.Chat.Types.UITheme
|
||||||
import qualified Simplex.FileTransfer.Transport as XFTP
|
import qualified Simplex.FileTransfer.Transport as XFTP
|
||||||
import Simplex.Messaging.Agent.Client (ProtocolTestFailure (..), ProtocolTestStep (..), SubscriptionsInfo (..))
|
import Simplex.Messaging.Agent.Client (ActivePendingSubs (..), ProtocolTestFailure (..), ProtocolTestStep (..), SubInfo (..), SubscriptionsInfo (..))
|
||||||
import Simplex.Messaging.Agent.Env.SQLite (NetworkConfig (..))
|
import Simplex.Messaging.Agent.Env.SQLite (NetworkConfig (..))
|
||||||
import Simplex.Messaging.Agent.Protocol
|
import Simplex.Messaging.Agent.Protocol
|
||||||
import Simplex.Messaging.Agent.Store.SQLite.DB (SlowQueryStats (..))
|
import Simplex.Messaging.Agent.Store.SQLite.DB (SlowQueryStats (..))
|
||||||
@@ -358,24 +357,21 @@ responseToView hu@(currentRH, user_) ChatConfig {logLevel, showReactions, showRe
|
|||||||
plain $ "agent locks: " <> LB.unpack (J.encode agentLocks)
|
plain $ "agent locks: " <> LB.unpack (J.encode agentLocks)
|
||||||
]
|
]
|
||||||
CRAgentStats stats -> map (plain . intercalate ",") stats
|
CRAgentStats stats -> map (plain . intercalate ",") stats
|
||||||
CRAgentSubs {activeSubs, pendingSubs, removedSubs} ->
|
CRAgentSubs SubscriptionsInfo {summary, servers} -> "Subscriptions:" : activePending summary <> concatMap (uncurry byServer) (M.assocs servers)
|
||||||
[plain $ "Subscriptions: active = " <> show (sum activeSubs) <> ", pending = " <> show (sum pendingSubs) <> ", removed = " <> show (sum $ M.map length removedSubs)]
|
|
||||||
<> ("active subscriptions:" : listSubs activeSubs)
|
|
||||||
<> ("pending subscriptions:" : listSubs pendingSubs)
|
|
||||||
<> ("removed subscriptions:" : listSubs removedSubs)
|
|
||||||
where
|
where
|
||||||
listSubs :: Show a => Map Text a -> [StyledString]
|
byServer srv aps = plain srv : activePending aps
|
||||||
listSubs = map (\(srv, info) -> plain $ srv <> ": " <> tshow info) . M.assocs
|
activePending ActivePendingSubs {active_, pending_} =
|
||||||
CRAgentSubsDetails SubscriptionsInfo {activeSubscriptions, pendingSubscriptions, removedSubscriptions} ->
|
[ " active: " <> subInfo active_,
|
||||||
("active subscriptions:" : map sShow activeSubscriptions)
|
" pending: " <> subInfo pending_
|
||||||
<> ("pending subscriptions: " : map sShow pendingSubscriptions)
|
]
|
||||||
<> ("removed subscriptions: " : map sShow removedSubscriptions)
|
subInfo SubInfo {count, clientsMissing, clientsExtra} = sShow count <> " (clients: -" <> sShow clientsMissing <> " +" <> sShow clientsExtra <> ")"
|
||||||
CRAgentWorkersSummary {agentWorkersSummary} -> ["agent workers summary: " <> plain (LB.unpack $ J.encode agentWorkersSummary)]
|
CRAgentWorkersSummary {agentWorkersSummary} -> ["agent workers summary: " <> plain (LB.unpack $ J.encode agentWorkersSummary)]
|
||||||
CRAgentWorkersDetails {agentWorkersDetails} ->
|
CRAgentWorkersDetails {agentWorkersDetails} ->
|
||||||
[ "agent workers details:",
|
[ "agent workers details:",
|
||||||
plain . LB.unpack $ J.encode agentWorkersDetails -- this would be huge, but copypastable when has its own line
|
plain . LB.unpack $ J.encode agentWorkersDetails -- this would be huge, but copypastable when has its own line
|
||||||
]
|
]
|
||||||
CRAgentMsgCounts {msgCounts} -> ["received messages (total, duplicates):", plain . LB.unpack $ J.encode msgCounts]
|
CRAgentMsgCounts {msgCounts} -> ["received messages (total, duplicates):", plain . LB.unpack $ J.encode msgCounts]
|
||||||
|
CRAgentUserNetworkState {networkState} -> ["user network state:", plain . LB.unpack $ J.encode networkState]
|
||||||
CRContactDisabled u c -> ttyUser u ["[" <> ttyContact' c <> "] connection is disabled, to enable: " <> highlight ("/enable " <> viewContactName c) <> ", to delete: " <> highlight ("/d " <> viewContactName c)]
|
CRContactDisabled u c -> ttyUser u ["[" <> ttyContact' c <> "] connection is disabled, to enable: " <> highlight ("/enable " <> viewContactName c) <> ", to delete: " <> highlight ("/d " <> viewContactName c)]
|
||||||
CRConnectionDisabled entity -> viewConnectionEntityDisabled entity
|
CRConnectionDisabled entity -> viewConnectionEntityDisabled entity
|
||||||
CRAgentRcvQueueDeleted acId srv aqId err_ ->
|
CRAgentRcvQueueDeleted acId srv aqId err_ ->
|
||||||
@@ -1766,7 +1762,6 @@ viewFileTransferStatusXFTP (AChatItem _ _ _ ChatItem {file = Just CIFile {fileId
|
|||||||
CIFSRcvInvitation -> ["receiving " <> fstr <> " not accepted yet, use " <> highlight ("/fr " <> show fileId) <> " to receive file"]
|
CIFSRcvInvitation -> ["receiving " <> fstr <> " not accepted yet, use " <> highlight ("/fr " <> show fileId) <> " to receive file"]
|
||||||
CIFSRcvAccepted -> ["receiving " <> fstr <> " just started"]
|
CIFSRcvAccepted -> ["receiving " <> fstr <> " just started"]
|
||||||
CIFSRcvTransfer progress total -> ["receiving " <> fstr <> " progress " <> fileProgressXFTP progress total fileSize]
|
CIFSRcvTransfer progress total -> ["receiving " <> fstr <> " progress " <> fileProgressXFTP progress total fileSize]
|
||||||
CIFSRcvAborted -> ["receiving " <> fstr <> " aborted, use " <> highlight ("/fr " <> show fileId) <> " to receive file"]
|
|
||||||
CIFSRcvComplete -> ["receiving " <> fstr <> " complete" <> maybe "" (\(CryptoFile fp _) -> ", path: " <> plain fp) fileSource]
|
CIFSRcvComplete -> ["receiving " <> fstr <> " complete" <> maybe "" (\(CryptoFile fp _) -> ", path: " <> plain fp) fileSource]
|
||||||
CIFSRcvCancelled -> ["receiving " <> fstr <> " cancelled"]
|
CIFSRcvCancelled -> ["receiving " <> fstr <> " cancelled"]
|
||||||
CIFSRcvError -> ["receiving " <> fstr <> " error"]
|
CIFSRcvError -> ["receiving " <> fstr <> " error"]
|
||||||
@@ -1970,7 +1965,6 @@ viewChatError logLevel testView = \case
|
|||||||
CEFileImageType _ -> ["image type must be jpg, send as a file using " <> highlight' "/f"]
|
CEFileImageType _ -> ["image type must be jpg, send as a file using " <> highlight' "/f"]
|
||||||
CEFileImageSize _ -> ["max image size: " <> sShow maxImageSize <> " bytes, resize it or send as a file using " <> highlight' "/f"]
|
CEFileImageSize _ -> ["max image size: " <> sShow maxImageSize <> " bytes, resize it or send as a file using " <> highlight' "/f"]
|
||||||
CEFileNotReceived fileId -> ["file " <> sShow fileId <> " not received"]
|
CEFileNotReceived fileId -> ["file " <> sShow fileId <> " not received"]
|
||||||
CEFileNotApproved fileId unknownSrvs -> ["file " <> sShow fileId <> " aborted, unknwon XFTP servers:"] <> map (plain . show) unknownSrvs
|
|
||||||
CEXFTPRcvFile fileId aFileId e -> ["error receiving XFTP file " <> sShow fileId <> ", agent file id " <> sShow aFileId <> ": " <> sShow e | logLevel == CLLError]
|
CEXFTPRcvFile fileId aFileId e -> ["error receiving XFTP file " <> sShow fileId <> ", agent file id " <> sShow aFileId <> ": " <> sShow e | logLevel == CLLError]
|
||||||
CEXFTPSndFile fileId aFileId e -> ["error sending XFTP file " <> sShow fileId <> ", agent file id " <> sShow aFileId <> ": " <> sShow e | logLevel == CLLError]
|
CEXFTPSndFile fileId aFileId e -> ["error sending XFTP file " <> sShow fileId <> ", agent file id " <> sShow aFileId <> ": " <> sShow e | logLevel == CLLError]
|
||||||
CEFallbackToSMPProhibited fileId -> ["recipient tried to accept file " <> sShow fileId <> " via old protocol, prohibited"]
|
CEFallbackToSMPProhibited fileId -> ["recipient tried to accept file " <> sShow fileId <> " via old protocol, prohibited"]
|
||||||
|
|||||||
Reference in New Issue
Block a user