summaryrefslogtreecommitdiff
path: root/sleekxmpp/roster
diff options
context:
space:
mode:
Diffstat (limited to 'sleekxmpp/roster')
-rw-r--r--sleekxmpp/roster/item.py23
-rw-r--r--sleekxmpp/roster/multi.py19
-rw-r--r--sleekxmpp/roster/single.py62
3 files changed, 90 insertions, 14 deletions
diff --git a/sleekxmpp/roster/item.py b/sleekxmpp/roster/item.py
index 6f956b31..9cb278a4 100644
--- a/sleekxmpp/roster/item.py
+++ b/sleekxmpp/roster/item.py
@@ -134,17 +134,22 @@ class RosterItem(object):
'subscription': 'none',
'name': '',
'groups': []}
+
self._db_state = {}
self.load()
- def set_backend(self, db=None):
+ def set_backend(self, db=None, save=True):
"""
Set the datastore interface object for the roster item.
Arguments:
- db -- The new datastore interface.
+ db -- The new datastore interface.
+ save -- If True, save the existing state to the new
+ backend datastore. Defaults to True.
"""
self.db = db
+ if save:
+ self.save()
self.load()
def load(self):
@@ -167,16 +172,25 @@ class RosterItem(object):
return self._state
return None
- def save(self):
+ def save(self, remove=False):
"""
Save the item's state information to an external datastore,
if one has been provided.
+
+ Arguments:
+ remove -- If True, expunge the item from the datastore.
"""
self['subscription'] = self._subscription()
+ if remove:
+ self._state['removed'] = True
if self.db:
self.db.save(self.owner, self.jid,
self._state, self._db_state)
+ # Finally, remove the in-memory copy if needed.
+ if remove:
+ del self.xmpp.roster[self.owner][self.jid]
+
def __getitem__(self, key):
"""Return a state field's value."""
if key in self._state:
@@ -482,3 +496,6 @@ class RosterItem(object):
a roster reset request.
"""
self.resources = {}
+
+ def __repr__(self):
+ return repr(self._state)
diff --git a/sleekxmpp/roster/multi.py b/sleekxmpp/roster/multi.py
index ee56f2a8..6a60778b 100644
--- a/sleekxmpp/roster/multi.py
+++ b/sleekxmpp/roster/multi.py
@@ -9,7 +9,6 @@
from sleekxmpp.xmlstream import JID
from sleekxmpp.roster import RosterNode
-
class Roster(object):
"""
@@ -68,6 +67,8 @@ class Roster(object):
"""
if isinstance(key, JID):
key = key.bare
+ if key is None:
+ key = self.xmpp.boundjid.bare
if key not in self._rosters:
self.add(key)
self._rosters[key].auto_authorize = self.auto_authorize
@@ -94,18 +95,23 @@ class Roster(object):
if node not in self._rosters:
self._rosters[node] = RosterNode(self.xmpp, node, self.db)
- def set_backend(self, db=None):
+ def set_backend(self, db=None, save=True):
"""
Set the datastore interface object for the roster.
Arguments:
db -- The new datastore interface.
+ save -- If True, save the existing state to the new
+ backend datastore. Defaults to True.
"""
self.db = db
- for node in self.db.entries(None, {}):
+ existing_entries = set(self._rosters)
+ new_entries = set(self.db.entries(None, {}))
+
+ for node in existing_entries:
+ self._rosters[node].set_backend(db, save)
+ for node in new_entries - existing_entries:
self.add(node)
- for node in self._rosters:
- self._rosters[node].set_backend(db)
def reset(self):
"""
@@ -182,3 +188,6 @@ class Roster(object):
self._auto_subscribe = value
for node in self._rosters:
self._rosters[node].auto_subscribe = value
+
+ def __repr__(self):
+ return repr(self._rosters)
diff --git a/sleekxmpp/roster/single.py b/sleekxmpp/roster/single.py
index c2c7497d..518afebe 100644
--- a/sleekxmpp/roster/single.py
+++ b/sleekxmpp/roster/single.py
@@ -57,11 +57,28 @@ class RosterNode(object):
self.auto_authorize = True
self.auto_subscribe = True
self.last_status = None
+ self._version = ''
self._jids = {}
if self.db:
+ if hasattr(self.db, 'version'):
+ self._version = self.db.version(self.jid)
for jid in self.db.entries(self.jid):
self.add(jid)
+
+ @property
+ def version(self):
+ """Retrieve the roster's version ID."""
+ if self.db and hasattr(self.db, 'version'):
+ self._version = self.db.version(self.jid)
+ return self._version
+
+ @version.setter
+ def version(self, version):
+ """Set the roster's version ID."""
+ self._version = version
+ if self.db and hasattr(self.db, 'set_version'):
+ self.db.set_version(self.jid, version)
def __getitem__(self, key):
"""
@@ -75,6 +92,17 @@ class RosterNode(object):
self.add(key, save=True)
return self._jids[key]
+ def __delitem__(self, key):
+ """
+ Remove a roster item from the local storage.
+
+ To remove an item from the server, use the remove() method.
+ """
+ if isinstance(key, JID):
+ key = key.bare
+ if key in self._jids:
+ del self._jids[key]
+
def __len__(self):
"""Return the number of JIDs referenced by the roster."""
return len(self._jids)
@@ -101,18 +129,23 @@ class RosterNode(object):
"""Iterate over the roster items."""
return self._jids.__iter__()
- def set_backend(self, db=None):
+ def set_backend(self, db=None, save=True):
"""
Set the datastore interface object for the roster node.
Arguments:
db -- The new datastore interface.
+ save -- If True, save the existing state to the new
+ backend datastore. Defaults to True.
"""
self.db = db
- for jid in self.db.entries(self.jid):
+ existing_entries = set(self._jids)
+ new_entries = set(self.db.entries(self.jid, {}))
+
+ for jid in existing_entries:
+ self._jids[jid].set_backend(db, save)
+ for jid in new_entries - existing_entries:
self.add(jid)
- for jid in self._jids:
- self._jids[jid].set_backend(db)
def add(self, jid, name='', groups=None, afrom=False, ato=False,
pending_in=False, pending_out=False, whitelisted=False,
@@ -144,6 +177,9 @@ class RosterNode(object):
"""
if isinstance(jid, JID):
key = jid.bare
+ else:
+ key = jid
+
state = {'name': name,
'groups': groups or [],
'from': afrom,
@@ -152,11 +188,11 @@ class RosterNode(object):
'pending_out': pending_out,
'whitelisted': whitelisted,
'subscription': 'none'}
- self._jids[jid] = RosterItem(self.xmpp, jid, self.jid,
+ self._jids[key] = RosterItem(self.xmpp, jid, self.jid,
state=state, db=self.db,
roster=self)
if save:
- self._jids[jid].save()
+ self._jids[key].save()
def subscribe(self, jid):
"""
@@ -285,3 +321,17 @@ class RosterNode(object):
if not self.xmpp.sentpresence:
self.xmpp.event('sent_presence')
self.xmpp.sentpresence = True
+
+ def send_last_presence(self):
+ if self.last_status is None:
+ self.send_presence()
+ else:
+ pres = self.last_status
+ if self.xmpp.is_component:
+ pres['from'] = self.jid
+ else:
+ del pres['from']
+ pres.send()
+
+ def __repr__(self):
+ return repr(self._jids)