import Foundation enum RosterSubsriptionType: String { case both case from case none case remove case to var isFrom: Bool { switch self { case .from, .both: return true case .none, .to, .remove: return false } } var isTo: Bool { switch self { case .to, .both: return true case .none, .from, .remove: return false } } } // Roster is a "transparent" structure // which is just wrap xml item around struct RosterItem: Identifiable, Equatable { let owner: String let wrapped: XMLElement init?(wrap: XMLElement, owner: JID) { guard wrap.name == "item", wrap.attributes.keys.contains("jid"), wrap.xmlns == "jabber:iq:roster" else { return nil } self.owner = owner.bare wrapped = wrap } var id: String { "\(owner)|\(jid?.bare ?? "???")" } var jid: JID? { guard let jidStr = wrapped.attributes["jid"] else { return nil } return try? JID(jidStr) } var name: String? { wrapped.name } var subsription: RosterSubsriptionType { let str = wrapped.attributes["subscription"] ?? "none" return RosterSubsriptionType(rawValue: str) ?? .none } static func == (_ rhs: RosterItem, _ lhs: RosterItem) -> Bool { rhs.id == lhs.id && rhs.wrapped == lhs.wrapped } } // TODO: Add groups and annotattions!