2011-09-06 00:45:53 +00:00
|
|
|
# Copyright 2010-2011 Florent Le Coz <louiz@louiz.org>
|
2010-09-16 17:57:27 +00:00
|
|
|
#
|
|
|
|
# This file is part of Poezio.
|
|
|
|
#
|
|
|
|
# Poezio is free software: you can redistribute it and/or modify
|
2011-09-11 15:10:05 +00:00
|
|
|
# it under the terms of the zlib license. See the COPYING file.
|
2010-09-16 17:57:27 +00:00
|
|
|
|
2010-10-27 22:49:52 +00:00
|
|
|
|
|
|
|
"""
|
|
|
|
Defines the Roster and RosterGroup classes
|
|
|
|
"""
|
2010-11-10 21:15:08 +00:00
|
|
|
import logging
|
|
|
|
log = logging.getLogger(__name__)
|
2010-10-27 22:49:52 +00:00
|
|
|
|
|
|
|
from config import config
|
2011-05-24 18:33:37 +00:00
|
|
|
from os import path as p
|
2010-10-17 17:27:07 +00:00
|
|
|
from contact import Contact, Resource
|
2010-11-10 21:15:08 +00:00
|
|
|
from sleekxmpp.xmlstream.stanzabase import JID
|
2010-09-26 18:01:38 +00:00
|
|
|
|
2010-09-16 17:57:27 +00:00
|
|
|
class Roster(object):
|
2010-09-26 18:01:38 +00:00
|
|
|
def __init__(self):
|
2010-10-31 18:57:48 +00:00
|
|
|
self._contact_filter = None # A tuple(function, *args)
|
|
|
|
# function to filter contacts,
|
|
|
|
# on search, for example
|
2010-10-17 17:27:07 +00:00
|
|
|
self._contacts = {} # key = bare jid; value = Contact()
|
2010-09-26 18:01:38 +00:00
|
|
|
self._roster_groups = []
|
|
|
|
|
2011-05-24 18:33:37 +00:00
|
|
|
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
|
|
|
|
|
2011-06-18 10:52:58 +00:00
|
|
|
def empty(self):
|
|
|
|
self._contacts = {}
|
|
|
|
self._roster_groups = []
|
|
|
|
|
2010-09-26 18:01:38 +00:00
|
|
|
def add_contact(self, contact, jid):
|
|
|
|
"""
|
|
|
|
Add a contact to the contact list
|
|
|
|
"""
|
|
|
|
self._contacts[jid] = contact
|
|
|
|
|
2011-01-11 05:43:31 +00:00
|
|
|
def remove_contact(self, jid):
|
|
|
|
"""
|
|
|
|
Remove a contact from the contact list
|
|
|
|
"""
|
|
|
|
contact = self.get_contact_by_jid(jid)
|
|
|
|
for group in contact._groups:
|
2011-01-12 05:49:33 +00:00
|
|
|
self.remove_contact_from_group(group, contact)
|
2011-01-11 05:43:31 +00:00
|
|
|
del self._contacts[jid]
|
|
|
|
|
2010-09-26 18:01:38 +00:00
|
|
|
def get_contact_len(self):
|
2010-10-27 22:49:52 +00:00
|
|
|
"""
|
|
|
|
Return the number of contacts in this group
|
|
|
|
"""
|
2010-09-26 18:01:38 +00:00
|
|
|
return len(self._contacts.keys())
|
|
|
|
|
|
|
|
def get_contact_by_jid(self, jid):
|
2010-10-27 22:49:52 +00:00
|
|
|
"""
|
|
|
|
Returns the contact with the given bare JID
|
|
|
|
"""
|
2010-11-10 21:15:08 +00:00
|
|
|
# Use only the bare jid
|
|
|
|
jid = JID(jid)
|
|
|
|
if jid.bare in self._contacts:
|
|
|
|
return self._contacts[jid.bare]
|
2010-09-26 18:01:38 +00:00
|
|
|
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
|
2010-10-27 22:49:52 +00:00
|
|
|
# If the contact hasn't any group, we put her in
|
|
|
|
# the virtual default 'none' group
|
2010-11-10 21:15:08 +00:00
|
|
|
if not len(groups):
|
2010-09-26 18:35:22 +00:00
|
|
|
groups = ['none']
|
2010-09-26 18:01:38 +00:00
|
|
|
for group in groups:
|
2010-10-27 22:49:52 +00:00
|
|
|
if group not in contact._groups:
|
2010-09-26 18:01:38 +00:00
|
|
|
# create the group if it doesn't exist yet
|
|
|
|
contact._groups.append(group)
|
2010-10-27 22:49:52 +00:00
|
|
|
self.add_contact_to_group(group, contact)
|
2010-09-26 18:01:38 +00:00
|
|
|
# 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
|
2011-10-01 12:26:19 +00:00
|
|
|
contact._groups.remove(group)
|
2010-09-26 18:01:38 +00:00
|
|
|
self.remove_contact_from_group(group, contact)
|
|
|
|
|
|
|
|
def remove_contact_from_group(self, group_name, contact):
|
|
|
|
"""
|
|
|
|
Remove the contact from the group.
|
2010-10-27 22:49:52 +00:00
|
|
|
Delete the group if this makes it empty
|
2010-09-26 18:01:38 +00:00
|
|
|
"""
|
|
|
|
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:
|
2010-10-27 22:49:52 +00:00
|
|
|
if not group.has_contact(contact):
|
|
|
|
group.add_contact(contact)
|
2010-09-26 18:01:38 +00:00
|
|
|
return
|
2010-12-17 14:36:14 +00:00
|
|
|
folded_groups = config.get('folded_roster_groups', '', section='var').split(':')
|
|
|
|
new_group = RosterGroup(group_name, folded=group_name in folded_groups)
|
2010-09-26 18:01:38 +00:00
|
|
|
self._roster_groups.append(new_group)
|
|
|
|
new_group.add_contact(contact)
|
|
|
|
|
|
|
|
def get_groups(self):
|
2010-10-27 22:49:52 +00:00
|
|
|
"""
|
|
|
|
Returns the list of groups
|
|
|
|
"""
|
2010-09-26 18:01:38 +00:00
|
|
|
return self._roster_groups
|
|
|
|
|
2011-01-11 05:43:31 +00:00
|
|
|
def get_contacts(self):
|
|
|
|
"""
|
|
|
|
Return a list of all the contact
|
|
|
|
"""
|
|
|
|
return [contact for contact in self._contacts.values()]
|
|
|
|
|
2010-12-17 14:36:14 +00:00
|
|
|
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')
|
|
|
|
|
2011-02-01 23:51:34 +00:00
|
|
|
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
|
|
|
|
|
2010-09-26 18:01:38 +00:00
|
|
|
def __len__(self):
|
|
|
|
"""
|
|
|
|
Return the number of line that would be printed
|
2010-10-27 22:49:52 +00:00
|
|
|
for the whole roster
|
2010-09-26 18:01:38 +00:00
|
|
|
"""
|
2010-10-27 22:49:52 +00:00
|
|
|
length = 0
|
2011-03-10 03:57:26 +00:00
|
|
|
show_offline = config.get('roster_show_offline', 'false') == 'true'
|
2010-09-26 18:01:38 +00:00
|
|
|
for group in self._roster_groups:
|
2011-03-10 03:57:26 +00:00
|
|
|
if not show_offline and group.get_nb_connected_contacts() == 0:
|
2010-10-27 22:49:52 +00:00
|
|
|
continue
|
|
|
|
length += 1 # One for the group's line itself
|
2010-09-26 18:01:38 +00:00
|
|
|
if not group.folded:
|
2010-10-31 18:57:48 +00:00
|
|
|
for contact in group.get_contacts(self._contact_filter):
|
2010-10-27 22:49:52 +00:00
|
|
|
# We do not count the offline contacts (depending on config)
|
2011-03-10 03:57:26 +00:00
|
|
|
if not show_offline and\
|
2010-10-27 22:49:52 +00:00
|
|
|
contact.get_nb_resources() == 0:
|
|
|
|
continue
|
|
|
|
length += 1 # One for the contact's line
|
2010-10-17 17:27:07 +00:00
|
|
|
if not contact._folded:
|
2010-10-27 22:49:52 +00:00
|
|
|
# One for each resource, if the contact is unfolded
|
|
|
|
length += contact.get_nb_resources()
|
|
|
|
return length
|
2010-09-26 18:01:38 +00:00
|
|
|
|
|
|
|
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'
|
|
|
|
|
2010-10-27 22:49:52 +00:00
|
|
|
PRESENCE_PRIORITY = {'unavailable': 0,
|
|
|
|
'xa': 1,
|
|
|
|
'away': 2,
|
|
|
|
'dnd': 3,
|
|
|
|
'': 4,
|
|
|
|
'available': 4}
|
|
|
|
|
2010-09-26 18:01:38 +00:00
|
|
|
class RosterGroup(object):
|
2010-09-16 17:57:27 +00:00
|
|
|
"""
|
2010-09-26 18:01:38 +00:00
|
|
|
A RosterGroup is a group containing contacts
|
|
|
|
It can be Friends/Family etc, but also can be
|
|
|
|
Online/Offline or whatever
|
2010-09-16 17:57:27 +00:00
|
|
|
"""
|
2010-09-26 18:01:38 +00:00
|
|
|
def __init__(self, name, folded=False):
|
|
|
|
self._contacts = []
|
|
|
|
self.name = name
|
|
|
|
self.folded = folded # if the group content is to be shown
|
2010-10-17 17:27:07 +00:00
|
|
|
|
2010-09-26 18:01:38 +00:00
|
|
|
def is_empty(self):
|
|
|
|
return len(self._contacts) == 0
|
2010-09-16 17:57:27 +00:00
|
|
|
|
2010-10-27 22:49:52 +00:00
|
|
|
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
|
|
|
|
|
2010-09-26 18:01:38 +00:00
|
|
|
def remove_contact(self, contact):
|
|
|
|
"""
|
2010-12-18 18:54:55 +00:00
|
|
|
Remove a Contact object from the list
|
2010-09-26 18:01:38 +00:00
|
|
|
"""
|
2011-01-12 06:50:12 +00:00
|
|
|
try:
|
|
|
|
self._contacts.remove(contact)
|
|
|
|
except ValueError:
|
|
|
|
pass
|
2010-09-16 17:57:27 +00:00
|
|
|
|
2010-09-26 18:01:38 +00:00
|
|
|
def add_contact(self, contact):
|
2010-09-16 17:57:27 +00:00
|
|
|
"""
|
2010-09-26 18:01:38 +00:00
|
|
|
append a Contact object to the list
|
2010-09-16 17:57:27 +00:00
|
|
|
"""
|
2010-09-26 18:01:38 +00:00
|
|
|
assert isinstance(contact, Contact)
|
|
|
|
assert contact not in self._contacts
|
|
|
|
self._contacts.append(contact)
|
2010-09-16 17:57:27 +00:00
|
|
|
|
2010-10-31 18:57:48 +00:00
|
|
|
def get_contacts(self, contact_filter):
|
2010-10-27 22:49:52 +00:00
|
|
|
def compare_contact(a):
|
|
|
|
if not a.get_highest_priority_resource():
|
|
|
|
return 0
|
|
|
|
show = a.get_highest_priority_resource().get_presence()
|
|
|
|
if show not in PRESENCE_PRIORITY:
|
|
|
|
return 5
|
|
|
|
return PRESENCE_PRIORITY[show]
|
2010-10-31 18:57:48 +00:00
|
|
|
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)
|
2010-10-27 22:49:52 +00:00
|
|
|
|
|
|
|
def toggle_folded(self):
|
|
|
|
self.folded = not self.folded
|
2010-09-16 17:57:27 +00:00
|
|
|
|
2010-09-26 18:01:38 +00:00
|
|
|
def __repr__(self):
|
|
|
|
return '<Roster_group: %s; %s>' % (self.name, self._contacts)
|
2010-10-17 17:27:07 +00:00
|
|
|
|
2010-10-27 22:49:52 +00:00
|
|
|
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
|
2010-10-31 18:57:48 +00:00
|
|
|
|
|
|
|
roster = Roster()
|