mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2025-06-28 20:29:53 +00:00
Merge commit '9329bf6144
' into master-android
This commit is contained in:
commit
a57c4404d1
237 changed files with 10493 additions and 5515 deletions
|
@ -54,7 +54,7 @@ class AppDelegate: NSObject, UIApplicationDelegate {
|
|||
try await apiVerifyToken(token: token, nonce: nonce, code: verification)
|
||||
m.tokenStatus = .active
|
||||
} catch {
|
||||
if let cr = error as? ChatResponse, case .chatCmdError(_, .errorAgent(.NTF(.AUTH))) = cr {
|
||||
if let cr = error as? ChatError, case .errorAgent(.NTF(.AUTH)) = cr {
|
||||
m.tokenStatus = .expired
|
||||
}
|
||||
logger.error("AppDelegate: didReceiveRemoteNotification: apiVerifyToken or apiIntervalNofication error: \(responseError(error))")
|
||||
|
|
2300
apps/ios/Shared/Model/AppAPITypes.swift
Normal file
2300
apps/ios/Shared/Model/AppAPITypes.swift
Normal file
File diff suppressed because it is too large
Load diff
|
@ -30,9 +30,18 @@ actor TerminalItems {
|
|||
}
|
||||
}
|
||||
|
||||
func addCommand(_ start: Date, _ cmd: ChatCommand, _ resp: ChatResponse) async {
|
||||
func addCommand<R: ChatAPIResult>(_ start: Date, _ cmd: ChatCommand, _ res: APIResult<R>) async {
|
||||
await add(.cmd(start, cmd))
|
||||
await add(.resp(.now, resp))
|
||||
await addResult(res)
|
||||
}
|
||||
|
||||
func addResult<R: ChatAPIResult>(_ res: APIResult<R>) async {
|
||||
let item: TerminalItem = switch res {
|
||||
case let .result(r): .res(.now, r)
|
||||
case let .error(e): .err(.now, e)
|
||||
case let .invalid(type, json): .bad(.now, type, json)
|
||||
}
|
||||
await add(item)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -54,9 +63,7 @@ class ItemsModel: ObservableObject {
|
|||
willSet { publisher.send() }
|
||||
}
|
||||
|
||||
// set listener here that will be notified on every add/delete of a chat item
|
||||
let chatState = ActiveChatState()
|
||||
var chatItemsChangesListener: RecalculatePositions = RecalculatePositions()
|
||||
|
||||
// Publishes directly to `objectWillChange` publisher,
|
||||
// this will cause reversedChatItems to be rendered without throttling
|
||||
|
@ -573,7 +580,7 @@ final class ChatModel: ObservableObject {
|
|||
ci.meta.itemStatus = status
|
||||
}
|
||||
im.reversedChatItems.insert(ci, at: hasLiveDummy ? 1 : 0)
|
||||
im.chatItemsChangesListener.added((ci.id, ci.isRcvNew), hasLiveDummy ? 1 : 0)
|
||||
im.chatState.itemAdded((ci.id, ci.isRcvNew), hasLiveDummy ? 1 : 0)
|
||||
im.itemAdded = true
|
||||
ChatItemDummyModel.shared.sendUpdate()
|
||||
return true
|
||||
|
@ -621,7 +628,7 @@ final class ChatModel: ObservableObject {
|
|||
if let i = getChatItemIndex(cItem) {
|
||||
withAnimation {
|
||||
let item = im.reversedChatItems.remove(at: i)
|
||||
im.chatItemsChangesListener.removed([(item.id, i, item.isRcvNew)], im.reversedChatItems.reversed())
|
||||
im.chatState.itemsRemoved([(item.id, i, item.isRcvNew)], im.reversedChatItems.reversed())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -709,7 +716,7 @@ final class ChatModel: ObservableObject {
|
|||
let cItem = ChatItem.liveDummy(chatInfo.chatType)
|
||||
withAnimation {
|
||||
im.reversedChatItems.insert(cItem, at: 0)
|
||||
im.chatItemsChangesListener.added((cItem.id, cItem.isRcvNew), 0)
|
||||
im.chatState.itemAdded((cItem.id, cItem.isRcvNew), 0)
|
||||
im.itemAdded = true
|
||||
}
|
||||
return cItem
|
||||
|
@ -743,7 +750,7 @@ final class ChatModel: ObservableObject {
|
|||
markChatItemRead_(i)
|
||||
i += 1
|
||||
}
|
||||
im.chatItemsChangesListener.read(nil, im.reversedChatItems.reversed())
|
||||
im.chatState.itemsRead(nil, im.reversedChatItems.reversed())
|
||||
}
|
||||
}
|
||||
func markChatUnread(_ cInfo: ChatInfo, unreadChat: Bool = true) {
|
||||
|
@ -767,7 +774,7 @@ final class ChatModel: ObservableObject {
|
|||
if chatId == cInfo.id {
|
||||
chatItemStatuses = [:]
|
||||
im.reversedChatItems = []
|
||||
im.chatItemsChangesListener.cleared()
|
||||
im.chatState.clear()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -785,7 +792,7 @@ final class ChatModel: ObservableObject {
|
|||
}
|
||||
i += 1
|
||||
}
|
||||
im.chatItemsChangesListener.read(unreadItemIds, im.reversedChatItems.reversed())
|
||||
im.chatState.itemsRead(unreadItemIds, im.reversedChatItems.reversed())
|
||||
}
|
||||
self.unreadCollector.changeUnreadCounter(cInfo.id, by: -itemIds.count, unreadMentions: -mentionsRead)
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -243,7 +243,7 @@ struct ActiveCallView: View {
|
|||
ChatReceiver.shared.messagesChannel = nil
|
||||
return
|
||||
}
|
||||
if case let .chatItemsStatusesUpdated(_, chatItems) = msg,
|
||||
if case let .result(.chatItemsStatusesUpdated(_, chatItems)) = msg,
|
||||
chatItems.contains(where: { ci in
|
||||
ci.chatInfo.id == call.contact.id &&
|
||||
ci.chatItem.content.isSndCall &&
|
||||
|
|
|
@ -7,10 +7,11 @@
|
|||
//
|
||||
|
||||
import SwiftUI
|
||||
import SimpleXChat
|
||||
|
||||
struct CIInvalidJSONView: View {
|
||||
@EnvironmentObject var theme: AppTheme
|
||||
var json: String
|
||||
var json: Data?
|
||||
@State private var showJSON = false
|
||||
|
||||
var body: some View {
|
||||
|
@ -25,7 +26,7 @@ struct CIInvalidJSONView: View {
|
|||
.textSelection(.disabled)
|
||||
.onTapGesture { showJSON = true }
|
||||
.appSheet(isPresented: $showJSON) {
|
||||
invalidJSONView(json)
|
||||
invalidJSONView(dataToString(json))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -49,6 +50,6 @@ func invalidJSONView(_ json: String) -> some View {
|
|||
|
||||
struct CIInvalidJSONView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
CIInvalidJSONView(json: "{}")
|
||||
CIInvalidJSONView(json: "{}".data(using: .utf8)!)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -321,6 +321,101 @@ class ActiveChatState {
|
|||
unreadAfter = 0
|
||||
unreadAfterNewestLoaded = 0
|
||||
}
|
||||
|
||||
func itemsRead(_ itemIds: Set<Int64>?, _ newItems: [ChatItem]) {
|
||||
guard let itemIds else {
|
||||
// special case when the whole chat became read
|
||||
unreadTotal = 0
|
||||
unreadAfter = 0
|
||||
return
|
||||
}
|
||||
var unreadAfterItemIndex: Int = -1
|
||||
// since it's more often that the newest items become read, it's logical to loop from the end of the list to finish it faster
|
||||
var i = newItems.count - 1
|
||||
var ids = itemIds
|
||||
// intermediate variables to prevent re-setting state value a lot of times without reason
|
||||
var newUnreadTotal = unreadTotal
|
||||
var newUnreadAfter = unreadAfter
|
||||
while i >= 0 {
|
||||
let item = newItems[i]
|
||||
if item.id == unreadAfterItemId {
|
||||
unreadAfterItemIndex = i
|
||||
}
|
||||
if ids.contains(item.id) {
|
||||
// was unread, now this item is read
|
||||
if (unreadAfterItemIndex == -1) {
|
||||
newUnreadAfter -= 1
|
||||
}
|
||||
newUnreadTotal -= 1
|
||||
ids.remove(item.id)
|
||||
if ids.isEmpty {
|
||||
break
|
||||
}
|
||||
}
|
||||
i -= 1
|
||||
}
|
||||
unreadTotal = newUnreadTotal
|
||||
unreadAfter = newUnreadAfter
|
||||
}
|
||||
|
||||
func itemAdded(_ item: (Int64, Bool), _ index: Int) {
|
||||
if item.1 {
|
||||
unreadAfter += 1
|
||||
unreadTotal += 1
|
||||
}
|
||||
}
|
||||
|
||||
func itemsRemoved(_ itemIds: [(Int64, Int, Bool)], _ newItems: [ChatItem]) {
|
||||
var newSplits: [Int64] = []
|
||||
for split in splits {
|
||||
let index = itemIds.firstIndex(where: { (delId, _, _) in delId == split })
|
||||
// deleted the item that was right before the split between items, find newer item so it will act like the split
|
||||
if let index {
|
||||
let idx = itemIds[index].1 - itemIds.filter { (_, delIndex, _) in delIndex <= index }.count
|
||||
let newSplit = newItems.count > idx && idx >= 0 ? newItems[idx].id : nil
|
||||
// it the whole section is gone and splits overlap, don't add it at all
|
||||
if let newSplit, !newSplits.contains(newSplit) {
|
||||
newSplits.append(newSplit)
|
||||
}
|
||||
} else {
|
||||
newSplits.append(split)
|
||||
}
|
||||
}
|
||||
splits = newSplits
|
||||
|
||||
let index = itemIds.firstIndex(where: { (delId, _, _) in delId == unreadAfterItemId })
|
||||
// unread after item was removed
|
||||
if let index {
|
||||
let idx = itemIds[index].1 - itemIds.filter { (_, delIndex, _) in delIndex <= index }.count
|
||||
var newUnreadAfterItemId = newItems.count > idx && idx >= 0 ? newItems[idx].id : nil
|
||||
let newUnreadAfterItemWasNull = newUnreadAfterItemId == nil
|
||||
if newUnreadAfterItemId == nil {
|
||||
// everything on top (including unread after item) were deleted, take top item as unread after id
|
||||
newUnreadAfterItemId = newItems.first?.id
|
||||
}
|
||||
if let newUnreadAfterItemId {
|
||||
unreadAfterItemId = newUnreadAfterItemId
|
||||
totalAfter -= itemIds.filter { (_, delIndex, _) in delIndex > index }.count
|
||||
unreadTotal -= itemIds.filter { (_, delIndex, isRcvNew) in delIndex <= index && isRcvNew }.count
|
||||
unreadAfter -= itemIds.filter { (_, delIndex, isRcvNew) in delIndex > index && isRcvNew }.count
|
||||
if newUnreadAfterItemWasNull {
|
||||
// since the unread after item was moved one item after initial position, adjust counters accordingly
|
||||
if newItems.first?.isRcvNew == true {
|
||||
unreadTotal += 1
|
||||
unreadAfter -= 1
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// all items were deleted, 0 items in chatItems
|
||||
unreadAfterItemId = -1
|
||||
totalAfter = 0
|
||||
unreadTotal = 0
|
||||
unreadAfter = 0
|
||||
}
|
||||
} else {
|
||||
totalAfter -= itemIds.count
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class BoxedValue<T: Hashable>: Equatable, Hashable {
|
||||
|
@ -359,101 +454,3 @@ func visibleItemIndexesNonReversed(_ listState: EndlessScrollView<MergedItem>.Li
|
|||
// visible items mapped to their underlying data structure which is ItemsModel.shared.reversedChatItems.reversed()
|
||||
return range
|
||||
}
|
||||
|
||||
class RecalculatePositions {
|
||||
private var chatState: ActiveChatState { get { ItemsModel.shared.chatState } }
|
||||
|
||||
func read(_ itemIds: Set<Int64>?, _ newItems: [ChatItem]) {
|
||||
guard let itemIds else {
|
||||
// special case when the whole chat became read
|
||||
chatState.unreadTotal = 0
|
||||
chatState.unreadAfter = 0
|
||||
return
|
||||
}
|
||||
var unreadAfterItemIndex: Int = -1
|
||||
// since it's more often that the newest items become read, it's logical to loop from the end of the list to finish it faster
|
||||
var i = newItems.count - 1
|
||||
var ids = itemIds
|
||||
// intermediate variables to prevent re-setting state value a lot of times without reason
|
||||
var newUnreadTotal = chatState.unreadTotal
|
||||
var newUnreadAfter = chatState.unreadAfter
|
||||
while i >= 0 {
|
||||
let item = newItems[i]
|
||||
if item.id == chatState.unreadAfterItemId {
|
||||
unreadAfterItemIndex = i
|
||||
}
|
||||
if ids.contains(item.id) {
|
||||
// was unread, now this item is read
|
||||
if (unreadAfterItemIndex == -1) {
|
||||
newUnreadAfter -= 1
|
||||
}
|
||||
newUnreadTotal -= 1
|
||||
ids.remove(item.id)
|
||||
if ids.isEmpty {
|
||||
break
|
||||
}
|
||||
}
|
||||
i -= 1
|
||||
}
|
||||
chatState.unreadTotal = newUnreadTotal
|
||||
chatState.unreadAfter = newUnreadAfter
|
||||
}
|
||||
func added(_ item: (Int64, Bool), _ index: Int) {
|
||||
if item.1 {
|
||||
chatState.unreadAfter += 1
|
||||
chatState.unreadTotal += 1
|
||||
}
|
||||
}
|
||||
func removed(_ itemIds: [(Int64, Int, Bool)], _ newItems: [ChatItem]) {
|
||||
var newSplits: [Int64] = []
|
||||
for split in chatState.splits {
|
||||
let index = itemIds.firstIndex(where: { (delId, _, _) in delId == split })
|
||||
// deleted the item that was right before the split between items, find newer item so it will act like the split
|
||||
if let index {
|
||||
let idx = itemIds[index].1 - itemIds.filter { (_, delIndex, _) in delIndex <= index }.count
|
||||
let newSplit = newItems.count > idx && idx >= 0 ? newItems[idx].id : nil
|
||||
// it the whole section is gone and splits overlap, don't add it at all
|
||||
if let newSplit, !newSplits.contains(newSplit) {
|
||||
newSplits.append(newSplit)
|
||||
}
|
||||
} else {
|
||||
newSplits.append(split)
|
||||
}
|
||||
}
|
||||
chatState.splits = newSplits
|
||||
|
||||
let index = itemIds.firstIndex(where: { (delId, _, _) in delId == chatState.unreadAfterItemId })
|
||||
// unread after item was removed
|
||||
if let index {
|
||||
let idx = itemIds[index].1 - itemIds.filter { (_, delIndex, _) in delIndex <= index }.count
|
||||
var newUnreadAfterItemId = newItems.count > idx && idx >= 0 ? newItems[idx].id : nil
|
||||
let newUnreadAfterItemWasNull = newUnreadAfterItemId == nil
|
||||
if newUnreadAfterItemId == nil {
|
||||
// everything on top (including unread after item) were deleted, take top item as unread after id
|
||||
newUnreadAfterItemId = newItems.first?.id
|
||||
}
|
||||
if let newUnreadAfterItemId {
|
||||
chatState.unreadAfterItemId = newUnreadAfterItemId
|
||||
chatState.totalAfter -= itemIds.filter { (_, delIndex, _) in delIndex > index }.count
|
||||
chatState.unreadTotal -= itemIds.filter { (_, delIndex, isRcvNew) in delIndex <= index && isRcvNew }.count
|
||||
chatState.unreadAfter -= itemIds.filter { (_, delIndex, isRcvNew) in delIndex > index && isRcvNew }.count
|
||||
if newUnreadAfterItemWasNull {
|
||||
// since the unread after item was moved one item after initial position, adjust counters accordingly
|
||||
if newItems.first?.isRcvNew == true {
|
||||
chatState.unreadTotal += 1
|
||||
chatState.unreadAfter -= 1
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// all items were deleted, 0 items in chatItems
|
||||
chatState.unreadAfterItemId = -1
|
||||
chatState.totalAfter = 0
|
||||
chatState.unreadTotal = 0
|
||||
chatState.unreadAfter = 0
|
||||
}
|
||||
} else {
|
||||
chatState.totalAfter -= itemIds.count
|
||||
}
|
||||
}
|
||||
func cleared() { chatState.clear() }
|
||||
}
|
||||
|
|
|
@ -281,7 +281,7 @@ struct ChatView: View {
|
|||
if chatModel.chatId == nil {
|
||||
chatModel.chatItemStatuses = [:]
|
||||
ItemsModel.shared.reversedChatItems = []
|
||||
ItemsModel.shared.chatItemsChangesListener.cleared()
|
||||
ItemsModel.shared.chatState.clear()
|
||||
chatModel.groupMembers = []
|
||||
chatModel.groupMembersIndexes.removeAll()
|
||||
chatModel.membersLoaded = false
|
||||
|
|
|
@ -579,14 +579,14 @@ struct ChatListNavLink: View {
|
|||
)
|
||||
}
|
||||
|
||||
private func invalidJSONPreview(_ json: String) -> some View {
|
||||
private func invalidJSONPreview(_ json: Data?) -> some View {
|
||||
Text("invalid chat data")
|
||||
.foregroundColor(.red)
|
||||
.padding(4)
|
||||
.frame(height: dynamicRowHeight)
|
||||
.onTapGesture { showInvalidJSON = true }
|
||||
.appSheet(isPresented: $showInvalidJSON) {
|
||||
invalidJSONView(json)
|
||||
invalidJSONView(dataToString(json))
|
||||
.environment(\EnvironmentValues.refresh as! WritableKeyPath<EnvironmentValues, RefreshAction?>, nil)
|
||||
}
|
||||
}
|
||||
|
@ -689,7 +689,7 @@ func joinGroup(_ groupId: Int64, _ onComplete: @escaping () async -> Void) {
|
|||
}
|
||||
|
||||
func getErrorAlert(_ error: Error, _ title: LocalizedStringKey) -> ErrorAlert {
|
||||
if let r = error as? ChatResponse,
|
||||
if let r = error as? ChatError,
|
||||
let alert = getNetworkErrorAlert(r) {
|
||||
return alert
|
||||
} else {
|
||||
|
|
|
@ -173,7 +173,7 @@ struct DatabaseEncryptionView: View {
|
|||
}
|
||||
return true
|
||||
} catch let error {
|
||||
if case .chatCmdError(_, .errorDatabase(.errorExport(.errorNotADatabase))) = error as? ChatResponse {
|
||||
if case .errorDatabase(.errorExport(.errorNotADatabase)) = error as? ChatError {
|
||||
await operationEnded(.currentPassphraseError)
|
||||
} else {
|
||||
await operationEnded(.error(title: "Error encrypting database", error: "\(responseError(error))"))
|
||||
|
|
|
@ -65,7 +65,7 @@ struct LocalAuthView: View {
|
|||
// Clear sensitive data on screen just in case app fails to hide its views while new database is created
|
||||
m.chatId = nil
|
||||
ItemsModel.shared.reversedChatItems = []
|
||||
ItemsModel.shared.chatItemsChangesListener.cleared()
|
||||
ItemsModel.shared.chatState.clear()
|
||||
m.updateChats([])
|
||||
m.users = []
|
||||
_ = kcAppPassword.set(password)
|
||||
|
|
|
@ -520,15 +520,15 @@ struct MigrateFromDevice: View {
|
|||
chatReceiver = MigrationChatReceiver(ctrl: ctrl, databaseUrl: tempDatabaseUrl) { msg in
|
||||
await MainActor.run {
|
||||
switch msg {
|
||||
case let .sndFileProgressXFTP(_, _, fileTransferMeta, sentSize, totalSize):
|
||||
case let .result(.sndFileProgressXFTP(_, _, fileTransferMeta, sentSize, totalSize)):
|
||||
if case let .uploadProgress(uploaded, total, _, _, _) = migrationState, uploaded != total {
|
||||
migrationState = .uploadProgress(uploadedBytes: sentSize, totalBytes: totalSize, fileId: fileTransferMeta.fileId, archivePath: archivePath, ctrl: ctrl)
|
||||
}
|
||||
case .sndFileRedirectStartXFTP:
|
||||
case .result(.sndFileRedirectStartXFTP):
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
||||
migrationState = .linkCreation
|
||||
}
|
||||
case let .sndStandaloneFileComplete(_, fileTransferMeta, rcvURIs):
|
||||
case let .result(.sndStandaloneFileComplete(_, fileTransferMeta, rcvURIs)):
|
||||
let cfg = getNetCfg()
|
||||
let proxy: NetworkProxy? = if cfg.socksProxy == nil {
|
||||
nil
|
||||
|
@ -546,7 +546,7 @@ struct MigrateFromDevice: View {
|
|||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
||||
migrationState = .linkShown(fileId: fileTransferMeta.fileId, link: data.addToLink(link: rcvURIs[0]), archivePath: archivePath, ctrl: ctrl)
|
||||
}
|
||||
case .sndFileError:
|
||||
case .result(.sndFileError):
|
||||
alert = .error(title: "Upload failed", error: "Check your internet connection and try again")
|
||||
migrationState = .uploadFailed(totalBytes: totalBytes, archivePath: archivePath)
|
||||
default:
|
||||
|
@ -691,7 +691,7 @@ private struct PassphraseConfirmationView: View {
|
|||
migrationState = .uploadConfirmation
|
||||
}
|
||||
} catch let error {
|
||||
if case .chatCmdError(_, .errorDatabase(.errorOpen(.errorNotADatabase))) = error as? ChatResponse {
|
||||
if case .errorDatabase(.errorOpen(.errorNotADatabase)) = error as? ChatError {
|
||||
showErrorOnMigrationIfNeeded(.errorNotADatabase(dbFile: ""), $alert)
|
||||
} else {
|
||||
alert = .error(title: "Error", error: NSLocalizedString("Error verifying passphrase:", comment: "") + " " + String(responseError(error)))
|
||||
|
@ -733,11 +733,11 @@ func chatStoppedView() -> some View {
|
|||
private class MigrationChatReceiver {
|
||||
let ctrl: chat_ctrl
|
||||
let databaseUrl: URL
|
||||
let processReceivedMsg: (ChatResponse) async -> Void
|
||||
let processReceivedMsg: (APIResult<ChatEvent>) async -> Void
|
||||
private var receiveLoop: Task<Void, Never>?
|
||||
private var receiveMessages = true
|
||||
|
||||
init(ctrl: chat_ctrl, databaseUrl: URL, _ processReceivedMsg: @escaping (ChatResponse) async -> Void) {
|
||||
init(ctrl: chat_ctrl, databaseUrl: URL, _ processReceivedMsg: @escaping (APIResult<ChatEvent>) async -> Void) {
|
||||
self.ctrl = ctrl
|
||||
self.databaseUrl = databaseUrl
|
||||
self.processReceivedMsg = processReceivedMsg
|
||||
|
@ -752,9 +752,9 @@ private class MigrationChatReceiver {
|
|||
|
||||
func receiveMsgLoop() async {
|
||||
// TODO use function that has timeout
|
||||
if let msg = await chatRecvMsg(ctrl) {
|
||||
if let msg: APIResult<ChatEvent> = await chatRecvMsg(ctrl) {
|
||||
Task {
|
||||
await TerminalItems.shared.add(.resp(.now, msg))
|
||||
await TerminalItems.shared.addResult(msg)
|
||||
}
|
||||
logger.debug("processReceivedMsg: \(msg.responseType)")
|
||||
await processReceivedMsg(msg)
|
||||
|
|
|
@ -496,10 +496,10 @@ struct MigrateToDevice: View {
|
|||
chatReceiver = MigrationChatReceiver(ctrl: ctrl, databaseUrl: tempDatabaseUrl) { msg in
|
||||
await MainActor.run {
|
||||
switch msg {
|
||||
case let .rcvFileProgressXFTP(_, _, receivedSize, totalSize, rcvFileTransfer):
|
||||
case let .result(.rcvFileProgressXFTP(_, _, receivedSize, totalSize, rcvFileTransfer)):
|
||||
migrationState = .downloadProgress(downloadedBytes: receivedSize, totalBytes: totalSize, fileId: rcvFileTransfer.fileId, link: link, archivePath: archivePath, ctrl: ctrl)
|
||||
MigrationToDeviceState.save(.downloadProgress(link: link, archiveName: URL(fileURLWithPath: archivePath).lastPathComponent))
|
||||
case .rcvStandaloneFileComplete:
|
||||
case .result(.rcvStandaloneFileComplete):
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
||||
// User closed the whole screen before new state was saved
|
||||
if migrationState == nil {
|
||||
|
@ -509,10 +509,10 @@ struct MigrateToDevice: View {
|
|||
MigrationToDeviceState.save(.archiveImport(archiveName: URL(fileURLWithPath: archivePath).lastPathComponent))
|
||||
}
|
||||
}
|
||||
case .rcvFileError:
|
||||
case .result(.rcvFileError):
|
||||
alert = .error(title: "Download failed", error: "File was deleted or link is invalid")
|
||||
migrationState = .downloadFailed(totalBytes: totalBytes, link: link, archivePath: archivePath)
|
||||
case .chatError(_, .error(.noRcvFileUser)):
|
||||
case .error(.error(.noRcvFileUser)):
|
||||
alert = .error(title: "Download failed", error: "File was deleted or link is invalid")
|
||||
migrationState = .downloadFailed(totalBytes: totalBytes, link: link, archivePath: archivePath)
|
||||
default:
|
||||
|
@ -751,11 +751,11 @@ private func progressView() -> some View {
|
|||
private class MigrationChatReceiver {
|
||||
let ctrl: chat_ctrl
|
||||
let databaseUrl: URL
|
||||
let processReceivedMsg: (ChatResponse) async -> Void
|
||||
let processReceivedMsg: (APIResult<ChatEvent>) async -> Void
|
||||
private var receiveLoop: Task<Void, Never>?
|
||||
private var receiveMessages = true
|
||||
|
||||
init(ctrl: chat_ctrl, databaseUrl: URL, _ processReceivedMsg: @escaping (ChatResponse) async -> Void) {
|
||||
init(ctrl: chat_ctrl, databaseUrl: URL, _ processReceivedMsg: @escaping (APIResult<ChatEvent>) async -> Void) {
|
||||
self.ctrl = ctrl
|
||||
self.databaseUrl = databaseUrl
|
||||
self.processReceivedMsg = processReceivedMsg
|
||||
|
@ -772,7 +772,7 @@ private class MigrationChatReceiver {
|
|||
// TODO use function that has timeout
|
||||
if let msg = await chatRecvMsg(ctrl) {
|
||||
Task {
|
||||
await TerminalItems.shared.add(.resp(.now, msg))
|
||||
await TerminalItems.shared.addResult(msg)
|
||||
}
|
||||
logger.debug("processReceivedMsg: \(msg.responseType)")
|
||||
await processReceivedMsg(msg)
|
||||
|
|
|
@ -236,15 +236,15 @@ private func showCreateProfileAlert(
|
|||
_ error: Error
|
||||
) {
|
||||
let m = ChatModel.shared
|
||||
switch error as? ChatResponse {
|
||||
case .chatCmdError(_, .errorStore(.duplicateName)),
|
||||
.chatCmdError(_, .error(.userExists)):
|
||||
switch error as? ChatError {
|
||||
case .errorStore(.duplicateName),
|
||||
.error(.userExists):
|
||||
if m.currentUser == nil {
|
||||
AlertManager.shared.showAlert(duplicateUserAlert)
|
||||
} else {
|
||||
showAlert(.duplicateUserError)
|
||||
}
|
||||
case .chatCmdError(_, .error(.invalidDisplayName)):
|
||||
case .error(.invalidDisplayName):
|
||||
if m.currentUser == nil {
|
||||
AlertManager.shared.showAlert(invalidDisplayNameAlert)
|
||||
} else {
|
||||
|
|
|
@ -456,12 +456,12 @@ struct ConnectDesktopView: View {
|
|||
}
|
||||
} catch let e {
|
||||
await MainActor.run {
|
||||
switch e as? ChatResponse {
|
||||
case .chatCmdError(_, .errorRemoteCtrl(.badInvitation)): alert = .badInvitationError
|
||||
case .chatCmdError(_, .error(.commandError)): alert = .badInvitationError
|
||||
case let .chatCmdError(_, .errorRemoteCtrl(.badVersion(v))): alert = .badVersionError(version: v)
|
||||
case .chatCmdError(_, .errorAgent(.RCP(.version))): alert = .badVersionError(version: nil)
|
||||
case .chatCmdError(_, .errorAgent(.RCP(.ctrlAuth))): alert = .desktopDisconnectedError
|
||||
switch e as? ChatError {
|
||||
case .errorRemoteCtrl(.badInvitation): alert = .badInvitationError
|
||||
case .error(.commandError): alert = .badInvitationError
|
||||
case let .errorRemoteCtrl(.badVersion(v)): alert = .badVersionError(version: v)
|
||||
case .errorAgent(.RCP(.version)): alert = .badVersionError(version: nil)
|
||||
case .errorAgent(.RCP(.ctrlAuth)): alert = .desktopDisconnectedError
|
||||
default: errorAlert(e)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -145,18 +145,18 @@ struct TerminalView: View {
|
|||
}
|
||||
|
||||
func consoleSendMessage() {
|
||||
let cmd = ChatCommand.string(composeState.message)
|
||||
if composeState.message.starts(with: "/sql") && (!prefPerformLA || !developerTools) {
|
||||
let resp = ChatResponse.chatCmdError(user_: nil, chatError: ChatError.error(errorType: ChatErrorType.commandError(message: "Failed reading: empty")))
|
||||
let resp: APIResult<ChatResponse2> = APIResult.error(ChatError.error(errorType: ChatErrorType.commandError(message: "Failed reading: empty")))
|
||||
Task {
|
||||
await TerminalItems.shared.addCommand(.now, cmd, resp)
|
||||
await TerminalItems.shared.addCommand(.now, .string(composeState.message), resp)
|
||||
}
|
||||
} else {
|
||||
let cmd = composeState.message
|
||||
DispatchQueue.global().async {
|
||||
Task {
|
||||
composeState.inProgress = true
|
||||
_ = await chatSendCmd(cmd)
|
||||
composeState.inProgress = false
|
||||
await MainActor.run { composeState.inProgress = true }
|
||||
await sendTerminalCmd(cmd)
|
||||
await MainActor.run { composeState.inProgress = false }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -164,12 +164,38 @@ struct TerminalView: View {
|
|||
}
|
||||
}
|
||||
|
||||
func sendTerminalCmd(_ cmd: String) async {
|
||||
let start: Date = .now
|
||||
await withCheckedContinuation { (cont: CheckedContinuation<Void, Never>) in
|
||||
let d = sendSimpleXCmdStr(cmd)
|
||||
Task {
|
||||
guard let d else {
|
||||
await TerminalItems.shared.addCommand(start, ChatCommand.string(cmd), APIResult<ChatResponse2>.error(.invalidJSON(json: nil)))
|
||||
return
|
||||
}
|
||||
let r0: APIResult<ChatResponse0> = decodeAPIResult(d)
|
||||
guard case .invalid = r0 else {
|
||||
await TerminalItems.shared.addCommand(start, .string(cmd), r0)
|
||||
return
|
||||
}
|
||||
let r1: APIResult<ChatResponse1> = decodeAPIResult(d)
|
||||
guard case .invalid = r1 else {
|
||||
await TerminalItems.shared.addCommand(start, .string(cmd), r1)
|
||||
return
|
||||
}
|
||||
let r2: APIResult<ChatResponse2> = decodeAPIResult(d)
|
||||
await TerminalItems.shared.addCommand(start, .string(cmd), r2)
|
||||
}
|
||||
cont.resume(returning: ())
|
||||
}
|
||||
}
|
||||
|
||||
struct TerminalView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
let chatModel = ChatModel()
|
||||
chatModel.terminalItems = [
|
||||
.resp(.now, ChatResponse.response(type: "contactSubscribed", json: "{}")),
|
||||
.resp(.now, ChatResponse.response(type: "newChatItems", json: "{}"))
|
||||
.err(.now, APIResult<ChatResponse2>.invalid(type: "contactSubscribed", json: "{}".data(using: .utf8)!).unexpected),
|
||||
.err(.now, APIResult<ChatResponse2>.invalid(type: "newChatItems", json: "{}".data(using: .utf8)!).unexpected)
|
||||
]
|
||||
return NavigationView {
|
||||
TerminalView()
|
||||
|
|
|
@ -209,11 +209,16 @@ struct AdvancedNetworkSettings: View {
|
|||
}
|
||||
|
||||
Section {
|
||||
Toggle("Use web port", isOn: $netCfg.smpWebPort)
|
||||
Picker("Use web port", selection: $netCfg.smpWebPortServers) {
|
||||
ForEach(SMPWebPortServers.allCases, id: \.self) { Text($0.text) }
|
||||
}
|
||||
.frame(height: 36)
|
||||
} header: {
|
||||
Text("TCP port for messaging")
|
||||
} footer: {
|
||||
Text("Use TCP port \(netCfg.smpWebPort ? "443" : "5223") when no port is specified.")
|
||||
netCfg.smpWebPortServers == .preset
|
||||
? Text("Use TCP port 443 for preset servers only.")
|
||||
: Text("Use TCP port \(netCfg.smpWebPortServers == .all ? "443" : "5223") when no port is specified.")
|
||||
}
|
||||
|
||||
Section("TCP connection") {
|
||||
|
|
127
apps/ios/SimpleX NSE/NSEAPITypes.swift
Normal file
127
apps/ios/SimpleX NSE/NSEAPITypes.swift
Normal file
|
@ -0,0 +1,127 @@
|
|||
//
|
||||
// APITypes.swift
|
||||
// SimpleX
|
||||
//
|
||||
// Created by EP on 01/05/2025.
|
||||
// Copyright © 2025 SimpleX Chat. All rights reserved.
|
||||
//
|
||||
|
||||
import SimpleXChat
|
||||
|
||||
enum NSEChatCommand: ChatCmdProtocol {
|
||||
case showActiveUser
|
||||
case startChat(mainApp: Bool, enableSndFiles: Bool)
|
||||
case apiActivateChat(restoreChat: Bool)
|
||||
case apiSuspendChat(timeoutMicroseconds: Int)
|
||||
case apiSetNetworkConfig(networkConfig: NetCfg)
|
||||
case apiSetAppFilePaths(filesFolder: String, tempFolder: String, assetsFolder: String)
|
||||
case apiSetEncryptLocalFiles(enable: Bool)
|
||||
case apiGetNtfConns(nonce: String, encNtfInfo: String)
|
||||
case apiGetConnNtfMessages(connMsgReqs: [ConnMsgReq])
|
||||
case receiveFile(fileId: Int64, userApprovedRelays: Bool, encrypted: Bool?, inline: Bool?)
|
||||
case setFileToReceive(fileId: Int64, userApprovedRelays: Bool, encrypted: Bool?)
|
||||
|
||||
var cmdString: String {
|
||||
switch self {
|
||||
case .showActiveUser: return "/u"
|
||||
case let .startChat(mainApp, enableSndFiles): return "/_start main=\(onOff(mainApp)) snd_files=\(onOff(enableSndFiles))"
|
||||
case let .apiActivateChat(restore): return "/_app activate restore=\(onOff(restore))"
|
||||
case let .apiSuspendChat(timeoutMicroseconds): return "/_app suspend \(timeoutMicroseconds)"
|
||||
case let .apiSetNetworkConfig(networkConfig): return "/_network \(encodeJSON(networkConfig))"
|
||||
case let .apiSetAppFilePaths(filesFolder, tempFolder, assetsFolder):
|
||||
return "/set file paths \(encodeJSON(AppFilePaths(appFilesFolder: filesFolder, appTempFolder: tempFolder, appAssetsFolder: assetsFolder)))"
|
||||
case let .apiSetEncryptLocalFiles(enable): return "/_files_encrypt \(onOff(enable))"
|
||||
case let .apiGetNtfConns(nonce, encNtfInfo): return "/_ntf conns \(nonce) \(encNtfInfo)"
|
||||
case let .apiGetConnNtfMessages(connMsgReqs): return "/_ntf conn messages \(connMsgReqs.map { $0.cmdString }.joined(separator: ","))"
|
||||
case let .receiveFile(fileId, userApprovedRelays, encrypt, inline): return "/freceive \(fileId)\(onOffParam("approved_relays", userApprovedRelays))\(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))"
|
||||
}
|
||||
}
|
||||
|
||||
private func onOffParam(_ param: String, _ b: Bool?) -> String {
|
||||
if let b = b {
|
||||
" \(param)=\(onOff(b))"
|
||||
} else {
|
||||
""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum NSEChatResponse: Decodable, ChatAPIResult {
|
||||
case activeUser(user: User)
|
||||
case chatStarted
|
||||
case chatRunning
|
||||
case rcvFileAccepted(user: UserRef, chatItem: AChatItem)
|
||||
case ntfConns(ntfConns: [NtfConn])
|
||||
case connNtfMessages(receivedMsgs: [RcvNtfMsgInfo])
|
||||
case ntfMessage(user: UserRef, connEntity: ConnectionEntity, ntfMessage: NtfMsgAckInfo)
|
||||
case cmdOk(user_: UserRef?)
|
||||
|
||||
var responseType: String {
|
||||
switch self {
|
||||
case .activeUser: "activeUser"
|
||||
case .chatStarted: "chatStarted"
|
||||
case .chatRunning: "chatRunning"
|
||||
case .rcvFileAccepted: "rcvFileAccepted"
|
||||
case .ntfConns: "ntfConns"
|
||||
case .connNtfMessages: "connNtfMessages"
|
||||
case .ntfMessage: "ntfMessage"
|
||||
case .cmdOk: "cmdOk"
|
||||
}
|
||||
}
|
||||
|
||||
var details: String {
|
||||
switch self {
|
||||
case let .activeUser(user): return String(describing: user)
|
||||
case .chatStarted: return noDetails
|
||||
case .chatRunning: return noDetails
|
||||
case let .rcvFileAccepted(u, chatItem): return withUser(u, String(describing: chatItem))
|
||||
case let .ntfConns(ntfConns): return String(describing: ntfConns)
|
||||
case let .connNtfMessages(receivedMsgs): return "receivedMsgs: \(String(describing: receivedMsgs))"
|
||||
case let .ntfMessage(u, connEntity, ntfMessage): return withUser(u, "connEntity: \(String(describing: connEntity))\nntfMessage: \(String(describing: ntfMessage))")
|
||||
case .cmdOk: return noDetails
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum NSEChatEvent: Decodable, ChatAPIResult {
|
||||
case chatSuspended
|
||||
case contactConnected(user: UserRef, contact: Contact, userCustomProfile: Profile?)
|
||||
case receivedContactRequest(user: UserRef, contactRequest: UserContactRequest)
|
||||
case newChatItems(user: UserRef, chatItems: [AChatItem])
|
||||
case rcvFileSndCancelled(user: UserRef, chatItem: AChatItem, rcvFileTransfer: RcvFileTransfer)
|
||||
case sndFileComplete(user: UserRef, chatItem: AChatItem, sndFileTransfer: SndFileTransfer)
|
||||
case sndFileRcvCancelled(user: UserRef, chatItem_: AChatItem?, sndFileTransfer: SndFileTransfer)
|
||||
case callInvitation(callInvitation: RcvCallInvitation)
|
||||
case ntfMessage(user: UserRef, connEntity: ConnectionEntity, ntfMessage: NtfMsgAckInfo)
|
||||
|
||||
var responseType: String {
|
||||
switch self {
|
||||
case .chatSuspended: "chatSuspended"
|
||||
case .contactConnected: "contactConnected"
|
||||
case .receivedContactRequest: "receivedContactRequest"
|
||||
case .newChatItems: "newChatItems"
|
||||
case .rcvFileSndCancelled: "rcvFileSndCancelled"
|
||||
case .sndFileComplete: "sndFileComplete"
|
||||
case .sndFileRcvCancelled: "sndFileRcvCancelled"
|
||||
case .callInvitation: "callInvitation"
|
||||
case .ntfMessage: "ntfMessage"
|
||||
}
|
||||
}
|
||||
|
||||
var details: String {
|
||||
switch self {
|
||||
case .chatSuspended: return noDetails
|
||||
case let .contactConnected(u, contact, _): return withUser(u, String(describing: contact))
|
||||
case let .receivedContactRequest(u, contactRequest): return withUser(u, String(describing: contactRequest))
|
||||
case let .newChatItems(u, chatItems):
|
||||
let itemsString = chatItems.map { chatItem in String(describing: chatItem) }.joined(separator: "\n")
|
||||
return withUser(u, itemsString)
|
||||
case let .rcvFileSndCancelled(u, chatItem, _): return withUser(u, String(describing: chatItem))
|
||||
case let .sndFileComplete(u, chatItem, _): return withUser(u, String(describing: chatItem))
|
||||
case let .sndFileRcvCancelled(u, chatItem, _): return withUser(u, String(describing: chatItem))
|
||||
case let .callInvitation(inv): return String(describing: inv)
|
||||
case let .ntfMessage(u, connEntity, ntfMessage): return withUser(u, "connEntity: \(String(describing: connEntity))\nntfMessage: \(String(describing: ntfMessage))")
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -13,58 +13,58 @@ import SimpleXChat
|
|||
let logger = Logger()
|
||||
|
||||
func apiGetActiveUser() throws -> User? {
|
||||
let r = sendSimpleXCmd(.showActiveUser)
|
||||
let r: APIResult<SEChatResponse> = sendSimpleXCmd(SEChatCommand.showActiveUser)
|
||||
switch r {
|
||||
case let .activeUser(user): return user
|
||||
case .chatCmdError(_, .error(.noActiveUser)): return nil
|
||||
default: throw r
|
||||
case let .result(.activeUser(user)): return user
|
||||
case .error(.error(.noActiveUser)): return nil
|
||||
default: throw r.unexpected
|
||||
}
|
||||
}
|
||||
|
||||
func apiStartChat() throws -> Bool {
|
||||
let r = sendSimpleXCmd(.startChat(mainApp: false, enableSndFiles: true))
|
||||
let r: APIResult<SEChatResponse> = sendSimpleXCmd(SEChatCommand.startChat(mainApp: false, enableSndFiles: true))
|
||||
switch r {
|
||||
case .chatStarted: return true
|
||||
case .chatRunning: return false
|
||||
default: throw r
|
||||
case .result(.chatStarted): return true
|
||||
case .result(.chatRunning): return false
|
||||
default: throw r.unexpected
|
||||
}
|
||||
}
|
||||
|
||||
func apiSetNetworkConfig(_ cfg: NetCfg) throws {
|
||||
let r = sendSimpleXCmd(.apiSetNetworkConfig(networkConfig: cfg))
|
||||
if case .cmdOk = r { return }
|
||||
throw r
|
||||
let r: APIResult<SEChatResponse> = sendSimpleXCmd(SEChatCommand.apiSetNetworkConfig(networkConfig: cfg))
|
||||
if case .result(.cmdOk) = r { return }
|
||||
throw r.unexpected
|
||||
}
|
||||
|
||||
func apiSetAppFilePaths(filesFolder: String, tempFolder: String, assetsFolder: String) throws {
|
||||
let r = sendSimpleXCmd(.apiSetAppFilePaths(filesFolder: filesFolder, tempFolder: tempFolder, assetsFolder: assetsFolder))
|
||||
if case .cmdOk = r { return }
|
||||
throw r
|
||||
let r: APIResult<SEChatResponse> = sendSimpleXCmd(SEChatCommand.apiSetAppFilePaths(filesFolder: filesFolder, tempFolder: tempFolder, assetsFolder: assetsFolder))
|
||||
if case .result(.cmdOk) = r { return }
|
||||
throw r.unexpected
|
||||
}
|
||||
|
||||
func apiSetEncryptLocalFiles(_ enable: Bool) throws {
|
||||
let r = sendSimpleXCmd(.apiSetEncryptLocalFiles(enable: enable))
|
||||
if case .cmdOk = r { return }
|
||||
throw r
|
||||
let r: APIResult<SEChatResponse> = sendSimpleXCmd(SEChatCommand.apiSetEncryptLocalFiles(enable: enable))
|
||||
if case .result(.cmdOk) = r { return }
|
||||
throw r.unexpected
|
||||
}
|
||||
|
||||
func apiGetChats(userId: User.ID) throws -> Array<ChatData> {
|
||||
let r = sendSimpleXCmd(.apiGetChats(userId: userId))
|
||||
if case let .apiChats(user: _, chats: chats) = r { return chats }
|
||||
throw r
|
||||
let r: APIResult<SEChatResponse> = sendSimpleXCmd(SEChatCommand.apiGetChats(userId: userId))
|
||||
if case let .result(.apiChats(user: _, chats: chats)) = r { return chats }
|
||||
throw r.unexpected
|
||||
}
|
||||
|
||||
func apiSendMessages(
|
||||
chatInfo: ChatInfo,
|
||||
composedMessages: [ComposedMessage]
|
||||
) throws -> [AChatItem] {
|
||||
let r = sendSimpleXCmd(
|
||||
let r: APIResult<SEChatResponse> = sendSimpleXCmd(
|
||||
chatInfo.chatType == .local
|
||||
? .apiCreateChatItems(
|
||||
? SEChatCommand.apiCreateChatItems(
|
||||
noteFolderId: chatInfo.apiId,
|
||||
composedMessages: composedMessages
|
||||
)
|
||||
: .apiSendMessages(
|
||||
: SEChatCommand.apiSendMessages(
|
||||
type: chatInfo.chatType,
|
||||
id: chatInfo.apiId,
|
||||
live: false,
|
||||
|
@ -72,32 +72,33 @@ func apiSendMessages(
|
|||
composedMessages: composedMessages
|
||||
)
|
||||
)
|
||||
if case let .newChatItems(_, chatItems) = r {
|
||||
if case let .result(.newChatItems(_, chatItems)) = r {
|
||||
return chatItems
|
||||
} else {
|
||||
for composedMessage in composedMessages {
|
||||
if let filePath = composedMessage.fileSource?.filePath { removeFile(filePath) }
|
||||
}
|
||||
throw r
|
||||
throw r.unexpected
|
||||
}
|
||||
}
|
||||
|
||||
func apiActivateChat() throws {
|
||||
chatReopenStore()
|
||||
let r = sendSimpleXCmd(.apiActivateChat(restoreChat: false))
|
||||
if case .cmdOk = r { return }
|
||||
throw r
|
||||
let r: APIResult<SEChatResponse> = sendSimpleXCmd(SEChatCommand.apiActivateChat(restoreChat: false))
|
||||
if case .result(.cmdOk) = r { return }
|
||||
throw r.unexpected
|
||||
}
|
||||
|
||||
func apiSuspendChat(expired: Bool) {
|
||||
let r = sendSimpleXCmd(.apiSuspendChat(timeoutMicroseconds: expired ? 0 : 3_000000))
|
||||
let r: APIResult<SEChatResponse> = sendSimpleXCmd(SEChatCommand.apiSuspendChat(timeoutMicroseconds: expired ? 0 : 3_000000))
|
||||
// Block until `chatSuspended` received or 3 seconds has passed
|
||||
var suspended = false
|
||||
if case .cmdOk = r, !expired {
|
||||
if case .result(.cmdOk) = r, !expired {
|
||||
let startTime = CFAbsoluteTimeGetCurrent()
|
||||
while CFAbsoluteTimeGetCurrent() - startTime < 3 {
|
||||
switch recvSimpleXMsg(messageTimeout: 3_500000) {
|
||||
case .chatSuspended:
|
||||
let msg: APIResult<SEChatEvent>? = recvSimpleXMsg(messageTimeout: 3_500000)
|
||||
switch msg {
|
||||
case .result(.chatSuspended):
|
||||
suspended = false
|
||||
break
|
||||
default: continue
|
||||
|
@ -105,9 +106,121 @@ func apiSuspendChat(expired: Bool) {
|
|||
}
|
||||
}
|
||||
if !suspended {
|
||||
_ = sendSimpleXCmd(.apiSuspendChat(timeoutMicroseconds: 0))
|
||||
let _r1: APIResult<SEChatResponse> = sendSimpleXCmd(SEChatCommand.apiSuspendChat(timeoutMicroseconds: 0))
|
||||
}
|
||||
logger.debug("close store")
|
||||
chatCloseStore()
|
||||
SEChatState.shared.set(.inactive)
|
||||
}
|
||||
|
||||
enum SEChatCommand: ChatCmdProtocol {
|
||||
case showActiveUser
|
||||
case startChat(mainApp: Bool, enableSndFiles: Bool)
|
||||
case apiActivateChat(restoreChat: Bool)
|
||||
case apiSuspendChat(timeoutMicroseconds: Int)
|
||||
case apiSetNetworkConfig(networkConfig: NetCfg)
|
||||
case apiSetAppFilePaths(filesFolder: String, tempFolder: String, assetsFolder: String)
|
||||
case apiSetEncryptLocalFiles(enable: Bool)
|
||||
case apiGetChats(userId: Int64)
|
||||
case apiCreateChatItems(noteFolderId: Int64, composedMessages: [ComposedMessage])
|
||||
case apiSendMessages(type: ChatType, id: Int64, live: Bool, ttl: Int?, composedMessages: [ComposedMessage])
|
||||
|
||||
var cmdString: String {
|
||||
switch self {
|
||||
case .showActiveUser: return "/u"
|
||||
case let .startChat(mainApp, enableSndFiles): return "/_start main=\(onOff(mainApp)) snd_files=\(onOff(enableSndFiles))"
|
||||
case let .apiActivateChat(restore): return "/_app activate restore=\(onOff(restore))"
|
||||
case let .apiSuspendChat(timeoutMicroseconds): return "/_app suspend \(timeoutMicroseconds)"
|
||||
case let .apiSetNetworkConfig(networkConfig): return "/_network \(encodeJSON(networkConfig))"
|
||||
case let .apiSetAppFilePaths(filesFolder, tempFolder, assetsFolder):
|
||||
return "/set file paths \(encodeJSON(AppFilePaths(appFilesFolder: filesFolder, appTempFolder: tempFolder, appAssetsFolder: assetsFolder)))"
|
||||
case let .apiSetEncryptLocalFiles(enable): return "/_files_encrypt \(onOff(enable))"
|
||||
case let .apiGetChats(userId): return "/_get chats \(userId) pcc=on"
|
||||
case let .apiCreateChatItems(noteFolderId, composedMessages):
|
||||
let msgs = encodeJSON(composedMessages)
|
||||
return "/_create *\(noteFolderId) json \(msgs)"
|
||||
case let .apiSendMessages(type, id, live, ttl, composedMessages):
|
||||
let msgs = encodeJSON(composedMessages)
|
||||
let ttlStr = ttl != nil ? "\(ttl!)" : "default"
|
||||
return "/_send \(ref(type, id)) live=\(onOff(live)) ttl=\(ttlStr) json \(msgs)"
|
||||
}
|
||||
}
|
||||
|
||||
func ref(_ type: ChatType, _ id: Int64) -> String {
|
||||
"\(type.rawValue)\(id)"
|
||||
}
|
||||
}
|
||||
|
||||
enum SEChatResponse: Decodable, ChatAPIResult {
|
||||
case activeUser(user: User)
|
||||
case chatStarted
|
||||
case chatRunning
|
||||
case apiChats(user: UserRef, chats: [ChatData])
|
||||
case newChatItems(user: UserRef, chatItems: [AChatItem])
|
||||
case cmdOk(user_: UserRef?)
|
||||
|
||||
var responseType: String {
|
||||
switch self {
|
||||
case .activeUser: "activeUser"
|
||||
case .chatStarted: "chatStarted"
|
||||
case .chatRunning: "chatRunning"
|
||||
case .apiChats: "apiChats"
|
||||
case .newChatItems: "newChatItems"
|
||||
case .cmdOk: "cmdOk"
|
||||
}
|
||||
}
|
||||
|
||||
var details: String {
|
||||
switch self {
|
||||
case let .activeUser(user): return String(describing: user)
|
||||
case .chatStarted: return noDetails
|
||||
case .chatRunning: return noDetails
|
||||
case let .apiChats(u, chats): return withUser(u, String(describing: chats))
|
||||
case let .newChatItems(u, chatItems):
|
||||
let itemsString = chatItems.map { chatItem in String(describing: chatItem) }.joined(separator: "\n")
|
||||
return withUser(u, itemsString)
|
||||
case .cmdOk: return noDetails
|
||||
}
|
||||
}
|
||||
|
||||
static func fallbackResult(_ type: String, _ json: NSDictionary) -> SEChatResponse? {
|
||||
if type == "apiChats", let r = parseApiChats(json) {
|
||||
.apiChats(user: r.user, chats: r.chats)
|
||||
} else {
|
||||
nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum SEChatEvent: Decodable, ChatAPIResult {
|
||||
case chatSuspended
|
||||
case sndFileProgressXFTP(user: UserRef, chatItem_: AChatItem?, fileTransferMeta: FileTransferMeta, sentSize: Int64, totalSize: Int64)
|
||||
case sndFileCompleteXFTP(user: UserRef, chatItem: AChatItem, fileTransferMeta: FileTransferMeta)
|
||||
case chatItemsStatusesUpdated(user: UserRef, chatItems: [AChatItem])
|
||||
case sndFileError(user: UserRef, chatItem_: AChatItem?, fileTransferMeta: FileTransferMeta, errorMessage: String)
|
||||
case sndFileWarning(user: UserRef, chatItem_: AChatItem?, fileTransferMeta: FileTransferMeta, errorMessage: String)
|
||||
|
||||
var responseType: String {
|
||||
switch self {
|
||||
case .chatSuspended: "chatSuspended"
|
||||
case .sndFileProgressXFTP: "sndFileProgressXFTP"
|
||||
case .sndFileCompleteXFTP: "sndFileCompleteXFTP"
|
||||
case .chatItemsStatusesUpdated: "chatItemsStatusesUpdated"
|
||||
case .sndFileError: "sndFileError"
|
||||
case .sndFileWarning: "sndFileWarning"
|
||||
}
|
||||
}
|
||||
|
||||
var details: String {
|
||||
switch self {
|
||||
case .chatSuspended: return noDetails
|
||||
case let .sndFileProgressXFTP(u, chatItem, _, sentSize, totalSize): return withUser(u, "chatItem: \(String(describing: chatItem))\nsentSize: \(sentSize)\ntotalSize: \(totalSize)")
|
||||
case let .sndFileCompleteXFTP(u, chatItem, _): return withUser(u, String(describing: chatItem))
|
||||
case let .chatItemsStatusesUpdated(u, chatItems):
|
||||
let itemsString = chatItems.map { chatItem in String(describing: chatItem) }.joined(separator: "\n")
|
||||
return withUser(u, itemsString)
|
||||
case let .sndFileError(u, chatItem, _, err): return withUser(u, "error: \(String(describing: err))\nchatItem: \(String(describing: chatItem))")
|
||||
case let .sndFileWarning(u, chatItem, _, err): return withUser(u, "error: \(String(describing: err))\nchatItem: \(String(describing: chatItem))")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -179,7 +179,7 @@ class ShareModel: ObservableObject {
|
|||
resetChatCtrl() // Clears retained migration result
|
||||
registerGroupDefaults()
|
||||
haskell_init_se()
|
||||
let (_, result) = chatMigrateInit(dbKey, confirmMigrations: defaultMigrationConfirmation())
|
||||
let (_, result) = chatMigrateInit(dbKey, confirmMigrations: defaultMigrationConfirmation(), backgroundMode: false)
|
||||
if let e = migrationError(result) { return e }
|
||||
try apiSetAppFilePaths(
|
||||
filesFolder: getAppFilesDirectory().path,
|
||||
|
@ -303,8 +303,9 @@ class ShareModel: ObservableObject {
|
|||
}
|
||||
}
|
||||
}
|
||||
switch recvSimpleXMsg(messageTimeout: 1_000_000) {
|
||||
case let .sndFileProgressXFTP(_, ci, _, sentSize, totalSize):
|
||||
let r: APIResult<SEChatEvent>? = recvSimpleXMsg(messageTimeout: 1_000_000)
|
||||
switch r {
|
||||
case let .result(.sndFileProgressXFTP(_, ci, _, sentSize, totalSize)):
|
||||
guard isMessage(for: ci) else { continue }
|
||||
networkTimeout = CFAbsoluteTimeGetCurrent()
|
||||
await MainActor.run {
|
||||
|
@ -313,14 +314,14 @@ class ShareModel: ObservableObject {
|
|||
bottomBar = .loadingBar(progress: progress)
|
||||
}
|
||||
}
|
||||
case let .sndFileCompleteXFTP(_, ci, _):
|
||||
case let .result(.sndFileCompleteXFTP(_, ci, _)):
|
||||
guard isMessage(for: ci) else { continue }
|
||||
if isGroupChat {
|
||||
await MainActor.run { bottomBar = .loadingSpinner }
|
||||
}
|
||||
await ch.completeFile()
|
||||
if await !ch.isRunning { break }
|
||||
case let .chatItemsStatusesUpdated(_, chatItems):
|
||||
case let .result(.chatItemsStatusesUpdated(_, chatItems)):
|
||||
guard let ci = chatItems.last else { continue }
|
||||
guard isMessage(for: ci) else { continue }
|
||||
if let (title, message) = ci.chatItem.meta.itemStatus.statusInfo {
|
||||
|
@ -342,17 +343,15 @@ class ShareModel: ObservableObject {
|
|||
}
|
||||
}
|
||||
}
|
||||
case let .sndFileError(_, ci, _, errorMessage):
|
||||
case let .result(.sndFileError(_, ci, _, errorMessage)):
|
||||
guard isMessage(for: ci) else { continue }
|
||||
if let ci { cleanupFile(ci) }
|
||||
return ErrorAlert(title: "File error", message: "\(fileErrorInfo(ci) ?? errorMessage)")
|
||||
case let .sndFileWarning(_, ci, _, errorMessage):
|
||||
case let .result(.sndFileWarning(_, ci, _, errorMessage)):
|
||||
guard isMessage(for: ci) else { continue }
|
||||
if let ci { cleanupFile(ci) }
|
||||
return ErrorAlert(title: "File error", message: "\(fileErrorInfo(ci) ?? errorMessage)")
|
||||
case let .chatError(_, chatError):
|
||||
return ErrorAlert(chatError)
|
||||
case let .chatCmdError(_, chatError):
|
||||
case let .error(chatError):
|
||||
return ErrorAlert(chatError)
|
||||
default: continue
|
||||
}
|
||||
|
|
|
@ -247,6 +247,8 @@
|
|||
E5DCF9712C590272007928CC /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = E5DCF96F2C590272007928CC /* Localizable.strings */; };
|
||||
E5DCF9842C5902CE007928CC /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = E5DCF9822C5902CE007928CC /* Localizable.strings */; };
|
||||
E5DCF9982C5906FF007928CC /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = E5DCF9962C5906FF007928CC /* InfoPlist.strings */; };
|
||||
E5DDBE6E2DC4106800A0EFF0 /* AppAPITypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = E5DDBE6D2DC4106200A0EFF0 /* AppAPITypes.swift */; };
|
||||
E5DDBE702DC4217900A0EFF0 /* NSEAPITypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = E5DDBE6F2DC4217900A0EFF0 /* NSEAPITypes.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
|
@ -653,6 +655,8 @@
|
|||
E5DCF9A62C590731007928CC /* th */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = th; path = th.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||
E5DCF9A72C590732007928CC /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||
E5DCF9A82C590732007928CC /* uk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = uk; path = uk.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||
E5DDBE6D2DC4106200A0EFF0 /* AppAPITypes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppAPITypes.swift; sourceTree = "<group>"; };
|
||||
E5DDBE6F2DC4217900A0EFF0 /* NSEAPITypes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSEAPITypes.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
|
@ -805,6 +809,7 @@
|
|||
5C764E87279CBC8E000C6508 /* Model */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E5DDBE6D2DC4106200A0EFF0 /* AppAPITypes.swift */,
|
||||
5C764E88279CBCB3000C6508 /* ChatModel.swift */,
|
||||
5C2E260627A2941F00F70299 /* SimpleXAPI.swift */,
|
||||
5C35CFC727B2782E00FB6C6D /* BGManager.swift */,
|
||||
|
@ -1000,6 +1005,7 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
5CDCAD5128186DE400503DA2 /* SimpleX NSE.entitlements */,
|
||||
E5DDBE6F2DC4217900A0EFF0 /* NSEAPITypes.swift */,
|
||||
5CDCAD472818589900503DA2 /* NotificationService.swift */,
|
||||
5CDCAD492818589900503DA2 /* Info.plist */,
|
||||
5CB0BA862826CB3A00B3292C /* InfoPlist.strings */,
|
||||
|
@ -1016,9 +1022,9 @@
|
|||
5CDCAD7228188CFF00503DA2 /* ChatTypes.swift */,
|
||||
5CDCAD7428188D2900503DA2 /* APITypes.swift */,
|
||||
5C5E5D3C282447AB00B0488A /* CallTypes.swift */,
|
||||
5CDCAD7D2818941F00503DA2 /* API.swift */,
|
||||
CE3097FA2C4C0C9F00180898 /* ErrorAlert.swift */,
|
||||
5C9FD96A27A56D4D0075386C /* JSON.swift */,
|
||||
5CDCAD7D2818941F00503DA2 /* API.swift */,
|
||||
5CDCAD80281A7E2700503DA2 /* Notifications.swift */,
|
||||
5CBD2859295711D700EC2CF4 /* ImageUtils.swift */,
|
||||
CE2AD9CD2C452A4D00E844E3 /* ChatUtils.swift */,
|
||||
|
@ -1544,6 +1550,7 @@
|
|||
5CA059EB279559F40002BEB4 /* SimpleXApp.swift in Sources */,
|
||||
64D0C2C029F9688300B38D5F /* UserAddressView.swift in Sources */,
|
||||
6448BBB628FA9D56000D2AB9 /* GroupLinkView.swift in Sources */,
|
||||
E5DDBE6E2DC4106800A0EFF0 /* AppAPITypes.swift in Sources */,
|
||||
8C9BC2652C240D5200875A27 /* ThemeModeEditor.swift in Sources */,
|
||||
5CB346E92869E8BA001FD2EF /* PushEnvironment.swift in Sources */,
|
||||
5C55A91F283AD0E400C4E99E /* CallManager.swift in Sources */,
|
||||
|
@ -1616,6 +1623,7 @@
|
|||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
5CDCAD482818589900503DA2 /* NotificationService.swift in Sources */,
|
||||
E5DDBE702DC4217900A0EFF0 /* NSEAPITypes.swift in Sources */,
|
||||
5CFE0922282EEAF60002594B /* ZoomableScrollView.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
@ -1973,7 +1981,7 @@
|
|||
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 273;
|
||||
CURRENT_PROJECT_VERSION = 274;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
ENABLE_BITCODE = NO;
|
||||
|
@ -1998,7 +2006,7 @@
|
|||
"@executable_path/Frameworks",
|
||||
);
|
||||
LLVM_LTO = YES_THIN;
|
||||
MARKETING_VERSION = 6.3.3;
|
||||
MARKETING_VERSION = 6.3.4;
|
||||
OTHER_LDFLAGS = "-Wl,-stack_size,0x1000000";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.app;
|
||||
PRODUCT_NAME = SimpleX;
|
||||
|
@ -2023,7 +2031,7 @@
|
|||
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 273;
|
||||
CURRENT_PROJECT_VERSION = 274;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
ENABLE_BITCODE = NO;
|
||||
|
@ -2048,7 +2056,7 @@
|
|||
"@executable_path/Frameworks",
|
||||
);
|
||||
LLVM_LTO = YES;
|
||||
MARKETING_VERSION = 6.3.3;
|
||||
MARKETING_VERSION = 6.3.4;
|
||||
OTHER_LDFLAGS = "-Wl,-stack_size,0x1000000";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.app;
|
||||
PRODUCT_NAME = SimpleX;
|
||||
|
@ -2065,11 +2073,11 @@
|
|||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 273;
|
||||
CURRENT_PROJECT_VERSION = 274;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
MARKETING_VERSION = 6.3.3;
|
||||
MARKETING_VERSION = 6.3.4;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.Tests-iOS";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = iphoneos;
|
||||
|
@ -2085,11 +2093,11 @@
|
|||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 273;
|
||||
CURRENT_PROJECT_VERSION = 274;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
MARKETING_VERSION = 6.3.3;
|
||||
MARKETING_VERSION = 6.3.4;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.Tests-iOS";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = iphoneos;
|
||||
|
@ -2110,7 +2118,7 @@
|
|||
CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements";
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 273;
|
||||
CURRENT_PROJECT_VERSION = 274;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
ENABLE_BITCODE = NO;
|
||||
GCC_OPTIMIZATION_LEVEL = s;
|
||||
|
@ -2125,7 +2133,7 @@
|
|||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
LLVM_LTO = YES;
|
||||
MARKETING_VERSION = 6.3.3;
|
||||
MARKETING_VERSION = 6.3.4;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.app.SimpleX-NSE";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
|
@ -2147,7 +2155,7 @@
|
|||
CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements";
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 273;
|
||||
CURRENT_PROJECT_VERSION = 274;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
ENABLE_BITCODE = NO;
|
||||
ENABLE_CODE_COVERAGE = NO;
|
||||
|
@ -2162,7 +2170,7 @@
|
|||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
LLVM_LTO = YES;
|
||||
MARKETING_VERSION = 6.3.3;
|
||||
MARKETING_VERSION = 6.3.4;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.app.SimpleX-NSE";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
|
@ -2184,7 +2192,7 @@
|
|||
CLANG_TIDY_BUGPRONE_REDUNDANT_BRANCH_CONDITION = YES;
|
||||
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 273;
|
||||
CURRENT_PROJECT_VERSION = 274;
|
||||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
|
@ -2210,7 +2218,7 @@
|
|||
"$(PROJECT_DIR)/Libraries/sim",
|
||||
);
|
||||
LLVM_LTO = YES;
|
||||
MARKETING_VERSION = 6.3.3;
|
||||
MARKETING_VERSION = 6.3.4;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.SimpleXChat;
|
||||
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||
SDKROOT = iphoneos;
|
||||
|
@ -2235,7 +2243,7 @@
|
|||
CLANG_TIDY_BUGPRONE_REDUNDANT_BRANCH_CONDITION = YES;
|
||||
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 273;
|
||||
CURRENT_PROJECT_VERSION = 274;
|
||||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
|
@ -2261,7 +2269,7 @@
|
|||
"$(PROJECT_DIR)/Libraries/sim",
|
||||
);
|
||||
LLVM_LTO = YES;
|
||||
MARKETING_VERSION = 6.3.3;
|
||||
MARKETING_VERSION = 6.3.4;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.SimpleXChat;
|
||||
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||
SDKROOT = iphoneos;
|
||||
|
@ -2286,7 +2294,7 @@
|
|||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||
CODE_SIGN_ENTITLEMENTS = "SimpleX SE/SimpleX SE.entitlements";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 273;
|
||||
CURRENT_PROJECT_VERSION = 274;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||
|
@ -2301,7 +2309,7 @@
|
|||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||
MARKETING_VERSION = 6.3.3;
|
||||
MARKETING_VERSION = 6.3.4;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.app.SimpleX-SE";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = iphoneos;
|
||||
|
@ -2320,7 +2328,7 @@
|
|||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||
CODE_SIGN_ENTITLEMENTS = "SimpleX SE/SimpleX SE.entitlements";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 273;
|
||||
CURRENT_PROJECT_VERSION = 274;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||
|
@ -2335,7 +2343,7 @@
|
|||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||
MARKETING_VERSION = 6.3.3;
|
||||
MARKETING_VERSION = 6.3.4;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.app.SimpleX-SE";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = iphoneos;
|
||||
|
|
|
@ -46,7 +46,7 @@ public func chatMigrateInit(_ useKey: String? = nil, confirmMigrations: Migratio
|
|||
var cConfirm = confirm.rawValue.cString(using: .utf8)!
|
||||
// the last parameter of chat_migrate_init is used to return the pointer to chat controller
|
||||
let cjson = chat_migrate_init_key(&cPath, &cKey, 1, &cConfirm, backgroundMode ? 1 : 0, &chatController)!
|
||||
let dbRes = dbMigrationResult(fromCString(cjson))
|
||||
let dbRes = dbMigrationResult(dataFromCString(cjson))
|
||||
let encrypted = dbKey != ""
|
||||
let keychainErr = dbRes == .ok && useKeychain && encrypted && !kcDatabasePassword.set(dbKey)
|
||||
let result = (encrypted, keychainErr ? .errorKeychain : dbRes)
|
||||
|
@ -63,7 +63,7 @@ public func chatInitTemporaryDatabase(url: URL, key: String? = nil, confirmation
|
|||
var cKey = dbKey.cString(using: .utf8)!
|
||||
var cConfirm = confirmation.rawValue.cString(using: .utf8)!
|
||||
let cjson = chat_migrate_init_key(&cPath, &cKey, 1, &cConfirm, 0, &temporaryController)!
|
||||
return (dbMigrationResult(fromCString(cjson)), temporaryController)
|
||||
return (dbMigrationResult(dataFromCString(cjson)), temporaryController)
|
||||
}
|
||||
|
||||
public func chatInitControllerRemovingDatabases() {
|
||||
|
@ -110,27 +110,42 @@ public func resetChatCtrl() {
|
|||
migrationResult = nil
|
||||
}
|
||||
|
||||
public func sendSimpleXCmd(_ cmd: ChatCommand, _ ctrl: chat_ctrl? = nil) -> ChatResponse {
|
||||
var c = cmd.cmdString.cString(using: .utf8)!
|
||||
let cjson = chat_send_cmd(ctrl ?? getChatCtrl(), &c)!
|
||||
return chatResponse(fromCString(cjson))
|
||||
@inline(__always)
|
||||
public func sendSimpleXCmd<R: ChatAPIResult>(_ cmd: ChatCmdProtocol, _ ctrl: chat_ctrl? = nil) -> APIResult<R> {
|
||||
if let d = sendSimpleXCmdStr(cmd.cmdString, ctrl) {
|
||||
decodeAPIResult(d)
|
||||
} else {
|
||||
APIResult.error(.invalidJSON(json: nil))
|
||||
}
|
||||
}
|
||||
|
||||
@inline(__always)
|
||||
public func sendSimpleXCmdStr(_ cmd: String, _ ctrl: chat_ctrl? = nil) -> Data? {
|
||||
var c = cmd.cString(using: .utf8)!
|
||||
return if let cjson = chat_send_cmd(ctrl ?? getChatCtrl(), &c) {
|
||||
dataFromCString(cjson)
|
||||
} else {
|
||||
nil
|
||||
}
|
||||
}
|
||||
|
||||
// in microseconds
|
||||
public let MESSAGE_TIMEOUT: Int32 = 15_000_000
|
||||
|
||||
public func recvSimpleXMsg(_ ctrl: chat_ctrl? = nil, messageTimeout: Int32 = MESSAGE_TIMEOUT) -> ChatResponse? {
|
||||
if let cjson = chat_recv_msg_wait(ctrl ?? getChatCtrl(), messageTimeout) {
|
||||
let s = fromCString(cjson)
|
||||
return s == "" ? nil : chatResponse(s)
|
||||
@inline(__always)
|
||||
public func recvSimpleXMsg<R: ChatAPIResult>(_ ctrl: chat_ctrl? = nil, messageTimeout: Int32 = MESSAGE_TIMEOUT) -> APIResult<R>? {
|
||||
if let cjson = chat_recv_msg_wait(ctrl ?? getChatCtrl(), messageTimeout),
|
||||
let d = dataFromCString(cjson) {
|
||||
decodeAPIResult(d)
|
||||
} else {
|
||||
nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
public func parseSimpleXMarkdown(_ s: String) -> [FormattedText]? {
|
||||
var c = s.cString(using: .utf8)!
|
||||
if let cjson = chat_parse_markdown(&c) {
|
||||
if let d = fromCString(cjson).data(using: .utf8) {
|
||||
if let d = dataFromCString(cjson) {
|
||||
do {
|
||||
let r = try jsonDecoder.decode(ParsedMarkdown.self, from: d)
|
||||
return r.formattedText
|
||||
|
@ -154,7 +169,7 @@ struct ParsedMarkdown: Decodable {
|
|||
public func parseServerAddress(_ s: String) -> ServerAddress? {
|
||||
var c = s.cString(using: .utf8)!
|
||||
if let cjson = chat_parse_server(&c) {
|
||||
if let d = fromCString(cjson).data(using: .utf8) {
|
||||
if let d = dataFromCString(cjson) {
|
||||
do {
|
||||
let r = try jsonDecoder.decode(ParsedServerAddress.self, from: d)
|
||||
return r.serverAddress
|
||||
|
@ -171,95 +186,34 @@ struct ParsedServerAddress: Decodable {
|
|||
var parseError: String
|
||||
}
|
||||
|
||||
@inline(__always)
|
||||
public func fromCString(_ c: UnsafeMutablePointer<CChar>) -> String {
|
||||
let s = String.init(cString: c)
|
||||
free(c)
|
||||
return s
|
||||
}
|
||||
|
||||
public func chatResponse(_ s: String) -> ChatResponse {
|
||||
let d = s.data(using: .utf8)!
|
||||
// TODO is there a way to do it without copying the data? e.g:
|
||||
// let p = UnsafeMutableRawPointer.init(mutating: UnsafeRawPointer(cjson))
|
||||
// let d = Data.init(bytesNoCopy: p, count: strlen(cjson), deallocator: .free)
|
||||
do {
|
||||
let r = try callWithLargeStack {
|
||||
try jsonDecoder.decode(APIResponse.self, from: d)
|
||||
}
|
||||
return r.resp
|
||||
} catch {
|
||||
logger.error("chatResponse jsonDecoder.decode error: \(error.localizedDescription)")
|
||||
}
|
||||
|
||||
var type: String?
|
||||
var json: String?
|
||||
if let j = try? JSONSerialization.jsonObject(with: d) as? NSDictionary {
|
||||
if let jResp = j["resp"] as? NSDictionary, jResp.count == 1 || jResp.count == 2 {
|
||||
type = jResp.allKeys[0] as? String
|
||||
if jResp.count == 2 && type == "_owsf" {
|
||||
type = jResp.allKeys[1] as? String
|
||||
}
|
||||
if type == "apiChats" {
|
||||
if let jApiChats = jResp["apiChats"] as? NSDictionary,
|
||||
let user: UserRef = try? decodeObject(jApiChats["user"] as Any),
|
||||
let jChats = jApiChats["chats"] as? NSArray {
|
||||
let chats = jChats.map { jChat in
|
||||
if let chatData = try? parseChatData(jChat) {
|
||||
return chatData.0
|
||||
}
|
||||
return ChatData.invalidJSON(serializeJSON(jChat, options: .prettyPrinted) ?? "")
|
||||
}
|
||||
return .apiChats(user: user, chats: chats)
|
||||
}
|
||||
} else if type == "apiChat" {
|
||||
if let jApiChat = jResp["apiChat"] as? NSDictionary,
|
||||
let user: UserRef = try? decodeObject(jApiChat["user"] as Any),
|
||||
let jChat = jApiChat["chat"] as? NSDictionary,
|
||||
let (chat, navInfo) = try? parseChatData(jChat, jApiChat["navInfo"] as? NSDictionary) {
|
||||
return .apiChat(user: user, chat: chat, navInfo: navInfo)
|
||||
}
|
||||
} else if type == "chatCmdError" {
|
||||
if let jError = jResp["chatCmdError"] as? NSDictionary {
|
||||
return .chatCmdError(user_: decodeUser_(jError), chatError: .invalidJSON(json: errorJson(jError) ?? ""))
|
||||
}
|
||||
} else if type == "chatError" {
|
||||
if let jError = jResp["chatError"] as? NSDictionary {
|
||||
return .chatError(user_: decodeUser_(jError), chatError: .invalidJSON(json: errorJson(jError) ?? ""))
|
||||
}
|
||||
}
|
||||
}
|
||||
json = serializeJSON(j, options: .prettyPrinted)
|
||||
}
|
||||
return ChatResponse.response(type: type ?? "invalid", json: json ?? s)
|
||||
}
|
||||
|
||||
private let largeStackSize: Int = 2 * 1024 * 1024
|
||||
|
||||
private func callWithLargeStack<T>(_ f: @escaping () throws -> T) throws -> T {
|
||||
let semaphore = DispatchSemaphore(value: 0)
|
||||
var result: Result<T, Error>?
|
||||
let thread = Thread {
|
||||
do {
|
||||
result = .success(try f())
|
||||
} catch {
|
||||
result = .failure(error)
|
||||
}
|
||||
semaphore.signal()
|
||||
}
|
||||
|
||||
thread.stackSize = largeStackSize
|
||||
thread.qualityOfService = Thread.current.qualityOfService
|
||||
thread.start()
|
||||
|
||||
semaphore.wait()
|
||||
|
||||
switch result! {
|
||||
case let .success(r): return r
|
||||
case let .failure(e): throw e
|
||||
@inline(__always)
|
||||
public func dataFromCString(_ c: UnsafeMutablePointer<CChar>) -> Data? {
|
||||
let len = strlen(c)
|
||||
if len > 0 {
|
||||
return Data(bytesNoCopy: c, count: len, deallocator: .free)
|
||||
} else {
|
||||
free(c)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
private func decodeUser_(_ jDict: NSDictionary) -> UserRef? {
|
||||
@inline(__always)
|
||||
public func dataToString(_ d: Data?) -> String {
|
||||
if let d {
|
||||
String(data: d, encoding: .utf8) ?? "invalid string"
|
||||
} else {
|
||||
"no data"
|
||||
}
|
||||
}
|
||||
|
||||
public func decodeUser_(_ jDict: NSDictionary) -> UserRef? {
|
||||
if let user_ = jDict["user_"] {
|
||||
try? decodeObject(user_ as Any)
|
||||
} else {
|
||||
|
@ -267,7 +221,7 @@ private func decodeUser_(_ jDict: NSDictionary) -> UserRef? {
|
|||
}
|
||||
}
|
||||
|
||||
private func errorJson(_ jDict: NSDictionary) -> String? {
|
||||
public func errorJson(_ jDict: NSDictionary) -> Data? {
|
||||
if let chatError = jDict["chatError"] {
|
||||
serializeJSON(chatError)
|
||||
} else {
|
||||
|
@ -275,11 +229,15 @@ private func errorJson(_ jDict: NSDictionary) -> String? {
|
|||
}
|
||||
}
|
||||
|
||||
func parseChatData(_ jChat: Any, _ jNavInfo: Any? = nil) throws -> (ChatData, NavigationInfo) {
|
||||
public func parseChatData(_ jChat: Any, _ jNavInfo: Any? = nil) throws -> (ChatData, NavigationInfo) {
|
||||
let jChatDict = jChat as! NSDictionary
|
||||
let chatInfo: ChatInfo = try decodeObject(jChatDict["chatInfo"]!)
|
||||
let chatStats: ChatStats = try decodeObject(jChatDict["chatStats"]!)
|
||||
let navInfo: NavigationInfo = jNavInfo == nil ? NavigationInfo() : try decodeObject((jNavInfo as! NSDictionary)["navInfo"]!)
|
||||
let navInfo: NavigationInfo = if let jNavInfo = jNavInfo as? NSDictionary, let jNav = jNavInfo["navInfo"] {
|
||||
try decodeObject(jNav)
|
||||
} else {
|
||||
NavigationInfo()
|
||||
}
|
||||
let jChatItems = jChatDict["chatItems"] as! NSArray
|
||||
let chatItems = jChatItems.map { jCI in
|
||||
if let ci: ChatItem = try? decodeObject(jCI) {
|
||||
|
@ -288,16 +246,18 @@ func parseChatData(_ jChat: Any, _ jNavInfo: Any? = nil) throws -> (ChatData, Na
|
|||
return ChatItem.invalidJSON(
|
||||
chatDir: decodeProperty(jCI, "chatDir"),
|
||||
meta: decodeProperty(jCI, "meta"),
|
||||
json: serializeJSON(jCI, options: .prettyPrinted) ?? ""
|
||||
json: serializeJSON(jCI, options: .prettyPrinted)
|
||||
)
|
||||
}
|
||||
return (ChatData(chatInfo: chatInfo, chatItems: chatItems, chatStats: chatStats), navInfo)
|
||||
}
|
||||
|
||||
func decodeObject<T: Decodable>(_ obj: Any) throws -> T {
|
||||
@inline(__always)
|
||||
public func decodeObject<T: Decodable>(_ obj: Any) throws -> T {
|
||||
try jsonDecoder.decode(T.self, from: JSONSerialization.data(withJSONObject: obj))
|
||||
}
|
||||
|
||||
@inline(__always)
|
||||
func decodeProperty<T: Decodable>(_ obj: Any, _ prop: NSString) -> T? {
|
||||
if let jProp = (obj as? NSDictionary)?[prop] {
|
||||
return try? decodeObject(jProp)
|
||||
|
@ -305,28 +265,52 @@ func decodeProperty<T: Decodable>(_ obj: Any, _ prop: NSString) -> T? {
|
|||
return nil
|
||||
}
|
||||
|
||||
func serializeJSON(_ obj: Any, options: JSONSerialization.WritingOptions = []) -> String? {
|
||||
if let d = try? JSONSerialization.data(withJSONObject: obj, options: options) {
|
||||
return String(decoding: d, as: UTF8.self)
|
||||
@inline(__always)
|
||||
func getOWSF(_ obj: NSDictionary, _ prop: NSString) -> (type: String, object: NSDictionary)? {
|
||||
if let j = obj[prop] as? NSDictionary, j.count == 1 || j.count == 2 {
|
||||
var type = j.allKeys[0] as? String
|
||||
if j.count == 2 && type == "_owsf" {
|
||||
type = j.allKeys[1] as? String
|
||||
}
|
||||
if let type {
|
||||
return (type, j)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
public func responseError(_ err: Error) -> String {
|
||||
if let r = err as? ChatResponse {
|
||||
switch r {
|
||||
case let .chatCmdError(_, chatError): return chatErrorString(chatError)
|
||||
case let .chatError(_, chatError): return chatErrorString(chatError)
|
||||
default: return "\(String(describing: r.responseType)), details: \(String(describing: r.details))"
|
||||
}
|
||||
@inline(__always)
|
||||
public func serializeJSON(_ obj: Any, options: JSONSerialization.WritingOptions = []) -> Data? {
|
||||
if let d = try? JSONSerialization.data(withJSONObject: obj, options: options) {
|
||||
dataPrefix(d)
|
||||
} else {
|
||||
return String(describing: err)
|
||||
nil
|
||||
}
|
||||
}
|
||||
|
||||
let MAX_JSON_VIEW_LENGTH = 2048
|
||||
|
||||
@inline(__always)
|
||||
public func dataPrefix(_ d: Data) -> Data {
|
||||
d.count > MAX_JSON_VIEW_LENGTH
|
||||
? Data(d.prefix(MAX_JSON_VIEW_LENGTH))
|
||||
: d
|
||||
}
|
||||
|
||||
public func responseError(_ err: Error) -> String {
|
||||
if let e = err as? ChatError {
|
||||
chatErrorString(e)
|
||||
} else {
|
||||
String(describing: err)
|
||||
}
|
||||
}
|
||||
|
||||
public func chatErrorString(_ err: ChatError) -> String {
|
||||
if case let .invalidJSON(json) = err { return json }
|
||||
return String(describing: err)
|
||||
switch err {
|
||||
case let .invalidJSON(json): dataToString(json)
|
||||
case let .unexpectedResult(type): "unexpected result: \(type)"
|
||||
default: String(describing: err)
|
||||
}
|
||||
}
|
||||
|
||||
public enum DBMigrationResult: Decodable, Equatable {
|
||||
|
@ -365,15 +349,15 @@ public enum MTRError: Decodable, Equatable {
|
|||
case different(appMigration: String, dbMigration: String)
|
||||
}
|
||||
|
||||
func dbMigrationResult(_ s: String) -> DBMigrationResult {
|
||||
let d = s.data(using: .utf8)!
|
||||
// TODO is there a way to do it without copying the data? e.g:
|
||||
// let p = UnsafeMutableRawPointer.init(mutating: UnsafeRawPointer(cjson))
|
||||
// let d = Data.init(bytesNoCopy: p, count: strlen(cjson), deallocator: .free)
|
||||
do {
|
||||
return try jsonDecoder.decode(DBMigrationResult.self, from: d)
|
||||
} catch let error {
|
||||
logger.error("chatResponse jsonDecoder.decode error: \(error.localizedDescription)")
|
||||
return .unknown(json: s)
|
||||
func dbMigrationResult(_ d: Data?) -> DBMigrationResult {
|
||||
if let d {
|
||||
do {
|
||||
return try jsonDecoder.decode(DBMigrationResult.self, from: d)
|
||||
} catch let error {
|
||||
logger.error("chatResponse jsonDecoder.decode error: \(error.localizedDescription)")
|
||||
return .unknown(json: dataToString(d))
|
||||
}
|
||||
} else {
|
||||
return .unknown(json: "no data")
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -40,7 +40,7 @@ let GROUP_DEFAULT_NETWORK_USE_ONION_HOSTS = "networkUseOnionHosts"
|
|||
let GROUP_DEFAULT_NETWORK_SESSION_MODE = "networkSessionMode"
|
||||
let GROUP_DEFAULT_NETWORK_SMP_PROXY_MODE = "networkSMPProxyMode"
|
||||
let GROUP_DEFAULT_NETWORK_SMP_PROXY_FALLBACK = "networkSMPProxyFallback"
|
||||
let GROUP_DEFAULT_NETWORK_SMP_WEB_PORT = "networkSMPWebPort"
|
||||
let GROUP_DEFAULT_NETWORK_SMP_WEB_PORT_SERVERS = "networkSMPWebPortServers"
|
||||
let GROUP_DEFAULT_NETWORK_TCP_CONNECT_TIMEOUT = "networkTCPConnectTimeout"
|
||||
let GROUP_DEFAULT_NETWORK_TCP_TIMEOUT = "networkTCPTimeout"
|
||||
let GROUP_DEFAULT_NETWORK_TCP_TIMEOUT_PER_KB = "networkTCPTimeoutPerKb"
|
||||
|
@ -72,7 +72,7 @@ public func registerGroupDefaults() {
|
|||
GROUP_DEFAULT_NETWORK_SESSION_MODE: TransportSessionMode.session.rawValue,
|
||||
GROUP_DEFAULT_NETWORK_SMP_PROXY_MODE: SMPProxyMode.unknown.rawValue,
|
||||
GROUP_DEFAULT_NETWORK_SMP_PROXY_FALLBACK: SMPProxyFallback.allowProtected.rawValue,
|
||||
GROUP_DEFAULT_NETWORK_SMP_WEB_PORT: false,
|
||||
GROUP_DEFAULT_NETWORK_SMP_WEB_PORT_SERVERS: SMPWebPortServers.preset.rawValue,
|
||||
GROUP_DEFAULT_NETWORK_TCP_CONNECT_TIMEOUT: NetCfg.defaults.tcpConnectTimeout,
|
||||
GROUP_DEFAULT_NETWORK_TCP_TIMEOUT: NetCfg.defaults.tcpTimeout,
|
||||
GROUP_DEFAULT_NETWORK_TCP_TIMEOUT_PER_KB: NetCfg.defaults.tcpTimeoutPerKb,
|
||||
|
@ -251,6 +251,12 @@ public let networkSMPProxyFallbackGroupDefault = EnumDefault<SMPProxyFallback>(
|
|||
withDefault: .allowProtected
|
||||
)
|
||||
|
||||
public let networkSMPWebPortServersDefault = EnumDefault<SMPWebPortServers>(
|
||||
defaults: groupDefaults,
|
||||
forKey: GROUP_DEFAULT_NETWORK_SMP_WEB_PORT_SERVERS,
|
||||
withDefault: .preset
|
||||
)
|
||||
|
||||
public let storeDBPassphraseGroupDefault = BoolDefault(defaults: groupDefaults, forKey: GROUP_DEFAULT_STORE_DB_PASSPHRASE)
|
||||
|
||||
public let initialRandomDBPassphraseGroupDefault = BoolDefault(defaults: groupDefaults, forKey: GROUP_DEFAULT_INITIAL_RANDOM_DB_PASSPHRASE)
|
||||
|
@ -305,12 +311,14 @@ public class EnumDefault<T: RawRepresentable> where T.RawValue == String {
|
|||
}
|
||||
|
||||
public class BoolDefault: Default<Bool> {
|
||||
@inline(__always)
|
||||
public func get() -> Bool {
|
||||
self.defaults.bool(forKey: self.key)
|
||||
}
|
||||
}
|
||||
|
||||
public class IntDefault: Default<Int> {
|
||||
@inline(__always)
|
||||
public func get() -> Int {
|
||||
self.defaults.integer(forKey: self.key)
|
||||
}
|
||||
|
@ -320,11 +328,13 @@ public class Default<T> {
|
|||
var defaults: UserDefaults
|
||||
var key: String
|
||||
|
||||
@inline(__always)
|
||||
public init(defaults: UserDefaults = UserDefaults.standard, forKey: String) {
|
||||
self.defaults = defaults
|
||||
self.key = forKey
|
||||
}
|
||||
|
||||
@inline(__always)
|
||||
public func set(_ value: T) {
|
||||
defaults.set(value, forKey: key)
|
||||
defaults.synchronize()
|
||||
|
@ -338,7 +348,7 @@ public func getNetCfg() -> NetCfg {
|
|||
let sessionMode = networkSessionModeGroupDefault.get()
|
||||
let smpProxyMode = networkSMPProxyModeGroupDefault.get()
|
||||
let smpProxyFallback = networkSMPProxyFallbackGroupDefault.get()
|
||||
let smpWebPort = groupDefaults.bool(forKey: GROUP_DEFAULT_NETWORK_SMP_WEB_PORT)
|
||||
let smpWebPortServers = networkSMPWebPortServersDefault.get()
|
||||
let tcpConnectTimeout = groupDefaults.integer(forKey: GROUP_DEFAULT_NETWORK_TCP_CONNECT_TIMEOUT)
|
||||
let tcpTimeout = groupDefaults.integer(forKey: GROUP_DEFAULT_NETWORK_TCP_TIMEOUT)
|
||||
let tcpTimeoutPerKb = groupDefaults.integer(forKey: GROUP_DEFAULT_NETWORK_TCP_TIMEOUT_PER_KB)
|
||||
|
@ -362,7 +372,7 @@ public func getNetCfg() -> NetCfg {
|
|||
sessionMode: sessionMode,
|
||||
smpProxyMode: smpProxyMode,
|
||||
smpProxyFallback: smpProxyFallback,
|
||||
smpWebPort: smpWebPort,
|
||||
smpWebPortServers: smpWebPortServers,
|
||||
tcpConnectTimeout: tcpConnectTimeout,
|
||||
tcpTimeout: tcpTimeout,
|
||||
tcpTimeoutPerKb: tcpTimeoutPerKb,
|
||||
|
@ -381,7 +391,7 @@ public func setNetCfg(_ cfg: NetCfg, networkProxy: NetworkProxy?) {
|
|||
networkSMPProxyFallbackGroupDefault.set(cfg.smpProxyFallback)
|
||||
let socksProxy = networkProxy?.toProxyString()
|
||||
groupDefaults.set(socksProxy, forKey: GROUP_DEFAULT_NETWORK_SOCKS_PROXY)
|
||||
groupDefaults.set(cfg.smpWebPort, forKey: GROUP_DEFAULT_NETWORK_SMP_WEB_PORT)
|
||||
networkSMPWebPortServersDefault.set(cfg.smpWebPortServers)
|
||||
groupDefaults.set(cfg.tcpConnectTimeout, forKey: GROUP_DEFAULT_NETWORK_TCP_CONNECT_TIMEOUT)
|
||||
groupDefaults.set(cfg.tcpTimeout, forKey: GROUP_DEFAULT_NETWORK_TCP_TIMEOUT)
|
||||
groupDefaults.set(cfg.tcpTimeoutPerKb, forKey: GROUP_DEFAULT_NETWORK_TCP_TIMEOUT_PER_KB)
|
||||
|
|
|
@ -1201,7 +1201,7 @@ public enum ChatInfo: Identifiable, Decodable, NamedChat, Hashable {
|
|||
case local(noteFolder: NoteFolder)
|
||||
case contactRequest(contactRequest: UserContactRequest)
|
||||
case contactConnection(contactConnection: PendingContactConnection)
|
||||
case invalidJSON(json: String)
|
||||
case invalidJSON(json: Data?)
|
||||
|
||||
private static let invalidChatName = NSLocalizedString("invalid chat", comment: "invalid chat data")
|
||||
|
||||
|
@ -1589,7 +1589,7 @@ public struct ChatData: Decodable, Identifiable, Hashable, ChatLike {
|
|||
self.chatStats = chatStats
|
||||
}
|
||||
|
||||
public static func invalidJSON(_ json: String) -> ChatData {
|
||||
public static func invalidJSON(_ json: Data?) -> ChatData {
|
||||
ChatData(
|
||||
chatInfo: .invalidJSON(json: json),
|
||||
chatItems: [],
|
||||
|
@ -2399,16 +2399,29 @@ public enum ConnectionEntity: Decodable, Hashable {
|
|||
|
||||
public var id: String? {
|
||||
switch self {
|
||||
case let .rcvDirectMsgConnection(_, contact):
|
||||
return contact?.id
|
||||
case let .rcvDirectMsgConnection(conn, contact):
|
||||
contact?.id ?? conn.id
|
||||
case let .rcvGroupMsgConnection(_, _, groupMember):
|
||||
return groupMember.id
|
||||
groupMember.id
|
||||
case let .userContactConnection(_, userContact):
|
||||
return userContact.id
|
||||
userContact.id
|
||||
default:
|
||||
return nil
|
||||
nil
|
||||
}
|
||||
}
|
||||
|
||||
// public var localDisplayName: String? {
|
||||
// switch self {
|
||||
// case let .rcvDirectMsgConnection(conn, contact):
|
||||
// if let name = contact?.localDisplayName { "@\(name)" } else { conn.id }
|
||||
// case let .rcvGroupMsgConnection(_, g, m):
|
||||
// "#\(g.localDisplayName) @\(m.localDisplayName)"
|
||||
// case let .userContactConnection(_, userContact):
|
||||
// userContact.id
|
||||
// default:
|
||||
// nil
|
||||
// }
|
||||
// }
|
||||
|
||||
public var conn: Connection {
|
||||
switch self {
|
||||
|
@ -2422,10 +2435,11 @@ public enum ConnectionEntity: Decodable, Hashable {
|
|||
}
|
||||
|
||||
public struct NtfConn: Decodable, Hashable {
|
||||
public var user_: User?
|
||||
public var connEntity_: ConnectionEntity?
|
||||
public var user: User
|
||||
public var agentConnId: String
|
||||
public var agentDbQueueId: Int64
|
||||
public var connEntity: ConnectionEntity
|
||||
public var expectedMsg_: NtfMsgInfo?
|
||||
|
||||
}
|
||||
|
||||
public struct NtfMsgInfo: Decodable, Hashable {
|
||||
|
@ -2433,6 +2447,44 @@ public struct NtfMsgInfo: Decodable, Hashable {
|
|||
public var msgTs: Date
|
||||
}
|
||||
|
||||
public enum RcvNtfMsgInfo: Decodable {
|
||||
case info(ntfMsgInfo: NtfMsgInfo?)
|
||||
case error(ntfMsgError: AgentErrorType)
|
||||
|
||||
@inline(__always)
|
||||
public var noMsg: Bool {
|
||||
if case let .info(msg) = self { msg == nil } else { true }
|
||||
}
|
||||
|
||||
@inline(__always)
|
||||
public var isError: Bool {
|
||||
if case .error = self { true } else { false }
|
||||
}
|
||||
}
|
||||
|
||||
let iso8601DateFormatter = {
|
||||
let f = ISO8601DateFormatter()
|
||||
f.formatOptions = [.withInternetDateTime]
|
||||
return f
|
||||
}()
|
||||
|
||||
// used in apiGetConnNtfMessages
|
||||
public struct ConnMsgReq {
|
||||
public var msgConnId: String
|
||||
public var msgDbQueueId: Int64
|
||||
public var msgTs: Date // SystemTime encodes as a number, should be taken from NtfMsgInfo
|
||||
|
||||
public init(msgConnId: String, msgDbQueueId: Int64, msgTs: Date) {
|
||||
self.msgConnId = msgConnId
|
||||
self.msgDbQueueId = msgDbQueueId
|
||||
self.msgTs = msgTs
|
||||
}
|
||||
|
||||
public var cmdString: String {
|
||||
"\(msgConnId):\(msgDbQueueId):\(iso8601DateFormatter.string(from: msgTs))"
|
||||
}
|
||||
}
|
||||
|
||||
public struct NtfMsgAckInfo: Decodable, Hashable {
|
||||
public var msgId: String
|
||||
public var msgTs_: Date?
|
||||
|
@ -2881,7 +2933,7 @@ public struct ChatItem: Identifiable, Decodable, Hashable {
|
|||
return item
|
||||
}
|
||||
|
||||
public static func invalidJSON(chatDir: CIDirection?, meta: CIMeta?, json: String) -> ChatItem {
|
||||
public static func invalidJSON(chatDir: CIDirection?, meta: CIMeta?, json: Data?) -> ChatItem {
|
||||
ChatItem(
|
||||
chatDir: chatDir ?? .directSnd,
|
||||
meta: meta ?? .invalidJSON,
|
||||
|
@ -3328,7 +3380,7 @@ public enum CIContent: Decodable, ItemContent, Hashable {
|
|||
case rcvDirectE2EEInfo(e2eeInfo: E2EEInfo)
|
||||
case sndGroupE2EEInfo(e2eeInfo: E2EEInfo)
|
||||
case rcvGroupE2EEInfo(e2eeInfo: E2EEInfo)
|
||||
case invalidJSON(json: String)
|
||||
case invalidJSON(json: Data?)
|
||||
|
||||
public var text: String {
|
||||
get {
|
||||
|
@ -3911,7 +3963,7 @@ public enum MsgContent: Equatable, Hashable {
|
|||
}
|
||||
}
|
||||
|
||||
var cmdString: String {
|
||||
public var cmdString: String {
|
||||
"json \(encodeJSON(self))"
|
||||
}
|
||||
|
||||
|
|
|
@ -18,10 +18,10 @@ public func writeCryptoFile(path: String, data: Data) throws -> CryptoFileArgs {
|
|||
memcpy(ptr, (data as NSData).bytes, data.count)
|
||||
var cPath = path.cString(using: .utf8)!
|
||||
let cjson = chat_write_file(getChatCtrl(), &cPath, ptr, Int32(data.count))!
|
||||
let d = fromCString(cjson).data(using: .utf8)!
|
||||
let d = dataFromCString(cjson)! // TODO [unsafe]
|
||||
switch try jsonDecoder.decode(WriteFileResult.self, from: d) {
|
||||
case let .result(cfArgs): return cfArgs
|
||||
case let .error(err): throw RuntimeError(err)
|
||||
case let .error(err): throw RuntimeError(err) // TODO [unsafe]
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -51,10 +51,10 @@ public func encryptCryptoFile(fromPath: String, toPath: String) throws -> Crypto
|
|||
var cFromPath = fromPath.cString(using: .utf8)!
|
||||
var cToPath = toPath.cString(using: .utf8)!
|
||||
let cjson = chat_encrypt_file(getChatCtrl(), &cFromPath, &cToPath)!
|
||||
let d = fromCString(cjson).data(using: .utf8)!
|
||||
let d = dataFromCString(cjson)! // TODO [unsafe]
|
||||
switch try jsonDecoder.decode(WriteFileResult.self, from: d) {
|
||||
case let .result(cfArgs): return cfArgs
|
||||
case let .error(err): throw RuntimeError(err)
|
||||
case let .error(err): throw RuntimeError(err) // TODO [unsafe]
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -37,22 +37,18 @@ public struct ErrorAlert: Error {
|
|||
}
|
||||
|
||||
public init(_ error: any Error) {
|
||||
self = if let chatResponse = error as? ChatResponse {
|
||||
ErrorAlert(chatResponse)
|
||||
self = if let e = error as? ChatError {
|
||||
ErrorAlert(e)
|
||||
} else {
|
||||
ErrorAlert("\(error.localizedDescription)")
|
||||
}
|
||||
}
|
||||
|
||||
public init(_ chatError: ChatError) {
|
||||
self = ErrorAlert("\(chatErrorString(chatError))")
|
||||
}
|
||||
|
||||
public init(_ chatResponse: ChatResponse) {
|
||||
self = if let networkErrorAlert = getNetworkErrorAlert(chatResponse) {
|
||||
self = if let networkErrorAlert = getNetworkErrorAlert(chatError) {
|
||||
networkErrorAlert
|
||||
} else {
|
||||
ErrorAlert("\(responseError(chatResponse))")
|
||||
ErrorAlert("\(chatErrorString(chatError))")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -94,22 +90,21 @@ extension View {
|
|||
}
|
||||
}
|
||||
|
||||
public func getNetworkErrorAlert(_ r: ChatResponse) -> ErrorAlert? {
|
||||
switch r {
|
||||
case let .chatCmdError(_, .errorAgent(.BROKER(addr, .TIMEOUT))):
|
||||
return ErrorAlert(title: "Connection timeout", message: "Please check your network connection with \(serverHostname(addr)) and try again.")
|
||||
case let .chatCmdError(_, .errorAgent(.BROKER(addr, .NETWORK))):
|
||||
return ErrorAlert(title: "Connection error", message: "Please check your network connection with \(serverHostname(addr)) and try again.")
|
||||
case let .chatCmdError(_, .errorAgent(.BROKER(addr, .HOST))):
|
||||
return ErrorAlert(title: "Connection error", message: "Server address is incompatible with network settings: \(serverHostname(addr)).")
|
||||
case let .chatCmdError(_, .errorAgent(.BROKER(addr, .TRANSPORT(.version)))):
|
||||
return ErrorAlert(title: "Connection error", message: "Server version is incompatible with your app: \(serverHostname(addr)).")
|
||||
case let .chatCmdError(_, .errorAgent(.SMP(serverAddress, .PROXY(proxyErr)))):
|
||||
return smpProxyErrorAlert(proxyErr, serverAddress)
|
||||
case let .chatCmdError(_, .errorAgent(.PROXY(proxyServer, relayServer, .protocolError(.PROXY(proxyErr))))):
|
||||
return proxyDestinationErrorAlert(proxyErr, proxyServer, relayServer)
|
||||
default:
|
||||
return nil
|
||||
public func getNetworkErrorAlert(_ e: ChatError) -> ErrorAlert? {
|
||||
switch e {
|
||||
case let .errorAgent(.BROKER(addr, .TIMEOUT)):
|
||||
ErrorAlert(title: "Connection timeout", message: "Please check your network connection with \(serverHostname(addr)) and try again.")
|
||||
case let .errorAgent(.BROKER(addr, .NETWORK)):
|
||||
ErrorAlert(title: "Connection error", message: "Please check your network connection with \(serverHostname(addr)) and try again.")
|
||||
case let .errorAgent(.BROKER(addr, .HOST)):
|
||||
ErrorAlert(title: "Connection error", message: "Server address is incompatible with network settings: \(serverHostname(addr)).")
|
||||
case let .errorAgent(.BROKER(addr, .TRANSPORT(.version))):
|
||||
ErrorAlert(title: "Connection error", message: "Server version is incompatible with your app: \(serverHostname(addr)).")
|
||||
case let .errorAgent(.SMP(serverAddress, .PROXY(proxyErr))):
|
||||
smpProxyErrorAlert(proxyErr, serverAddress)
|
||||
case let .errorAgent(.PROXY(proxyServer, relayServer, .protocolError(.PROXY(proxyErr)))):
|
||||
proxyDestinationErrorAlert(proxyErr, proxyServer, relayServer)
|
||||
default: nil
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -29,10 +29,10 @@ void haskell_init_nse(void) {
|
|||
char *argv[] = {
|
||||
"simplex",
|
||||
"+RTS", // requires `hs_init_with_rtsopts`
|
||||
"-A1m", // chunk size for new allocations
|
||||
"-H1m", // initial heap size
|
||||
"-A256k", // chunk size for new allocations
|
||||
"-H512k", // initial heap size
|
||||
"-F0.5", // heap growth triggering GC
|
||||
"-Fd1", // memory return
|
||||
"-Fd0.3", // memory return
|
||||
"-c", // compacting garbage collector
|
||||
0
|
||||
};
|
||||
|
|
|
@ -229,5 +229,5 @@ fun isMediaIntent(intent: Intent): Boolean =
|
|||
// val str: String = """
|
||||
// """.trimIndent()
|
||||
//
|
||||
// println(json.decodeFromString<APIResponse>(str))
|
||||
// println(json.decodeFromString<APIResult>(str))
|
||||
//}
|
||||
|
|
|
@ -38,6 +38,7 @@ import java.net.URI
|
|||
import java.time.format.DateTimeFormatter
|
||||
import java.time.format.FormatStyle
|
||||
import java.util.*
|
||||
import java.util.concurrent.atomic.AtomicLong
|
||||
import kotlin.collections.ArrayList
|
||||
import kotlin.random.Random
|
||||
import kotlin.time.*
|
||||
|
@ -1396,19 +1397,21 @@ sealed class ChatInfo: SomeChat, NamedChat {
|
|||
}
|
||||
|
||||
@Serializable @SerialName("invalidJSON")
|
||||
class InvalidJSON(val json: String): ChatInfo() {
|
||||
class InvalidJSON(
|
||||
val json: String,
|
||||
override val apiId: Long = -idGenerator.getAndIncrement(),
|
||||
override val createdAt: Instant = Clock.System.now(),
|
||||
override val updatedAt: Instant = Clock.System.now()
|
||||
): ChatInfo() {
|
||||
override val chatType get() = ChatType.Direct
|
||||
override val localDisplayName get() = invalidChatName
|
||||
override val id get() = ""
|
||||
override val apiId get() = 0L
|
||||
override val id get() = "?$apiId"
|
||||
override val ready get() = false
|
||||
override val chatDeleted get() = false
|
||||
override val sendMsgEnabled get() = false
|
||||
override val incognito get() = false
|
||||
override fun featureEnabled(feature: ChatFeature) = false
|
||||
override val timedMessagesTTL: Int? get() = null
|
||||
override val createdAt get() = Clock.System.now()
|
||||
override val updatedAt get() = Clock.System.now()
|
||||
override val displayName get() = invalidChatName
|
||||
override val fullName get() = invalidChatName
|
||||
override val image get() = null
|
||||
|
@ -1416,6 +1419,7 @@ sealed class ChatInfo: SomeChat, NamedChat {
|
|||
|
||||
companion object {
|
||||
private val invalidChatName = generalGetString(MR.strings.invalid_chat)
|
||||
private val idGenerator = AtomicLong(0)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -48,7 +48,7 @@ private fun sendCommand(chatModel: ChatModel, composeState: MutableState<Compose
|
|||
val prefPerformLA = chatModel.controller.appPrefs.performLA.get()
|
||||
val s = composeState.value.message
|
||||
if (s.text.startsWith("/sql") && (!prefPerformLA || !developerTools)) {
|
||||
val resp = CR.ChatCmdError(null, ChatError.ChatErrorChat(ChatErrorType.CommandError("Failed reading: empty")))
|
||||
val resp = API.Error(null, ChatError.ChatErrorChat(ChatErrorType.CommandError("Failed reading: empty")))
|
||||
chatModel.addTerminalItem(TerminalItem.cmd(null, CC.Console(s.text)))
|
||||
chatModel.addTerminalItem(TerminalItem.resp(null, resp))
|
||||
composeState.value = ComposeState(useLinkPreviews = false)
|
||||
|
|
|
@ -10,13 +10,13 @@ import kotlinx.coroutines.*
|
|||
expect fun ActiveCallView()
|
||||
|
||||
fun activeCallWaitDeliveryReceipt(scope: CoroutineScope) = scope.launch(Dispatchers.Default) {
|
||||
for (apiResp in controller.messagesChannel) {
|
||||
for (msg in controller.messagesChannel) {
|
||||
val call = chatModel.activeCall.value
|
||||
if (call == null || call.callState > CallState.InvitationSent) break
|
||||
val msg = apiResp.resp
|
||||
if (apiResp.remoteHostId == call.remoteHostId &&
|
||||
msg is CR.ChatItemsStatusesUpdated &&
|
||||
msg.chatItems.any {
|
||||
if (msg.rhId == call.remoteHostId &&
|
||||
msg is API.Result &&
|
||||
msg.res is CR.ChatItemsStatusesUpdated &&
|
||||
msg.res.chatItems.any {
|
||||
it.chatInfo.id == call.contact.id && it.chatItem.content is CIContent.SndCall && it.chatItem.meta.itemStatus is CIStatus.SndRcvd
|
||||
}
|
||||
) {
|
||||
|
|
|
@ -554,11 +554,11 @@ fun ChatView(
|
|||
ChatItemInfoView(chatRh, cItem, ciInfo, devTools = chatModel.controller.appPrefs.developerTools.get(), chatInfo)
|
||||
LaunchedEffect(cItem.id) {
|
||||
withContext(Dispatchers.Default) {
|
||||
for (apiResp in controller.messagesChannel) {
|
||||
val msg = apiResp.resp
|
||||
if (apiResp.remoteHostId == chatRh &&
|
||||
msg is CR.ChatItemsStatusesUpdated &&
|
||||
msg.chatItems.any { it.chatItem.id == cItem.id }
|
||||
for (msg in controller.messagesChannel) {
|
||||
if (msg.rhId == chatRh &&
|
||||
msg is API.Result &&
|
||||
msg.res is CR.ChatItemsStatusesUpdated &&
|
||||
msg.res.chatItems.any { it.chatItem.id == cItem.id }
|
||||
) {
|
||||
ciInfo = loadChatItemInfo() ?: return@withContext
|
||||
initialCiInfo = ciInfo
|
||||
|
|
|
@ -435,7 +435,7 @@ suspend fun encryptDatabase(
|
|||
}
|
||||
val error = m.controller.apiStorageEncryption(currentKey.value, newKey.value)
|
||||
appPrefs.encryptionStartedAt.set(null)
|
||||
val sqliteError = ((error?.chatError as? ChatError.ChatErrorDatabase)?.databaseError as? DatabaseError.ErrorExport)?.sqliteError
|
||||
val sqliteError = ((error as? ChatError.ChatErrorDatabase)?.databaseError as? DatabaseError.ErrorExport)?.sqliteError
|
||||
when {
|
||||
sqliteError is SQLiteError.ErrorNotADatabase -> {
|
||||
operationEnded(m, progressIndicator) {
|
||||
|
@ -449,7 +449,7 @@ suspend fun encryptDatabase(
|
|||
error != null -> {
|
||||
operationEnded(m, progressIndicator) {
|
||||
AlertManager.shared.showAlertMsg(generalGetString(MR.strings.error_encrypting_database),
|
||||
"failed to set storage encryption: ${error.responseType} ${error.details}"
|
||||
"failed to set storage encryption: error ${error.string}"
|
||||
)
|
||||
}
|
||||
false
|
||||
|
|
|
@ -468,12 +468,12 @@ private suspend fun MutableState<MigrationFromState>.verifyDatabasePassphrase(db
|
|||
val error = controller.testStorageEncryption(dbKey)
|
||||
if (error == null) {
|
||||
state = MigrationFromState.UploadConfirmation
|
||||
} else if (((error.chatError as? ChatError.ChatErrorDatabase)?.databaseError as? DatabaseError.ErrorOpen)?.sqliteError is SQLiteError.ErrorNotADatabase) {
|
||||
} else if (((error as? ChatError.ChatErrorDatabase)?.databaseError as? DatabaseError.ErrorOpen)?.sqliteError is SQLiteError.ErrorNotADatabase) {
|
||||
showErrorOnMigrationIfNeeded(DBMigrationResult.ErrorNotADatabase(""))
|
||||
} else {
|
||||
AlertManager.shared.showAlertMsg(
|
||||
title = generalGetString(MR.strings.error),
|
||||
text = generalGetString(MR.strings.migrate_from_device_error_verifying_passphrase) + " " + error.details
|
||||
text = generalGetString(MR.strings.migrate_from_device_error_verifying_passphrase) + " " + error.string
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -556,11 +556,12 @@ private fun MutableState<MigrationFromState>.startUploading(
|
|||
) {
|
||||
withBGApi {
|
||||
chatReceiver.value = MigrationFromChatReceiver(ctrl, tempDatabaseFile) { msg ->
|
||||
when (msg) {
|
||||
val r = msg.result
|
||||
when (r) {
|
||||
is CR.SndFileProgressXFTP -> {
|
||||
val s = state
|
||||
if (s is MigrationFromState.UploadProgress && s.uploadedBytes != s.totalBytes) {
|
||||
state = MigrationFromState.UploadProgress(msg.sentSize, msg.totalSize, msg.fileTransferMeta.fileId, archivePath, ctrl, user)
|
||||
state = MigrationFromState.UploadProgress(r.sentSize, r.totalSize, r.fileTransferMeta.fileId, archivePath, ctrl, user)
|
||||
}
|
||||
}
|
||||
is CR.SndFileRedirectStartXFTP -> {
|
||||
|
@ -578,7 +579,7 @@ private fun MutableState<MigrationFromState>.startUploading(
|
|||
requiredHostMode = cfg.requiredHostMode
|
||||
)
|
||||
)
|
||||
state = MigrationFromState.LinkShown(msg.fileTransferMeta.fileId, data.addToLink(msg.rcvURIs[0]), ctrl)
|
||||
state = MigrationFromState.LinkShown(r.fileTransferMeta.fileId, data.addToLink(r.rcvURIs[0]), ctrl)
|
||||
}
|
||||
is CR.SndFileError -> {
|
||||
AlertManager.shared.showAlertMsg(
|
||||
|
@ -692,7 +693,7 @@ private class MigrationFromChatReceiver(
|
|||
val ctrl: ChatCtrl,
|
||||
val databaseUrl: File,
|
||||
var receiveMessages: Boolean = true,
|
||||
val processReceivedMsg: suspend (CR) -> Unit
|
||||
val processReceivedMsg: suspend (API) -> Unit
|
||||
) {
|
||||
fun start() {
|
||||
Log.d(TAG, "MigrationChatReceiver startReceiver")
|
||||
|
@ -701,19 +702,18 @@ private class MigrationFromChatReceiver(
|
|||
try {
|
||||
val msg = ChatController.recvMsg(ctrl)
|
||||
if (msg != null && receiveMessages) {
|
||||
val r = msg.resp
|
||||
val rhId = msg.remoteHostId
|
||||
Log.d(TAG, "processReceivedMsg: ${r.responseType}")
|
||||
chatModel.addTerminalItem(TerminalItem.resp(rhId, r))
|
||||
val rhId = msg.rhId
|
||||
Log.d(TAG, "processReceivedMsg: ${msg.responseType}")
|
||||
chatModel.addTerminalItem(TerminalItem.resp(rhId, msg))
|
||||
val finishedWithoutTimeout = withTimeoutOrNull(60_000L) {
|
||||
processReceivedMsg(r)
|
||||
processReceivedMsg(msg)
|
||||
}
|
||||
if (finishedWithoutTimeout == null) {
|
||||
Log.e(TAG, "Timeout reached while processing received message: " + msg.resp.responseType)
|
||||
Log.e(TAG, "Timeout reached while processing received message: " + msg.responseType)
|
||||
if (appPreferences.developerTools.get() && appPreferences.showSlowApiCalls.get()) {
|
||||
AlertManager.shared.showAlertMsg(
|
||||
title = generalGetString(MR.strings.possible_slow_function_title),
|
||||
text = generalGetString(MR.strings.possible_slow_function_desc).format(60, msg.resp.responseType + "\n" + Exception().stackTraceToString()),
|
||||
text = generalGetString(MR.strings.possible_slow_function_desc).format(60, msg.responseType + "\n" + Exception().stackTraceToString()),
|
||||
shareText = true
|
||||
)
|
||||
}
|
||||
|
|
|
@ -580,12 +580,13 @@ private fun MutableState<MigrationToState?>.startDownloading(
|
|||
) {
|
||||
withBGApi {
|
||||
chatReceiver.value = MigrationToChatReceiver(ctrl, tempDatabaseFile) { msg ->
|
||||
when (msg) {
|
||||
is CR.RcvFileProgressXFTP -> {
|
||||
state = MigrationToState.DownloadProgress(msg.receivedSize, msg.totalSize, msg.rcvFileTransfer.fileId, link, archivePath, netCfg, networkProxy, ctrl)
|
||||
val r = msg.result
|
||||
when {
|
||||
r is CR.RcvFileProgressXFTP -> {
|
||||
state = MigrationToState.DownloadProgress(r.receivedSize, r.totalSize, r.rcvFileTransfer.fileId, link, archivePath, netCfg, networkProxy, ctrl)
|
||||
MigrationToDeviceState.save(MigrationToDeviceState.DownloadProgress(link, File(archivePath).name, netCfg, networkProxy))
|
||||
}
|
||||
is CR.RcvStandaloneFileComplete -> {
|
||||
r is CR.RcvStandaloneFileComplete -> {
|
||||
delay(500)
|
||||
// User closed the whole screen before new state was saved
|
||||
if (state == null) {
|
||||
|
@ -595,22 +596,22 @@ private fun MutableState<MigrationToState?>.startDownloading(
|
|||
MigrationToDeviceState.save(MigrationToDeviceState.ArchiveImport(File(archivePath).name, netCfg, networkProxy))
|
||||
}
|
||||
}
|
||||
is CR.RcvFileError -> {
|
||||
r is CR.RcvFileError -> {
|
||||
AlertManager.shared.showAlertMsg(
|
||||
generalGetString(MR.strings.migrate_to_device_download_failed),
|
||||
generalGetString(MR.strings.migrate_to_device_file_delete_or_link_invalid)
|
||||
)
|
||||
state = MigrationToState.DownloadFailed(totalBytes, link, archivePath, netCfg, networkProxy)
|
||||
}
|
||||
is CR.ChatRespError -> {
|
||||
if (msg.chatError is ChatError.ChatErrorChat && msg.chatError.errorType is ChatErrorType.NoRcvFileUser) {
|
||||
msg is API.Error -> {
|
||||
if (msg.err is ChatError.ChatErrorChat && msg.err.errorType is ChatErrorType.NoRcvFileUser) {
|
||||
AlertManager.shared.showAlertMsg(
|
||||
generalGetString(MR.strings.migrate_to_device_download_failed),
|
||||
generalGetString(MR.strings.migrate_to_device_file_delete_or_link_invalid)
|
||||
)
|
||||
state = MigrationToState.DownloadFailed(totalBytes, link, archivePath, netCfg, networkProxy)
|
||||
} else {
|
||||
Log.d(TAG, "unsupported error: ${msg.responseType}, ${json.encodeToString(msg.chatError)}")
|
||||
Log.d(TAG, "unsupported error: ${msg.responseType}, ${json.encodeToString(msg.err)}")
|
||||
}
|
||||
}
|
||||
else -> Log.d(TAG, "unsupported event: ${msg.responseType}")
|
||||
|
@ -739,7 +740,7 @@ private class MigrationToChatReceiver(
|
|||
val ctrl: ChatCtrl,
|
||||
val databaseUrl: File,
|
||||
var receiveMessages: Boolean = true,
|
||||
val processReceivedMsg: suspend (CR) -> Unit
|
||||
val processReceivedMsg: suspend (API) -> Unit
|
||||
) {
|
||||
fun start() {
|
||||
Log.d(TAG, "MigrationChatReceiver startReceiver")
|
||||
|
@ -748,19 +749,18 @@ private class MigrationToChatReceiver(
|
|||
try {
|
||||
val msg = ChatController.recvMsg(ctrl)
|
||||
if (msg != null && receiveMessages) {
|
||||
val r = msg.resp
|
||||
val rhId = msg.remoteHostId
|
||||
Log.d(TAG, "processReceivedMsg: ${r.responseType}")
|
||||
chatModel.addTerminalItem(TerminalItem.resp(rhId, r))
|
||||
val rhId = msg.rhId
|
||||
Log.d(TAG, "processReceivedMsg: ${msg.responseType}")
|
||||
chatModel.addTerminalItem(TerminalItem.resp(rhId, msg))
|
||||
val finishedWithoutTimeout = withTimeoutOrNull(60_000L) {
|
||||
processReceivedMsg(r)
|
||||
processReceivedMsg(msg)
|
||||
}
|
||||
if (finishedWithoutTimeout == null) {
|
||||
Log.e(TAG, "Timeout reached while processing received message: " + msg.resp.responseType)
|
||||
Log.e(TAG, "Timeout reached while processing received message: " + msg.responseType)
|
||||
if (appPreferences.developerTools.get() && appPreferences.showSlowApiCalls.get()) {
|
||||
AlertManager.shared.showAlertMsg(
|
||||
title = generalGetString(MR.strings.possible_slow_function_title),
|
||||
text = generalGetString(MR.strings.possible_slow_function_desc).format(60, msg.resp.responseType + "\n" + Exception().stackTraceToString()),
|
||||
text = generalGetString(MR.strings.possible_slow_function_desc).format(60, msg.responseType + "\n" + Exception().stackTraceToString()),
|
||||
shareText = true
|
||||
)
|
||||
}
|
||||
|
|
|
@ -492,7 +492,7 @@ private suspend fun connectDesktopAddress(sessionAddress: MutableState<String>,
|
|||
}
|
||||
}
|
||||
|
||||
private suspend fun connectDesktop(sessionAddress: MutableState<String>, connect: suspend () -> Pair<SomeRemoteCtrl?, CR.ChatCmdError?>): Boolean {
|
||||
private suspend fun connectDesktop(sessionAddress: MutableState<String>, connect: suspend () -> Pair<SomeRemoteCtrl?, ChatError?>): Boolean {
|
||||
val res = connect()
|
||||
if (res.first != null) {
|
||||
val (rc_, ctrlAppInfo, v) = res.first!!
|
||||
|
@ -505,13 +505,13 @@ private suspend fun connectDesktop(sessionAddress: MutableState<String>, connect
|
|||
} else {
|
||||
val e = res.second ?: return false
|
||||
when {
|
||||
e.chatError is ChatError.ChatErrorRemoteCtrl && e.chatError.remoteCtrlError is RemoteCtrlError.BadInvitation -> showBadInvitationErrorAlert()
|
||||
e.chatError is ChatError.ChatErrorChat && e.chatError.errorType is ChatErrorType.CommandError -> showBadInvitationErrorAlert()
|
||||
e.chatError is ChatError.ChatErrorRemoteCtrl && e.chatError.remoteCtrlError is RemoteCtrlError.BadVersion -> showBadVersionAlert(v = e.chatError.remoteCtrlError.appVersion)
|
||||
e.chatError is ChatError.ChatErrorAgent && e.chatError.agentError is AgentErrorType.RCP && e.chatError.agentError.rcpErr is RCErrorType.VERSION -> showBadVersionAlert(v = null)
|
||||
e.chatError is ChatError.ChatErrorAgent && e.chatError.agentError is AgentErrorType.RCP && e.chatError.agentError.rcpErr is RCErrorType.CTRL_AUTH -> showDesktopDisconnectedErrorAlert()
|
||||
e is ChatError.ChatErrorRemoteCtrl && e.remoteCtrlError is RemoteCtrlError.BadInvitation -> showBadInvitationErrorAlert()
|
||||
e is ChatError.ChatErrorChat && e.errorType is ChatErrorType.CommandError -> showBadInvitationErrorAlert()
|
||||
e is ChatError.ChatErrorRemoteCtrl && e.remoteCtrlError is RemoteCtrlError.BadVersion -> showBadVersionAlert(v = e.remoteCtrlError.appVersion)
|
||||
e is ChatError.ChatErrorAgent && e.agentError is AgentErrorType.RCP && e.agentError.rcpErr is RCErrorType.VERSION -> showBadVersionAlert(v = null)
|
||||
e is ChatError.ChatErrorAgent && e.agentError is AgentErrorType.RCP && e.agentError.rcpErr is RCErrorType.CTRL_AUTH -> showDesktopDisconnectedErrorAlert()
|
||||
else -> {
|
||||
val errMsg = "${e.responseType}: ${e.details}"
|
||||
val errMsg = "error: ${e.string}"
|
||||
Log.e(TAG, "bad response: $errMsg")
|
||||
AlertManager.shared.showAlertMsg(generalGetString(MR.strings.error), errMsg)
|
||||
}
|
||||
|
|
|
@ -291,7 +291,7 @@ private fun DeliveryReceiptsSection(
|
|||
SectionView(stringResource(MR.strings.settings_section_title_delivery_receipts)) {
|
||||
SettingsActionItemWithContent(painterResource(MR.images.ic_person), stringResource(MR.strings.receipts_section_contacts)) {
|
||||
DefaultSwitch(
|
||||
checked = currentUser.sendRcptsContacts ?: false,
|
||||
checked = currentUser.sendRcptsContacts,
|
||||
onCheckedChange = { enable ->
|
||||
setOrAskSendReceiptsContacts(enable)
|
||||
}
|
||||
|
@ -299,7 +299,7 @@ private fun DeliveryReceiptsSection(
|
|||
}
|
||||
SettingsActionItemWithContent(painterResource(MR.images.ic_group), stringResource(MR.strings.receipts_section_groups)) {
|
||||
DefaultSwitch(
|
||||
checked = currentUser.sendRcptsSmallGroups ?: false,
|
||||
checked = currentUser.sendRcptsSmallGroups,
|
||||
onCheckedChange = { enable ->
|
||||
setOrAskSendReceiptsGroups(enable)
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ import dev.icerock.moko.resources.compose.painterResource
|
|||
import dev.icerock.moko.resources.compose.stringResource
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import chat.simplex.common.model.*
|
||||
import chat.simplex.common.model.ChatController.appPrefs
|
||||
import chat.simplex.common.ui.theme.*
|
||||
|
@ -45,7 +46,7 @@ fun ModalData.AdvancedNetworkSettingsView(showModal: (ModalData.() -> Unit) -> U
|
|||
val sessionMode = remember { mutableStateOf(currentCfgVal.sessionMode) }
|
||||
val smpProxyMode = remember { mutableStateOf(currentCfgVal.smpProxyMode) }
|
||||
val smpProxyFallback = remember { mutableStateOf(currentCfgVal.smpProxyFallback) }
|
||||
val smpWebPort = remember { mutableStateOf(currentCfgVal.smpWebPort) }
|
||||
val smpWebPortServers = remember { mutableStateOf(currentCfgVal.smpWebPortServers) }
|
||||
|
||||
val networkTCPConnectTimeout = remember { mutableStateOf(currentCfgVal.tcpConnectTimeout) }
|
||||
val networkTCPTimeout = remember { mutableStateOf(currentCfgVal.tcpTimeout) }
|
||||
|
@ -84,7 +85,7 @@ fun ModalData.AdvancedNetworkSettingsView(showModal: (ModalData.() -> Unit) -> U
|
|||
sessionMode = sessionMode.value,
|
||||
smpProxyMode = smpProxyMode.value,
|
||||
smpProxyFallback = smpProxyFallback.value,
|
||||
smpWebPort = smpWebPort.value,
|
||||
smpWebPortServers = smpWebPortServers.value,
|
||||
tcpConnectTimeout = networkTCPConnectTimeout.value,
|
||||
tcpTimeout = networkTCPTimeout.value,
|
||||
tcpTimeoutPerKb = networkTCPTimeoutPerKb.value,
|
||||
|
@ -99,7 +100,7 @@ fun ModalData.AdvancedNetworkSettingsView(showModal: (ModalData.() -> Unit) -> U
|
|||
sessionMode.value = cfg.sessionMode
|
||||
smpProxyMode.value = cfg.smpProxyMode
|
||||
smpProxyFallback.value = cfg.smpProxyFallback
|
||||
smpWebPort.value = cfg.smpWebPort
|
||||
smpWebPortServers.value = cfg.smpWebPortServers
|
||||
networkTCPConnectTimeout.value = cfg.tcpConnectTimeout
|
||||
networkTCPTimeout.value = cfg.tcpTimeout
|
||||
networkTCPTimeoutPerKb.value = cfg.tcpTimeoutPerKb
|
||||
|
@ -154,7 +155,7 @@ fun ModalData.AdvancedNetworkSettingsView(showModal: (ModalData.() -> Unit) -> U
|
|||
sessionMode = sessionMode,
|
||||
smpProxyMode = smpProxyMode,
|
||||
smpProxyFallback = smpProxyFallback,
|
||||
smpWebPort,
|
||||
smpWebPortServers,
|
||||
networkTCPConnectTimeout,
|
||||
networkTCPTimeout,
|
||||
networkTCPTimeoutPerKb,
|
||||
|
@ -187,7 +188,7 @@ fun ModalData.AdvancedNetworkSettingsView(showModal: (ModalData.() -> Unit) -> U
|
|||
sessionMode: MutableState<TransportSessionMode>,
|
||||
smpProxyMode: MutableState<SMPProxyMode>,
|
||||
smpProxyFallback: MutableState<SMPProxyFallback>,
|
||||
smpWebPort: MutableState<Boolean>,
|
||||
smpWebPortServers: MutableState<SMPWebPortServers>,
|
||||
networkTCPConnectTimeout: MutableState<Long>,
|
||||
networkTCPTimeout: MutableState<Long>,
|
||||
networkTCPTimeoutPerKb: MutableState<Long>,
|
||||
|
@ -226,11 +227,16 @@ fun ModalData.AdvancedNetworkSettingsView(showModal: (ModalData.() -> Unit) -> U
|
|||
}
|
||||
SectionDividerSpaced()
|
||||
SectionView(stringResource(MR.strings.network_smp_web_port_section_title).uppercase()) {
|
||||
PreferenceToggle(stringResource(MR.strings.network_smp_web_port_toggle), checked = smpWebPort.value) {
|
||||
smpWebPort.value = it
|
||||
}
|
||||
ExposedDropDownSettingRow(
|
||||
stringResource(MR.strings.network_smp_web_port_toggle),
|
||||
SMPWebPortServers.entries.map { it to stringResource(it.text) },
|
||||
smpWebPortServers
|
||||
) { smpWebPortServers.value = it }
|
||||
}
|
||||
SectionTextFooter(String.format(stringResource(MR.strings.network_smp_web_port_footer), if (smpWebPort.value) "443" else "5223"))
|
||||
SectionTextFooter(
|
||||
if (smpWebPortServers.value == SMPWebPortServers.Preset) stringResource(MR.strings.network_smp_web_port_preset_footer)
|
||||
else String.format(stringResource(MR.strings.network_smp_web_port_footer), if (smpWebPortServers.value == SMPWebPortServers.All) "443" else "5223")
|
||||
)
|
||||
SectionDividerSpaced(maxTopPadding = true)
|
||||
|
||||
SectionView(stringResource(MR.strings.network_option_tcp_connection).uppercase()) {
|
||||
|
@ -320,7 +326,7 @@ private fun SMPProxyModePicker(
|
|||
) {
|
||||
val density = LocalDensity.current
|
||||
val values = remember {
|
||||
SMPProxyMode.values().map {
|
||||
SMPProxyMode.entries.map {
|
||||
when (it) {
|
||||
SMPProxyMode.Always -> ValueTitleDesc(SMPProxyMode.Always, generalGetString(MR.strings.network_smp_proxy_mode_always), escapedHtmlToAnnotatedString(generalGetString(MR.strings.network_smp_proxy_mode_always_description), density))
|
||||
SMPProxyMode.Unknown -> ValueTitleDesc(SMPProxyMode.Unknown, generalGetString(MR.strings.network_smp_proxy_mode_unknown), escapedHtmlToAnnotatedString(generalGetString(MR.strings.network_smp_proxy_mode_unknown_description), density))
|
||||
|
@ -355,7 +361,7 @@ private fun SMPProxyFallbackPicker(
|
|||
) {
|
||||
val density = LocalDensity.current
|
||||
val values = remember {
|
||||
SMPProxyFallback.values().map {
|
||||
SMPProxyFallback.entries.map {
|
||||
when (it) {
|
||||
SMPProxyFallback.Allow -> ValueTitleDesc(SMPProxyFallback.Allow, generalGetString(MR.strings.network_smp_proxy_fallback_allow), escapedHtmlToAnnotatedString(generalGetString(MR.strings.network_smp_proxy_fallback_allow_description), density))
|
||||
SMPProxyFallback.AllowProtected -> ValueTitleDesc(SMPProxyFallback.AllowProtected, generalGetString(MR.strings.network_smp_proxy_fallback_allow_protected), escapedHtmlToAnnotatedString(generalGetString(MR.strings.network_smp_proxy_fallback_allow_protected_description), density))
|
||||
|
@ -548,7 +554,7 @@ fun PreviewAdvancedNetworkSettingsLayout() {
|
|||
sessionMode = remember { mutableStateOf(TransportSessionMode.User) },
|
||||
smpProxyMode = remember { mutableStateOf(SMPProxyMode.Never) },
|
||||
smpProxyFallback = remember { mutableStateOf(SMPProxyFallback.Allow) },
|
||||
smpWebPort = remember { mutableStateOf(false) },
|
||||
smpWebPortServers = remember { mutableStateOf(SMPWebPortServers.Preset) },
|
||||
networkTCPConnectTimeout = remember { mutableStateOf(10_000000) },
|
||||
networkTCPTimeout = remember { mutableStateOf(10_000000) },
|
||||
networkTCPTimeoutPerKb = remember { mutableStateOf(10_000) },
|
||||
|
|
|
@ -964,6 +964,10 @@
|
|||
<string name="network_smp_web_port_section_title">TCP port for messaging</string>
|
||||
<string name="network_smp_web_port_toggle">Use web port</string>
|
||||
<string name="network_smp_web_port_footer">Use TCP port %1$s when no port is specified.</string>
|
||||
<string name="network_smp_web_port_preset_footer">Use TCP port 443 for preset servers only.</string>
|
||||
<string name="network_smp_web_port_all">All servers</string>
|
||||
<string name="network_smp_web_port_preset">Preset servers</string>
|
||||
<string name="network_smp_web_port_off">Off</string>
|
||||
<string name="appearance_settings">Appearance</string>
|
||||
<string name="customize_theme_title">Customize theme</string>
|
||||
<string name="theme_colors_section_title">INTERFACE COLORS</string>
|
||||
|
|
|
@ -2440,6 +2440,10 @@
|
|||
<string name="report_compose_reason_header_other">Пожаловаться: увидят только модераторы группы.</string>
|
||||
<string name="mute_all_chat">Выключить уведомления для всех</string>
|
||||
<string name="network_smp_web_port_footer">Использовать TCP-порт %1$s, когда порт не указан.</string>
|
||||
<string name="network_smp_web_port_preset_footer">Использовать TCP-порт 443 только для серверов по умолчанию.</string>
|
||||
<string name="network_smp_web_port_all">Все серверы</string>
|
||||
<string name="network_smp_web_port_preset">Серверы по умолчанию</string>
|
||||
<string name="network_smp_web_port_off">Нет</string>
|
||||
<string name="network_smp_web_port_toggle">Использовать веб-порт</string>
|
||||
<string name="privacy_chat_list_open_links_no">Нет</string>
|
||||
<string name="report_compose_reason_header_illegal">Пожаловаться на сообщение: увидят только модераторы группы.</string>
|
||||
|
|
|
@ -43,12 +43,12 @@ mySquaringBot :: User -> ChatController -> IO ()
|
|||
mySquaringBot _user cc = do
|
||||
initializeBotAddress cc
|
||||
race_ (forever $ void getLine) . forever $ do
|
||||
(_, _, resp) <- atomically . readTBQueue $ outputQ cc
|
||||
case resp of
|
||||
CRContactConnected _ contact _ -> do
|
||||
(_, evt) <- atomically . readTBQueue $ outputQ cc
|
||||
case evt of
|
||||
Right (CEvtContactConnected _ contact _) -> do
|
||||
contactConnected contact
|
||||
sendMessage cc contact welcomeMessage
|
||||
CRNewChatItems {chatItems = (AChatItem _ SMDRcv (DirectChat contact) ChatItem {content = mc@CIRcvMsgContent {}}) : _} -> do
|
||||
Right CEvtNewChatItems {chatItems = (AChatItem _ SMDRcv (DirectChat contact) ChatItem {content = mc@CIRcvMsgContent {}}) : _} -> do
|
||||
let msg = ciContentToText mc
|
||||
number_ = readMaybe (T.unpack msg) :: Maybe Integer
|
||||
sendMessage cc contact $ case number_ of
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
{-# LANGUAGE GADTs #-}
|
||||
{-# LANGUAGE LambdaCase #-}
|
||||
{-# LANGUAGE NamedFieldPuns #-}
|
||||
{-# LANGUAGE OverloadedLists #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
|
||||
module Broadcast.Bot where
|
||||
|
@ -36,38 +37,31 @@ broadcastBot :: BroadcastBotOpts -> User -> ChatController -> IO ()
|
|||
broadcastBot BroadcastBotOpts {publishers, welcomeMessage, prohibitedMessage} _user cc = do
|
||||
initializeBotAddress cc
|
||||
race_ (forever $ void getLine) . forever $ do
|
||||
(_, _, resp) <- atomically . readTBQueue $ outputQ cc
|
||||
case resp of
|
||||
CRContactConnected _ ct _ -> do
|
||||
(_, evt) <- atomically . readTBQueue $ outputQ cc
|
||||
case evt of
|
||||
Right (CEvtContactConnected _ ct _) -> do
|
||||
contactConnected ct
|
||||
sendMessage cc ct welcomeMessage
|
||||
CRNewChatItems {chatItems = (AChatItem _ SMDRcv (DirectChat ct) ci@ChatItem {content = CIRcvMsgContent mc}) : _}
|
||||
| publisher `elem` publishers ->
|
||||
if allowContent mc
|
||||
then do
|
||||
sendChatCmd cc ListContacts >>= \case
|
||||
CRContactsList _ cts -> void . forkIO $ do
|
||||
let cts' = filter broadcastTo cts
|
||||
forM_ cts' $ \ct' -> sendComposedMessage cc ct' Nothing mc
|
||||
sendReply $ "Forwarded to " <> tshow (length cts') <> " contact(s)"
|
||||
r -> putStrLn $ "Error getting contacts list: " <> show r
|
||||
else sendReply "!1 Message is not supported!"
|
||||
| otherwise -> do
|
||||
sendReply prohibitedMessage
|
||||
deleteMessage cc ct $ chatItemId' ci
|
||||
Right CEvtNewChatItems {chatItems = (AChatItem _ SMDRcv (DirectChat ct) ci@ChatItem {content = CIRcvMsgContent mc}) : _}
|
||||
| sender `notElem` publishers -> do
|
||||
sendReply prohibitedMessage
|
||||
deleteMessage cc ct $ chatItemId' ci
|
||||
| allowContent mc ->
|
||||
void $ forkIO $
|
||||
sendChatCmd cc (SendMessageBroadcast mc) >>= \case
|
||||
Right CRBroadcastSent {successes, failures} ->
|
||||
sendReply $ "Forwarded to " <> tshow successes <> " contact(s), " <> tshow failures <> " errors"
|
||||
r -> putStrLn $ "Error broadcasting message: " <> show r
|
||||
| otherwise ->
|
||||
sendReply "!1 Message is not supported!"
|
||||
where
|
||||
sendReply = sendComposedMessage cc ct (Just $ chatItemId' ci) . MCText
|
||||
publisher = KnownContact {contactId = contactId' ct, localDisplayName = localDisplayName' ct}
|
||||
sender = KnownContact {contactId = contactId' ct, localDisplayName = localDisplayName' ct}
|
||||
allowContent = \case
|
||||
MCText _ -> True
|
||||
MCLink {} -> True
|
||||
MCImage {} -> True
|
||||
_ -> False
|
||||
broadcastTo Contact {activeConn = Nothing} = False
|
||||
broadcastTo ct'@Contact {activeConn = Just conn@Connection {connStatus}} =
|
||||
(connStatus == ConnSndReady || connStatus == ConnReady)
|
||||
&& not (connDisabled conn)
|
||||
&& contactId' ct' /= contactId' ct
|
||||
_ -> pure ()
|
||||
where
|
||||
contactConnected ct = putStrLn $ T.unpack (localDisplayName' ct) <> " connected"
|
||||
|
|
|
@ -2,17 +2,23 @@
|
|||
{-# LANGUAGE DeriveGeneric #-}
|
||||
{-# LANGUAGE DuplicateRecordFields #-}
|
||||
{-# LANGUAGE FlexibleContexts #-}
|
||||
{-# LANGUAGE FlexibleInstances #-}
|
||||
{-# LANGUAGE GADTs #-}
|
||||
{-# LANGUAGE LambdaCase #-}
|
||||
{-# LANGUAGE NamedFieldPuns #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE TemplateHaskell #-}
|
||||
{-# LANGUAGE UndecidableInstances #-}
|
||||
|
||||
module Server where
|
||||
|
||||
import Control.Monad
|
||||
import Control.Monad.Except
|
||||
import Control.Monad.Reader
|
||||
import Data.Aeson (FromJSON, ToJSON)
|
||||
import Data.Aeson (FromJSON, ToJSON (..))
|
||||
import qualified Data.Aeson as J
|
||||
import qualified Data.Aeson.TH as JQ
|
||||
import Data.Bifunctor (first)
|
||||
import Data.Text (Text)
|
||||
import Data.Text.Encoding (encodeUtf8)
|
||||
import GHC.Generics (Generic)
|
||||
|
@ -23,11 +29,44 @@ import Simplex.Chat.Controller
|
|||
import Simplex.Chat.Core
|
||||
import Simplex.Chat.Library.Commands
|
||||
import Simplex.Chat.Options
|
||||
import Simplex.Messaging.Parsers (defaultJSON, dropPrefix, taggedObjectJSON)
|
||||
import Simplex.Messaging.Transport.Server (runLocalTCPServer)
|
||||
import Simplex.Messaging.Util (raceAny_)
|
||||
import UnliftIO.Exception
|
||||
import UnliftIO.STM
|
||||
|
||||
data ChatSrvRequest = ChatSrvRequest {corrId :: Text, cmd :: Text}
|
||||
deriving (Generic, FromJSON)
|
||||
|
||||
data ChatSrvResponse r = ChatSrvResponse {corrId :: Maybe Text, resp :: CSRBody r}
|
||||
|
||||
data CSRBody r = CSRBody {csrBody :: Either ChatError r}
|
||||
|
||||
-- backwards compatible encoding, to avoid breaking any chat bots
|
||||
data ObjChatCmdError = ObjChatCmdError {chatError :: ChatError}
|
||||
|
||||
data ObjChatError = ObjChatError {chatError :: ChatError}
|
||||
|
||||
$(JQ.deriveToJSON (taggedObjectJSON $ dropPrefix "Obj") ''ObjChatCmdError)
|
||||
|
||||
$(JQ.deriveToJSON (taggedObjectJSON $ dropPrefix "Obj") ''ObjChatError)
|
||||
|
||||
instance ToJSON (CSRBody ChatResponse) where
|
||||
toJSON = toJSON . first ObjChatCmdError . csrBody
|
||||
toEncoding = toEncoding . first ObjChatCmdError . csrBody
|
||||
|
||||
instance ToJSON (CSRBody ChatEvent) where
|
||||
toJSON = toJSON . first ObjChatError . csrBody
|
||||
toEncoding = toEncoding . first ObjChatError . csrBody
|
||||
|
||||
data AChatSrvResponse = forall r. ToJSON (ChatSrvResponse r) => ACR (ChatSrvResponse r)
|
||||
|
||||
$(pure [])
|
||||
|
||||
instance ToJSON (CSRBody r) => ToJSON (ChatSrvResponse r) where
|
||||
toEncoding = $(JQ.mkToEncoding defaultJSON ''ChatSrvResponse)
|
||||
toJSON = $(JQ.mkToJSON defaultJSON ''ChatSrvResponse)
|
||||
|
||||
simplexChatServer :: ServiceName -> ChatConfig -> ChatOpts -> IO ()
|
||||
simplexChatServer chatPort cfg opts =
|
||||
simplexChatCore cfg opts . const $ runChatServer defaultChatServerConfig {chatPort}
|
||||
|
@ -44,19 +83,9 @@ defaultChatServerConfig =
|
|||
clientQSize = 1
|
||||
}
|
||||
|
||||
data ChatSrvRequest = ChatSrvRequest {corrId :: Text, cmd :: Text}
|
||||
deriving (Generic, FromJSON)
|
||||
|
||||
data ChatSrvResponse = ChatSrvResponse {corrId :: Maybe Text, resp :: ChatResponse}
|
||||
deriving (Generic)
|
||||
|
||||
instance ToJSON ChatSrvResponse where
|
||||
toEncoding = J.genericToEncoding J.defaultOptions {J.omitNothingFields = True}
|
||||
toJSON = J.genericToJSON J.defaultOptions {J.omitNothingFields = True}
|
||||
|
||||
data ChatClient = ChatClient
|
||||
{ rcvQ :: TBQueue (Text, ChatCommand),
|
||||
sndQ :: TBQueue ChatSrvResponse
|
||||
sndQ :: TBQueue AChatSrvResponse
|
||||
}
|
||||
|
||||
newChatServerClient :: Natural -> STM ChatClient
|
||||
|
@ -78,14 +107,14 @@ runChatServer ChatServerConfig {chatPort, clientQSize} cc = do
|
|||
getConnection sock = WS.makePendingConnection sock WS.defaultConnectionOptions >>= WS.acceptRequest
|
||||
send ws ChatClient {sndQ} =
|
||||
forever $
|
||||
atomically (readTBQueue sndQ) >>= WS.sendTextData ws . J.encode
|
||||
atomically (readTBQueue sndQ) >>= \(ACR r) -> WS.sendTextData ws (J.encode r)
|
||||
client ChatClient {rcvQ, sndQ} = forever $ do
|
||||
atomically (readTBQueue rcvQ)
|
||||
>>= processCommand
|
||||
>>= atomically . writeTBQueue sndQ
|
||||
>>= atomically . writeTBQueue sndQ . ACR
|
||||
output ChatClient {sndQ} = forever $ do
|
||||
(_, _, resp) <- atomically . readTBQueue $ outputQ cc
|
||||
atomically $ writeTBQueue sndQ ChatSrvResponse {corrId = Nothing, resp}
|
||||
(_, r) <- atomically . readTBQueue $ outputQ cc
|
||||
atomically $ writeTBQueue sndQ $ ACR ChatSrvResponse {corrId = Nothing, resp = CSRBody r}
|
||||
receive ws ChatClient {rcvQ, sndQ} = forever $ do
|
||||
s <- WS.receiveData ws
|
||||
case J.decodeStrict' s of
|
||||
|
@ -96,11 +125,9 @@ runChatServer ChatServerConfig {chatPort, clientQSize} cc = do
|
|||
Left e -> sendError (Just corrId) e
|
||||
Nothing -> sendError Nothing "invalid request"
|
||||
where
|
||||
sendError corrId e = atomically $ writeTBQueue sndQ ChatSrvResponse {corrId, resp = chatCmdError Nothing e}
|
||||
sendError corrId e = atomically $ writeTBQueue sndQ $ ACR ChatSrvResponse {corrId, resp = CSRBody $ chatCmdError e}
|
||||
processCommand (corrId, cmd) =
|
||||
runReaderT (runExceptT $ processChatCommand cmd) cc >>= \case
|
||||
Right resp -> response resp
|
||||
Left e -> response $ CRChatCmdError Nothing e
|
||||
response <$> runReaderT (runExceptT $ processChatCommand cmd) cc
|
||||
where
|
||||
response resp = pure ChatSrvResponse {corrId = Just corrId, resp}
|
||||
response r = ChatSrvResponse {corrId = Just corrId, resp = CSRBody r}
|
||||
clientDisconnected _ = pure ()
|
||||
|
|
|
@ -63,41 +63,44 @@ data DirectoryEvent
|
|||
| DELogChatResponse Text
|
||||
deriving (Show)
|
||||
|
||||
crDirectoryEvent :: ChatResponse -> Maybe DirectoryEvent
|
||||
crDirectoryEvent :: Either ChatError ChatEvent -> Maybe DirectoryEvent
|
||||
crDirectoryEvent = \case
|
||||
CRContactConnected {contact} -> Just $ DEContactConnected contact
|
||||
CRReceivedGroupInvitation {contact, groupInfo, fromMemberRole, memberRole} -> Just $ DEGroupInvitation {contact, groupInfo, fromMemberRole, memberRole}
|
||||
CRUserJoinedGroup {groupInfo, hostMember} -> (\contactId -> DEServiceJoinedGroup {contactId, groupInfo, hostMember}) <$> memberContactId hostMember
|
||||
CRGroupUpdated {fromGroup, toGroup, member_} -> (\member -> DEGroupUpdated {member, fromGroup, toGroup}) <$> member_
|
||||
CRJoinedGroupMember {groupInfo, member = m}
|
||||
Right evt -> crDirectoryEvent_ evt
|
||||
Left e -> case e of
|
||||
ChatErrorAgent {agentError = BROKER _ NETWORK} -> Nothing
|
||||
ChatErrorAgent {agentError = BROKER _ TIMEOUT} -> Nothing
|
||||
_ -> Just $ DELogChatResponse $ "chat error: " <> tshow e
|
||||
|
||||
crDirectoryEvent_ :: ChatEvent -> Maybe DirectoryEvent
|
||||
crDirectoryEvent_ = \case
|
||||
CEvtContactConnected {contact} -> Just $ DEContactConnected contact
|
||||
CEvtReceivedGroupInvitation {contact, groupInfo, fromMemberRole, memberRole} -> Just $ DEGroupInvitation {contact, groupInfo, fromMemberRole, memberRole}
|
||||
CEvtUserJoinedGroup {groupInfo, hostMember} -> (\contactId -> DEServiceJoinedGroup {contactId, groupInfo, hostMember}) <$> memberContactId hostMember
|
||||
CEvtGroupUpdated {fromGroup, toGroup, member_} -> (\member -> DEGroupUpdated {member, fromGroup, toGroup}) <$> member_
|
||||
CEvtJoinedGroupMember {groupInfo, member = m}
|
||||
| pending m -> Just $ DEPendingMember groupInfo m
|
||||
| otherwise -> Nothing
|
||||
CRNewChatItems {chatItems = AChatItem _ _ (GroupChat g) ci : _} -> case ci of
|
||||
CEvtNewChatItems {chatItems = AChatItem _ _ (GroupChat g) ci : _} -> case ci of
|
||||
ChatItem {chatDir = CIGroupRcv m, content = CIRcvMsgContent (MCText t)} | pending m -> Just $ DEPendingMemberMsg g m (chatItemId' ci) t
|
||||
_ -> Nothing
|
||||
CRMemberRole {groupInfo, member, toRole}
|
||||
CEvtMemberRole {groupInfo, member, toRole}
|
||||
| groupMemberId' member == groupMemberId' (membership groupInfo) -> Just $ DEServiceRoleChanged groupInfo toRole
|
||||
| otherwise -> (\ctId -> DEContactRoleChanged groupInfo ctId toRole) <$> memberContactId member
|
||||
CRDeletedMember {groupInfo, deletedMember} -> (`DEContactRemovedFromGroup` groupInfo) <$> memberContactId deletedMember
|
||||
CRLeftMember {groupInfo, member} -> (`DEContactLeftGroup` groupInfo) <$> memberContactId member
|
||||
CRDeletedMemberUser {groupInfo} -> Just $ DEServiceRemovedFromGroup groupInfo
|
||||
CRGroupDeleted {groupInfo} -> Just $ DEGroupDeleted groupInfo
|
||||
CRChatItemUpdated {chatItem = AChatItem _ SMDRcv (DirectChat ct) _} -> Just $ DEItemEditIgnored ct
|
||||
CRChatItemsDeleted {chatItemDeletions = ((ChatItemDeletion (AChatItem _ SMDRcv (DirectChat ct) _) _) : _), byUser = False} -> Just $ DEItemDeleteIgnored ct
|
||||
CRNewChatItems {chatItems = (AChatItem _ SMDRcv (DirectChat ct) ci@ChatItem {content = CIRcvMsgContent mc, meta = CIMeta {itemLive}}) : _} ->
|
||||
CEvtDeletedMember {groupInfo, deletedMember} -> (`DEContactRemovedFromGroup` groupInfo) <$> memberContactId deletedMember
|
||||
CEvtLeftMember {groupInfo, member} -> (`DEContactLeftGroup` groupInfo) <$> memberContactId member
|
||||
CEvtDeletedMemberUser {groupInfo} -> Just $ DEServiceRemovedFromGroup groupInfo
|
||||
CEvtGroupDeleted {groupInfo} -> Just $ DEGroupDeleted groupInfo
|
||||
CEvtChatItemUpdated {chatItem = AChatItem _ SMDRcv (DirectChat ct) _} -> Just $ DEItemEditIgnored ct
|
||||
CEvtChatItemsDeleted {chatItemDeletions = ((ChatItemDeletion (AChatItem _ SMDRcv (DirectChat ct) _) _) : _), byUser = False} -> Just $ DEItemDeleteIgnored ct
|
||||
CEvtNewChatItems {chatItems = (AChatItem _ SMDRcv (DirectChat ct) ci@ChatItem {content = CIRcvMsgContent mc, meta = CIMeta {itemLive}}) : _} ->
|
||||
Just $ case (mc, itemLive) of
|
||||
(MCText t, Nothing) -> DEContactCommand ct ciId $ fromRight err $ A.parseOnly (directoryCmdP <* A.endOfInput) $ T.dropWhileEnd isSpace t
|
||||
_ -> DEUnsupportedMessage ct ciId
|
||||
where
|
||||
ciId = chatItemId' ci
|
||||
err = ADC SDRUser DCUnknownCommand
|
||||
CRMessageError {severity, errorMessage} -> Just $ DELogChatResponse $ "message error: " <> severity <> ", " <> errorMessage
|
||||
CRChatCmdError {chatError} -> Just $ DELogChatResponse $ "chat cmd error: " <> tshow chatError
|
||||
CRChatError {chatError} -> case chatError of
|
||||
ChatErrorAgent {agentError = BROKER _ NETWORK} -> Nothing
|
||||
ChatErrorAgent {agentError = BROKER _ TIMEOUT} -> Nothing
|
||||
_ -> Just $ DELogChatResponse $ "chat error: " <> tshow chatError
|
||||
CRChatErrors {chatErrors} -> Just $ DELogChatResponse $ "chat errors: " <> T.intercalate ", " (map tshow chatErrors)
|
||||
CEvtMessageError {severity, errorMessage} -> Just $ DELogChatResponse $ "message error: " <> severity <> ", " <> errorMessage
|
||||
CEvtChatErrors {chatErrors} -> Just $ DELogChatResponse $ "chat errors: " <> T.intercalate ", " (map tshow chatErrors)
|
||||
_ -> Nothing
|
||||
where
|
||||
pending m = memberStatus m == GSMemPendingApproval
|
||||
|
|
|
@ -60,7 +60,7 @@ import Simplex.Chat.Terminal (terminalChatConfig)
|
|||
import Simplex.Chat.Terminal.Main (simplexChatCLI')
|
||||
import Simplex.Chat.Types
|
||||
import Simplex.Chat.Types.Shared
|
||||
import Simplex.Chat.View (serializeChatResponse, simplexChatContact, viewContactName, viewGroupName)
|
||||
import Simplex.Chat.View (serializeChatError, serializeChatResponse, simplexChatContact, viewContactName, viewGroupName)
|
||||
import Simplex.Messaging.Agent.Protocol (AConnectionLink (..), ConnectionLink (..), CreatedConnLink (..))
|
||||
import Simplex.Messaging.Agent.Store.Common (withTransaction)
|
||||
import Simplex.Messaging.Agent.Protocol (SConnectionMode (..), sameConnReqContact, sameShortLinkContact)
|
||||
|
@ -153,7 +153,7 @@ directoryService :: DirectoryStore -> DirectoryOpts -> ServiceState -> User -> C
|
|||
directoryService st opts@DirectoryOpts {testing} env user cc = do
|
||||
initializeBotAddress' (not testing) cc
|
||||
race_ (forever $ void getLine) . forever $ do
|
||||
(_, _, resp) <- atomically . readTBQueue $ outputQ cc
|
||||
(_, resp) <- atomically . readTBQueue $ outputQ cc
|
||||
directoryServiceEvent st opts env user cc resp
|
||||
|
||||
acceptMemberHook :: DirectoryOpts -> ServiceState -> GroupInfo -> GroupLinkInfo -> Profile -> IO (Either GroupRejectionReason (GroupAcceptance, GroupMemberRole))
|
||||
|
@ -197,7 +197,7 @@ readBlockedWordsConfig DirectoryOpts {blockedFragmentsFile, blockedWordsFile, na
|
|||
unless testing $ putStrLn $ "Blocked fragments: " <> show (length blockedFragments) <> ", blocked words: " <> show (length blockedWords) <> ", spelling rules: " <> show (M.size spelling)
|
||||
pure BlockedWordsConfig {blockedFragments, blockedWords, extensionRules, spelling}
|
||||
|
||||
directoryServiceEvent :: DirectoryStore -> DirectoryOpts -> ServiceState -> User -> ChatController -> ChatResponse -> IO ()
|
||||
directoryServiceEvent :: DirectoryStore -> DirectoryOpts -> ServiceState -> User -> ChatController -> Either ChatError ChatEvent -> IO ()
|
||||
directoryServiceEvent st opts@DirectoryOpts {adminUsers, superUsers, serviceName, ownersGroup, searchResults} env@ServiceState {searchRequests} user@User {userId} cc event =
|
||||
forM_ (crDirectoryEvent event) $ \case
|
||||
DEContactConnected ct -> deContactConnected ct
|
||||
|
@ -249,7 +249,7 @@ directoryServiceEvent st opts@DirectoryOpts {adminUsers, superUsers, serviceName
|
|||
getGroups_ :: Maybe Text -> IO (Maybe [(GroupInfo, GroupSummary)])
|
||||
getGroups_ search_ =
|
||||
sendChatCmd cc (APIListGroups userId Nothing $ T.unpack <$> search_) >>= \case
|
||||
CRGroupsList {groups} -> pure $ Just groups
|
||||
Right CRGroupsList {groups} -> pure $ Just groups
|
||||
_ -> pure Nothing
|
||||
|
||||
getDuplicateGroup :: GroupInfo -> IO (Maybe DuplicateGroup)
|
||||
|
@ -281,7 +281,7 @@ directoryServiceEvent st opts@DirectoryOpts {adminUsers, superUsers, serviceName
|
|||
void $ addGroupReg st ct g GRSProposed
|
||||
r <- sendChatCmd cc $ APIJoinGroup groupId MFNone
|
||||
sendMessage cc ct $ case r of
|
||||
CRUserAcceptedGroupSent {} -> "Joining the group " <> displayName <> "…"
|
||||
Right CRUserAcceptedGroupSent {} -> "Joining the group " <> displayName <> "…"
|
||||
_ -> "Error joining group " <> displayName <> ", please re-send the invitation!"
|
||||
|
||||
deContactConnected :: Contact -> IO ()
|
||||
|
@ -337,7 +337,7 @@ directoryServiceEvent st opts@DirectoryOpts {adminUsers, superUsers, serviceName
|
|||
$>>= \mId -> resp <$> sendChatCmd cc (APIGroupMemberInfo dbGroupId mId)
|
||||
where
|
||||
resp = \case
|
||||
CRGroupMemberInfo {member} -> Just member
|
||||
Right CRGroupMemberInfo {member} -> Just member
|
||||
_ -> Nothing
|
||||
|
||||
deServiceJoinedGroup :: ContactId -> GroupInfo -> GroupMember -> IO ()
|
||||
|
@ -349,7 +349,7 @@ directoryServiceEvent st opts@DirectoryOpts {adminUsers, superUsers, serviceName
|
|||
let GroupInfo {groupId, groupProfile = GroupProfile {displayName}} = g
|
||||
notifyOwner gr $ "Joined the group " <> displayName <> ", creating the link…"
|
||||
sendChatCmd cc (APICreateGroupLink groupId GRMember False) >>= \case
|
||||
CRGroupLinkCreated {connLinkContact = CCLink gLink _} -> do
|
||||
Right CRGroupLinkCreated {connLinkContact = CCLink gLink _} -> do
|
||||
setGroupStatus st gr GRSPendingUpdate
|
||||
notifyOwner
|
||||
gr
|
||||
|
@ -357,7 +357,7 @@ directoryServiceEvent st opts@DirectoryOpts {adminUsers, superUsers, serviceName
|
|||
\Please add it to the group welcome message.\n\
|
||||
\For example, add:"
|
||||
notifyOwner gr $ "Link to join the group " <> displayName <> ": " <> strEncodeTxt (simplexChatContact gLink)
|
||||
CRChatCmdError _ (ChatError e) -> case e of
|
||||
Left (ChatError e) -> case e of
|
||||
CEGroupUserRole {} -> notifyOwner gr "Failed creating group link, as service is no longer an admin."
|
||||
CEGroupMemberUserRemoved -> notifyOwner gr "Failed creating group link, as service is removed from the group."
|
||||
CEGroupNotJoined _ -> notifyOwner gr $ unexpectedError "group not joined"
|
||||
|
@ -446,7 +446,7 @@ directoryServiceEvent st opts@DirectoryOpts {adminUsers, superUsers, serviceName
|
|||
groupProfileUpdate = profileUpdate <$> sendChatCmd cc (APIGetGroupLink groupId)
|
||||
where
|
||||
profileUpdate = \case
|
||||
CRGroupLink {connLinkContact = CCLink cr sl_} ->
|
||||
Right CRGroupLink {connLinkContact = CCLink cr sl_} ->
|
||||
let hadLinkBefore = profileHasGroupLink fromGroup
|
||||
hasLinkNow = profileHasGroupLink toGroup
|
||||
profileHasGroupLink GroupInfo {groupProfile = gp} =
|
||||
|
@ -503,7 +503,7 @@ directoryServiceEvent st opts@DirectoryOpts {adminUsers, superUsers, serviceName
|
|||
let role = if useMemberFilter image (makeObserver a) then GRObserver else maybe GRMember (\GroupLinkInfo {memberRole} -> memberRole) gli_
|
||||
gmId = groupMemberId' m
|
||||
sendChatCmd cc (APIAcceptMember groupId gmId role) >>= \case
|
||||
CRJoinedGroupMember {} -> do
|
||||
Right CRJoinedGroupMember {} -> do
|
||||
atomically $ TM.delete gmId $ pendingCaptchas env
|
||||
logInfo $ "Member " <> viewName displayName <> " accepted, group " <> tshow groupId <> ":" <> viewGroupName g
|
||||
r -> logError $ "unexpected accept member response: " <> tshow r
|
||||
|
@ -528,7 +528,7 @@ directoryServiceEvent st opts@DirectoryOpts {adminUsers, superUsers, serviceName
|
|||
let gmId = groupMemberId' m
|
||||
sendComposedMessages cc (SRGroup groupId $ Just gmId) [MCText rjctNotice]
|
||||
sendChatCmd cc (APIRemoveMembers groupId [gmId] False) >>= \case
|
||||
CRUserDeletedMembers _ _ (_ : _) _ -> do
|
||||
Right (CRUserDeletedMembers _ _ (_ : _) _) -> do
|
||||
atomically $ TM.delete gmId $ pendingCaptchas env
|
||||
logInfo $ "Member " <> viewName displayName <> " rejected, group " <> tshow groupId <> ":" <> viewGroupName g
|
||||
r -> logError $ "unexpected remove member response: " <> tshow r
|
||||
|
@ -699,11 +699,6 @@ directoryServiceEvent st opts@DirectoryOpts {adminUsers, superUsers, serviceName
|
|||
DCListUserGroups ->
|
||||
getUserGroupRegs st (contactId' ct) >>= \grs -> do
|
||||
sendReply $ tshow (length grs) <> " registered group(s)"
|
||||
-- debug how it can be that user has 0 registered groups
|
||||
when (length grs == 0) $ do
|
||||
total <- length <$> readTVarIO (groupRegs st)
|
||||
withSuperUsers $ \ctId -> sendMessage' cc ctId $
|
||||
"0 registered groups for " <> localDisplayName' ct <> " (" <> tshow (contactId' ct) <> ") out of " <> tshow total <> " registrations"
|
||||
void . forkIO $ forM_ (reverse grs) $ \gr@GroupReg {userGroupRegId} ->
|
||||
sendGroupInfo ct gr userGroupRegId Nothing
|
||||
DCDeleteGroup gId gName ->
|
||||
|
@ -896,18 +891,21 @@ directoryServiceEvent st opts@DirectoryOpts {adminUsers, superUsers, serviceName
|
|||
let groupRef = groupReference' groupId gName
|
||||
withGroupAndReg sendReply groupId gName $ \_ _ ->
|
||||
sendChatCmd cc (APIGetGroupLink groupId) >>= \case
|
||||
CRGroupLink {connLinkContact = CCLink cReq _, memberRole} ->
|
||||
Right CRGroupLink {connLinkContact = CCLink cReq _, memberRole} ->
|
||||
sendReply $ T.unlines
|
||||
[ "The link to join the group " <> groupRef <> ":",
|
||||
strEncodeTxt $ simplexChatContact cReq,
|
||||
"New member role: " <> strEncodeTxt memberRole
|
||||
]
|
||||
CRChatCmdError _ (ChatErrorStore (SEGroupLinkNotFound _)) ->
|
||||
Left (ChatErrorStore (SEGroupLinkNotFound _)) ->
|
||||
sendReply $ "The group " <> groupRef <> " has no public link."
|
||||
r -> do
|
||||
Right r -> do
|
||||
ts <- getCurrentTime
|
||||
tz <- getCurrentTimeZone
|
||||
let resp = T.pack $ serializeChatResponse (Nothing, Just user) ts tz Nothing r
|
||||
let resp = T.pack $ serializeChatResponse (Nothing, Just user) (config cc) ts tz Nothing r
|
||||
sendReply $ "Unexpected error:\n" <> resp
|
||||
Left e -> do
|
||||
let resp = T.pack $ serializeChatError True (config cc) e
|
||||
sendReply $ "Unexpected error:\n" <> resp
|
||||
DCSendToGroupOwner groupId gName msg -> do
|
||||
let groupRef = groupReference' groupId gName
|
||||
|
@ -949,11 +947,11 @@ directoryServiceEvent st opts@DirectoryOpts {adminUsers, superUsers, serviceName
|
|||
inviteToOwnersGroup :: KnownGroup -> GroupReg -> (Either Text () -> IO a) -> IO a
|
||||
inviteToOwnersGroup KnownGroup {groupId = ogId} GroupReg {dbContactId = ctId} cont =
|
||||
sendChatCmd cc (APIListMembers ogId) >>= \case
|
||||
CRGroupMembers _ (Group _ ms)
|
||||
Right (CRGroupMembers _ (Group _ ms))
|
||||
| alreadyMember ms -> cont $ Left "Owner is already a member of owners' group"
|
||||
| otherwise -> do
|
||||
sendChatCmd cc (APIAddMember ogId ctId GRMember) >>= \case
|
||||
CRSentGroupInvitation {} -> do
|
||||
Right CRSentGroupInvitation {} -> do
|
||||
printLog cc CLLInfo $ "invited contact ID " <> show ctId <> " to owners' group"
|
||||
cont $ Right ()
|
||||
r -> contErr r
|
||||
|
@ -974,10 +972,13 @@ directoryServiceEvent st opts@DirectoryOpts {adminUsers, superUsers, serviceName
|
|||
deSuperUserCommand ct ciId cmd
|
||||
| knownContact ct `elem` superUsers = case cmd of
|
||||
DCExecuteCommand cmdStr ->
|
||||
sendChatCmdStr cc cmdStr >>= \r -> do
|
||||
ts <- getCurrentTime
|
||||
tz <- getCurrentTimeZone
|
||||
sendReply $ T.pack $ serializeChatResponse (Nothing, Just user) ts tz Nothing r
|
||||
sendChatCmdStr cc cmdStr >>= \case
|
||||
Right r -> do
|
||||
ts <- getCurrentTime
|
||||
tz <- getCurrentTimeZone
|
||||
sendReply $ T.pack $ serializeChatResponse (Nothing, Just user) (config cc) ts tz Nothing r
|
||||
Left e ->
|
||||
sendReply $ T.pack $ serializeChatError True (config cc) e
|
||||
DCCommandError tag -> sendReply $ "Command error: " <> tshow tag
|
||||
| otherwise = sendReply "You are not allowed to use this command"
|
||||
where
|
||||
|
@ -1050,7 +1051,7 @@ setGroupLinkRole :: ChatController -> GroupInfo -> GroupMemberRole -> IO (Maybe
|
|||
setGroupLinkRole cc GroupInfo {groupId} mRole = resp <$> sendChatCmd cc (APIGroupLinkMemberRole groupId mRole)
|
||||
where
|
||||
resp = \case
|
||||
CRGroupLink _ _ (CCLink gLink _) _ -> Just gLink
|
||||
Right (CRGroupLink _ _ (CCLink gLink _) _) -> Just gLink
|
||||
_ -> Nothing
|
||||
|
||||
unexpectedError :: Text -> Text
|
||||
|
|
|
@ -212,7 +212,7 @@ delGroupReg st GroupReg {dbGroupId = gId, groupRegStatus} = do
|
|||
logGDelete st gId
|
||||
atomically $ writeTVar groupRegStatus GRSRemoved
|
||||
atomically $ unlistGroup st gId
|
||||
atomically $ modifyTVar' (groupRegs st) $ filter ((gId ==) . dbGroupId)
|
||||
atomically $ modifyTVar' (groupRegs st) $ filter ((gId /=) . dbGroupId)
|
||||
|
||||
setGroupStatus :: DirectoryStore -> GroupReg -> GroupRegStatus -> IO ()
|
||||
setGroupStatus st gr grStatus = do
|
||||
|
|
|
@ -12,7 +12,7 @@ constraints: zip +disable-bzip2 +disable-zstd
|
|||
source-repository-package
|
||||
type: git
|
||||
location: https://github.com/simplex-chat/simplexmq.git
|
||||
tag: ec5a60430d6e2b1b4f33fa1790effbb6060bf7b8
|
||||
tag: deaec3cce286e959bd594b9620c307954b510a07
|
||||
|
||||
source-repository-package
|
||||
type: git
|
||||
|
|
177
docs/dependencies/HASKELL.md
Normal file
177
docs/dependencies/HASKELL.md
Normal file
|
@ -0,0 +1,177 @@
|
|||
# Dependency License Report
|
||||
|
||||
Bold-faced **`package-name`**s denote standard libraries bundled with `ghc-9.6.3`.
|
||||
|
||||
## Direct dependencies of `simplex-chat:exe:simplex-chat`
|
||||
|
||||
| Name | Version | [SPDX](https://spdx.org/licenses/) License Id | Description | Also depended upon by |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| **`base`** | [`4.18.1.0`](http://hackage.haskell.org/package/base-4.18.1.0) | [`BSD-3-Clause`](http://hackage.haskell.org/package/base-4.18.1.0/src/LICENSE) | Basic libraries | *(core library)* |
|
||||
| `base64-bytestring` | [`1.2.1.0`](http://hackage.haskell.org/package/base64-bytestring-1.2.1.0) | [`BSD-3-Clause`](./licences/haskell/base64-bytestring-1.2.1.0/LICENSE) | Fast base64 encoding and decoding for ByteStrings | `simplexmq`, `websockets` |
|
||||
| **`bytestring`** | [`0.11.5.2`](http://hackage.haskell.org/package/bytestring-0.11.5.2) | [`BSD-3-Clause`](http://hackage.haskell.org/package/bytestring-0.11.5.2/src/LICENSE) | Fast, compact, strict and lazy byte strings with a list interface | `SHA`, `aeson`, `appar`, `asn1-encoding`, `asn1-parse`, `asn1-types`, `attoparsec`, `base64-bytestring`, `binary`, `bitvec`, `blaze-builder`, `blaze-textual`, `bytestring-builder`, `case-insensitive`, `cereal`, `conduit`, `conduit-extra`, `cryptohash-md5`, `cryptohash-sha1`, `crypton`, `crypton-x509`, `crypton-x509-store`, `crypton-x509-validation`, `cryptostore`, `digest`, `direct-sqlcipher`, `email-validate`, `entropy`, `fast-logger`, `file-embed`, `filepath`, `hashable`, `http-types`, `http2`, `integer-conversion`, `iproute`, `libyaml`, `memory`, `monad-logger`, `mono-traversable`, `network`, `network-byte-order`, `network-transport`, `network-udp`, `parsec`, `pem`, `random`, `scientific`, `simplexmq`, `socks`, `sqlcipher-simple`, `streaming-commons`, `strict`, `terminal`, `text`, `text-short`, `tls`, `typed-process`, `unix`, `unix-time`, `unliftio`, `uuid`, `uuid-types`, `vector-algorithms`, `websockets`, `yaml`, `zip`, `zlib`, `zstd` |
|
||||
| `composition` | [`1.0.2.2`](http://hackage.haskell.org/package/composition-1.0.2.2) | [`BSD-3-Clause`](./licences/haskell/composition-1.0.2.2/LICENSE) | Combinators for unorthodox function composition | `simplexmq` |
|
||||
| `constraints` | [`0.14`](http://hackage.haskell.org/package/constraints-0.14) | [`BSD-2-Clause`](./licences/haskell/constraints-0.14/LICENSE) | Constraint manipulation | `simplexmq` |
|
||||
| **`containers`** | [`0.6.7`](http://hackage.haskell.org/package/containers-0.6.7) | [`BSD-3-Clause`](http://hackage.haskell.org/package/containers-0.6.7/src/LICENSE) | Assorted concrete container types | `QuickCheck`, `aeson`, `attoparsec`, `bifunctors`, `binary`, `cereal`, `comonad`, `crypton-x509`, `crypton-x509-store`, `crypton-x509-validation`, `data-default-instances-containers`, `hashable`, `http2`, `indexed-traversable`, `iproute`, `mono-traversable`, `network-udp`, `resourcet`, `scientific`, `semialign`, `semigroupoids`, `simplexmq`, `sqlcipher-simple`, `th-abstraction`, `websockets`, `witherable`, `yaml`, `zip` |
|
||||
| `crypton` | [`0.34`](http://hackage.haskell.org/package/crypton-0.34) | [`BSD-3-Clause`](./licences/haskell/crypton-0.34/LICENSE) | Cryptography Primitives sink | `crypton-x509`, `crypton-x509-store`, `crypton-x509-validation`, `cryptostore`, `simplexmq`, `tls` |
|
||||
| `uuid` | [`1.3.15`](http://hackage.haskell.org/package/uuid-1.3.15) | [`BSD-3-Clause`](./licences/haskell/uuid-1.3.15/LICENSE) | For creating, comparing, parsing and printing Universally Unique Identifiers | |
|
||||
| **`directory`** | [`1.3.8.1`](http://hackage.haskell.org/package/directory-1.3.8.1) | [`BSD-3-Clause`](http://hackage.haskell.org/package/directory-1.3.8.1/src/LICENSE) | Platform-agnostic library for filesystem operations | `conduit`, `conduit-extra`, `crypton-x509-store`, `easy-file`, `fast-logger`, `file-embed`, `network`, `process`, `simplexmq`, `streaming-commons`, `temporary`, `unliftio`, `yaml`, `zip` |
|
||||
| `direct-sqlcipher` | [`2.3.28`](http://hackage.haskell.org/package/direct-sqlcipher-2.3.28) | *MISSING* | *MISSING* | `simplexmq`, `sqlcipher-simple` |
|
||||
| `data-default` | [`0.7.1.1`](http://hackage.haskell.org/package/data-default-0.7.1.1) | [`BSD-3-Clause`](./licences/haskell/data-default-0.7.1.1/LICENSE) | A class for types with a default value | `simplexmq` |
|
||||
| **`exceptions`** | [`0.10.7`](http://hackage.haskell.org/package/exceptions-0.10.7) | [`BSD-3-Clause`](http://hackage.haskell.org/package/exceptions-0.10.7/src/LICENSE) | Extensible optionally-pure exceptions | `aeson`, `conduit`, `filepath`, `monad-logger`, `resourcet`, `safe-exceptions`, `sqlcipher-simple`, `temporary`, `terminal`, `zip` |
|
||||
| **`filepath`** | [`1.4.100.4`](http://hackage.haskell.org/package/filepath-1.4.100.4) | [`BSD-3-Clause`](http://hackage.haskell.org/package/filepath-1.4.100.4/src/LICENSE) | Library for manipulating FilePaths in a cross platform way. | `conduit`, `conduit-extra`, `crypton-x509-store`, `directory`, `easy-file`, `fast-logger`, `file-embed`, `hashable`, `process`, `simplexmq`, `temporary`, `unix`, `unliftio`, `yaml`, `zip` |
|
||||
| `file-embed` | [`0.0.15.0`](http://hackage.haskell.org/package/file-embed-0.0.15.0) | [`BSD-2-Clause`](./licences/haskell/file-embed-0.0.15.0/LICENSE) | Use Template Haskell to embed file contents directly. | |
|
||||
| `http-types` | [`0.12.4`](http://hackage.haskell.org/package/http-types-0.12.4) | [`BSD-3-Clause`](./licences/haskell/http-types-0.12.4/LICENSE) | Generic HTTP types for Haskell (for both client and server code). | `http2`, `simplexmq` |
|
||||
| `http2` | [`5.0.0`](http://hackage.haskell.org/package/http2-5.0.0) | [`BSD-3-Clause`](./licences/haskell/http2-5.0.0/LICENSE) | HTTP/2 library | `simplexmq` |
|
||||
| `email-validate` | [`2.3.2.19`](http://hackage.haskell.org/package/email-validate-2.3.2.19) | [`BSD-3-Clause`](./licences/haskell/email-validate-2.3.2.19/LICENSE) | Email address validation | |
|
||||
| `memory` | [`0.18.0`](http://hackage.haskell.org/package/memory-0.18.0) | [`BSD-3-Clause`](./licences/haskell/memory-0.18.0/LICENSE) | memory and related abstraction stuff | `asn1-types`, `crypton`, `crypton-x509`, `crypton-x509-validation`, `cryptostore`, `pem`, `simplexmq`, `tls` |
|
||||
| **`mtl`** | [`2.3.1`](http://hackage.haskell.org/package/mtl-2.3.1) | [`BSD-3-Clause`](http://hackage.haskell.org/package/mtl-2.3.1/src/LICENSE) | Monad classes for transformers, using functional dependencies | `conduit`, `constraints`, `crypton-x509-store`, `crypton-x509-validation`, `exceptions`, `monad-logger`, `parsec`, `random`, `resourcet`, `simple-logger`, `simplexmq`, `tls`, `yaml`, `zip` |
|
||||
| `unliftio` | [`0.2.25.0`](http://hackage.haskell.org/package/unliftio-0.2.25.0) | [`MIT`](./licences/haskell/unliftio-0.2.25.0/LICENSE) | The MonadUnliftIO typeclass for unlifting monads to IO (batteries included) | `http2`, `simplexmq`, `time-manager` |
|
||||
| `unliftio-core` | [`0.2.1.0`](http://hackage.haskell.org/package/unliftio-core-0.2.1.0) | [`MIT`](./licences/haskell/unliftio-core-0.2.1.0/LICENSE) | The MonadUnliftIO typeclass for unlifting monads to IO | `conduit`, `conduit-extra`, `monad-logger`, `resourcet`, `simplexmq`, `typed-process`, `unliftio` |
|
||||
| `ansi-terminal` | [`1.0`](http://hackage.haskell.org/package/ansi-terminal-1.0) | [`BSD-3-Clause`](./licences/haskell/ansi-terminal-1.0/LICENSE) | Simple ANSI terminal support | `prettyprinter-ansi-terminal` |
|
||||
| `network` | [`3.1.4.0`](http://hackage.haskell.org/package/network-3.1.4.0) | [`BSD-3-Clause`](./licences/haskell/network-3.1.4.0/LICENSE) | Low-level networking interface | `conduit-extra`, `http2`, `iproute`, `network-udp`, `simplexmq`, `socks`, `streaming-commons`, `tls`, `websockets` |
|
||||
| `network-transport` | [`0.5.6`](http://hackage.haskell.org/package/network-transport-0.5.6) | [`BSD-3-Clause`](./licences/haskell/network-transport-0.5.6/LICENSE) | Network abstraction layer | `simplexmq` |
|
||||
| **`process`** | [`1.6.17.0`](http://hackage.haskell.org/package/process-1.6.17.0) | [`BSD-3-Clause`](http://hackage.haskell.org/package/process-1.6.17.0/src/LICENSE) | Process libraries | `conduit-extra`, `optparse-applicative`, `simplexmq`, `streaming-commons`, `typed-process`, `unliftio` |
|
||||
| `optparse-applicative` | [`0.18.1.0`](http://hackage.haskell.org/package/optparse-applicative-0.18.1.0) | [`BSD-3-Clause`](./licences/haskell/optparse-applicative-0.18.1.0/LICENSE) | Utilities and combinators for parsing command line options | `simplexmq` |
|
||||
| `record-hasfield` | [`1.0`](http://hackage.haskell.org/package/record-hasfield-1.0) | [`BSD-3-Clause`](./licences/haskell/record-hasfield-1.0/LICENSE) | A version of GHC.Records as available in future GHCs. | |
|
||||
| `random` | [`1.2.1.1`](http://hackage.haskell.org/package/random-1.2.1.1) | [`BSD-3-Clause`](./licences/haskell/random-1.2.1.1/LICENSE) | Pseudo-random number generation | `QuickCheck`, `simplexmq`, `streaming-commons`, `temporary`, `uuid`, `uuid-types`, `websockets` |
|
||||
| `socks` | [`0.6.1`](http://hackage.haskell.org/package/socks-0.6.1) | [`BSD-3-Clause`](./licences/haskell/socks-0.6.1/LICENSE) | Socks proxy (ver 5) | `simplexmq` |
|
||||
| `scientific` | [`0.3.7.0`](http://hackage.haskell.org/package/scientific-0.3.7.0) | [`BSD-3-Clause`](./licences/haskell/scientific-0.3.7.0/LICENSE) | Numbers represented using scientific notation | `aeson`, `attoparsec`, `yaml` |
|
||||
| `simple-logger` | [`0.1.1`](http://hackage.haskell.org/package/simple-logger-0.1.1) | [`MIT`](./licences/haskell/simple-logger-0.1.1/LICENSE) | A very simple but efficient logging framework | `simplexmq` |
|
||||
| `simplexmq` | [`6.4.0.1`](http://hackage.haskell.org/package/simplexmq-6.4.0.1) | *MISSING* | *MISSING* | |
|
||||
| `aeson` | [`2.2.1.0`](http://hackage.haskell.org/package/aeson-2.2.1.0) | [`BSD-3-Clause`](./licences/haskell/aeson-2.2.1.0/LICENSE) | Fast JSON parsing and encoding | `simplexmq`, `yaml` |
|
||||
| `sqlcipher-simple` | [`0.4.18.1`](http://hackage.haskell.org/package/sqlcipher-simple-0.4.18.1) | *MISSING* | *MISSING* | `simplexmq` |
|
||||
| **`stm`** | [`2.5.1.0`](http://hackage.haskell.org/package/stm-2.5.1.0) | [`BSD-3-Clause`](http://hackage.haskell.org/package/stm-2.5.1.0/src/LICENSE) | Software Transactional Memory | `StateVar`, `async`, `conduit-extra`, `exceptions`, `fast-logger`, `http2`, `monad-control`, `monad-logger`, `simplexmq`, `stm-chans`, `streaming-commons`, `terminal`, `transformers-base`, `typed-process`, `unliftio` |
|
||||
| `async` | [`2.2.5`](http://hackage.haskell.org/package/async-2.2.5) | [`BSD-3-Clause`](./licences/haskell/async-2.2.5/LICENSE) | Run IO operations asynchronously and wait for their results | `conduit-extra`, `http2`, `simplexmq`, `streaming-commons`, `terminal`, `tls`, `typed-process`, `unliftio`, `websockets` |
|
||||
| **`template-haskell`** | [`2.20.0.0`](http://hackage.haskell.org/package/template-haskell-2.20.0.0) | [`BSD-3-Clause`](http://hackage.haskell.org/package/template-haskell-2.20.0.0/src/LICENSE) | Support library for Template Haskell | `OneTuple`, `QuickCheck`, `aeson`, `bifunctors`, `bytestring`, `containers`, `email-validate`, `exceptions`, `file-embed`, `filepath`, `monad-logger`, `network-uri`, `primitive`, `scientific`, `semigroupoids`, `sqlcipher-simple`, `tagged`, `text`, `text-short`, `th-abstraction`, `th-compat`, `unordered-containers`, `uuid-types`, `yaml` |
|
||||
| **`text`** | [`2.0.2`](http://hackage.haskell.org/package/text-2.0.2) | [`BSD-2-Clause`](http://hackage.haskell.org/package/text-2.0.2/src/LICENSE) | An efficient packed Unicode text type. | `aeson`, `attoparsec`, `blaze-builder`, `blaze-textual`, `case-insensitive`, `conduit`, `conduit-extra`, `direct-sqlcipher`, `fast-logger`, `hashable`, `http-types`, `ini`, `integer-conversion`, `monad-logger`, `mono-traversable`, `optparse-applicative`, `parsec`, `prettyprinter`, `prettyprinter-ansi-terminal`, `scientific`, `simple-logger`, `simplexmq`, `sqlcipher-simple`, `streaming-commons`, `strict`, `terminal`, `text-iso8601`, `text-short`, `uuid`, `uuid-types`, `websockets`, `yaml`, `zip` |
|
||||
| **`time`** | [`1.12.2`](http://hackage.haskell.org/package/time-1.12.2) | [`BSD-2-Clause`](http://hackage.haskell.org/package/time-1.12.2/src/LICENSE) | A time library | `aeson`, `directory`, `easy-file`, `iso8601-time`, `simplexmq`, `sqlcipher-simple`, `text-iso8601`, `time-compat`, `unix`, `unliftio`, `uuid`, `zip` |
|
||||
| `tls` | [`1.9.0`](http://hackage.haskell.org/package/tls-1.9.0) | [`BSD-3-Clause`](./licences/haskell/tls-1.9.0/LICENSE) | TLS/SSL protocol native implementation (Server and Client) | `simplexmq` |
|
||||
| `terminal` | [`0.2.0.0`](http://hackage.haskell.org/package/terminal-0.2.0.0) | [`BSD-3-Clause`](./licences/haskell/terminal-0.2.0.0/LICENSE) | Portable terminal interaction library | |
|
||||
| `attoparsec` | [`0.14.4`](http://hackage.haskell.org/package/attoparsec-0.14.4) | [`BSD-3-Clause`](./licences/haskell/attoparsec-0.14.4/LICENSE) | Fast combinator parsing for bytestrings and text | `conduit-extra`, `email-validate`, `ini`, `simplexmq`, `sqlcipher-simple`, `websockets`, `yaml` |
|
||||
| `websockets` | [`0.12.7.3`](http://hackage.haskell.org/package/websockets-0.12.7.3) | [`BSD-3-Clause`](./licences/haskell/websockets-0.12.7.3/LICENCE) | A sensible and clean way to write WebSocket-capable servers in Haskell. | `simplexmq` |
|
||||
| `zip` | [`2.0.0`](http://hackage.haskell.org/package/zip-2.0.0) | [`BSD-3-Clause`](./licences/haskell/zip-2.0.0/LICENSE.md) | Operations on zip archives | |
|
||||
|
||||
## Indirect transitive dependencies
|
||||
|
||||
| Name | Version | [SPDX](https://spdx.org/licenses/) License Id | Description | Depended upon by |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `OneTuple` | [`0.4.1.1`](http://hackage.haskell.org/package/OneTuple-0.4.1.1) | [`BSD-3-Clause`](./licences/haskell/OneTuple-0.4.1.1/LICENSE) | Singleton Tuple | `aeson`, `indexed-traversable-instances` |
|
||||
| `Only` | [`0.1`](http://hackage.haskell.org/package/Only-0.1) | [`BSD-3-Clause`](./licences/haskell/Only-0.1/LICENSE) | The 1-tuple type or single-value "collection" | `sqlcipher-simple` |
|
||||
| `QuickCheck` | [`2.14.3`](http://hackage.haskell.org/package/QuickCheck-2.14.3) | [`BSD-3-Clause`](./licences/haskell/QuickCheck-2.14.3/LICENSE) | Automatic testing of Haskell programs | `aeson` |
|
||||
| `SHA` | [`1.6.4.4`](http://hackage.haskell.org/package/SHA-1.6.4.4) | [`BSD-3-Clause`](./licences/haskell/SHA-1.6.4.4/LICENSE) | Implementations of the SHA suite of message digest functions | `websockets` |
|
||||
| `StateVar` | [`1.2.2`](http://hackage.haskell.org/package/StateVar-1.2.2) | [`BSD-3-Clause`](./licences/haskell/StateVar-1.2.2/LICENSE) | State variables | `contravariant` |
|
||||
| **`array`** | [`0.5.5.0`](http://hackage.haskell.org/package/array-0.5.5.0) | [`BSD-3-Clause`](http://hackage.haskell.org/package/array-0.5.5.0/src/LICENSE) | Mutable and immutable arrays | `SHA`, `attoparsec`, `binary`, `cereal`, `containers`, `deepseq`, `fast-logger`, `http-types`, `http2`, `indexed-traversable`, `integer-logarithms`, `stm`, `streaming-commons`, `text` |
|
||||
| `bifunctors` | [`5.6.1`](http://hackage.haskell.org/package/bifunctors-5.6.1) | [`BSD-3-Clause`](./licences/haskell/bifunctors-5.6.1/LICENSE) | Bifunctors | `semigroupoids` |
|
||||
| **`binary`** | [`0.8.9.1`](http://hackage.haskell.org/package/binary-0.8.9.1) | [`BSD-3-Clause`](http://hackage.haskell.org/package/binary-0.8.9.1/src/LICENSE) | Binary serialisation for Haskell values using lazy ByteStrings | `SHA`, `constraints`, `network-transport`, `scientific`, `strict`, `text`, `text-short`, `these`, `unix-time`, `uuid`, `uuid-types`, `websockets` |
|
||||
| `blaze-builder` | [`0.4.2.3`](http://hackage.haskell.org/package/blaze-builder-0.4.2.3) | [`BSD-3-Clause`](./licences/haskell/blaze-builder-0.4.2.3/LICENSE) | Efficient buffered output. | `blaze-textual`, `sqlcipher-simple` |
|
||||
| `blaze-textual` | [`0.2.3.1`](http://hackage.haskell.org/package/blaze-textual-0.2.3.1) | [`BSD-3-Clause`](./licences/haskell/blaze-textual-0.2.3.1/LICENSE) | Fast rendering of common datatypes | `sqlcipher-simple` |
|
||||
| `boring` | [`0.2.1`](http://hackage.haskell.org/package/boring-0.2.1) | [`BSD-3-Clause`](./licences/haskell/boring-0.2.1/LICENSE) | Boring and Absurd types | `constraints` |
|
||||
| `base-orphans` | [`0.9.1`](http://hackage.haskell.org/package/base-orphans-0.9.1) | [`MIT`](./licences/haskell/base-orphans-0.9.1/LICENSE) | Backwards-compatible orphan instances for base | `distributive`, `semigroupoids`, `time-compat`, `transformers-base`, `witherable` |
|
||||
| `basement` | [`0.0.16`](http://hackage.haskell.org/package/basement-0.0.16) | [`BSD-3-Clause`](./licences/haskell/basement-0.0.16/LICENSE) | Foundation scrap box of array & string | `crypton`, `cryptostore`, `memory`, `pem`, `socks` |
|
||||
| `bitvec` | [`1.1.5.0`](http://hackage.haskell.org/package/bitvec-1.1.5.0) | [`BSD-3-Clause`](./licences/haskell/bitvec-1.1.5.0/LICENSE) | Space-efficient bit vectors | `vector-algorithms` |
|
||||
| `byteorder` | [`1.0.4`](http://hackage.haskell.org/package/byteorder-1.0.4) | [`BSD-3-Clause`](./licences/haskell/byteorder-1.0.4/LICENSE) | Exposes the native endianness or byte ordering of the system. | `iproute` |
|
||||
| `bytestring-builder` | [`0.10.8.2.0`](http://hackage.haskell.org/package/bytestring-builder-0.10.8.2.0) | [`BSD-3-Clause`](./licences/haskell/bytestring-builder-0.10.8.2.0/LICENSE) | The new bytestring builder, packaged outside of GHC | `websockets` |
|
||||
| `clock` | [`0.8.4`](http://hackage.haskell.org/package/clock-0.8.4) | [`BSD-3-Clause`](./licences/haskell/clock-0.8.4/LICENSE) | High-resolution clock functions: monotonic, realtime, cputime. | `websockets` |
|
||||
| `colour` | [`2.3.6`](http://hackage.haskell.org/package/colour-2.3.6) | [`MIT`](./licences/haskell/colour-2.3.6/LICENSE) | A model for human colour/color perception | `ansi-terminal`, `ansi-terminal-types` |
|
||||
| `comonad` | [`5.0.8`](http://hackage.haskell.org/package/comonad-5.0.8) | [`BSD-3-Clause`](./licences/haskell/comonad-5.0.8/LICENSE) | Comonads | `bifunctors`, `semigroupoids` |
|
||||
| `conduit` | [`1.3.5`](http://hackage.haskell.org/package/conduit-1.3.5) | [`MIT`](./licences/haskell/conduit-1.3.5/LICENSE) | Streaming data processing library. | `conduit-extra`, `libyaml`, `monad-logger`, `yaml`, `zip` |
|
||||
| `conduit-extra` | [`1.3.6`](http://hackage.haskell.org/package/conduit-extra-1.3.6) | [`MIT`](./licences/haskell/conduit-extra-1.3.6/LICENSE) | Batteries included conduit: adapters for common libraries. | `monad-logger`, `zip` |
|
||||
| `contravariant` | [`1.5.5`](http://hackage.haskell.org/package/contravariant-1.5.5) | [`BSD-3-Clause`](./licences/haskell/contravariant-1.5.5/LICENSE) | Contravariant functors | `semigroupoids` |
|
||||
| `cereal` | [`0.5.8.3`](http://hackage.haskell.org/package/cereal-0.5.8.3) | [`BSD-3-Clause`](./licences/haskell/cereal-0.5.8.3/LICENSE) | A binary serialization library | `socks`, `tls`, `zip` |
|
||||
| `cryptohash-md5` | [`0.11.101.0`](http://hackage.haskell.org/package/cryptohash-md5-0.11.101.0) | [`BSD-3-Clause`](./licences/haskell/cryptohash-md5-0.11.101.0/LICENSE) | Fast, pure and practical MD5 implementation | `uuid` |
|
||||
| `cryptohash-sha1` | [`0.11.101.0`](http://hackage.haskell.org/package/cryptohash-sha1-0.11.101.0) | [`BSD-3-Clause`](./licences/haskell/cryptohash-sha1-0.11.101.0/LICENSE) | Fast, pure and practical SHA-1 implementation | `uuid` |
|
||||
| `crypton-x509` | [`1.7.6`](http://hackage.haskell.org/package/crypton-x509-1.7.6) | [`BSD-3-Clause`](./licences/haskell/crypton-x509-1.7.6/LICENSE) | X509 reader and writer | `crypton-x509-store`, `crypton-x509-validation`, `cryptostore`, `simplexmq`, `tls` |
|
||||
| `crypton-x509-store` | [`1.6.9`](http://hackage.haskell.org/package/crypton-x509-store-1.6.9) | [`BSD-3-Clause`](./licences/haskell/crypton-x509-store-1.6.9/LICENSE) | X.509 collection accessing and storing methods | `crypton-x509-validation`, `simplexmq`, `tls` |
|
||||
| `crypton-x509-validation` | [`1.6.12`](http://hackage.haskell.org/package/crypton-x509-validation-1.6.12) | [`BSD-3-Clause`](./licences/haskell/crypton-x509-validation-1.6.12/LICENSE) | X.509 Certificate and CRL validation | `cryptostore`, `simplexmq`, `tls` |
|
||||
| `cryptostore` | [`0.3.0.1`](http://hackage.haskell.org/package/cryptostore-0.3.0.1) | [`BSD-3-Clause`](./licences/haskell/cryptostore-0.3.0.1/LICENSE) | Serialization of cryptographic data types | `simplexmq` |
|
||||
| `case-insensitive` | [`1.2.1.0`](http://hackage.haskell.org/package/case-insensitive-1.2.1.0) | [`BSD-3-Clause`](./licences/haskell/case-insensitive-1.2.1.0/LICENSE) | Case insensitive string comparison | `http-types`, `http2`, `simplexmq`, `websockets`, `zip` |
|
||||
| `uuid-types` | [`1.0.5.1`](http://hackage.haskell.org/package/uuid-types-1.0.5.1) | [`BSD-3-Clause`](./licences/haskell/uuid-types-1.0.5.1/LICENSE) | Type definitions for Universally Unique Identifiers | `aeson`, `uuid` |
|
||||
| **`deepseq`** | [`1.4.8.1`](http://hackage.haskell.org/package/deepseq-1.4.8.1) | [`BSD-3-Clause`](http://hackage.haskell.org/package/deepseq-1.4.8.1/src/LICENSE) | Deep evaluation of data structures | `Only`, `QuickCheck`, `aeson`, `attoparsec`, `bitvec`, `blaze-builder`, `bytestring`, `bytestring-builder`, `case-insensitive`, `constraints`, `containers`, `crypton`, `data-fix`, `dlist`, `filepath`, `hashable`, `hourglass`, `memory`, `network`, `network-transport`, `network-uri`, `pretty`, `primitive`, `process`, `psqueues`, `random`, `safe-exceptions`, `scientific`, `splitmix`, `strict`, `tagged`, `text`, `text-short`, `these`, `time`, `time-compat`, `unliftio`, `unordered-containers`, `uuid-types`, `vector`, `zstd` |
|
||||
| `digest` | [`0.0.1.7`](http://hackage.haskell.org/package/digest-0.0.1.7) | [`BSD-2-Clause`](./licences/haskell/digest-0.0.1.7/LICENSE) | Various hashes for bytestrings; CRC32 and Adler32 for now. | `zip` |
|
||||
| `dlist` | [`1.0`](http://hackage.haskell.org/package/dlist-1.0) | [`BSD-3-Clause`](./licences/haskell/dlist-1.0/license.md) | Difference lists | `aeson`, `data-default-instances-dlist`, `zip` |
|
||||
| `distributive` | [`0.6.2.1`](http://hackage.haskell.org/package/distributive-0.6.2.1) | [`BSD-3-Clause`](./licences/haskell/distributive-0.6.2.1/LICENSE) | Distributive functors -- Dual to Traversable | `comonad`, `semigroupoids` |
|
||||
| `data-default-class` | [`0.1.2.0`](http://hackage.haskell.org/package/data-default-class-0.1.2.0) | [`BSD-3-Clause`](./licences/haskell/data-default-class-0.1.2.0/LICENSE) | A class for types with a default value | `crypton-x509-validation`, `data-default`, `data-default-instances-containers`, `data-default-instances-dlist`, `data-default-instances-old-locale`, `tls` |
|
||||
| `data-default-instances-containers` | [`0.0.1`](http://hackage.haskell.org/package/data-default-instances-containers-0.0.1) | [`BSD-3-Clause`](./licences/haskell/data-default-instances-containers-0.0.1/LICENSE) | Default instances for types in containers | `data-default` |
|
||||
| `data-default-instances-dlist` | [`0.0.1`](http://hackage.haskell.org/package/data-default-instances-dlist-0.0.1) | [`BSD-3-Clause`](./licences/haskell/data-default-instances-dlist-0.0.1/LICENSE) | Default instances for types in dlist | `data-default` |
|
||||
| `data-default-instances-old-locale` | [`0.0.1`](http://hackage.haskell.org/package/data-default-instances-old-locale-0.0.1) | [`BSD-3-Clause`](./licences/haskell/data-default-instances-old-locale-0.0.1/LICENSE) | Default instances for types in old-locale | `data-default` |
|
||||
| `data-fix` | [`0.3.2`](http://hackage.haskell.org/package/data-fix-0.3.2) | [`BSD-3-Clause`](./licences/haskell/data-fix-0.3.2/LICENSE) | Fixpoint data types | `aeson` |
|
||||
| `fast-logger` | [`3.2.2`](http://hackage.haskell.org/package/fast-logger-3.2.2) | [`BSD-3-Clause`](./licences/haskell/fast-logger-3.2.2/LICENSE) | A fast logging system | `monad-logger`, `simple-logger` |
|
||||
| **`ghc-bignum`** | [`1.3`](http://hackage.haskell.org/package/ghc-bignum-1.3) | [`BSD-3-Clause`](http://hackage.haskell.org/package/ghc-bignum-1.3/src/LICENSE) | GHC BigNum library | `base`, `bitvec`, `hashable`, `integer-gmp`, `integer-logarithms` |
|
||||
| **`ghc-boot-th`** | [`9.6.3`](http://hackage.haskell.org/package/ghc-boot-th-9.6.3) | [`BSD-3-Clause`](http://hackage.haskell.org/package/ghc-boot-th-9.6.3/src/LICENSE) | Shared functionality between GHC and the @template-haskell@ library | `template-haskell` |
|
||||
| **`ghc-prim`** | [`0.10.0`](http://hackage.haskell.org/package/ghc-prim-0.10.0) | [`BSD-3-Clause`](http://hackage.haskell.org/package/ghc-prim-0.10.0/src/LICENSE) | GHC primitives | *(core library)* |
|
||||
| `generically` | [`0.1.1`](http://hackage.haskell.org/package/generically-0.1.1) | [`BSD-3-Clause`](./licences/haskell/generically-0.1.1/LICENSE) | Generically newtype to use with DerivingVia | `aeson` |
|
||||
| `hourglass` | [`0.2.12`](http://hackage.haskell.org/package/hourglass-0.2.12) | [`BSD-3-Clause`](./licences/haskell/hourglass-0.2.12/LICENSE) | simple performant time related library | `asn1-encoding`, `asn1-types`, `crypton-x509`, `crypton-x509-validation`, `cryptostore`, `simplexmq` |
|
||||
| `hashable` | [`1.4.3.0`](http://hackage.haskell.org/package/hashable-1.4.3.0) | [`BSD-3-Clause`](./licences/haskell/hashable-1.4.3.0/LICENSE) | A class for types that can be converted to a hash value | `aeson`, `async`, `case-insensitive`, `constraints`, `data-fix`, `mono-traversable`, `network-transport`, `psqueues`, `scientific`, `semialign`, `semigroupoids`, `simplexmq`, `strict`, `text-short`, `these`, `time-compat`, `unordered-containers`, `uuid-types`, `witherable` |
|
||||
| **`integer-gmp`** | [`1.1`](http://hackage.haskell.org/package/integer-gmp-1.1) | [`BSD-3-Clause`](http://hackage.haskell.org/package/integer-gmp-1.1/src/LICENSE) | Integer library based on GMP | *(core library)* |
|
||||
| `libyaml` | [`0.1.2`](http://hackage.haskell.org/package/libyaml-0.1.2) | [`BSD-3-Clause`](./licences/haskell/libyaml-0.1.2/LICENSE) | Low-level, streaming YAML interface. | `yaml` |
|
||||
| `old-locale` | [`1.0.0.7`](http://hackage.haskell.org/package/old-locale-1.0.0.7) | [`BSD-3-Clause`](./licences/haskell/old-locale-1.0.0.7/LICENSE) | locale library | `blaze-textual`, `data-default-instances-old-locale`, `old-time` |
|
||||
| `old-time` | [`1.1.0.4`](http://hackage.haskell.org/package/old-time-1.1.0.4) | [`BSD-3-Clause`](./licences/haskell/old-time-1.1.0.4/LICENSE) | Time library | `unix-time` |
|
||||
| `lifted-base` | [`0.2.3.12`](http://hackage.haskell.org/package/lifted-base-0.2.3.12) | [`BSD-3-Clause`](./licences/haskell/lifted-base-0.2.3.12/LICENSE) | lifted IO operations from the base library | `monad-logger` |
|
||||
| `mono-traversable` | [`1.0.15.3`](http://hackage.haskell.org/package/mono-traversable-1.0.15.3) | [`MIT`](./licences/haskell/mono-traversable-1.0.15.3/LICENSE) | Type classes for mapping, folding, and traversing monomorphic containers | `conduit` |
|
||||
| `monad-control` | [`1.0.3.1`](http://hackage.haskell.org/package/monad-control-1.0.3.1) | [`BSD-3-Clause`](./licences/haskell/monad-control-1.0.3.1/LICENSE) | Lift control operations, like exception catching, through monad transformers | `lifted-base`, `monad-logger`, `zip` |
|
||||
| `monad-logger` | [`0.3.40`](http://hackage.haskell.org/package/monad-logger-0.3.40) | [`MIT`](./licences/haskell/monad-logger-0.3.40/LICENSE) | A class of monads which can log messages. | `simple-logger` |
|
||||
| `monad-loops` | [`0.4.3`](http://hackage.haskell.org/package/monad-loops-0.4.3) | [`LicenseRef-PublicDomain`](http://hackage.haskell.org/package/monad-loops-0.4.3) | Monadic loops | `monad-logger` |
|
||||
| `ini` | [`0.4.2`](http://hackage.haskell.org/package/ini-0.4.2) | [`BSD-3-Clause`](./licences/haskell/ini-0.4.2/LICENSE) | Configuration files in the INI format. | `simplexmq` |
|
||||
| `indexed-traversable` | [`0.1.3`](http://hackage.haskell.org/package/indexed-traversable-0.1.3) | [`BSD-2-Clause`](./licences/haskell/indexed-traversable-0.1.3/LICENSE) | FunctorWithIndex, FoldableWithIndex, TraversableWithIndex | `aeson`, `comonad`, `indexed-traversable-instances`, `semialign`, `witherable` |
|
||||
| `indexed-traversable-instances` | [`0.1.1.2`](http://hackage.haskell.org/package/indexed-traversable-instances-0.1.1.2) | [`BSD-2-Clause`](./licences/haskell/indexed-traversable-instances-0.1.1.2/LICENSE) | More instances of FunctorWithIndex, FoldableWithIndex, TraversableWithIndex | `semialign`, `witherable` |
|
||||
| `unordered-containers` | [`0.2.19.1`](http://hackage.haskell.org/package/unordered-containers-0.2.19.1) | [`BSD-3-Clause`](./licences/haskell/unordered-containers-0.2.19.1/LICENSE) | Efficient hashing-based container types | `aeson`, `indexed-traversable-instances`, `ini`, `mono-traversable`, `semialign`, `semigroupoids`, `witherable`, `yaml` |
|
||||
| `ansi-terminal-types` | [`0.11.5`](http://hackage.haskell.org/package/ansi-terminal-types-0.11.5) | [`BSD-3-Clause`](./licences/haskell/ansi-terminal-types-0.11.5/LICENSE) | Types and functions used to represent SGR aspects | `ansi-terminal` |
|
||||
| `integer-conversion` | [`0.1.0.1`](http://hackage.haskell.org/package/integer-conversion-0.1.0.1) | [`BSD-3-Clause`](./licences/haskell/integer-conversion-0.1.0.1/LICENSE) | Conversion from strings to Integer | `aeson`, `text-iso8601` |
|
||||
| `integer-logarithms` | [`1.0.3.1`](http://hackage.haskell.org/package/integer-logarithms-1.0.3.1) | [`MIT`](./licences/haskell/integer-logarithms-1.0.3.1/LICENSE) | Integer logarithms. | `aeson`, `scientific` |
|
||||
| `entropy` | [`0.4.1.10`](http://hackage.haskell.org/package/entropy-0.4.1.10) | [`BSD-3-Clause`](./licences/haskell/entropy-0.4.1.10/LICENSE) | A platform independent entropy source | `uuid`, `websockets` |
|
||||
| `network-byte-order` | [`0.1.7`](http://hackage.haskell.org/package/network-byte-order-0.1.7) | [`BSD-3-Clause`](./licences/haskell/network-byte-order-0.1.7/LICENSE) | Network byte order utilities | `http2` |
|
||||
| `network-control` | [`0.0.2`](http://hackage.haskell.org/package/network-control-0.0.2) | [`BSD-3-Clause`](./licences/haskell/network-control-0.0.2/LICENSE) | Library to control network protocols | `http2` |
|
||||
| `network-udp` | [`0.0.0`](http://hackage.haskell.org/package/network-udp-0.0.0) | [`BSD-3-Clause`](./licences/haskell/network-udp-0.0.0/LICENSE) | UDP library | `simplexmq` |
|
||||
| `network-info` | [`0.2.1`](http://hackage.haskell.org/package/network-info-0.2.1) | [`BSD-3-Clause`](./licences/haskell/network-info-0.2.1/LICENSE) | Access the local computer's basic network configuration | `simplexmq`, `uuid` |
|
||||
| `network-uri` | [`2.6.4.2`](http://hackage.haskell.org/package/network-uri-2.6.4.2) | [`BSD-3-Clause`](./licences/haskell/network-uri-2.6.4.2/LICENSE) | URI manipulation | `aeson` |
|
||||
| `unix-compat` | [`0.7.1`](http://hackage.haskell.org/package/unix-compat-0.7.1) | [`BSD-3-Clause`](./licences/haskell/unix-compat-0.7.1/LICENSE) | Portable POSIX-compatibility layer. | `fast-logger` |
|
||||
| `unix-time` | [`0.4.11`](http://hackage.haskell.org/package/unix-time-0.4.11) | [`BSD-3-Clause`](./licences/haskell/unix-time-0.4.11/LICENSE) | Unix time parser/formatter and utilities | `fast-logger`, `http2`, `network-control`, `tls` |
|
||||
| **`parsec`** | [`3.1.16.1`](http://hackage.haskell.org/package/parsec-3.1.16.1) | [`BSD-2-Clause`](http://hackage.haskell.org/package/parsec-3.1.16.1/src/LICENSE) | Monadic parser combinators | `network-uri` |
|
||||
| `pem` | [`0.2.4`](http://hackage.haskell.org/package/pem-0.2.4) | [`BSD-3-Clause`](./licences/haskell/pem-0.2.4/LICENSE) | Privacy Enhanced Mail (PEM) format reader and writer. | `crypton-x509`, `crypton-x509-store`, `crypton-x509-validation`, `cryptostore` |
|
||||
| `appar` | [`0.1.8`](http://hackage.haskell.org/package/appar-0.1.8) | [`BSD-3-Clause`](./licences/haskell/appar-0.1.8/LICENSE) | A simple applicative parser | `iproute` |
|
||||
| **`pretty`** | [`1.1.3.6`](http://hackage.haskell.org/package/pretty-1.1.3.6) | [`BSD-3-Clause`](http://hackage.haskell.org/package/pretty-1.1.3.6/src/LICENSE) | Pretty-printing library | `template-haskell` |
|
||||
| `primitive` | [`0.9.0.0`](http://hackage.haskell.org/package/primitive-0.9.0.0) | [`BSD-3-Clause`](./licences/haskell/primitive-0.9.0.0/LICENSE) | Primitive memory-related operations | `aeson`, `bitvec`, `conduit`, `conduit-extra`, `integer-conversion`, `resourcet`, `scientific`, `vector`, `vector-algorithms` |
|
||||
| `iproute` | [`1.7.12`](http://hackage.haskell.org/package/iproute-1.7.12) | [`BSD-3-Clause`](./licences/haskell/iproute-1.7.12/LICENSE) | IP Routing Table | `network-udp`, `simplexmq` |
|
||||
| `prettyprinter` | [`1.7.1`](http://hackage.haskell.org/package/prettyprinter-1.7.1) | [`BSD-2-Clause`](./licences/haskell/prettyprinter-1.7.1/LICENSE.md) | A modern, easy to use, well-documented, extensible pretty-printer. | `optparse-applicative`, `prettyprinter-ansi-terminal`, `terminal` |
|
||||
| `prettyprinter-ansi-terminal` | [`1.1.3`](http://hackage.haskell.org/package/prettyprinter-ansi-terminal-1.1.3) | [`BSD-2-Clause`](./licences/haskell/prettyprinter-ansi-terminal-1.1.3/LICENSE.md) | ANSI terminal backend for the »prettyprinter« package. | `optparse-applicative` |
|
||||
| `psqueues` | [`0.2.8.0`](http://hackage.haskell.org/package/psqueues-0.2.8.0) | [`BSD-3-Clause`](./licences/haskell/psqueues-0.2.8.0/LICENSE) | Pure priority search queues | `network-control` |
|
||||
| `resourcet` | [`1.3.0`](http://hackage.haskell.org/package/resourcet-1.3.0) | [`BSD-3-Clause`](./licences/haskell/resourcet-1.3.0/LICENSE) | Deterministic allocation and freeing of scarce resources. | `conduit`, `conduit-extra`, `libyaml`, `monad-logger`, `yaml`, `zip` |
|
||||
| `iso8601-time` | [`0.1.5`](http://hackage.haskell.org/package/iso8601-time-0.1.5) | [`MIT`](http://hackage.haskell.org/package/iso8601-time-0.1.5) | Convert to/from the ISO 8601 time format | `simplexmq` |
|
||||
| `safe-exceptions` | [`0.1.7.4`](http://hackage.haskell.org/package/safe-exceptions-0.1.7.4) | [`MIT`](./licences/haskell/safe-exceptions-0.1.7.4/LICENSE) | Safe, consistent, and easy exception handling | `unliftio` |
|
||||
| `semigroupoids` | [`6.0.0.1`](http://hackage.haskell.org/package/semigroupoids-6.0.0.1) | [`BSD-2-Clause`](./licences/haskell/semigroupoids-6.0.0.1/LICENSE) | Semigroupoids: Category sans id | `semialign` |
|
||||
| `semialign` | [`1.3`](http://hackage.haskell.org/package/semialign-1.3) | [`BSD-3-Clause`](./licences/haskell/semialign-1.3/LICENSE) | Align and Zip type-classes from the common Semialign ancestor. | `aeson` |
|
||||
| `asn1-encoding` | [`0.9.6`](http://hackage.haskell.org/package/asn1-encoding-0.9.6) | [`BSD-3-Clause`](./licences/haskell/asn1-encoding-0.9.6/LICENSE) | ASN1 data reader and writer in RAW, BER and DER forms | `asn1-parse`, `crypton-x509`, `crypton-x509-store`, `crypton-x509-validation`, `cryptostore`, `simplexmq`, `tls` |
|
||||
| `asn1-parse` | [`0.9.5`](http://hackage.haskell.org/package/asn1-parse-0.9.5) | [`BSD-3-Clause`](./licences/haskell/asn1-parse-0.9.5/LICENSE) | Simple monadic parser for ASN1 stream types. | `crypton-x509` |
|
||||
| `asn1-types` | [`0.3.4`](http://hackage.haskell.org/package/asn1-types-0.3.4) | [`BSD-3-Clause`](./licences/haskell/asn1-types-0.3.4/LICENSE) | ASN.1 types | `asn1-encoding`, `asn1-parse`, `crypton-x509`, `crypton-x509-store`, `crypton-x509-validation`, `cryptostore`, `simplexmq`, `tls` |
|
||||
| `split` | [`0.2.4`](http://hackage.haskell.org/package/split-0.2.4) | [`BSD-3-Clause`](./licences/haskell/split-0.2.4/LICENSE) | Combinator library for splitting lists. | `mono-traversable` |
|
||||
| `splitmix` | [`0.1.0.5`](http://hackage.haskell.org/package/splitmix-0.1.0.5) | [`BSD-3-Clause`](./licences/haskell/splitmix-0.1.0.5/LICENSE) | Fast Splittable PRNG | `QuickCheck`, `random` |
|
||||
| `assoc` | [`1.1`](http://hackage.haskell.org/package/assoc-1.1) | [`BSD-3-Clause`](./licences/haskell/assoc-1.1/LICENSE) | swap and assoc: Symmetric and Semigroupy Bifunctors | `bifunctors`, `strict`, `these` |
|
||||
| `stm-chans` | [`3.0.0.9`](http://hackage.haskell.org/package/stm-chans-3.0.0.9) | [`BSD-3-Clause`](./licences/haskell/stm-chans-3.0.0.9/LICENSE) | Additional types of channels for STM. | `monad-logger` |
|
||||
| `strict` | [`0.5`](http://hackage.haskell.org/package/strict-0.5) | [`BSD-3-Clause`](./licences/haskell/strict-0.5/LICENSE) | Strict data types and String IO. | `aeson` |
|
||||
| `streaming-commons` | [`0.2.2.6`](http://hackage.haskell.org/package/streaming-commons-0.2.2.6) | [`MIT`](./licences/haskell/streaming-commons-0.2.2.6/LICENSE) | Common lower-level functions needed by various streaming data libraries | `conduit-extra`, `websockets` |
|
||||
| `easy-file` | [`0.2.5`](http://hackage.haskell.org/package/easy-file-0.2.5) | [`BSD-3-Clause`](./licences/haskell/easy-file-0.2.5/LICENSE) | Cross-platform File handling | `fast-logger` |
|
||||
| `auto-update` | [`0.1.6`](http://hackage.haskell.org/package/auto-update-0.1.6) | [`MIT`](./licences/haskell/auto-update-0.1.6/LICENSE) | Efficiently run periodic, on-demand actions | `fast-logger`, `time-manager` |
|
||||
| `tagged` | [`0.8.8`](http://hackage.haskell.org/package/tagged-0.8.8) | [`BSD-3-Clause`](./licences/haskell/tagged-0.8.8/LICENSE) | Haskell 98 phantom types to avoid unsafely passing dummy arguments | `aeson`, `assoc`, `bifunctors`, `boring`, `comonad`, `distributive`, `indexed-traversable-instances`, `semialign`, `semigroupoids` |
|
||||
| `th-abstraction` | [`0.6.0.0`](http://hackage.haskell.org/package/th-abstraction-0.6.0.0) | [`ISC`](./licences/haskell/th-abstraction-0.6.0.0/LICENSE) | Nicer interface for reified information about data types | `aeson`, `bifunctors` |
|
||||
| `th-compat` | [`0.1.4`](http://hackage.haskell.org/package/th-compat-0.1.4) | [`BSD-3-Clause`](./licences/haskell/th-compat-0.1.4/LICENSE) | Backward- (and forward-)compatible Quote and Code types | `network-uri` |
|
||||
| `these` | [`1.2`](http://hackage.haskell.org/package/these-1.2) | [`BSD-3-Clause`](./licences/haskell/these-1.2/LICENSE) | An either-or-both data type. | `aeson`, `semialign`, `strict` |
|
||||
| `time-compat` | [`1.9.6.1`](http://hackage.haskell.org/package/time-compat-1.9.6.1) | [`BSD-3-Clause`](./licences/haskell/time-compat-1.9.6.1/LICENSE) | Compatibility package for time | `aeson`, `text-iso8601` |
|
||||
| `time-manager` | [`0.0.1`](http://hackage.haskell.org/package/time-manager-0.0.1) | [`MIT`](./licences/haskell/time-manager-0.0.1/LICENSE) | Scalable timer | `http2`, `simplexmq` |
|
||||
| `temporary` | [`1.3`](http://hackage.haskell.org/package/temporary-1.3) | [`BSD-3-Clause`](./licences/haskell/temporary-1.3/LICENSE) | Portable temporary file and directory support | `simplexmq` |
|
||||
| **`transformers`** | [`0.6.1.0`](http://hackage.haskell.org/package/transformers-0.6.1.0) | [`BSD-3-Clause`](http://hackage.haskell.org/package/transformers-0.6.1.0/src/LICENSE) | Concrete functor and monad transformers | `QuickCheck`, `StateVar`, `attoparsec`, `bifunctors`, `boring`, `comonad`, `conduit`, `conduit-extra`, `constraints`, `contravariant`, `crypton-x509`, `distributive`, `exceptions`, `indexed-traversable`, `monad-control`, `monad-logger`, `mono-traversable`, `mtl`, `network-transport`, `optparse-applicative`, `primitive`, `resourcet`, `safe-exceptions`, `semialign`, `semigroupoids`, `simplexmq`, `sqlcipher-simple`, `streaming-commons`, `strict`, `tagged`, `temporary`, `terminal`, `tls`, `transformers-base`, `transformers-compat`, `typed-process`, `unliftio`, `unliftio-core`, `witherable`, `yaml`, `zip` |
|
||||
| `transformers-base` | [`0.4.6`](http://hackage.haskell.org/package/transformers-base-0.4.6) | [`BSD-3-Clause`](./licences/haskell/transformers-base-0.4.6/LICENSE) | Lift computations from the bottom of a transformer stack | `lifted-base`, `monad-control`, `monad-logger`, `zip` |
|
||||
| `transformers-compat` | [`0.7.2`](http://hackage.haskell.org/package/transformers-compat-0.7.2) | [`BSD-3-Clause`](./licences/haskell/transformers-compat-0.7.2/LICENSE) | A small compatibility shim for the transformers library | `comonad`, `monad-control`, `monad-logger`, `optparse-applicative`, `semigroupoids`, `transformers-base` |
|
||||
| `attoparsec` | [`0.14.4`](http://hackage.haskell.org/package/attoparsec-0.14.4) | [`BSD-3-Clause`](./licences/haskell/attoparsec-0.14.4/LICENSE) | Fast combinator parsing for bytestrings and text | `attoparsec` |
|
||||
| `text-iso8601` | [`0.1`](http://hackage.haskell.org/package/text-iso8601-0.1) | [`BSD-3-Clause`](./licences/haskell/text-iso8601-0.1/LICENSE) | Converting time to and from ISO 8601 text. | `aeson` |
|
||||
| `text-short` | [`0.1.5`](http://hackage.haskell.org/package/text-short-0.1.5) | [`BSD-3-Clause`](./licences/haskell/text-short-0.1.5/LICENSE) | Memory-efficient representation of Unicode text strings | `aeson` |
|
||||
| `type-equality` | [`1`](http://hackage.haskell.org/package/type-equality-1) | [`BSD-3-Clause`](./licences/haskell/type-equality-1/LICENSE) | Data.Type.Equality compat package | `constraints` |
|
||||
| `typed-process` | [`0.2.11.1`](http://hackage.haskell.org/package/typed-process-0.2.11.1) | [`MIT`](./licences/haskell/typed-process-0.2.11.1/LICENSE) | Run external processes, with strong typing of streams | `conduit-extra` |
|
||||
| **`unix`** | [`2.8.1.0`](http://hackage.haskell.org/package/unix-2.8.1.0) | [`BSD-3-Clause`](http://hackage.haskell.org/package/unix-2.8.1.0/src/LICENSE) | POSIX functionality | `conduit`, `directory`, `easy-file`, `entropy`, `process`, `streaming-commons`, `temporary`, `unix-compat`, `unliftio`, `zip` |
|
||||
| `vector` | [`0.13.1.0`](http://hackage.haskell.org/package/vector-0.13.1.0) | [`BSD-3-Clause`](./licences/haskell/vector-0.13.1.0/LICENSE) | Efficient Arrays | `aeson`, `bitvec`, `blaze-textual`, `conduit`, `indexed-traversable-instances`, `mono-traversable`, `semialign`, `vector-algorithms`, `witherable`, `yaml` |
|
||||
| `vector-algorithms` | [`0.9.0.1`](http://hackage.haskell.org/package/vector-algorithms-0.9.0.1) | [`BSD-3-Clause`](./licences/haskell/vector-algorithms-0.9.0.1/LICENSE) | Efficient algorithms for vector arrays | `mono-traversable` |
|
||||
| `vector-stream` | [`0.1.0.0`](http://hackage.haskell.org/package/vector-stream-0.1.0.0) | [`BSD-3-Clause`](./licences/haskell/vector-stream-0.1.0.0/LICENSE) | Efficient Streams | `vector` |
|
||||
| `witherable` | [`0.4.2`](http://hackage.haskell.org/package/witherable-0.4.2) | [`BSD-3-Clause`](./licences/haskell/witherable-0.4.2/LICENSE) | filterable traversable | `aeson` |
|
||||
| `yaml` | [`0.11.11.2`](http://hackage.haskell.org/package/yaml-0.11.11.2) | [`BSD-3-Clause`](./licences/haskell/yaml-0.11.11.2/LICENSE) | Support for parsing and rendering YAML documents. | `simplexmq` |
|
||||
| `zlib` | [`0.6.3.0`](http://hackage.haskell.org/package/zlib-0.6.3.0) | [`BSD-3-Clause`](./licences/haskell/zlib-0.6.3.0/LICENSE) | Compression and decompression in the gzip and zlib formats | `streaming-commons` |
|
||||
| `zstd` | [`0.1.3.0`](http://hackage.haskell.org/package/zstd-0.1.3.0) | [`BSD-3-Clause`](./licences/haskell/zstd-0.1.3.0/LICENSE) | Haskell bindings to the Zstandard compression algorithm | `simplexmq` |
|
||||
|
9
docs/dependencies/README.md
Normal file
9
docs/dependencies/README.md
Normal file
|
@ -0,0 +1,9 @@
|
|||
# SimpleX Chat and SimpleX servers dependencies
|
||||
|
||||
[SQLCipher](https://github.com/sqlcipher/sqlcipher): Extension of [SQLite](https://sqlite.org) with encryption ([BSD-style](./licences/build/sqlcipher/LICENSE.md))
|
||||
|
||||
[vlc](https://github.com/videolan/vlc): VLC media player library ([LGPLv2](./licences/build/vlc/COPYING.LIB))
|
||||
|
||||
[WebRTC](https://webrtc.googlesource.com/src/): RTC for calls ([BSD-3-clause](./licences/build/webrtc/LICENSE))
|
||||
|
||||
[Haskell dependencies](./HASKELL.md).
|
24
docs/dependencies/licences/apps/sqlcipher/LICENSE.md
Normal file
24
docs/dependencies/licences/apps/sqlcipher/LICENSE.md
Normal file
|
@ -0,0 +1,24 @@
|
|||
Copyright (c) 2025, ZETETIC LLC
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the ZETETIC LLC nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY ZETETIC LLC ''AS IS'' AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL ZETETIC LLC BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
502
docs/dependencies/licences/apps/vlc/COPYING.LIB
Normal file
502
docs/dependencies/licences/apps/vlc/COPYING.LIB
Normal file
|
@ -0,0 +1,502 @@
|
|||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 2.1, February 1999
|
||||
|
||||
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
[This is the first released version of the Lesser GPL. It also counts
|
||||
as the successor of the GNU Library Public License, version 2, hence
|
||||
the version number 2.1.]
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
Licenses are intended to guarantee your freedom to share and change
|
||||
free software--to make sure the software is free for all its users.
|
||||
|
||||
This license, the Lesser General Public License, applies to some
|
||||
specially designated software packages--typically libraries--of the
|
||||
Free Software Foundation and other authors who decide to use it. You
|
||||
can use it too, but we suggest you first think carefully about whether
|
||||
this license or the ordinary General Public License is the better
|
||||
strategy to use in any particular case, based on the explanations below.
|
||||
|
||||
When we speak of free software, we are referring to freedom of use,
|
||||
not price. Our General Public Licenses are designed to make sure that
|
||||
you have the freedom to distribute copies of free software (and charge
|
||||
for this service if you wish); that you receive source code or can get
|
||||
it if you want it; that you can change the software and use pieces of
|
||||
it in new free programs; and that you are informed that you can do
|
||||
these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
distributors to deny you these rights or to ask you to surrender these
|
||||
rights. These restrictions translate to certain responsibilities for
|
||||
you if you distribute copies of the library or if you modify it.
|
||||
|
||||
For example, if you distribute copies of the library, whether gratis
|
||||
or for a fee, you must give the recipients all the rights that we gave
|
||||
you. You must make sure that they, too, receive or can get the source
|
||||
code. If you link other code with the library, you must provide
|
||||
complete object files to the recipients, so that they can relink them
|
||||
with the library after making changes to the library and recompiling
|
||||
it. And you must show them these terms so they know their rights.
|
||||
|
||||
We protect your rights with a two-step method: (1) we copyright the
|
||||
library, and (2) we offer you this license, which gives you legal
|
||||
permission to copy, distribute and/or modify the library.
|
||||
|
||||
To protect each distributor, we want to make it very clear that
|
||||
there is no warranty for the free library. Also, if the library is
|
||||
modified by someone else and passed on, the recipients should know
|
||||
that what they have is not the original version, so that the original
|
||||
author's reputation will not be affected by problems that might be
|
||||
introduced by others.
|
||||
|
||||
Finally, software patents pose a constant threat to the existence of
|
||||
any free program. We wish to make sure that a company cannot
|
||||
effectively restrict the users of a free program by obtaining a
|
||||
restrictive license from a patent holder. Therefore, we insist that
|
||||
any patent license obtained for a version of the library must be
|
||||
consistent with the full freedom of use specified in this license.
|
||||
|
||||
Most GNU software, including some libraries, is covered by the
|
||||
ordinary GNU General Public License. This license, the GNU Lesser
|
||||
General Public License, applies to certain designated libraries, and
|
||||
is quite different from the ordinary General Public License. We use
|
||||
this license for certain libraries in order to permit linking those
|
||||
libraries into non-free programs.
|
||||
|
||||
When a program is linked with a library, whether statically or using
|
||||
a shared library, the combination of the two is legally speaking a
|
||||
combined work, a derivative of the original library. The ordinary
|
||||
General Public License therefore permits such linking only if the
|
||||
entire combination fits its criteria of freedom. The Lesser General
|
||||
Public License permits more lax criteria for linking other code with
|
||||
the library.
|
||||
|
||||
We call this license the "Lesser" General Public License because it
|
||||
does Less to protect the user's freedom than the ordinary General
|
||||
Public License. It also provides other free software developers Less
|
||||
of an advantage over competing non-free programs. These disadvantages
|
||||
are the reason we use the ordinary General Public License for many
|
||||
libraries. However, the Lesser license provides advantages in certain
|
||||
special circumstances.
|
||||
|
||||
For example, on rare occasions, there may be a special need to
|
||||
encourage the widest possible use of a certain library, so that it becomes
|
||||
a de-facto standard. To achieve this, non-free programs must be
|
||||
allowed to use the library. A more frequent case is that a free
|
||||
library does the same job as widely used non-free libraries. In this
|
||||
case, there is little to gain by limiting the free library to free
|
||||
software only, so we use the Lesser General Public License.
|
||||
|
||||
In other cases, permission to use a particular library in non-free
|
||||
programs enables a greater number of people to use a large body of
|
||||
free software. For example, permission to use the GNU C Library in
|
||||
non-free programs enables many more people to use the whole GNU
|
||||
operating system, as well as its variant, the GNU/Linux operating
|
||||
system.
|
||||
|
||||
Although the Lesser General Public License is Less protective of the
|
||||
users' freedom, it does ensure that the user of a program that is
|
||||
linked with the Library has the freedom and the wherewithal to run
|
||||
that program using a modified version of the Library.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow. Pay close attention to the difference between a
|
||||
"work based on the library" and a "work that uses the library". The
|
||||
former contains code derived from the library, whereas the latter must
|
||||
be combined with the library in order to run.
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License Agreement applies to any software library or other
|
||||
program which contains a notice placed by the copyright holder or
|
||||
other authorized party saying it may be distributed under the terms of
|
||||
this Lesser General Public License (also called "this License").
|
||||
Each licensee is addressed as "you".
|
||||
|
||||
A "library" means a collection of software functions and/or data
|
||||
prepared so as to be conveniently linked with application programs
|
||||
(which use some of those functions and data) to form executables.
|
||||
|
||||
The "Library", below, refers to any such software library or work
|
||||
which has been distributed under these terms. A "work based on the
|
||||
Library" means either the Library or any derivative work under
|
||||
copyright law: that is to say, a work containing the Library or a
|
||||
portion of it, either verbatim or with modifications and/or translated
|
||||
straightforwardly into another language. (Hereinafter, translation is
|
||||
included without limitation in the term "modification".)
|
||||
|
||||
"Source code" for a work means the preferred form of the work for
|
||||
making modifications to it. For a library, complete source code means
|
||||
all the source code for all modules it contains, plus any associated
|
||||
interface definition files, plus the scripts used to control compilation
|
||||
and installation of the library.
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running a program using the Library is not restricted, and output from
|
||||
such a program is covered only if its contents constitute a work based
|
||||
on the Library (independent of the use of the Library in a tool for
|
||||
writing it). Whether that is true depends on what the Library does
|
||||
and what the program that uses the Library does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Library's
|
||||
complete source code as you receive it, in any medium, provided that
|
||||
you conspicuously and appropriately publish on each copy an
|
||||
appropriate copyright notice and disclaimer of warranty; keep intact
|
||||
all the notices that refer to this License and to the absence of any
|
||||
warranty; and distribute a copy of this License along with the
|
||||
Library.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy,
|
||||
and you may at your option offer warranty protection in exchange for a
|
||||
fee.
|
||||
|
||||
2. You may modify your copy or copies of the Library or any portion
|
||||
of it, thus forming a work based on the Library, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) The modified work must itself be a software library.
|
||||
|
||||
b) You must cause the files modified to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
c) You must cause the whole of the work to be licensed at no
|
||||
charge to all third parties under the terms of this License.
|
||||
|
||||
d) If a facility in the modified Library refers to a function or a
|
||||
table of data to be supplied by an application program that uses
|
||||
the facility, other than as an argument passed when the facility
|
||||
is invoked, then you must make a good faith effort to ensure that,
|
||||
in the event an application does not supply such function or
|
||||
table, the facility still operates, and performs whatever part of
|
||||
its purpose remains meaningful.
|
||||
|
||||
(For example, a function in a library to compute square roots has
|
||||
a purpose that is entirely well-defined independent of the
|
||||
application. Therefore, Subsection 2d requires that any
|
||||
application-supplied function or table used by this function must
|
||||
be optional: if the application does not supply it, the square
|
||||
root function must still compute square roots.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Library,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Library, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote
|
||||
it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Library.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Library
|
||||
with the Library (or with a work based on the Library) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||
License instead of this License to a given copy of the Library. To do
|
||||
this, you must alter all the notices that refer to this License, so
|
||||
that they refer to the ordinary GNU General Public License, version 2,
|
||||
instead of to this License. (If a newer version than version 2 of the
|
||||
ordinary GNU General Public License has appeared, then you can specify
|
||||
that version instead if you wish.) Do not make any other change in
|
||||
these notices.
|
||||
|
||||
Once this change is made in a given copy, it is irreversible for
|
||||
that copy, so the ordinary GNU General Public License applies to all
|
||||
subsequent copies and derivative works made from that copy.
|
||||
|
||||
This option is useful when you wish to copy part of the code of
|
||||
the Library into a program that is not a library.
|
||||
|
||||
4. You may copy and distribute the Library (or a portion or
|
||||
derivative of it, under Section 2) in object code or executable form
|
||||
under the terms of Sections 1 and 2 above provided that you accompany
|
||||
it with the complete corresponding machine-readable source code, which
|
||||
must be distributed under the terms of Sections 1 and 2 above on a
|
||||
medium customarily used for software interchange.
|
||||
|
||||
If distribution of object code is made by offering access to copy
|
||||
from a designated place, then offering equivalent access to copy the
|
||||
source code from the same place satisfies the requirement to
|
||||
distribute the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
5. A program that contains no derivative of any portion of the
|
||||
Library, but is designed to work with the Library by being compiled or
|
||||
linked with it, is called a "work that uses the Library". Such a
|
||||
work, in isolation, is not a derivative work of the Library, and
|
||||
therefore falls outside the scope of this License.
|
||||
|
||||
However, linking a "work that uses the Library" with the Library
|
||||
creates an executable that is a derivative of the Library (because it
|
||||
contains portions of the Library), rather than a "work that uses the
|
||||
library". The executable is therefore covered by this License.
|
||||
Section 6 states terms for distribution of such executables.
|
||||
|
||||
When a "work that uses the Library" uses material from a header file
|
||||
that is part of the Library, the object code for the work may be a
|
||||
derivative work of the Library even though the source code is not.
|
||||
Whether this is true is especially significant if the work can be
|
||||
linked without the Library, or if the work is itself a library. The
|
||||
threshold for this to be true is not precisely defined by law.
|
||||
|
||||
If such an object file uses only numerical parameters, data
|
||||
structure layouts and accessors, and small macros and small inline
|
||||
functions (ten lines or less in length), then the use of the object
|
||||
file is unrestricted, regardless of whether it is legally a derivative
|
||||
work. (Executables containing this object code plus portions of the
|
||||
Library will still fall under Section 6.)
|
||||
|
||||
Otherwise, if the work is a derivative of the Library, you may
|
||||
distribute the object code for the work under the terms of Section 6.
|
||||
Any executables containing that work also fall under Section 6,
|
||||
whether or not they are linked directly with the Library itself.
|
||||
|
||||
6. As an exception to the Sections above, you may also combine or
|
||||
link a "work that uses the Library" with the Library to produce a
|
||||
work containing portions of the Library, and distribute that work
|
||||
under terms of your choice, provided that the terms permit
|
||||
modification of the work for the customer's own use and reverse
|
||||
engineering for debugging such modifications.
|
||||
|
||||
You must give prominent notice with each copy of the work that the
|
||||
Library is used in it and that the Library and its use are covered by
|
||||
this License. You must supply a copy of this License. If the work
|
||||
during execution displays copyright notices, you must include the
|
||||
copyright notice for the Library among them, as well as a reference
|
||||
directing the user to the copy of this License. Also, you must do one
|
||||
of these things:
|
||||
|
||||
a) Accompany the work with the complete corresponding
|
||||
machine-readable source code for the Library including whatever
|
||||
changes were used in the work (which must be distributed under
|
||||
Sections 1 and 2 above); and, if the work is an executable linked
|
||||
with the Library, with the complete machine-readable "work that
|
||||
uses the Library", as object code and/or source code, so that the
|
||||
user can modify the Library and then relink to produce a modified
|
||||
executable containing the modified Library. (It is understood
|
||||
that the user who changes the contents of definitions files in the
|
||||
Library will not necessarily be able to recompile the application
|
||||
to use the modified definitions.)
|
||||
|
||||
b) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (1) uses at run time a
|
||||
copy of the library already present on the user's computer system,
|
||||
rather than copying library functions into the executable, and (2)
|
||||
will operate properly with a modified version of the library, if
|
||||
the user installs one, as long as the modified version is
|
||||
interface-compatible with the version that the work was made with.
|
||||
|
||||
c) Accompany the work with a written offer, valid for at
|
||||
least three years, to give the same user the materials
|
||||
specified in Subsection 6a, above, for a charge no more
|
||||
than the cost of performing this distribution.
|
||||
|
||||
d) If distribution of the work is made by offering access to copy
|
||||
from a designated place, offer equivalent access to copy the above
|
||||
specified materials from the same place.
|
||||
|
||||
e) Verify that the user has already received a copy of these
|
||||
materials or that you have already sent this user a copy.
|
||||
|
||||
For an executable, the required form of the "work that uses the
|
||||
Library" must include any data and utility programs needed for
|
||||
reproducing the executable from it. However, as a special exception,
|
||||
the materials to be distributed need not include anything that is
|
||||
normally distributed (in either source or binary form) with the major
|
||||
components (compiler, kernel, and so on) of the operating system on
|
||||
which the executable runs, unless that component itself accompanies
|
||||
the executable.
|
||||
|
||||
It may happen that this requirement contradicts the license
|
||||
restrictions of other proprietary libraries that do not normally
|
||||
accompany the operating system. Such a contradiction means you cannot
|
||||
use both them and the Library together in an executable that you
|
||||
distribute.
|
||||
|
||||
7. You may place library facilities that are a work based on the
|
||||
Library side-by-side in a single library together with other library
|
||||
facilities not covered by this License, and distribute such a combined
|
||||
library, provided that the separate distribution of the work based on
|
||||
the Library and of the other library facilities is otherwise
|
||||
permitted, and provided that you do these two things:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work
|
||||
based on the Library, uncombined with any other library
|
||||
facilities. This must be distributed under the terms of the
|
||||
Sections above.
|
||||
|
||||
b) Give prominent notice with the combined library of the fact
|
||||
that part of it is a work based on the Library, and explaining
|
||||
where to find the accompanying uncombined form of the same work.
|
||||
|
||||
8. You may not copy, modify, sublicense, link with, or distribute
|
||||
the Library except as expressly provided under this License. Any
|
||||
attempt otherwise to copy, modify, sublicense, link with, or
|
||||
distribute the Library is void, and will automatically terminate your
|
||||
rights under this License. However, parties who have received copies,
|
||||
or rights, from you under this License will not have their licenses
|
||||
terminated so long as such parties remain in full compliance.
|
||||
|
||||
9. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Library or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Library (or any work based on the
|
||||
Library), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Library or works based on it.
|
||||
|
||||
10. Each time you redistribute the Library (or any work based on the
|
||||
Library), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute, link with or modify the Library
|
||||
subject to these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties with
|
||||
this License.
|
||||
|
||||
11. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Library at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Library by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Library.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under any
|
||||
particular circumstance, the balance of the section is intended to apply,
|
||||
and the section as a whole is intended to apply in other circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
12. If the distribution and/or use of the Library is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Library under this License may add
|
||||
an explicit geographical distribution limitation excluding those countries,
|
||||
so that distribution is permitted only in or among countries not thus
|
||||
excluded. In such case, this License incorporates the limitation as if
|
||||
written in the body of this License.
|
||||
|
||||
13. The Free Software Foundation may publish revised and/or new
|
||||
versions of the Lesser General Public License from time to time.
|
||||
Such new versions will be similar in spirit to the present version,
|
||||
but may differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Library
|
||||
specifies a version number of this License which applies to it and
|
||||
"any later version", you have the option of following the terms and
|
||||
conditions either of that version or of any later version published by
|
||||
the Free Software Foundation. If the Library does not specify a
|
||||
license version number, you may choose any version ever published by
|
||||
the Free Software Foundation.
|
||||
|
||||
14. If you wish to incorporate parts of the Library into other free
|
||||
programs whose distribution conditions are incompatible with these,
|
||||
write to the author to ask for permission. For software which is
|
||||
copyrighted by the Free Software Foundation, write to the Free
|
||||
Software Foundation; we sometimes make exceptions for this. Our
|
||||
decision will be guided by the two goals of preserving the free status
|
||||
of all derivatives of our free software and of promoting the sharing
|
||||
and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
||||
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
||||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||||
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
||||
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
||||
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
||||
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
||||
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Libraries
|
||||
|
||||
If you develop a new library, and you want it to be of the greatest
|
||||
possible use to the public, we recommend making it free software that
|
||||
everyone can redistribute and change. You can do so by permitting
|
||||
redistribution under these terms (or, alternatively, under the terms of the
|
||||
ordinary General Public License).
|
||||
|
||||
To apply these terms, attach the following notices to the library. It is
|
||||
safest to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least the
|
||||
"copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the library's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the library, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
||||
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1990
|
||||
Ty Coon, President of Vice
|
||||
|
||||
That's all there is to it!
|
24
docs/dependencies/licences/apps/webrtc/LICENSE
Normal file
24
docs/dependencies/licences/apps/webrtc/LICENSE
Normal file
|
@ -0,0 +1,24 @@
|
|||
Copyright (c) 2011, The WebRTC project authors. All rights reserved.
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google nor the names of its contributors may
|
||||
be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
34
docs/dependencies/licences/haskell/OneTuple-0.4.1.1/LICENSE
Normal file
34
docs/dependencies/licences/haskell/OneTuple-0.4.1.1/LICENSE
Normal file
|
@ -0,0 +1,34 @@
|
|||
|
||||
Copyright (c) 2008, John A. Dorsey.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of John Dorsey nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
30
docs/dependencies/licences/haskell/Only-0.1/LICENSE
Normal file
30
docs/dependencies/licences/haskell/Only-0.1/LICENSE
Normal file
|
@ -0,0 +1,30 @@
|
|||
Copyright (c) 2017, Herbert Valerio Riedel
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
|
||||
* Neither the name of Herbert Valerio Riedel nor the names of other
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
29
docs/dependencies/licences/haskell/QuickCheck-2.14.3/LICENSE
Normal file
29
docs/dependencies/licences/haskell/QuickCheck-2.14.3/LICENSE
Normal file
|
@ -0,0 +1,29 @@
|
|||
(The following is the 3-clause BSD license.)
|
||||
|
||||
Copyright (c) 2000-2019, Koen Claessen
|
||||
Copyright (c) 2006-2008, Björn Bringert
|
||||
Copyright (c) 2009-2019, Nick Smallbone
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
- Neither the names of the copyright owners nor the names of the
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
29
docs/dependencies/licences/haskell/SHA-1.6.4.4/LICENSE
Normal file
29
docs/dependencies/licences/haskell/SHA-1.6.4.4/LICENSE
Normal file
|
@ -0,0 +1,29 @@
|
|||
Copyright (c) 2008, Galois, Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of the Galois, Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
29
docs/dependencies/licences/haskell/StateVar-1.2.2/LICENSE
Normal file
29
docs/dependencies/licences/haskell/StateVar-1.2.2/LICENSE
Normal file
|
@ -0,0 +1,29 @@
|
|||
Copyright (c) 2014-2015, Edward Kmett
|
||||
Copyright (c) 2009-2021, Sven Panne
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the author nor the names of its contributors may be
|
||||
used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
0
docs/dependencies/licences/haskell/aeson-2.2.1.0/LICENSE
Normal file
0
docs/dependencies/licences/haskell/aeson-2.2.1.0/LICENSE
Normal file
22
docs/dependencies/licences/haskell/ansi-terminal-1.0/LICENSE
Normal file
22
docs/dependencies/licences/haskell/ansi-terminal-1.0/LICENSE
Normal file
|
@ -0,0 +1,22 @@
|
|||
Copyright (c) 2008, Maximilian Bolingbroke
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted
|
||||
provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this list of
|
||||
conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this list of
|
||||
conditions and the following disclaimer in the documentation and/or other materials
|
||||
provided with the distribution.
|
||||
* Neither the name of Maximilian Bolingbroke nor the names of other contributors may be used to
|
||||
endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -0,0 +1,25 @@
|
|||
Copyright (c) 2008, Maximilian Bolingbroke
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of Maximilian Bolingbroke nor the names of other contributors
|
||||
may be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
29
docs/dependencies/licences/haskell/appar-0.1.8/LICENSE
Normal file
29
docs/dependencies/licences/haskell/appar-0.1.8/LICENSE
Normal file
|
@ -0,0 +1,29 @@
|
|||
Copyright (c) 2009, IIJ Innovation Institute Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of the copyright holders nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
|
@ -0,0 +1,27 @@
|
|||
Copyright (c) 2010-2013 Vincent Hanquez <vincent@snarc.org>
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the author nor the names of his contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
27
docs/dependencies/licences/haskell/asn1-parse-0.9.5/LICENSE
Normal file
27
docs/dependencies/licences/haskell/asn1-parse-0.9.5/LICENSE
Normal file
|
@ -0,0 +1,27 @@
|
|||
Copyright (c) 2010-2013 Vincent Hanquez <vincent@snarc.org>
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the author nor the names of his contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
27
docs/dependencies/licences/haskell/asn1-types-0.3.4/LICENSE
Normal file
27
docs/dependencies/licences/haskell/asn1-types-0.3.4/LICENSE
Normal file
|
@ -0,0 +1,27 @@
|
|||
Copyright (c) 2010-2013 Vincent Hanquez <vincent@snarc.org>
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the author nor the names of his contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
30
docs/dependencies/licences/haskell/assoc-1.1/LICENSE
Normal file
30
docs/dependencies/licences/haskell/assoc-1.1/LICENSE
Normal file
|
@ -0,0 +1,30 @@
|
|||
Copyright (c) 2017, Oleg Grenrus
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
|
||||
* Neither the name of Oleg Grenrus nor the names of other
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
30
docs/dependencies/licences/haskell/async-2.2.5/LICENSE
Normal file
30
docs/dependencies/licences/haskell/async-2.2.5/LICENSE
Normal file
|
@ -0,0 +1,30 @@
|
|||
Copyright (c) 2012, Simon Marlow
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
|
||||
* Neither the name of Simon Marlow nor the names of other
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
30
docs/dependencies/licences/haskell/attoparsec-0.14.4/LICENSE
Normal file
30
docs/dependencies/licences/haskell/attoparsec-0.14.4/LICENSE
Normal file
|
@ -0,0 +1,30 @@
|
|||
Copyright (c) Lennart Kolmodin
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the author nor the names of his contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
|
||||
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
20
docs/dependencies/licences/haskell/auto-update-0.1.6/LICENSE
Normal file
20
docs/dependencies/licences/haskell/auto-update-0.1.6/LICENSE
Normal file
|
@ -0,0 +1,20 @@
|
|||
Copyright (c) 2014 Michael Snoyman
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -0,0 +1,20 @@
|
|||
Copyright (c) 2015-2017 Simon Hengel <sol@typeful.net>, João Cristóvão <jmacristovao@gmail.com>, Ryan Scott <ryan.gl.scott@gmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -0,0 +1,30 @@
|
|||
Copyright (c) 2010 Bryan O'Sullivan <bos@serpentine.com>
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the author nor the names of his contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
|
||||
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
28
docs/dependencies/licences/haskell/basement-0.0.16/LICENSE
Normal file
28
docs/dependencies/licences/haskell/basement-0.0.16/LICENSE
Normal file
|
@ -0,0 +1,28 @@
|
|||
Copyright (c) 2015-2017 Vincent Hanquez <vincent@snarc.org>
|
||||
Copyright (c) 2017-2019 Foundation Maintainers
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the author nor the names of his contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS AS IS'' AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
26
docs/dependencies/licences/haskell/bifunctors-5.6.1/LICENSE
Normal file
26
docs/dependencies/licences/haskell/bifunctors-5.6.1/LICENSE
Normal file
|
@ -0,0 +1,26 @@
|
|||
Copyright 2008-2016 Edward Kmett
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
|
@ -0,0 +1,30 @@
|
|||
Copyright Jasper Van der Jeugt 2010, Simon Meier 2010 & 2011
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
|
||||
* Neither the name of Jasper Van der Jeugt nor the names of other
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
30
docs/dependencies/licences/haskell/boring-0.2.1/LICENSE
Normal file
30
docs/dependencies/licences/haskell/boring-0.2.1/LICENSE
Normal file
|
@ -0,0 +1,30 @@
|
|||
Copyright (c) 2017, Oleg Grenrus
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
|
||||
* Neither the name of Oleg Grenrus nor the names of other
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
30
docs/dependencies/licences/haskell/byteorder-1.0.4/LICENSE
Normal file
30
docs/dependencies/licences/haskell/byteorder-1.0.4/LICENSE
Normal file
|
@ -0,0 +1,30 @@
|
|||
Copyright 2009, Antoine Latter
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
|
||||
* Neither the name of the author nor the names of other
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -0,0 +1,30 @@
|
|||
Copyright Jasper Van der Jeugt 2010, Simon Meier 2010-2013
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
|
||||
* Neither the name of Jasper Van der Jeugt nor the names of other
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -0,0 +1,31 @@
|
|||
Copyright (c) 2011-2013 Bas van Dijk
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
|
||||
* The name of Bas van Dijk and the names of contributors may NOT
|
||||
be used to endorse or promote products derived from this
|
||||
software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
30
docs/dependencies/licences/haskell/cereal-0.5.8.3/LICENSE
Normal file
30
docs/dependencies/licences/haskell/cereal-0.5.8.3/LICENSE
Normal file
|
@ -0,0 +1,30 @@
|
|||
Copyright (c) Lennart Kolmodin, Galois, Inc.
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the author nor the names of his contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
|
||||
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
31
docs/dependencies/licences/haskell/clock-0.8.4/LICENSE
Normal file
31
docs/dependencies/licences/haskell/clock-0.8.4/LICENSE
Normal file
|
@ -0,0 +1,31 @@
|
|||
Copyright (c) 2009-2022, Clock Contributors
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
|
||||
* The names of contributors may not be used to endorse or promote
|
||||
products derived from this software without specific prior
|
||||
written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
20
docs/dependencies/licences/haskell/colour-2.3.6/LICENSE
Normal file
20
docs/dependencies/licences/haskell/colour-2.3.6/LICENSE
Normal file
|
@ -0,0 +1,20 @@
|
|||
Copyright (c) 2008, 2009
|
||||
Russell O'Connor
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
27
docs/dependencies/licences/haskell/comonad-5.0.8/LICENSE
Normal file
27
docs/dependencies/licences/haskell/comonad-5.0.8/LICENSE
Normal file
|
@ -0,0 +1,27 @@
|
|||
Copyright 2008-2014 Edward Kmett
|
||||
Copyright 2004-2008 Dave Menendez
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
|
@ -0,0 +1,30 @@
|
|||
Copyright (c) 2011-2012, Dan Burton
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
|
||||
* Neither the name of Dan Burton nor the names of other
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
0
docs/dependencies/licences/haskell/conduit-1.3.5/LICENSE
Normal file
0
docs/dependencies/licences/haskell/conduit-1.3.5/LICENSE
Normal file
|
@ -0,0 +1,30 @@
|
|||
Copyright 2007-2015 Edward Kmett
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the author nor the names of his contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
|
@ -0,0 +1,28 @@
|
|||
Copyright (c) 2010-2014 Vincent Hanquez <vincent@snarc.org>
|
||||
2016 Herbert Valerio Riedel <hvr@gnu.org>
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the author nor the names of his contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
|
@ -0,0 +1,28 @@
|
|||
Copyright (c) 2010-2014 Vincent Hanquez <vincent@snarc.org>
|
||||
2016 Herbert Valerio Riedel <hvr@gnu.org>
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the author nor the names of his contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
28
docs/dependencies/licences/haskell/crypton-0.34/LICENSE
Normal file
28
docs/dependencies/licences/haskell/crypton-0.34/LICENSE
Normal file
|
@ -0,0 +1,28 @@
|
|||
Copyright (c) 2006-2015 Vincent Hanquez <vincent@snarc.org>
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the author nor the names of his contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS AS IS'' AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
|
@ -0,0 +1,27 @@
|
|||
Copyright (c) 2010-2013 Vincent Hanquez <vincent@snarc.org>
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the author nor the names of his contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
|
@ -0,0 +1,27 @@
|
|||
Copyright (c) 2010-2013 Vincent Hanquez <vincent@snarc.org>
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the author nor the names of his contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
|
@ -0,0 +1,27 @@
|
|||
Copyright (c) 2010-2013 Vincent Hanquez <vincent@snarc.org>
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the author nor the names of his contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
|
@ -0,0 +1,30 @@
|
|||
Copyright (c) 2018-2023, Olivier Chéron
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
|
||||
* Neither the name of Olivier Chéron nor the names of other
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -0,0 +1,26 @@
|
|||
Copyright (c) 2013 Lukas Mai
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of the author nor the names of his contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -0,0 +1,26 @@
|
|||
Copyright (c) 2013 Lukas Mai
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of the author nor the names of his contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue