Integrate roster with BaseXMPP.
Last sent stanzas are saved regardless of if the roster is used directly or self.send_presence
This commit is contained in:
parent
251a47db8c
commit
29d775e675
5 changed files with 177 additions and 35 deletions
|
@ -426,7 +426,7 @@ class BaseXMPP(XMLStream):
|
|||
msubject -- Optional subject for the message.
|
||||
mtype -- The message's type, such as 'chat' or 'groupchat'.
|
||||
mhtml -- Optional HTML body content.
|
||||
mfrom -- The sender of the message. If sending from a client,
|
||||
mfrom -- The sender of the message. if sending from a client,
|
||||
be aware that some servers require that the full JID
|
||||
of the sender be used.
|
||||
mnick -- Optional nickname of the sender.
|
||||
|
@ -441,7 +441,7 @@ class BaseXMPP(XMLStream):
|
|||
return message
|
||||
|
||||
def make_presence(self, pshow=None, pstatus=None, ppriority=None,
|
||||
pto=None, ptype=None, pfrom=None):
|
||||
pto=None, ptype=None, pfrom=None, pnick=None):
|
||||
"""
|
||||
Create and initialize a new Presence stanza.
|
||||
|
||||
|
@ -452,14 +452,16 @@ class BaseXMPP(XMLStream):
|
|||
pto -- The recipient of a directed presence.
|
||||
ptype -- The type of presence, such as 'subscribe'.
|
||||
pfrom -- The sender of the presence.
|
||||
pnick -- Optional nickname of the presence's sender.
|
||||
"""
|
||||
presence = self.Presence(stype=ptype, sfrom=pfrom, sto=pto)
|
||||
if pshow is not None:
|
||||
presence['type'] = pshow
|
||||
if pfrom is None:
|
||||
if pfrom is None and self.is_component:
|
||||
presence['from'] = self.boundjid.full
|
||||
presence['priority'] = ppriority
|
||||
presence['status'] = pstatus
|
||||
presence['nick'] = pnick
|
||||
return presence
|
||||
|
||||
def send_message(self, mto, mbody, msubject=None, mtype=None,
|
||||
|
@ -467,13 +469,22 @@ class BaseXMPP(XMLStream):
|
|||
"""
|
||||
Create, initialize, and send a Message stanza.
|
||||
|
||||
|
||||
Arguments:
|
||||
mto -- The recipient of the message.
|
||||
mbody -- The main contents of the message.
|
||||
msubject -- Optional subject for the message.
|
||||
mtype -- The message's type, such as 'chat' or 'groupchat'.
|
||||
mhtml -- Optional HTML body content.
|
||||
mfrom -- The sender of the message. if sending from a client,
|
||||
be aware that some servers require that the full JID
|
||||
of the sender be used.
|
||||
mnick -- Optional nickname of the sender.
|
||||
"""
|
||||
self.makeMessage(mto, mbody, msubject, mtype,
|
||||
mhtml, mfrom, mnick).send()
|
||||
self.make_message(mto, mbody, msubject, mtype,
|
||||
mhtml, mfrom, mnick).send()
|
||||
|
||||
def send_presence(self, pshow=None, pstatus=None, ppriority=None,
|
||||
pto=None, pfrom=None, ptype=None):
|
||||
pto=None, pfrom=None, ptype=None, pnick=None):
|
||||
"""
|
||||
Create, initialize, and send a Presence stanza.
|
||||
|
||||
|
@ -484,13 +495,20 @@ class BaseXMPP(XMLStream):
|
|||
pto -- The recipient of a directed presence.
|
||||
ptype -- The type of presence, such as 'subscribe'.
|
||||
pfrom -- The sender of the presence.
|
||||
pnick -- Optional nickname of the presence's sender.
|
||||
"""
|
||||
self.makePresence(pshow, pstatus, ppriority, pto,
|
||||
ptype=ptype, pfrom=pfrom).send()
|
||||
# Unexpected errors may occur if
|
||||
if not self.sentpresence:
|
||||
self.event('sent_presence')
|
||||
self.sentpresence = True
|
||||
# Python2.6 chokes on Unicode strings for dict keys.
|
||||
args = {str('pto'): pto,
|
||||
str('ptype'): ptype,
|
||||
str('pshow'): pshow,
|
||||
str('pstatus'): pstatus,
|
||||
str('ppriority'): ppriority,
|
||||
str('pnick'): pnick}
|
||||
|
||||
if self.is_component:
|
||||
self.roster[pfrom].send_presence(**args)
|
||||
else:
|
||||
self.client_roster.send_presence(**args)
|
||||
|
||||
def send_presence_subscription(self, pto, pfrom=None,
|
||||
ptype='subscribe', pnick=None):
|
||||
|
|
|
@ -105,23 +105,25 @@ class RosterItem(object):
|
|||
"""
|
||||
|
||||
def __init__(self, xmpp, jid, owner=None,
|
||||
state=None, db=None):
|
||||
state=None, db=None, roster=None):
|
||||
"""
|
||||
Create a new roster item.
|
||||
|
||||
Arguments:
|
||||
xmpp -- The main SleekXMPP instance.
|
||||
jid -- The item's JID.
|
||||
owner -- The roster owner's JID. Defaults
|
||||
so self.xmpp.boundjid.bare.
|
||||
state -- A dictionary of initial state values.
|
||||
db -- An optional interface to an external datastore.
|
||||
xmpp -- The main SleekXMPP instance.
|
||||
jid -- The item's JID.
|
||||
owner -- The roster owner's JID. Defaults
|
||||
so self.xmpp.boundjid.bare.
|
||||
state -- A dictionary of initial state values.
|
||||
db -- An optional interface to an external datastore.
|
||||
roster -- The roster object containing this entry.
|
||||
"""
|
||||
self.xmpp = xmpp
|
||||
self.jid = jid
|
||||
self.owner = owner or self.xmpp.boundjid.bare
|
||||
self.last_status = None
|
||||
self.resources = {}
|
||||
self.roster = roster
|
||||
self.db = db
|
||||
self._state = state or {
|
||||
'from': False,
|
||||
|
@ -290,19 +292,46 @@ class RosterItem(object):
|
|||
p['from'] = self.owner
|
||||
p.send()
|
||||
|
||||
def send_presence(self, ptype='available', status=None):
|
||||
p = self.xmpp.Presence()
|
||||
p['to'] = self.jid
|
||||
p['type'] = ptype
|
||||
p['status'] = status
|
||||
def send_presence(self, ptype=None, pshow=None, pstatus=None,
|
||||
ppriority=None, pnick=None):
|
||||
"""
|
||||
Create, initialize, and send a Presence stanza.
|
||||
|
||||
Arguments:
|
||||
pshow -- The presence's show value.
|
||||
pstatus -- The presence's status message.
|
||||
ppriority -- This connections' priority.
|
||||
ptype -- The type of presence, such as 'subscribe'.
|
||||
pnick -- Optional nickname of the presence's sender.
|
||||
"""
|
||||
p = self.xmpp.make_presence(pshow=pshow,
|
||||
pstatus=pstatus,
|
||||
ppriority=ppriority,
|
||||
ptype=ptype,
|
||||
pnick=pnick,
|
||||
pto=self.jid)
|
||||
if self.xmpp.is_component:
|
||||
p['from'] = self.owner
|
||||
self.last_status = p
|
||||
if p['type'] in p.showtypes or p['type'] == 'available':
|
||||
self.last_status = p
|
||||
p.send()
|
||||
|
||||
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()
|
||||
pres = self.roster.last_status
|
||||
if pres is None:
|
||||
self.send_presence()
|
||||
else:
|
||||
pres['to'] = self.jid
|
||||
if self.xmpp.is_component:
|
||||
pres['from'] = self.owner
|
||||
else:
|
||||
del pres['from']
|
||||
pres.send()
|
||||
else:
|
||||
self.last_status.send()
|
||||
|
||||
|
|
|
@ -34,7 +34,8 @@ class Roster(object):
|
|||
Defaults to True.
|
||||
|
||||
Methods:
|
||||
add -- Create a new roster node for a JID.
|
||||
add -- Create a new roster node for a JID.
|
||||
send_presence -- Shortcut for sending a presence stanza.
|
||||
"""
|
||||
|
||||
def __init__(self, xmpp, db=None):
|
||||
|
@ -113,3 +114,27 @@ class Roster(object):
|
|||
"""
|
||||
for node in self:
|
||||
self[node].reset()
|
||||
|
||||
def send_presence(self, pshow=None, pstatus=None, ppriority=None,
|
||||
pto=None, pfrom=None, ptype=None, pnick=None):
|
||||
"""
|
||||
Create, initialize, and send a Presence stanza.
|
||||
|
||||
Forwards the send request to the appropriate roster to
|
||||
perform the actual sending.
|
||||
|
||||
Arguments:
|
||||
pshow -- The presence's show value.
|
||||
pstatus -- The presence's status message.
|
||||
ppriority -- This connections' priority.
|
||||
pto -- The recipient of a directed presence.
|
||||
ptype -- The type of presence, such as 'subscribe'.
|
||||
pfrom -- The sender of the presence.
|
||||
pnick -- Optional nickname of the presence's sender.
|
||||
"""
|
||||
self[pfrom].send_presence(ptype=ptype,
|
||||
pshow=pshow,
|
||||
pstatus=pstatus,
|
||||
ppriority=ppriority,
|
||||
pnick=pnick,
|
||||
pto=pto)
|
||||
|
|
|
@ -29,14 +29,17 @@ class RosterNode(object):
|
|||
are created after automatically authrorizing
|
||||
a subscription request.
|
||||
Defaults to True
|
||||
last_status -- The last sent presence status that was broadcast
|
||||
to all contact JIDs.
|
||||
|
||||
Methods:
|
||||
add -- Add a JID to the roster.
|
||||
update -- Update a JID's subscription information.
|
||||
subscribe -- Subscribe to a JID.
|
||||
unsubscribe -- Unsubscribe from a JID.
|
||||
remove -- Remove a JID from the roster.
|
||||
presence -- Return presence information for a JID's resources.
|
||||
add -- Add a JID to the roster.
|
||||
update -- Update a JID's subscription information.
|
||||
subscribe -- Subscribe to a JID.
|
||||
unsubscribe -- Unsubscribe from a JID.
|
||||
remove -- Remove a JID from the roster.
|
||||
presence -- Return presence information for a JID's resources.
|
||||
send_presence -- Shortcut for sending a presence stanza.
|
||||
"""
|
||||
|
||||
def __init__(self, xmpp, jid, db=None):
|
||||
|
@ -53,6 +56,7 @@ class RosterNode(object):
|
|||
self.db = db
|
||||
self.auto_authorize = True
|
||||
self.auto_subscribe = True
|
||||
self.last_status = None
|
||||
self._jids = {}
|
||||
|
||||
if self.db:
|
||||
|
@ -135,7 +139,8 @@ class RosterNode(object):
|
|||
'whitelisted': whitelisted,
|
||||
'subscription': 'none'}
|
||||
self._jids[jid] = RosterItem(self.xmpp, jid, self.jid,
|
||||
state=state, db=self.db)
|
||||
state=state, db=self.db,
|
||||
roster=self)
|
||||
if save:
|
||||
self._jids[jid].save()
|
||||
|
||||
|
@ -220,3 +225,38 @@ class RosterNode(object):
|
|||
"""
|
||||
for jid in self:
|
||||
self[jid].reset()
|
||||
|
||||
def send_presence(self, ptype=None, pshow=None, pstatus=None,
|
||||
ppriority=None, pnick=None, pto=None):
|
||||
"""
|
||||
Create, initialize, and send a Presence stanza.
|
||||
|
||||
If no recipient is specified, send the presence immediately.
|
||||
Otherwise, forward the send request to the recipient's roster
|
||||
entry for processing.
|
||||
|
||||
Arguments:
|
||||
pshow -- The presence's show value.
|
||||
pstatus -- The presence's status message.
|
||||
ppriority -- This connections' priority.
|
||||
pto -- The recipient of a directed presence.
|
||||
ptype -- The type of presence, such as 'subscribe'.
|
||||
"""
|
||||
if pto:
|
||||
self[pto].send_presence(ptype, pshow, pstatus,
|
||||
ppriority, pnick)
|
||||
else:
|
||||
p = self.xmpp.make_presence(pshow=pshow,
|
||||
pstatus=pstatus,
|
||||
ppriority=ppriority,
|
||||
ptype=ptype,
|
||||
pnick=pnick)
|
||||
if self.xmpp.is_component:
|
||||
p['from'] = self.jid
|
||||
if p['type'] in p.showtypes or p['type'] == 'available':
|
||||
self.last_status = p
|
||||
p.send()
|
||||
|
||||
if not self.xmpp.sentpresence:
|
||||
self.xmpp.event('sent_presence')
|
||||
self.xmpp.sentpresence = True
|
||||
|
|
|
@ -203,5 +203,35 @@ class TestStreamRoster(SleekTest):
|
|||
self.failUnless(result == expected,
|
||||
"Unexpected roster values: %s" % result)
|
||||
|
||||
def testSendLastPresence(self):
|
||||
"""Test that sending the last presence works."""
|
||||
self.stream_start()
|
||||
self.xmpp.send_presence(pshow='dnd')
|
||||
self.xmpp.auto_authorize = True
|
||||
self.xmpp.auto_subscribe = True
|
||||
|
||||
self.send("""
|
||||
<presence>
|
||||
<show>dnd</show>
|
||||
</presence>
|
||||
""")
|
||||
|
||||
self.recv("""
|
||||
<presence from="user@localhost"
|
||||
to="tester@localhost"
|
||||
type="subscribe" />
|
||||
""")
|
||||
|
||||
self.send("""
|
||||
<presence to="user@localhost"
|
||||
type="subscribed" />
|
||||
""")
|
||||
|
||||
self.send("""
|
||||
<presence to="user@localhost">
|
||||
<show>dnd</show>
|
||||
</presence>
|
||||
""")
|
||||
|
||||
|
||||
suite = unittest.TestLoader().loadTestsFromTestCase(TestStreamRoster)
|
||||
|
|
Loading…
Reference in a new issue