def __init__(self): super(ContactsManager, self).__init__() self.__seq = SeqTaskQueue() self.__seq.suspend() self.__tasks = ContactTaskQueue([block_tasks.SyncBlockItemTask()]) self.__cooldown = XmppCooldownManager() self.__subsBatch = sub_helper.InboundSubscriptionsBatch() self.__subsRestrictions = sub_helper.SubscriptionsRestrictions() self.__presence = _UserPresence() self.__presence.addListeners() self.__voip = VoipHandler() self.__voip.addListeners() g_messengerEvents.onPluginConnectFailed += self.__me_onPluginConnectFailed self.usersStorage.onRestoredFromCache += self.__us_onRestoredFromCache g_settings.onUserPreferencesUpdated += self.__ms_onUserPreferencesUpdated
def __init__(self): super(ContactsManager, self).__init__() self.__seq = SeqTaskQueue() self.__tasks = ContactTaskQueue() self.__cooldown = XmppCooldownManager() self.__presence = _UserPresence() self.__presence.addListeners() self.__voip = _VoipHandler() self.__voip.addListeners() g_messengerEvents.onPluginConnectFailed += self.__me_onPluginConnectFailed self.usersStorage.onRestoredFromCache += self.__us_onRestoredFromCache
def __init__(self): super(ContactsManager, self).__init__() self.__seq = SeqTaskQueue() self.__seq.suspend() self.__tasks = ContactTaskQueue([block_tasks.SyncBlockItemTask()]) self.__cooldown = XmppCooldownManager() self.__subsBatch = sub_helper.InboundSubscriptionsBatch() self.__subsRestrictions = sub_helper.SubscriptionsRestrictions() self.__presence = _UserPresence() self.__presence.addListeners() self.__voip = _VoipHandler() self.__voip.addListeners() g_messengerEvents.onPluginConnectFailed += self.__me_onPluginConnectFailed self.usersStorage.onRestoredFromCache += self.__us_onRestoredFromCache g_settings.onUserPreferencesUpdated += self.__ms_onUserPreferencesUpdated
class ContactsManager(ClientEventsHandler): __slots__ = ('__seq', '__tasks', '__cooldown', '__presence', '__voip', '__rqRestrictions', '__subsBatch', '__subsRestrictions') def __init__(self): super(ContactsManager, self).__init__() self.__seq = SeqTaskQueue() self.__seq.suspend() self.__tasks = ContactTaskQueue([block_tasks.SyncBlockItemTask()]) self.__cooldown = XmppCooldownManager() self.__subsBatch = sub_helper.InboundSubscriptionsBatch() self.__subsRestrictions = sub_helper.SubscriptionsRestrictions() self.__presence = _UserPresence() self.__presence.addListeners() self.__voip = VoipHandler() self.__voip.addListeners() g_messengerEvents.onPluginConnectFailed += self.__me_onPluginConnectFailed self.usersStorage.onRestoredFromCache += self.__us_onRestoredFromCache g_settings.onUserPreferencesUpdated += self.__ms_onUserPreferencesUpdated @storage_getter('users') def usersStorage(self): return None @storage_getter('playerCtx') def playerCtx(self): return None def isInited(self): return self.__seq.isInited() def clear(self): g_settings.onUserPreferencesUpdated -= self.__ms_onUserPreferencesUpdated g_messengerEvents.onPluginConnectFailed -= self.__me_onPluginConnectFailed self.usersStorage.onRestoredFromCache -= self.__us_onRestoredFromCache self.__presence.removeListeners() self.__voip.removeListeners() self.__subsBatch.clear() self.__clearTemporaryFlags() super(ContactsManager, self).clear() def switch(self, scope): self.__presence.switch(scope) self.__clearTemporaryFlags() @notations.contacts(PROTO_TYPE.XMPP, log=False) def registerHandlers(self): register = self.client().registerHandler register(_EVENT.CONNECTED, self.__handleConnected) register(_EVENT.DISCONNECTED, self.__handleDisconnected) register(_EVENT.IQ, self.__handleIQ) register(_EVENT.ROSTER_QUERY, self.__handleRosterQuery) register(_EVENT.ROSTER_RESULT, self.__handleRosterResult) register(_EVENT.ROSTER_ITEM_SET, self.__handleRosterItemSet) register(_EVENT.ROSTER_ITEM_REMOVED, self.__handleRosterItemRemoved) register(_EVENT.PRESENCE, self.__handlePresence) register(_EVENT.SUBSCRIPTION_REQUEST, self.__handleSubscriptionRequest) @notations.contacts(PROTO_TYPE.XMPP, log=False) def unregisterHandlers(self): unregister = self.client().unregisterHandler unregister(_EVENT.CONNECTED, self.__handleConnected) unregister(_EVENT.DISCONNECTED, self.__handleDisconnected) unregister(_EVENT.IQ, self.__handleIQ) unregister(_EVENT.ROSTER_QUERY, self.__handleRosterQuery) unregister(_EVENT.ROSTER_RESULT, self.__handleRosterResult) unregister(_EVENT.ROSTER_ITEM_SET, self.__handleRosterItemSet) unregister(_EVENT.ROSTER_ITEM_REMOVED, self.__handleRosterItemRemoved) unregister(_EVENT.PRESENCE, self.__handlePresence) unregister(_EVENT.SUBSCRIPTION_REQUEST, self.__handleSubscriptionRequest) self.__tasks.clear() @xmpp_query(QUERY_SIGN.DATABASE_ID, QUERY_SIGN.ACCOUNT_NAME, QUERY_SIGN.OPT_GROUP_NAME) def addFriend(self, dbID, name, group=None): error = self._checkCooldown(CLIENT_ACTION_ID.ADD_FRIEND) if error: return (False, error) else: if group: if not self.usersStorage.isGroupExists(group): return (False, ClientContactError( CONTACT_ERROR_ID.GROUP_NOT_FOUND, group)) groups = {group} else: groups = None contact = self.usersStorage.getUser(dbID, PROTO_TYPE.XMPP) tasks, itemType = [], XMPP_ITEM_TYPE.EMPTY_ITEM if contact: if contact.isCurrentPlayer(): return (False, ClientActionError(CLIENT_ACTION_ID.ADD_FRIEND, CLIENT_ERROR_ID.GENERIC)) jid = contact.getJID() itemType = contact.getItemType() if itemType in XMPP_ITEM_TYPE.ROSTER_ITEMS: return (False, ClientContactError( CONTACT_ERROR_ID.ROSTER_ITEM_EXISTS, contact.getFullName())) subTo = contact.getSubscription()[0] else: jid = makeContactJID(dbID) subTo = _SUB.OFF result, error = self.__subsRestrictions.canAddFriends() if not result: return (False, error) if itemType == XMPP_ITEM_TYPE.TMP_BLOCK_ITEM: tasks.append(block_tasks.RemoveTmpBlockItemTask(jid, name)) tasks.append(roster_tasks.AddRosterItemTask(jid, name, groups)) elif itemType == XMPP_ITEM_TYPE.ROSTER_TMP_BLOCK_ITEM: tasks.append(block_tasks.RemoveTmpBlockItemTask(jid, name)) elif itemType == XMPP_ITEM_TYPE.BLOCK_ITEM: tasks.append(block_tasks.RemoveBlockItemTask(jid, name)) tasks.append(roster_tasks.AddRosterItemTask(jid, name, groups)) elif itemType == XMPP_ITEM_TYPE.ROSTER_BLOCK_ITEM: tasks.append(block_tasks.RemoveBlockItemTask(jid, name)) task, exclude = None, set() rosterGroups = contact.getItem().getRosterGroups() for rosterGroup in rosterGroups: if self.usersStorage.isGroupEmpty(rosterGroup): exclude.add(rosterGroup) if groups: if groups != exclude: task = roster_tasks.ChangeRosterItemGroupsTask( jid, name, groups, exclude) elif rosterGroups: task = roster_tasks.ChangeRosterItemGroupsTask( jid, name, set(), exclude) if task: tasks.append(task) elif itemType in XMPP_ITEM_TYPE.SUB_PENDING_ITEMS: if itemType == XMPP_ITEM_TYPE.SUB_PENDING_TMP_BLOCK_ITEM: tasks.append(block_tasks.RemoveTmpBlockItemTask(jid, name)) tasks.append(sub_tasks.ApproveSubscriptionTask(jid, name)) if groups: tasks.append( roster_tasks.ChangeRosterItemGroupsTask( jid, name, groups)) else: tasks.append(roster_tasks.AddRosterItemTask(jid, name, groups)) if subTo == _SUB.OFF: tasks.append(sub_tasks.AskSubscriptionTask(jid)) self.__cooldown.process(CLIENT_ACTION_ID.ADD_FRIEND) return self.__addTasks(CLIENT_ACTION_ID.ADD_FRIEND, jid, *tasks) @xmpp_query(QUERY_SIGN.DATABASE_ID) def removeFriend(self, dbID): error = self._checkCooldown(CLIENT_ACTION_ID.REMOVE_FRIEND) if error: return (False, error) contact = self.usersStorage.getUser(dbID, PROTO_TYPE.XMPP) if not contact: return (False, ClientContactError( CONTACT_ERROR_ID.CONTACT_ITEM_NOT_FOUND)) if contact.getItemType() not in XMPP_ITEM_TYPE.ROSTER_ITEMS: return (False, ClientContactError(CONTACT_ERROR_ID.ROSTER_ITEM_NOT_FOUND, contact.getFullName())) jid = contact.getJID() self.__cooldown.process(CLIENT_ACTION_ID.REMOVE_FRIEND) tasks = [ roster_tasks.RemoveRosterItemTask(jid, contact.getName(), groups=contact.getGroups()) ] if note_tasks.canNoteAutoDelete(contact): tasks.append(note_tasks.RemoveNoteTask(jid)) return self.__addTasks(CLIENT_ACTION_ID.REMOVE_FRIEND, jid, *tasks) @xmpp_query(QUERY_SIGN.DATABASE_ID, QUERY_SIGN.OPT_GROUP_NAME, QUERY_SIGN.OPT_GROUP_NAME) def moveFriendToGroup(self, dbID, include=None, exclude=None): error = self._checkCooldown(CLIENT_ACTION_ID.CHANGE_GROUP) if error: return (False, error) else: contact = self.usersStorage.getUser(dbID, PROTO_TYPE.XMPP) if not contact: return (False, ClientContactError( CONTACT_ERROR_ID.CONTACT_ITEM_NOT_FOUND)) if contact.getItemType() not in XMPP_ITEM_TYPE.ROSTER_ITEMS: return (False, ClientContactError( CONTACT_ERROR_ID.ROSTER_ITEM_NOT_FOUND, contact.getFullName())) groups = contact.getGroups() if include: if not self.usersStorage.isGroupExists(include): return (False, ClientContactError( CONTACT_ERROR_ID.GROUP_NOT_FOUND, include)) groups.add(include) if exclude: if not self.usersStorage.isGroupExists(exclude): return (False, ClientContactError( CONTACT_ERROR_ID.GROUP_NOT_FOUND, exclude)) groups.discard(exclude) if contact.getGroups() == groups: return (True, None) jid = contact.getJID() self.__cooldown.process(CLIENT_ACTION_ID.CHANGE_GROUP) return self.__addTasks( CLIENT_ACTION_ID.CHANGE_GROUP, jid, roster_tasks.ChangeRosterItemGroupsTask( jid, contact.getName(), groups, {exclude} if exclude else None)) @xmpp_query(QUERY_SIGN.GROUP_NAME) def addGroup(self, name): error = self._checkCooldown(CLIENT_ACTION_ID.ADD_GROUP) if error: return (False, error) elif self.usersStorage.isGroupExists(name): return (False, ClientContactError(CONTACT_ERROR_ID.GROUP_EXISTS, name)) elif len(self.usersStorage.getGroups() ) >= CONTACT_LIMIT.GROUPS_MAX_COUNT: return (False, ClientIntLimitError(LIMIT_ERROR_ID.MAX_GROUP, CONTACT_LIMIT.GROUPS_MAX_COUNT)) else: self.usersStorage.addEmptyGroup(name) g_messengerEvents.users.onEmptyGroupsChanged({name}, None) self.__cooldown.process(CLIENT_ACTION_ID.ADD_GROUP) return (True, None) @xmpp_query(QUERY_SIGN.GROUP_NAME, QUERY_SIGN.GROUP_NAME) def renameGroup(self, oldName, newName): error = self._checkCooldown(CLIENT_ACTION_ID.CHANGE_GROUP) if error: return (False, error) elif self.usersStorage.isGroupExists(newName): return (False, ClientContactError(CONTACT_ERROR_ID.GROUP_EXISTS)) elif newName == oldName: return (False, ClientActionError(CLIENT_ACTION_ID.CHANGE_GROUP, CLIENT_ERROR_ID.GENERIC)) elif self.usersStorage.isGroupEmpty(oldName): self.usersStorage.changeEmptyGroup(oldName, newName) g_messengerEvents.users.onEmptyGroupsChanged({newName}, {oldName}) return (True, None) else: task = self.__makeChangeGroupsChain(oldName, newName) self.__cooldown.process(CLIENT_ACTION_ID.CHANGE_GROUP) return self.__addTasks(CLIENT_ACTION_ID.CHANGE_GROUP, task.getJID(), task) @xmpp_query(QUERY_SIGN.GROUP_NAME) def removeGroup(self, name, isForced=False): error = self._checkCooldown(CLIENT_ACTION_ID.CHANGE_GROUP) if error: return (False, error) elif not self.usersStorage.isGroupExists(name): return (False, ClientContactError(CONTACT_ERROR_ID.GROUP_NOT_FOUND, name)) elif self.usersStorage.isGroupEmpty(name): self.usersStorage.changeEmptyGroup(name) g_messengerEvents.users.onEmptyGroupsChanged(None, {name}) return (True, None) else: if isForced: task = self.__makeRemoveItemsByGroupChain(name) else: task = self.__makeChangeGroupsChain(name) self.__cooldown.process(CLIENT_ACTION_ID.CHANGE_GROUP) return self.__addTasks(CLIENT_ACTION_ID.CHANGE_GROUP, task.getJID(), task) @xmpp_query(QUERY_SIGN.DATABASE_ID) def requestFriendship(self, dbID): error = self._checkCooldown(CLIENT_ACTION_ID.RQ_FRIENDSHIP) if error: return (False, error) contact = self.usersStorage.getUser(dbID, PROTO_TYPE.XMPP) if not contact or contact.isCurrentPlayer(): return (False, ClientContactError( CONTACT_ERROR_ID.CONTACT_ITEM_NOT_FOUND)) itemType = contact.getItemType() if itemType == XMPP_ITEM_TYPE.BLOCK_ITEM: return (False, ClientContactError(CONTACT_ERROR_ID.BLOCK_ITEM_EXISTS, contact.getFullName())) if itemType not in XMPP_ITEM_TYPE.ROSTER_ITEMS: return (False, ClientContactError(CONTACT_ERROR_ID.ROSTER_ITEM_NOT_FOUND, contact.getFullName())) jid = contact.getJID() self.__cooldown.process(CLIENT_ACTION_ID.RQ_FRIENDSHIP) return self.__addTasks(CLIENT_ACTION_ID.RQ_FRIENDSHIP, jid, sub_tasks.AskSubscriptionTask(jid)) def canApproveFriendship(self, contact): return (False, ClientError(CLIENT_ERROR_ID.NOT_CONNECTED) ) if not self.client() or not self.client().isConnected( ) else self.__subsRestrictions.canApproveFriendship(contact) def canCancelFriendship(self, contact): return (False, ClientError(CLIENT_ERROR_ID.NOT_CONNECTED) ) if not self.client() or not self.client().isConnected( ) else self.__subsRestrictions.canCancelFriendship(contact) @xmpp_query(QUERY_SIGN.DATABASE_ID) def approveFriendship(self, dbID): contact = self.usersStorage.getUser(dbID, PROTO_TYPE.XMPP) result, error = self.canApproveFriendship(contact) if not result: return (result, error) if contact.getItemType() in XMPP_ITEM_TYPE.ROSTER_ITEMS: jid = contact.getJID() tasks = [sub_tasks.ApproveSubscriptionTask(jid)] if contact.getSubscription()[0] == _SUB.OFF: tasks.append(sub_tasks.AskSubscriptionTask(jid)) else: jid = makeContactJID(dbID) tasks = (sub_tasks.ApproveSubscriptionTask(jid), sub_tasks.AskSubscriptionTask(jid)) return self.__addTasks(CLIENT_ACTION_ID.APPROVE_FRIENDSHIP, jid, *tasks) @xmpp_query(QUERY_SIGN.DATABASE_ID) def cancelFriendship(self, dbID): contact = self.usersStorage.getUser(dbID, PROTO_TYPE.XMPP) result, error = self.canCancelFriendship(contact) if not result: return (result, error) jid = contact.getJID() tasks = [sub_tasks.CancelSubscriptionTask(jid)] if note_tasks.canNoteAutoDelete(contact): tasks.append(note_tasks.RemoveNoteTask(jid)) return self.__addTasks(CLIENT_ACTION_ID.CANCEL_FRIENDSHIP, jid, *tasks) def getFriendshipRqs(self): return self.usersStorage.getList(RqFriendshipCriteria()) @xmpp_query(QUERY_SIGN.DATABASE_ID, QUERY_SIGN.ACCOUNT_NAME) def addIgnored(self, dbID, name): error = self._checkCooldown(CLIENT_ACTION_ID.ADD_IGNORED) if error: return (False, error) tasks, itemType = [], XMPP_ITEM_TYPE.EMPTY_ITEM contact = self.usersStorage.getUser(dbID, PROTO_TYPE.XMPP) if contact: if contact.isCurrentPlayer(): return (False, ClientActionError(CLIENT_ACTION_ID.ADD_IGNORED, CLIENT_ERROR_ID.GENERIC)) itemType = contact.getItemType() if itemType in XMPP_ITEM_TYPE.BLOCK_ITEMS: return (False, ClientContactError(CONTACT_ERROR_ID.BLOCK_ITEM_EXISTS, contact.getFullName())) length = self.usersStorage.getCount( ItemsFindCriteria(XMPP_ITEM_TYPE.PERSISTENT_BLOCKING_LIST)) if length >= CONTACT_LIMIT.BLOCK_MAX_COUNT: return (False, ClientIntLimitError(LIMIT_ERROR_ID.MAX_BLOCK_ITEMS, CONTACT_LIMIT.BLOCK_MAX_COUNT)) if contact: jid = contact.getJID() if itemType in XMPP_ITEM_TYPE.SUB_PENDING_ITEMS: tasks.append(sub_tasks.CancelSubscriptionTask(jid)) else: jid = makeContactJID(dbID) tasks.append(block_tasks.AddBlockItemTask(jid, name)) if itemType in XMPP_ITEM_TYPE.ROSTER_ITEMS: groups = contact.getGroups() if groups: tasks.append(roster_tasks.EmptyGroupsTask(jid, groups=groups)) self.__cooldown.process(CLIENT_ACTION_ID.ADD_IGNORED) return self.__addTasks(CLIENT_ACTION_ID.ADD_IGNORED, jid, *tasks) def addTmpIgnored(self, dbID, name): error = self._checkCooldown(CLIENT_ACTION_ID.ADD_IGNORED) if error: return (False, error) tasks, itemType = [], XMPP_ITEM_TYPE.EMPTY_ITEM contact = self.usersStorage.getUser(dbID, PROTO_TYPE.XMPP) if contact: if contact.isCurrentPlayer(): return (False, ClientActionError(CLIENT_ACTION_ID.ADD_IGNORED, CLIENT_ERROR_ID.GENERIC)) itemType = contact.getItemType() if itemType in XMPP_ITEM_TYPE.BLOCK_ITEMS: return (False, ClientContactError(CONTACT_ERROR_ID.BLOCK_ITEM_EXISTS, contact.getFullName())) if contact: jid = contact.getJID() else: jid = makeContactJID(dbID) tasks.append(block_tasks.AddTmpBlockItemTask(jid, name)) self.__cooldown.process(CLIENT_ACTION_ID.ADD_IGNORED) return self.__addTasks(CLIENT_ACTION_ID.ADD_IGNORED, jid, *tasks) def removeIgnored(self, dbID): error = self._checkCooldown(CLIENT_ACTION_ID.REMOVE_IGNORED) if error: return (False, error) contact = self.usersStorage.getUser(dbID, PROTO_TYPE.XMPP) if not contact: return (False, ClientContactError( CONTACT_ERROR_ID.CONTACT_ITEM_NOT_FOUND)) itemType = contact.getItemType() if itemType not in XMPP_ITEM_TYPE.PERSISTENT_BLOCKING_LIST: return (False, ClientContactError(CONTACT_ERROR_ID.BLOCK_ITEM_NOT_FOUND, contact.getFullName())) jid = contact.getJID() tasks = [block_tasks.RemoveBlockItemTask(jid, contact.getName())] if itemType == XMPP_ITEM_TYPE.ROSTER_BLOCK_ITEM: tasks.append( roster_tasks.RemoveRosterItemTask( jid, contact.getName(), groups=contact.getItem().getRosterGroups())) if note_tasks.canNoteAutoDelete(contact): tasks.append(note_tasks.RemoveNoteTask(jid)) self.__cooldown.process(CLIENT_ACTION_ID.REMOVE_IGNORED) return self.__addTasks(CLIENT_ACTION_ID.REMOVE_IGNORED, jid, *tasks) @xmpp_query(QUERY_SIGN.DATABASE_ID) def removeTmpIgnored(self, dbID): return self.__removeTmpIgnored(dbID) @local_query(QUERY_SIGN.DATABASE_ID, QUERY_SIGN.ACCOUNT_NAME) def setMuted(self, dbID, name): error = self._checkCooldown(CLIENT_ACTION_ID.SET_MUTE) if error: return (False, error) else: contact = self.usersStorage.getUser(dbID) if not contact: contact = entities.XMPPUserEntity(dbID, name=name, tags={USER_TAG.MUTED}) self.usersStorage.setUser(contact) else: contact.addTags({USER_TAG.MUTED}) g_messengerEvents.users.onUserActionReceived( USER_ACTION_ID.MUTE_SET, contact) self.__cooldown.process(CLIENT_ACTION_ID.SET_MUTE) return (True, None) @local_query(QUERY_SIGN.DATABASE_ID) def unsetMuted(self, dbID): error = self._checkCooldown(CLIENT_ACTION_ID.UNSET_MUTE) if error: return (False, error) else: contact = self.usersStorage.getUser(dbID) if not contact: return (False, ClientContactError( CONTACT_ERROR_ID.CONTACT_ITEM_NOT_FOUND)) if not contact.isMuted(): return (False, ClientContactError( CONTACT_ERROR_ID.MUTED_ITEM_NOT_FOUND, contact.getFullName())) contact.removeTags({USER_TAG.MUTED}) g_messengerEvents.users.onUserActionReceived( USER_ACTION_ID.MUTE_UNSET, contact) self.__cooldown.process(CLIENT_ACTION_ID.UNSET_MUTE) return (True, None) @xmpp_query(QUERY_SIGN.DATABASE_ID, QUERY_SIGN.NOTE_TEXT) def setNote(self, dbID, note): error = self._checkCooldown(CLIENT_ACTION_ID.SET_NOTE) if error: return (False, error) contact = self.usersStorage.getUser(dbID) if not contact or not contact.getTags(): return (False, ClientContactError( CONTACT_ERROR_ID.CONTACT_ITEM_NOT_FOUND)) jid = makeContactJID(dbID) self.__cooldown.process(CLIENT_ACTION_ID.SET_NOTE) return self.__addTasks(CLIENT_ACTION_ID.SET_NOTE, jid, note_tasks.SetNoteTask(jid, note)) @xmpp_query(QUERY_SIGN.DATABASE_ID) def removeNote(self, dbID): error = self._checkCooldown(CLIENT_ACTION_ID.REMOVE_NOTE) if error: return (False, error) contact = self.usersStorage.getUser(dbID) if not contact or not contact.getTags(): return (False, ClientContactError( CONTACT_ERROR_ID.CONTACT_ITEM_NOT_FOUND)) if not contact.getNote(): return (False, ClientContactError(CONTACT_ERROR_ID.NOTE_NOT_FOUND, name=contact.getFullName())) jid = makeContactJID(dbID) self.__cooldown.process(CLIENT_ACTION_ID.REMOVE_NOTE) return self.__addTasks(CLIENT_ACTION_ID.SET_NOTE, jid, note_tasks.RemoveNoteTask(jid)) def getUserScope(self): return self.__presence.getUserScope() def _checkCooldown(self, actionID): error = None if self.__cooldown.isInProcess(actionID): error = ChatCoolDownError(actionID, self.__cooldown.getDefaultCoolDown()) return error def _processCooldown(self, actionID): self.__cooldown.process(actionID) def __makeChangeGroupsChain(self, exclude, include=None): chain = [] for contact in self.usersStorage.getList(GroupFindCriteria(exclude)): jid = contact.getJID() groups = contact.getGroups() groups.discard(exclude) if include: groups.add(include) chain.append((jid, contact.getName(), groups)) return roster_tasks.ChangeRosterItemsGroupsChain(chain) def __makeRemoveItemsByGroupChain(self, name): chain = [] for contact in self.usersStorage.getList(GroupFindCriteria(name)): groups = contact.getGroups() groups.discard(name) chain.append((contact.getJID(), contact.getName(), groups)) return roster_tasks.RemoveRosterItemsGroupsChain(chain) def __addTasks(self, actionID, jid, *tasks): if self.__tasks.addTasks(jid, *tasks): self.__tasks.runFirstTask(jid) else: return (False, ClientActionError(actionID, CLIENT_ERROR_ID.LOCKED)) return (True, None) def __removeTmpIgnored(self, dbID, forced=False): if not forced: error = self._checkCooldown(CLIENT_ACTION_ID.REMOVE_IGNORED) if error: return (False, error) contact = self.usersStorage.getUser(dbID, PROTO_TYPE.XMPP) if not contact: return (False, ClientContactError( CONTACT_ERROR_ID.CONTACT_ITEM_NOT_FOUND)) itemType = contact.getItemType() if itemType not in XMPP_ITEM_TYPE.TMP_BLOCKING_LIST: return (False, ClientContactError(CONTACT_ERROR_ID.BLOCK_ITEM_NOT_FOUND, contact.getFullName())) jid = contact.getJID() tasks = [block_tasks.RemoveTmpBlockItemTask(jid, contact.getName())] if not forced: self.__cooldown.process(CLIENT_ACTION_ID.REMOVE_IGNORED) return self.__addTasks(CLIENT_ACTION_ID.REMOVE_IGNORED, jid, *tasks) def __clearTemporaryFlags(self): tmpIgnored = self.usersStorage.getList(TemporaryIgnoredFindCriteria()) for usr in tmpIgnored: self.__removeTmpIgnored(usr.getID(), forced=True) def __handleConnected(self): self.__tasks.suspend() self.__seq.onInited += self.__onSeqsInited self.__seq.init(roster_tasks.RosterResultTask(), block_tasks.BlockListResultTask(), note_tasks.NotesListTask()) def __handleDisconnected(self, reason, description): if reason == DISCONNECT_REASON.BY_REQUEST: self.__seq.suspend() self.__seq.fini() self.__tasks.clear() self.__subsBatch.clear() for contact in self.usersStorage.getList( ProtoFindCriteria(PROTO_TYPE.XMPP)): resources = contact.getItem().getResources() if not resources.isEmpty(): resources.clear() g_messengerEvents.users.onUserStatusUpdated(contact) def __handleIQ(self, iqID, iqType, pyGlooxTag): if not self.__seq.handleIQ(iqID, iqType, pyGlooxTag): self.__tasks.handleIQ(iqID, iqType, pyGlooxTag) def __handleRosterQuery(self, iqID, jid, context): self.__tasks.setIQ(iqID, jid, context) def __handleRosterResult(self, generator): g_logOutput.debug(_LOG.ROSTER, 'Roster result is received') self.__seq.sync(0, generator()) def __handleRosterItemSet(self, jid, name, groups, sub, clanInfo): g_logOutput.debug(_LOG.ROSTER, 'Roster push is received', jid, name, groups, sub, clanInfo) self.__tasks.sync(jid, name, groups, sub, clanInfo, defaultTask=roster_tasks.SyncSubscriptionTask) def __handleRosterItemRemoved(self, jid): self.__tasks.sync(jid, defaultTask=roster_tasks.RemoveRosterItemTask) def __handlePresence(self, jid, resource): jid = ContactJID(jid) dbID = jid.getDatabaseID() if not dbID: return else: user = self.usersStorage.getUser(dbID, PROTO_TYPE.XMPP) if resource.presence == PRESENCE.UNAVAILABLE: if user and not user.isCurrentPlayer(): user.update(jid=jid, resource=None, clanInfo=resource.getClanInfo()) g_logOutput.debug(_LOG.RESOURCE, 'Resource is removed', user.getName(), jid.getResource(), resource) elif resource.presence != PRESENCE.UNKNOWN: if not user: user = entities.XMPPUserEntity(dbID) self.usersStorage.setUser(user) if user.isCurrentPlayer(): self.playerCtx.setBanInfo(resource.getBanInfo()) else: user.update(jid=jid, resource=resource, clanInfo=resource.getClanInfo()) g_logOutput.debug(_LOG.RESOURCE, 'Resource is set', user.getName(), jid.getResource(), resource) if user: g_messengerEvents.users.onUserStatusUpdated(user) return def __handleSubscriptionRequest(self, subs): self.__subsBatch.addSubs(subs) if not self.__seq.isInited(): return self.__subsRestrictions.setToUseCachedCounts(True) self.__subsBatch.process(self.__tasks) self.__subsRestrictions.setToUseCachedCounts(False) def __onSeqsInited(self): g_logOutput.debug(_LOG.GENERIC, 'Starts to process contacts tasks') self.__presence.sendPresence(True) self.__tasks.release() self.__tasks.onSeqTaskRequested += self.__onSeqTaskRequested self.__subsRestrictions.setToUseCachedCounts(True) self.__subsBatch.process(self.__tasks) self.__subsRestrictions.setToUseCachedCounts(False) g_messengerEvents.users.onUsersListReceived({ USER_TAG.FRIEND, USER_TAG.IGNORED, USER_TAG.IGNORED_TMP, USER_TAG.MUTED }) def __onSeqTaskRequested(self, task): self.__seq.addMultiRq(task) def __me_onPluginConnectFailed(self, protoType, _, tries): if protoType != PROTO_TYPE.XMPP: return scope = self.__presence.getUserScope() if scope == MESSENGER_SCOPE.BATTLE: threshold = _MAX_TRIES_FAILED_IN_BATTLE else: threshold = _MAX_TRIES_FAILED_IN_LOBBY if tries == threshold: g_messengerEvents.users.onUsersListReceived({ USER_TAG.CACHED, USER_TAG.FRIEND, USER_TAG.IGNORED, USER_TAG.IGNORED_TMP, USER_TAG.MUTED }) def __us_onRestoredFromCache(self, stateGenerator): if not g_settings.server.XMPP.isEnabled(): return if stateGenerator: setUser = self.usersStorage.setUser isInited = self.__seq.isInited() for dbID, state in stateGenerator(PROTO_TYPE.XMPP): contact = entities.XMPPUserEntity(dbID) result = contact.setPersistentState(state) if result and (not isInited or contact.getItemType() in XMPP_ITEM_TYPE.SUB_PENDING_ITEMS): setUser(contact) g_messengerEvents.users.onUsersListReceived({ USER_TAG.CACHED, USER_TAG.FRIEND, USER_TAG.IGNORED, USER_TAG.IGNORED_TMP, USER_TAG.MUTED }) def __ms_onUserPreferencesUpdated(self): self.__seq.release()
class ContactsManager(ClientEventsHandler): __slots__ = ('__seq', '__tasks', '__cooldown', '__presence', '__voip') def __init__(self): super(ContactsManager, self).__init__() self.__seq = SeqTaskQueue() self.__tasks = ContactTaskQueue() self.__cooldown = XmppCooldownManager() self.__presence = _UserPresence() self.__presence.addListeners() self.__voip = _VoipHandler() self.__voip.addListeners() g_messengerEvents.onPluginConnectFailed += self.__me_onPluginConnectFailed self.usersStorage.onRestoredFromCache += self.__us_onRestoredFromCache @storage_getter('users') def usersStorage(self): return None @storage_getter('playerCtx') def playerCtx(self): return None def isInited(self): return self.__seq.isInited() def clear(self): g_messengerEvents.onPluginConnectFailed -= self.__me_onPluginConnectFailed self.usersStorage.onRestoredFromCache -= self.__us_onRestoredFromCache self.__presence.removeListeners() self.__voip.removeListeners() super(ContactsManager, self).clear() def switch(self, scope): self.__presence.switch(scope) @notations.contacts(PROTO_TYPE.XMPP, log=False) def registerHandlers(self): register = self.client().registerHandler register(_EVENT.CONNECTED, self.__handleConnected) register(_EVENT.DISCONNECTED, self.__handleDisconnected) register(_EVENT.IQ, self.__handleIQ) register(_EVENT.ROSTER_QUERY, self.__handleRosterQuery) register(_EVENT.ROSTER_RESULT, self.__handleRosterResult) register(_EVENT.ROSTER_ITEM_SET, self.__handleRosterItemSet) register(_EVENT.ROSTER_ITEM_REMOVED, self.__handleRosterItemRemoved) register(_EVENT.ROSTER_RESOURCE_ADDED, self.__handleRosterResourceAdded) register(_EVENT.ROSTER_RESOURCE_REMOVED, self.__handleRosterResourceRemoved) register(_EVENT.SUBSCRIPTION_REQUEST, self.__handleSubscriptionRequest) register(_EVENT.IGR, self.__handlePresenceWithIGR) @notations.contacts(PROTO_TYPE.XMPP, log=False) def unregisterHandlers(self): unregister = self.client().unregisterHandler unregister(_EVENT.CONNECTED, self.__handleConnected) unregister(_EVENT.DISCONNECTED, self.__handleDisconnected) unregister(_EVENT.IQ, self.__handleIQ) unregister(_EVENT.ROSTER_QUERY, self.__handleRosterQuery) unregister(_EVENT.ROSTER_RESULT, self.__handleRosterResult) unregister(_EVENT.ROSTER_ITEM_SET, self.__handleRosterItemSet) unregister(_EVENT.ROSTER_ITEM_REMOVED, self.__handleRosterItemRemoved) unregister(_EVENT.ROSTER_RESOURCE_ADDED, self.__handleRosterResourceAdded) unregister(_EVENT.ROSTER_RESOURCE_REMOVED, self.__handleRosterResourceRemoved) unregister(_EVENT.SUBSCRIPTION_REQUEST, self.__handleSubscriptionRequest) unregister(_EVENT.IGR, self.__handlePresenceWithIGR) self.__tasks.clear() @xmpp_query(QUERY_SIGN.DATABASE_ID, QUERY_SIGN.ACCOUNT_NAME, QUERY_SIGN.OPT_GROUP_NAME) def addFriend(self, dbID, name, group = None): error = self.__checkCooldown(CLIENT_ACTION_ID.ADD_FRIEND) if error: return (False, error) else: if group: if not self.usersStorage.isGroupExists(group): return (False, ClientContactError(CONTACT_ERROR_ID.GROUP_NOT_FOUND, group)) groups = {group} else: groups = None contact = self.usersStorage.getUser(dbID, PROTO_TYPE.XMPP) tasks, itemType = [], XMPP_ITEM_TYPE.EMPTY_ITEM if contact: if contact.isCurrentPlayer(): return (False, ClientActionError(CLIENT_ACTION_ID.ADD_FRIEND, CLIENT_ERROR_ID.GENERIC)) jid = contact.getJID() itemType = contact.getItemType() if itemType == XMPP_ITEM_TYPE.ROSTER_ITEM: return (False, ClientContactError(CONTACT_ERROR_ID.ROSTER_ITEM_EXISTS, contact.getFullName())) subTo = contact.getSubscription()[0] else: jid = makeContactJID(dbID) subTo = _SUB.OFF error = self.__checkRosterSize() if error: return (False, error) if itemType == XMPP_ITEM_TYPE.BLOCK_ITEM: tasks.append(block_tasks.RemoveBlockItemTask(jid, name)) tasks.append(roster_tasks.AddRosterItemTask(jid, name, groups)) elif itemType == XMPP_ITEM_TYPE.ROSTER_BLOCK_ITEM: tasks.append(block_tasks.RemoveBlockItemTask(jid, name)) task, exclude = None, set() rosterGroups = contact.getItem().getRosterGroups() for group in rosterGroups: if self.usersStorage.isGroupEmpty(group): exclude.add(group) if groups: if groups != exclude: task = roster_tasks.ChangeRosterItemGroupsTask(jid, name, groups, exclude) elif rosterGroups: task = roster_tasks.ChangeRosterItemGroupsTask(jid, name, set(), exclude) if task: tasks.append(task) elif itemType == XMPP_ITEM_TYPE.SUB_PENDING: tasks.append(sub_tasks.ApproveSubscriptionTask(jid, name)) if groups: tasks.append(roster_tasks.ChangeRosterItemGroupsTask(jid, name, groups)) else: tasks.append(roster_tasks.AddRosterItemTask(jid, name, groups)) if subTo == _SUB.OFF: tasks.append(sub_tasks.AskSubscriptionTask(jid)) self.__cooldown.process(CLIENT_ACTION_ID.ADD_FRIEND) return self.__addTasks(CLIENT_ACTION_ID.ADD_FRIEND, jid, *tasks) @xmpp_query(QUERY_SIGN.DATABASE_ID) def removeFriend(self, dbID): error = self.__checkCooldown(CLIENT_ACTION_ID.REMOVE_FRIEND) if error: return (False, error) contact = self.usersStorage.getUser(dbID, PROTO_TYPE.XMPP) if not contact: return (False, ClientContactError(CONTACT_ERROR_ID.CONTACT_ITEM_NOT_FOUND)) if contact.getItemType() != XMPP_ITEM_TYPE.ROSTER_ITEM: return (False, ClientContactError(CONTACT_ERROR_ID.ROSTER_ITEM_NOT_FOUND, contact.getFullName())) jid = contact.getJID() self.__cooldown.process(CLIENT_ACTION_ID.REMOVE_FRIEND) return self.__addTasks(CLIENT_ACTION_ID.REMOVE_FRIEND, jid, roster_tasks.RemoveRosterItemTask(jid, contact.getName(), groups=contact.getGroups())) @xmpp_query(QUERY_SIGN.DATABASE_ID, QUERY_SIGN.OPT_GROUP_NAME, QUERY_SIGN.OPT_GROUP_NAME) def moveFriendToGroup(self, dbID, include = None, exclude = None): error = self.__checkCooldown(CLIENT_ACTION_ID.CHANGE_GROUP) if error: return (False, error) else: contact = self.usersStorage.getUser(dbID, PROTO_TYPE.XMPP) if not contact: return (False, ClientContactError(CONTACT_ERROR_ID.CONTACT_ITEM_NOT_FOUND)) if contact.getItemType() != XMPP_ITEM_TYPE.ROSTER_ITEM: return (False, ClientContactError(CONTACT_ERROR_ID.ROSTER_ITEM_NOT_FOUND, contact.getFullName())) groups = contact.getGroups() if include: if not self.usersStorage.isGroupExists(include): return (False, ClientContactError(CONTACT_ERROR_ID.GROUP_NOT_FOUND, include)) groups.add(include) if exclude: if not self.usersStorage.isGroupExists(exclude): return (False, ClientContactError(CONTACT_ERROR_ID.GROUP_NOT_FOUND, exclude)) groups.discard(exclude) jid = contact.getJID() self.__cooldown.process(CLIENT_ACTION_ID.CHANGE_GROUP) return self.__addTasks(CLIENT_ACTION_ID.CHANGE_GROUP, jid, roster_tasks.ChangeRosterItemGroupsTask(jid, contact.getName(), groups, {exclude} if exclude else None)) @xmpp_query(QUERY_SIGN.GROUP_NAME) def addGroup(self, name): error = self.__checkCooldown(CLIENT_ACTION_ID.ADD_GROUP) if error: return (False, error) elif self.usersStorage.isGroupExists(name): return (False, ClientContactError(CONTACT_ERROR_ID.GROUP_EXISTS, name)) elif len(self.usersStorage.getGroups()) >= CONTACT_LIMIT.GROUPS_MAX_COUNT: return (False, ClientIntLimitError(LIMIT_ERROR_ID.MAX_GROUP, CONTACT_LIMIT.GROUPS_MAX_COUNT)) else: self.usersStorage.addEmptyGroup(name) g_messengerEvents.users.onEmptyGroupsChanged({name}, None) self.__cooldown.process(CLIENT_ACTION_ID.ADD_GROUP) return (True, None) @xmpp_query(QUERY_SIGN.GROUP_NAME, QUERY_SIGN.GROUP_NAME) def renameGroup(self, oldName, newName): error = self.__checkCooldown(CLIENT_ACTION_ID.CHANGE_GROUP) if error: return (False, error) elif self.usersStorage.isGroupExists(newName): return (False, ClientContactError(CONTACT_ERROR_ID.GROUP_EXISTS)) elif newName == oldName: return (False, ClientActionError(CLIENT_ACTION_ID.CHANGE_GROUP, CLIENT_ERROR_ID.GENERIC)) elif self.usersStorage.isGroupEmpty(oldName): self.usersStorage.changeEmptyGroup(oldName, newName) g_messengerEvents.users.onEmptyGroupsChanged({newName}, {oldName}) return (True, None) else: task = self.__makeChangeGroupsChain(oldName, newName) self.__cooldown.process(CLIENT_ACTION_ID.CHANGE_GROUP) return self.__addTasks(CLIENT_ACTION_ID.CHANGE_GROUP, task.getJID(), task) @xmpp_query(QUERY_SIGN.GROUP_NAME) def removeGroup(self, name, isForced = False): error = self.__checkCooldown(CLIENT_ACTION_ID.CHANGE_GROUP) if error: return (False, error) elif not self.usersStorage.isGroupExists(name): return (False, ClientContactError(CONTACT_ERROR_ID.GROUP_NOT_FOUND, name)) elif self.usersStorage.isGroupEmpty(name): self.usersStorage.changeEmptyGroup(name) g_messengerEvents.users.onEmptyGroupsChanged(None, {name}) return (True, None) else: if isForced: task = self.__makeRemoveItemsByGroupChain(name) else: task = self.__makeChangeGroupsChain(name) self.__cooldown.process(CLIENT_ACTION_ID.CHANGE_GROUP) return self.__addTasks(CLIENT_ACTION_ID.CHANGE_GROUP, task.getJID(), task) @xmpp_query(QUERY_SIGN.DATABASE_ID) def requestFriendship(self, dbID): error = self.__checkCooldown(CLIENT_ACTION_ID.RQ_FRIENDSHIP) if error: return (False, error) contact = self.usersStorage.getUser(dbID, PROTO_TYPE.XMPP) if not contact or contact.isCurrentPlayer(): return (False, ClientContactError(CONTACT_ERROR_ID.CONTACT_ITEM_NOT_FOUND)) itemType = contact.getItemType() if itemType == XMPP_ITEM_TYPE.BLOCK_ITEM: return (False, ClientContactError(CONTACT_ERROR_ID.BLOCK_ITEM_EXISTS, contact.getFullName())) if itemType != XMPP_ITEM_TYPE.ROSTER_ITEM: return (False, ClientContactError(CONTACT_ERROR_ID.ROSTER_ITEM_NOT_FOUND, contact.getFullName())) jid = contact.getJID() self.__cooldown.process(CLIENT_ACTION_ID.RQ_FRIENDSHIP) return self.__addTasks(CLIENT_ACTION_ID.RQ_FRIENDSHIP, jid, sub_tasks.AskSubscriptionTask(jid)) def canApproveFriendship(self, contact): if not self.client() or not self.client().isConnected(): return (False, ClientError(CLIENT_ERROR_ID.NOT_CONNECTED)) elif not contact: return (False, ClientContactError(CONTACT_ERROR_ID.CONTACT_ITEM_NOT_FOUND)) tags = contact.getTags() if USER_TAG.SUB_APPROVED in tags: return (False, ClientContactError(CONTACT_ERROR_ID.FRIENDSHIP_APPROVED, contact.getFullName())) if contact.getItemType() == XMPP_ITEM_TYPE.ROSTER_ITEM: if USER_TAG.SUB_FROM in contact.getTags(): return (False, ClientContactError(CONTACT_ERROR_ID.FRIENDSHIP_APPROVED, contact.getFullName())) else: return (True, None) if contact.getItemType() == XMPP_ITEM_TYPE.SUB_PENDING: if USER_TAG.SUB_IN_PROCESS in tags: return (False, ClientContactError(CONTACT_ERROR_ID.FRIENDSHIP_RQ_PROCESS, contact.getFullName())) if USER_TAG.SUB_CANCELED in tags: return (False, ClientContactError(CONTACT_ERROR_ID.FRIENDSHIP_CANCELED, contact.getFullName())) error = self.__checkRosterSize() if error: return (False, error) return (True, None) else: return (False, ClientContactError(CONTACT_ERROR_ID.CONTACT_ITEM_NOT_FOUND)) def canCancelFriendship(self, contact): if not self.client() or not self.client().isConnected(): return (False, ClientError(CLIENT_ERROR_ID.NOT_CONNECTED)) elif not contact: return (False, ClientContactError(CONTACT_ERROR_ID.CONTACT_ITEM_NOT_FOUND)) tags = contact.getTags() if USER_TAG.SUB_APPROVED in tags: return (False, ClientContactError(CONTACT_ERROR_ID.FRIENDSHIP_APPROVED, contact.getFullName())) elif USER_TAG.SUB_FROM in tags: return (False, ClientContactError(CONTACT_ERROR_ID.FRIENDSHIP_APPROVED, contact.getFullName())) elif USER_TAG.SUB_IN_PROCESS in tags: return (False, ClientContactError(CONTACT_ERROR_ID.FRIENDSHIP_RQ_PROCESS, contact.getFullName())) elif USER_TAG.SUB_CANCELED in tags: return (False, ClientContactError(CONTACT_ERROR_ID.FRIENDSHIP_CANCELED, contact.getFullName())) elif contact.getItemType() == XMPP_ITEM_TYPE.ROSTER_ITEM: return (False, ClientContactError(CONTACT_ERROR_ID.ROSTER_ITEM_EXISTS, contact.getFullName())) else: return (True, None) @xmpp_query(QUERY_SIGN.DATABASE_ID) def approveFriendship(self, dbID): contact = self.usersStorage.getUser(dbID, PROTO_TYPE.XMPP) result, error = self.canApproveFriendship(contact) if not result: return (result, error) if contact.getItemType() == XMPP_ITEM_TYPE.ROSTER_ITEM: jid = contact.getJID() tasks = [sub_tasks.ApproveSubscriptionTask(jid)] if contact.getSubscription()[0] == _SUB.OFF: tasks.append(sub_tasks.AskSubscriptionTask(jid)) else: jid = makeContactJID(dbID) tasks = (sub_tasks.ApproveSubscriptionTask(jid), sub_tasks.AskSubscriptionTask(jid)) return self.__addTasks(CLIENT_ACTION_ID.APPROVE_FRIENDSHIP, jid, *tasks) @xmpp_query(QUERY_SIGN.DATABASE_ID) def cancelFriendship(self, dbID): contact = self.usersStorage.getUser(dbID, PROTO_TYPE.XMPP) result, error = self.canCancelFriendship(contact) if not result: return (result, error) jid = contact.getJID() task = sub_tasks.CancelSubscriptionTask(jid) return self.__addTasks(CLIENT_ACTION_ID.CANCEL_FRIENDSHIP, jid, task) def getFriendshipRqs(self): return self.usersStorage.getList(RqFriendshipCriteria()) @xmpp_query(QUERY_SIGN.DATABASE_ID, QUERY_SIGN.ACCOUNT_NAME) def addIgnored(self, dbID, name): error = self.__checkCooldown(CLIENT_ACTION_ID.ADD_IGNORED) if error: return (False, error) tasks, itemType = [], XMPP_ITEM_TYPE.EMPTY_ITEM contact = self.usersStorage.getUser(dbID, PROTO_TYPE.XMPP) if contact: if contact.isCurrentPlayer(): return (False, ClientActionError(CLIENT_ACTION_ID.ADD_FRIEND, CLIENT_ERROR_ID.GENERIC)) itemType = contact.getItemType() if itemType == XMPP_ITEM_TYPE.BLOCK_ITEM: return (False, ClientContactError(CONTACT_ERROR_ID.BLOCK_ITEM_EXISTS, contact.getFullName())) length = self.usersStorage.getCount(ItemsFindCriteria(XMPP_ITEM_TYPE.BLOCKING_LIST)) if length >= CONTACT_LIMIT.BLOCK_MAX_COUNT: return (False, ClientIntLimitError(LIMIT_ERROR_ID.MAX_BLOCK_ITEMS, CONTACT_LIMIT.BLOCK_MAX_COUNT)) if contact: jid = contact.getJID() if itemType == XMPP_ITEM_TYPE.SUB_PENDING: tasks.append(sub_tasks.CancelSubscriptionTask(jid)) else: jid = makeContactJID(dbID) tasks.append(block_tasks.AddBlockItemTask(jid, name)) if itemType == XMPP_ITEM_TYPE.ROSTER_ITEM: groups = contact.getGroups() if groups: tasks.append(roster_tasks.EmptyGroupsTask(jid, groups=groups)) self.__cooldown.process(CLIENT_ACTION_ID.ADD_IGNORED) return self.__addTasks(CLIENT_ACTION_ID.ADD_IGNORED, jid, *tasks) @xmpp_query(QUERY_SIGN.DATABASE_ID) def removeIgnored(self, dbID): error = self.__checkCooldown(CLIENT_ACTION_ID.REMOVE_IGNORED) if error: return (False, error) contact = self.usersStorage.getUser(dbID, PROTO_TYPE.XMPP) if not contact: return (False, ClientContactError(CONTACT_ERROR_ID.CONTACT_ITEM_NOT_FOUND)) itemType = contact.getItemType() if itemType not in XMPP_ITEM_TYPE.BLOCKING_LIST: return (False, ClientContactError(CONTACT_ERROR_ID.BLOCK_ITEM_NOT_FOUND, contact.getFullName())) jid = contact.getJID() tasks = [block_tasks.RemoveBlockItemTask(jid, contact.getName())] if itemType == XMPP_ITEM_TYPE.ROSTER_BLOCK_ITEM: tasks.append(roster_tasks.RemoveRosterItemTask(jid, contact.getName())) self.__cooldown.process(CLIENT_ACTION_ID.REMOVE_IGNORED) return self.__addTasks(CLIENT_ACTION_ID.REMOVE_IGNORED, jid, *tasks) @local_query(QUERY_SIGN.DATABASE_ID, QUERY_SIGN.ACCOUNT_NAME) def setMuted(self, dbID, name): error = self.__checkCooldown(CLIENT_ACTION_ID.SET_MUTE) if error: return (False, error) else: contact = self.usersStorage.getUser(dbID) if not contact: contact = entities.XMPPUserEntity(dbID, name=name, tags={USER_TAG.MUTED}) self.usersStorage.setUser(contact) else: contact.addTags({USER_TAG.MUTED}) g_messengerEvents.users.onUserActionReceived(USER_ACTION_ID.MUTE_SET, contact) self.__cooldown.process(CLIENT_ACTION_ID.SET_MUTE) return (True, None) @local_query(QUERY_SIGN.DATABASE_ID) def unsetMuted(self, dbID): error = self.__checkCooldown(CLIENT_ACTION_ID.UNSET_MUTE) if error: return (False, error) else: contact = self.usersStorage.getUser(dbID) if not contact: return (False, ClientContactError(CONTACT_ERROR_ID.CONTACT_ITEM_NOT_FOUND)) if not contact.isMuted(): return (False, ClientContactError(CONTACT_ERROR_ID.MUTED_ITEM_NOT_FOUND, contact.getFullName())) contact.removeTags({USER_TAG.MUTED}) g_messengerEvents.users.onUserActionReceived(USER_ACTION_ID.MUTE_SET, contact) self.__cooldown.process(CLIENT_ACTION_ID.UNSET_MUTE) return (True, None) @xmpp_query(QUERY_SIGN.DATABASE_ID, QUERY_SIGN.NOTE_TEXT) def setNote(self, dbID, note): error = self.__checkCooldown(CLIENT_ACTION_ID.SET_NOTE) if error: return (False, error) contact = self.usersStorage.getUser(dbID) if not contact or not contact.getTags(): return (False, ClientContactError(CONTACT_ERROR_ID.CONTACT_ITEM_NOT_FOUND)) jid = makeContactJID(dbID) self.__cooldown.process(CLIENT_ACTION_ID.SET_NOTE) return self.__addTasks(CLIENT_ACTION_ID.SET_NOTE, jid, note_tasks.SetNoteTask(jid, note)) @xmpp_query(QUERY_SIGN.DATABASE_ID) def removeNote(self, dbID): error = self.__checkCooldown(CLIENT_ACTION_ID.REMOVE_NOTE) if error: return (False, error) contact = self.usersStorage.getUser(dbID) if not contact or not contact.getTags(): return (False, ClientContactError(CONTACT_ERROR_ID.CONTACT_ITEM_NOT_FOUND)) if not contact.getNote(): return (False, ClientContactError(CONTACT_ERROR_ID.NOTE_NOT_FOUND, name=contact.getFullName())) jid = makeContactJID(dbID) self.__cooldown.process(CLIENT_ACTION_ID.REMOVE_NOTE) return self.__addTasks(CLIENT_ACTION_ID.SET_NOTE, jid, note_tasks.RemoveNoteTask(jid)) def __makeChangeGroupsChain(self, exclude, include = None): chain = [] for contact in self.usersStorage.getList(GroupFindCriteria(exclude)): jid = contact.getJID() groups = contact.getGroups() groups.discard(exclude) if include: groups.add(include) chain.append((jid, contact.getName(), groups)) return roster_tasks.ChangeRosterItemsGroupsChain(chain) def __makeRemoveItemsByGroupChain(self, name): chain = [] for contact in self.usersStorage.getList(GroupFindCriteria(name)): groups = contact.getGroups() groups.discard(name) chain.append((contact.getJID(), contact.getName(), groups)) return roster_tasks.RemoveRosterItemsGroupsChain(chain) def __addTasks(self, actionID, jid, *tasks): if self.__tasks.addTasks(jid, *tasks): self.__tasks.runFirstTask(jid) else: return (False, ClientActionError(actionID, CLIENT_ERROR_ID.LOCKED)) return (True, None) def __checkCooldown(self, actionID): error = None if self.__cooldown.isInProcess(actionID): error = ChatCoolDownError(actionID, self.__cooldown.getDefaultCoolDown()) return error def __checkRosterSize(self): length = self.usersStorage.getCount(ItemsFindCriteria((XMPP_ITEM_TYPE.ROSTER_ITEM,))) if length >= CONTACT_LIMIT.ROSTER_MAX_COUNT: return ClientIntLimitError(LIMIT_ERROR_ID.MAX_ROSTER_ITEMS, CONTACT_LIMIT.ROSTER_MAX_COUNT) else: return None def __handleConnected(self): self.__tasks.suspend() self.__seq.onInited += self.__onSeqsInited tasks = [roster_tasks.RosterResultTask(), block_tasks.BlockListResultTask()] if GUI_SETTINGS.isXmppNotesEnabled: tasks.append(note_tasks.NotesListTask()) self.__seq.init(*tasks) def __handleDisconnected(self, reason, description): self.__seq.fini() self.__tasks.clear() for contact in self.usersStorage.getList(ProtoFindCriteria(PROTO_TYPE.XMPP)): resources = contact.getItem().getResources() if not resources.isEmpty(): resources.clear() g_messengerEvents.users.onUserStatusUpdated(contact) def __handleIQ(self, iqID, iqType, pyGlooxTag): if not self.__seq.handleIQ(iqID, iqType, pyGlooxTag): self.__tasks.handleIQ(iqID, iqType, pyGlooxTag) def __handleRosterQuery(self, iqID, jid, context): self.__tasks.setIQ(iqID, jid, context) def __handleRosterResult(self, generator): g_logOutput.debug(CLIENT_LOG_AREA.ROSTER, 'Roster result is received') self.__seq.sync(0, generator()) def __handleRosterItemSet(self, jid, name, groups, to, from_): g_logOutput.debug(CLIENT_LOG_AREA.ROSTER, 'Roster push is received', jid, name, groups, to, from_) self.__tasks.sync(jid, name, groups, to, from_, defaultTask=roster_tasks.SyncSubscriptionTask) def __handleRosterItemRemoved(self, jid): self.__tasks.sync(jid) def __handleRosterResourceAdded(self, jid, resource): dbID = jid.getDatabaseID() user = self.usersStorage.getUser(dbID, PROTO_TYPE.XMPP) if not user: user = entities.XMPPUserEntity(dbID) self.usersStorage.setUser(user) if not user.isCurrentPlayer(): user.update(jid=jid, resource=resource) g_logOutput.debug(CLIENT_LOG_AREA.RESOURCE, 'Resource is set', user.getName(), jid.getResource(), resource) g_messengerEvents.users.onUserStatusUpdated(user) def __handleRosterResourceRemoved(self, jid): user = self.usersStorage.getUser(jid.getDatabaseID(), PROTO_TYPE.XMPP) if user and not user.isCurrentPlayer(): user.update(jid=jid, resource=None) g_logOutput.debug(CLIENT_LOG_AREA.RESOURCE, 'Resource is removed', jid.getResource(), user.getName()) g_messengerEvents.users.onUserStatusUpdated(user) return def __handleSubscriptionRequest(self, jid, name, _): self.__addTasks(USER_ACTION_ID.SUBSCRIPTION_CHANGED, jid, sub_tasks.InboundSubscriptionTask(jid, name)) def __handlePresenceWithIGR(self, jid, resource): dbID = jid.getDatabaseID() user = self.usersStorage.getUser(dbID, PROTO_TYPE.XMPP) if user and user.isCurrentPlayer(): return if not user: user = entities.XMPPUserEntity(dbID) self.usersStorage.setUser(user) user.update(jid=jid, resource=resource) g_logOutput.debug(CLIENT_LOG_AREA.RESOURCE, 'Resource with IGR is set', user.getName(), jid.getResource(), resource) g_messengerEvents.users.onUserActionReceived(USER_ACTION_ID.IGR_CHANGED, user) def __onSeqsInited(self): self.__presence.sendPresence(True) self.__tasks.release() g_messengerEvents.users.onUsersListReceived({USER_TAG.FRIEND, USER_TAG.IGNORED, USER_TAG.MUTED}) def __me_onPluginConnectFailed(self, protoType, _, tries): if protoType != PROTO_TYPE.XMPP or tries != _MAX_CONNECTION_FAILED_COUNT: return g_messengerEvents.users.onUsersListReceived({USER_TAG.CACHED, USER_TAG.FRIEND, USER_TAG.IGNORED, USER_TAG.MUTED}) def __us_onRestoredFromCache(self, stateGenerator): if not g_settings.server.XMPP.isEnabled(): return if stateGenerator and not self.__seq.isInited(): setUser = self.usersStorage.setUser for dbID, state in stateGenerator(PROTO_TYPE.XMPP): contact = entities.XMPPUserEntity(dbID) if contact.setPersistentState(state): setUser(contact) g_messengerEvents.users.onUsersListReceived({USER_TAG.CACHED, USER_TAG.FRIEND, USER_TAG.IGNORED, USER_TAG.MUTED})