# Copyright (C) 2019 Philipp Hörist # # This file is part of OMEMO Gajim Plugin. # # OMEMO Gajim Plugin is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published # by the Free Software Foundation; version 3 only. # # OMEMO Gajim Plugin 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 General Public License for more details. # # You should have received a copy of the GNU General Public License # along with OMEMO Gajim Plugin. If not, see . from collections import defaultdict from gajim.common import app from omemo.backend.util import UNACKNOWLEDGED_COUNT class DeviceManager: def __init__(self): self.__device_store = defaultdict(set) self.__muc_member_store = defaultdict(set) reg_id = self._storage.getLocalRegistrationId() if reg_id is None: raise ValueError('No own device found') self.__own_device = reg_id self.add_device(self._own_jid, self.__own_device) self._log.info('Our device id: %s', self.__own_device) for jid, device in self._storage.getActiveDeviceTuples(): self._log.info('Load device from storage: %s - %s', jid, device) self.add_device(jid, device) def update_devicelist(self, jid, devicelist): for device in list(devicelist): if device == self.own_device: continue count = self._storage.getUnacknowledgedCount(jid, device) if count > UNACKNOWLEDGED_COUNT: self._log.warning('Ignore device because of %s unacknowledged' ' messages: %s %s', count, jid, device) devicelist.remove(device) self.__device_store[jid] = set(devicelist) self._log.info('Saved devices for %s', jid) self._storage.setActiveState(jid, devicelist) def add_muc_member(self, room_jid, jid): self._log.info('Saved MUC member %s %s', room_jid, jid) self.__muc_member_store[room_jid].add(jid) def remove_muc_member(self, room_jid, jid): self._log.info('Removed MUC member %s %s', room_jid, jid) self.__muc_member_store[room_jid].discard(jid) def get_muc_members(self, room_jid, without_self=True): members = set(self.__muc_member_store[room_jid]) if without_self: members.discard(self._own_jid) return members def add_device(self, jid, device): self.__device_store[jid].add(device) def remove_device(self, jid, device): self.__device_store[jid].discard(device) self._storage.setInactive(jid, device) def get_devices(self, jid, without_self=False): devices = set(self.__device_store[jid]) if without_self: devices.discard(self.own_device) return devices def get_devices_for_encryption(self, jid): devices_for_encryption = [] client = app.get_client(self._account) contact = client.get_module('Contacts').get_contact(jid) if contact.is_groupchat: devices_for_encryption = self._get_devices_for_muc_encryption(jid) else: devices_for_encryption = self._get_devices_for_encryption(jid) if not devices_for_encryption: raise NoDevicesFound devices_for_encryption += self._get_own_devices_for_encryption() return set(devices_for_encryption) def _get_devices_for_muc_encryption(self, jid): devices_for_encryption = [] for jid_ in self.__muc_member_store[jid]: devices_for_encryption += self._get_devices_for_encryption(jid_) return devices_for_encryption def _get_own_devices_for_encryption(self): devices_for_encryption = [] own_devices = self.get_devices(self._own_jid, without_self=True) for device in own_devices: if self._storage.isTrusted(self._own_jid, device): devices_for_encryption.append((self._own_jid, device)) return devices_for_encryption def _get_devices_for_encryption(self, jid): devices_for_encryption = [] devices = self.get_devices(jid) for device in devices: if self._storage.isTrusted(jid, device): devices_for_encryption.append((jid, device)) return devices_for_encryption @property def own_device(self): return self.__own_device @property def devices_for_publish(self): devices = self.get_devices(self._own_jid) if self.own_device not in devices: devices.add(self.own_device) return devices @property def is_own_device_published(self): return self.own_device in self.get_devices(self._own_jid) class NoDevicesFound(Exception): pass