diff --git a/.gitmodules b/.gitmodules index b8c1e3809..61586027d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "LibSession-Util"] path = LibSession-Util - url = https://github.com/oxen-io/libsession-util.git + url = git@github.com:session-foundation/libsession-util.git diff --git a/LibSession-Util b/LibSession-Util index 10f15aeb1..4f5a4a818 160000 --- a/LibSession-Util +++ b/LibSession-Util @@ -1 +1 @@ -Subproject commit 10f15aeb1f9712452adf55a8d0826be6271c10e4 +Subproject commit 4f5a4a81816f4d1d95a7b42e28db4ee19b5983c1 diff --git a/SessionMessagingKit/LibSession/Config Handling/LibSession+GroupMembers.swift b/SessionMessagingKit/LibSession/Config Handling/LibSession+GroupMembers.swift index 8879cc4c2..42c535b6b 100644 --- a/SessionMessagingKit/LibSession/Config Handling/LibSession+GroupMembers.swift +++ b/SessionMessagingKit/LibSession/Config Handling/LibSession+GroupMembers.swift @@ -163,7 +163,7 @@ internal extension LibSession { static func getPendingMemberRemovals( groupSessionId: SessionId, using dependencies: Dependencies - ) throws -> [String: Bool] { + ) throws -> [String: GROUP_MEMBER_STATUS] { return try dependencies.mutate(cache: .libSession) { cache in guard case .object(let conf) = cache.config(for: .groupMembers, sessionId: groupSessionId) else { throw LibSessionError.invalidConfigObject @@ -322,12 +322,7 @@ internal extension LibSession { try memberIds.forEach { memberId in // Only update members if they already exist in the group var cMemberId: [CChar] = try memberId.cString(using: .utf8) ?? { throw LibSessionError.invalidCConversion }() - var groupMember: config_group_member = config_group_member() - - guard groups_members_get(conf, &groupMember, &cMemberId) else { return } - - groupMember.removed = (removeMessages ? 2 : 1) - groups_members_set(conf, &groupMember) + groups_members_set_removed(conf, &cMemberId, removeMessages) try LibSessionError.throwIfNeeded(conf) } } @@ -381,26 +376,20 @@ internal extension LibSession { var cMemberId: [CChar] = try member.profileId.cString(using: .utf8) ?? { throw LibSessionError.invalidCConversion }() - var groupMember: config_group_member = config_group_member() - - guard groups_members_get(conf, &groupMember, &cMemberId) else { - return - } // Update the role and status to match - switch member.role { - case .admin: - groupMember.admin = true - groupMember.invited = 0 - groupMember.promoted = member.roleStatus.libSessionValue - - default: - groupMember.admin = false - groupMember.invited = member.roleStatus.libSessionValue - groupMember.promoted = 0 + switch (member.role, member.roleStatus) { + case (.admin, .accepted): groups_members_set_promotion_accepted(conf, &cMemberId) + case (.admin, .failed): groups_members_set_promotion_failed(conf, &cMemberId) + case (.admin, .pending): groups_members_set_promotion_sent(conf, &cMemberId) + case (.admin, .notSentYet): groups_members_set_promoted(conf, &cMemberId) + + case (_, .accepted): groups_members_set_invite_accepted(conf, &cMemberId) + case (_, .failed): groups_members_set_invite_failed(conf, &cMemberId) + case (_, .pending): groups_members_set_invite_sent(conf, &cMemberId) + case (_, .notSentYet): break // Default state (can't return to this after creation) } - groups_members_set(conf, &groupMember) try LibSessionError.throwIfNeeded(conf) } } @@ -434,23 +423,17 @@ internal extension LibSession { while !groups_members_iterator_done(membersIterator, &member) { try LibSession.checkLoopLimitReached(&infiniteLoopGuard, for: .groupMembers) + let status: GROUP_MEMBER_STATUS = group_member_status(&member); // Ignore members pending removal - guard member.removed == 0 else { continue } + guard !status.isRemoveStatus else { continue } result.append( GroupMember( groupId: groupSessionId.hexString, profileId: member.get(\.session_id), - role: (member.admin || (member.promoted > 0) ? .admin : .standard), - roleStatus: { - switch (member.invited, member.promoted, member.admin) { - case (2, _, _), (_, 2, _): return .failed // Explicitly failed - case (3, _, _), (_, 3, _): return .notSentYet // Explicitly notSentYet - case (1..., _, _), (_, 1..., _): return .pending // Pending if not one of the above - default: return .accepted // Otherwise it's accepted - } - }(), + role: (status.isAdmin(member.get(\.admin)) ? .admin : .standard), + roleStatus: status.roleStatus, isHidden: false ) ) @@ -465,21 +448,22 @@ internal extension LibSession { static func extractPendingRemovals( from conf: UnsafeMutablePointer?, groupSessionId: SessionId - ) throws -> [String: Bool] { + ) throws -> [String: GROUP_MEMBER_STATUS] { var infiniteLoopGuard: Int = 0 - var result: [String: Bool] = [:] + var result: [String: GROUP_MEMBER_STATUS] = [:] var member: config_group_member = config_group_member() let membersIterator: UnsafeMutablePointer = groups_members_iterator_new(conf) while !groups_members_iterator_done(membersIterator, &member) { try LibSession.checkLoopLimitReached(&infiniteLoopGuard, for: .groupMembers) + let status: GROUP_MEMBER_STATUS = group_member_status(&member); - guard member.removed > 0 else { + guard status.isRemoveStatus else { groups_members_iterator_advance(membersIterator) continue } - result[member.get(\.session_id)] = (member.removed == 2) + result[member.get(\.session_id)] = status groups_members_iterator_advance(membersIterator) } groups_members_iterator_free(membersIterator) // Need to free the iterator @@ -536,3 +520,45 @@ fileprivate extension GroupMember.RoleStatus { } } } + +fileprivate extension GROUP_MEMBER_STATUS { + func isAdmin(_ memberAdminFlag: Bool) -> Bool { + switch self { + case GROUP_MEMBER_STATUS_PROMOTION_UNKNOWN, GROUP_MEMBER_STATUS_PROMOTION_NOT_SENT, + GROUP_MEMBER_STATUS_PROMOTION_FAILED, GROUP_MEMBER_STATUS_PROMOTION_SENT, + GROUP_MEMBER_STATUS_PROMOTION_ACCEPTED: + return true + + default: return memberAdminFlag + } + } + + var roleStatus: GroupMember.RoleStatus { + switch self { + case GROUP_MEMBER_STATUS_INVITE_NOT_SENT, GROUP_MEMBER_STATUS_PROMOTION_NOT_SENT: + return .notSentYet + + case GROUP_MEMBER_STATUS_INVITE_ACCEPTED, GROUP_MEMBER_STATUS_PROMOTION_ACCEPTED: + return .accepted + + case GROUP_MEMBER_STATUS_INVITE_FAILED, GROUP_MEMBER_STATUS_PROMOTION_FAILED: + return .failed + + case GROUP_MEMBER_STATUS_INVITE_SENT, GROUP_MEMBER_STATUS_PROMOTION_SENT: + return .pending + + // Default to "accepted" as that's what the `libSession.groups.member.status()` function does + default: return .accepted + } + } + + var isRemoveStatus: Bool { + switch self { + case GROUP_MEMBER_STATUS_REMOVED, GROUP_MEMBER_STATUS_REMOVED_UNKNOWN, + GROUP_MEMBER_STATUS_REMOVED_MEMBER_AND_MESSAGES: + return true + + default: return false + } + } +}