Files
Luma/Sources/Shared/Models/ServerInformation.swift
T
wt 0317277d46
iOS CI / Build and Test SwiftUI App (push) Canceled after 0s
Build Unsigned iOS and macOS Apps / Build Unsigned iOS IPA (push) Canceled after 0s
Build Unsigned iOS and macOS Apps / Build macOS ZIP (push) Canceled after 0s
add server info screen, connection stats, and emoji picker
Server information (Monal-style):
- Add ServerInformation model and ServerInfoView reachable from
  Settings,
  showing server software (XEP-0092), disco#info identities and
  features,
  conference (MUC) services via disco#items, and STUN/TURN via XEP-0215.
- Add a curated XEP capability list with per-XEP success/error status
  derived
  from server/account disco features and connection flags.
- Detect PEP (0163) from account disco pubsub#* features, HTTP Upload
  (0363)
  from the main domain plus its components, and add Roster Versioning
  (0237),
  Pre-Authenticated Roster Subscription (0379), and SASL SCRAM Downgrade
  Protection (0474, neutral because Martin does not expose SSDP).

Connection statistics:
- Add LumaConnectionStatsModule, an XmppStanzaFilter registered before
  stream
  management, to count sent / acknowledged / received stanzas.
- Track last login and SMACKS session timestamps, and read SASL
  mechanisms
  and Client State Indication from the raw stream features.

MAM / OMEMO handling:
- Prefer a plaintext <body> fallback when OMEMO decryption fails instead
  of
  showing "failed to decrypt".
- Keep the optimistic text of our own outgoing message when its echo
  cannot
  be decrypted back, instead of replacing it with a placeholder.

Emoji picker:
- Add EmojiCatalog and a cross-platform EmojiPickerView.
- Open the picker for reactions (replacing the static quick list) and
  from
  the composer's smiley button, inserting the chosen emoji into the
  draft.
2026-08-18 21:44:27 +07:00

157 lines
6.6 KiB
Swift

import Foundation
/// Snapshot of everything the "server details" screen shows, modelled after
/// Monal's `ServerDetails`: server software (XEP-0092), disco#info identities
/// and features (XEP-0030), conference (MUC) services, STUN/TURN services
/// (XEP-0215) and a few connection-level capability flags.
struct ServerInformation: Equatable, Sendable {
enum CapabilityStatus: Equatable, Sendable {
case success, normal, warning, error
}
struct Software: Equatable, Sendable {
let name: String?
let version: String?
let os: String?
}
struct Identity: Equatable, Sendable, Identifiable {
let category: String
let type: String
let name: String?
var id: String { "\(category)/\(type)" }
var title: String { "\(category) / \(type)" }
}
struct ConferenceServer: Equatable, Sendable, Identifiable {
let jid: String
let name: String?
let type: String
let category: String
var id: String { jid }
}
struct ExternalService: Equatable, Sendable, Identifiable {
let type: String
let host: String
let port: UInt16?
let transport: String?
var id: String { "\(type)|\(host)|\(port.map(String.init) ?? "")" }
}
struct ConnectionStats: Equatable, Sendable {
let lastLogin: Date?
let smacksSessionEstablished: Date?
let sent: UInt32
let acknowledged: UInt32
let received: UInt32
var unacknowledged: UInt32 {
sent > acknowledged ? sent - acknowledged : 0
}
}
struct Capability: Equatable, Sendable, Identifiable {
let title: String
let detail: String
let status: CapabilityStatus
var id: String { title }
}
let serverDomain: String
let software: Software
let identities: [Identity]
let serverFeatures: [String]
let accountFeatures: [String]
let conferenceServers: [ConferenceServer]
let externalServices: [ExternalService]
let connectionStats: ConnectionStats
let saslMethods: [String]
let supportsStreamManagement: Bool
let supportsCarbons: Bool
let supportsClientState: Bool
let supportsHTTPUpload: Bool
let supportsRosterVersioning: Bool
let supportsRosterPreApproval: Bool
/// The curated XEP list Monal shows, with a status derived from the server
/// and account disco features plus the connection-level flags.
var capabilities: [Capability] {
let server = Set(serverFeatures)
let account = Set(accountFeatures)
let supportsPubSub = account.contains { $0.hasPrefix("http://jabber.org/protocol/pubsub") }
return [
Capability(
title: "XEP-0163 Personal Eventing Protocol",
detail: "Публикация событий состояния аккаунта (аватары, статусы) через publish-subscribe.",
status: supportsPubSub ? .success : .error
),
Capability(
title: "XEP-0191 Blocking Command",
detail: "Расширение XMPP для блокировки контактов.",
status: server.contains("urn:xmpp:blocking") ? .success : .error
),
Capability(
title: "XEP-0198 Stream Management",
detail: "Возобновление потока при обрыве соединения — быстрее переподключение и экономия заряда.",
status: supportsStreamManagement ? .success : .error
),
Capability(
title: "XEP-0199 XMPP Ping",
detail: "Пинг уровня приложения поверх XML-потока.",
status: server.contains("urn:xmpp:ping") ? .success : .error
),
Capability(
title: "XEP-0215 External Service Discovery",
detail: "Обнаружение внешних сервисов (STUN/TURN) для аудио- и видеозвонков.",
status: server.contains("urn:xmpp:extdisco:2") ? .success : .error
),
Capability(
title: "XEP-0237 Roster Versioning",
detail: "Версионирование ростера, чтобы сервер не отправлял его повторно, если он не менялся.",
status: supportsRosterVersioning ? .success : .error
),
Capability(
title: "XEP-0280 Message Carbons",
detail: "Синхронизация сообщений между всеми вашими устройствами.",
status: supportsCarbons ? .success : .error
),
Capability(
title: "XEP-0313 Message Archive Management",
detail: "Доступ к архиву сообщений на сервере.",
status: account.contains("urn:xmpp:mam:2") ? .success : .error
),
Capability(
title: "XEP-0352 Client State Indication",
detail: "Указывает, активно ли устройство. Экономит заряд.",
status: supportsClientState ? .success : .error
),
Capability(
title: "XEP-0357 Push Notifications",
detail: "Push-уведомления через Apple даже когда приложение выгружено.",
status: account.contains("urn:xmpp:push:0") ? .success : .error
),
Capability(
title: "XEP-0363 HTTP File Upload",
detail: "Загрузка файлов на сервер для обмена с собеседниками.",
status: supportsHTTPUpload ? .success : .error
),
Capability(
title: "XEP-0379 Pre-Authenticated Roster Subscription",
detail: "Ссылки для предварительно аутентифицированной подписки на присутствие.",
status: supportsRosterPreApproval ? .success : .error
),
Capability(
title: "XEP-0474 SASL SCRAM Downgrade Protection",
detail: "Защита SASL/SASL2-рукопожатия от понижения метода и channel-binding. Определяется во время SCRAM-аутентификации, а не рекламируется статически.",
status: .normal
),
]
}
}