# Copyright 2010-2011 Florent Le Coz <louiz@louiz.org> # # This file is part of Poezio. # # Poezio is free software: you can redistribute it and/or modify # it under the terms of the zlib license. See the COPYING file. """ Defines the Roster and RosterGroup classes """ import logging log = logging.getLogger(__name__) from config import config from os import path as p from contact import Contact from sleekxmpp.xmlstream.stanzabase import JID class Roster(object): def __init__(self): self._contact_filter = None # A tuple(function, *args) # function to filter contacts, # on search, for example self._contacts = {} # key = bare jid; value = Contact() self._roster_groups = [] def export(self, path): if p.isfile(path): return try: f = open(path, 'w+') f.writelines([i + "\n" for i in self._contacts]) f.close() return True except IOError: return def empty(self): self._contacts = {} self._roster_groups = [] def add_contact(self, contact, jid): """ Add a contact to the contact list """ self._contacts[jid] = contact def remove_contact(self, jid): """ Remove a contact from the contact list """ contact = self.get_contact_by_jid(jid) for group in contact._groups: self.remove_contact_from_group(group, contact) del self._contacts[jid] def get_contact_len(self): """ Return the number of contacts in this group """ return len(self._contacts.keys()) def get_contact_by_jid(self, jid): """ Returns the contact with the given bare JID """ # Use only the bare jid jid = JID(jid) if jid.bare in self._contacts: return self._contacts[jid.bare] return None def edit_groups_of_contact(self, contact, groups): """ Edit the groups the contact is in Add or remove RosterGroup if needed """ # add the contact to each group he is in # If the contact hasn't any group, we put her in # the virtual default 'none' group if not len(groups): groups = ['none'] for group in groups: if group not in contact._groups: # create the group if it doesn't exist yet contact._groups.append(group) self.add_contact_to_group(group, contact) # remove the contact from each group he is not in for group in contact._groups: if group not in groups: # the contact is not in the group anymore contact._groups.remove(group) self.remove_contact_from_group(group, contact) def remove_contact_from_group(self, group_name, contact): """ Remove the contact from the group. Delete the group if this makes it empty """ for group in self._roster_groups: if group.name == group_name: group.remove_contact(contact) if group.is_empty(): self._roster_groups.remove(group) return def add_contact_to_group(self, group_name, contact): """ Add the contact to the group. Create the group if it doesn't already exist """ for group in self._roster_groups: if group.name == group_name: if not group.has_contact(contact): group.add_contact(contact) return folded_groups = config.get('folded_roster_groups', '', section='var').split(':') new_group = RosterGroup(group_name, folded=group_name in folded_groups) self._roster_groups.append(new_group) new_group.add_contact(contact) def get_groups(self): """ Returns the list of groups """ return self._roster_groups def get_contacts(self): """ Return a list of all the contact """ return [contact for contact in self._contacts.values()] def save_to_config_file(self): """ Save various information to the config file e.g. the folded groups """ folded_groups = ':'.join([group.name for group in self._roster_groups\ if group.folded]) log.debug('folded:%s\n' %folded_groups) config.set_and_save('folded_roster_groups', folded_groups, 'var') def get_nb_connected_contacts(self): """ Return the number of contacts connected """ length = 0 for group in self._roster_groups: length += group.get_nb_connected_contacts() return length def __len__(self): """ Return the number of line that would be printed for the whole roster """ length = 0 show_offline = config.get('roster_show_offline', 'false') == 'true' for group in self._roster_groups: if not show_offline and group.get_nb_connected_contacts() == 0: continue length += 1 # One for the group's line itself if not group.folded: for contact in group.get_contacts(self._contact_filter): # We do not count the offline contacts (depending on config) if not show_offline and\ contact.get_nb_resources() == 0: continue length += 1 # One for the contact's line if not contact._folded: # One for each resource, if the contact is unfolded length += contact.get_nb_resources() return length def __repr__(self): ret = '== Roster:\nContacts:\n' for contact in self._contacts: ret += '%s\n' % (contact,) ret += 'Groups\n' for group in self._roster_groups: ret += '%s\n' % (group,) return ret + '\n' PRESENCE_PRIORITY = {'unavailable': 0, 'xa': 1, 'away': 2, 'dnd': 3, '': 4, 'available': 4} class RosterGroup(object): """ A RosterGroup is a group containing contacts It can be Friends/Family etc, but also can be Online/Offline or whatever """ def __init__(self, name, folded=False): self._contacts = [] self.name = name self.folded = folded # if the group content is to be shown def is_empty(self): return len(self._contacts) == 0 def has_contact(self, contact): """ Return a bool, telling if the contact is already in the group """ if contact in self._contacts: return True return False def remove_contact(self, contact): """ Remove a Contact object from the list """ try: self._contacts.remove(contact) except ValueError: pass def add_contact(self, contact): """ append a Contact object to the list """ assert isinstance(contact, Contact) assert contact not in self._contacts self._contacts.append(contact) def get_contacts(self, contact_filter): def compare_contact(a): if not a.get_highest_priority_resource(): return 0 show = a.get_highest_priority_resource() if show not in PRESENCE_PRIORITY: return 5 return PRESENCE_PRIORITY[show] contact_list = self._contacts if not contact_filter\ else [contact for contact in self._contacts if contact_filter[0](contact, contact_filter[1])] return sorted(contact_list, key=compare_contact, reverse=True) def toggle_folded(self): self.folded = not self.folded def __repr__(self): return '<Roster_group: %s; %s>' % (self.name, self._contacts) def __len__(self): return len(self._contacts) def get_nb_connected_contacts(self): l = 0 for contact in self._contacts: if contact.get_highest_priority_resource(): l += 1 return l roster = Roster()