Added MUC invite handler to XEP-0045 plugin.

Originally contributed by damium/romeira, with some
modifications.

Also, converted tabs to spaces to prepare for future cleanup.
This commit is contained in:
Lance Stout 2010-12-16 16:18:49 -05:00
parent 67775fb8bd
commit 988a90a176

View file

@ -20,325 +20,333 @@ log = logging.getLogger(__name__)
class MUCPresence(ElementBase): class MUCPresence(ElementBase):
name = 'x' name = 'x'
namespace = 'http://jabber.org/protocol/muc#user' namespace = 'http://jabber.org/protocol/muc#user'
plugin_attrib = 'muc' plugin_attrib = 'muc'
interfaces = set(('affiliation', 'role', 'jid', 'nick', 'room')) interfaces = set(('affiliation', 'role', 'jid', 'nick', 'room'))
affiliations = set(('', )) affiliations = set(('', ))
roles = set(('', )) roles = set(('', ))
def getXMLItem(self): def getXMLItem(self):
item = self.xml.find('{http://jabber.org/protocol/muc#user}item') item = self.xml.find('{http://jabber.org/protocol/muc#user}item')
if item is None: if item is None:
item = ET.Element('{http://jabber.org/protocol/muc#user}item') item = ET.Element('{http://jabber.org/protocol/muc#user}item')
self.xml.append(item) self.xml.append(item)
return item return item
def getAffiliation(self): def getAffiliation(self):
#TODO if no affilation, set it to the default and return default #TODO if no affilation, set it to the default and return default
item = self.getXMLItem() item = self.getXMLItem()
return item.get('affiliation', '') return item.get('affiliation', '')
def setAffiliation(self, value): def setAffiliation(self, value):
item = self.getXMLItem() item = self.getXMLItem()
#TODO check for valid affiliation #TODO check for valid affiliation
item.attrib['affiliation'] = value item.attrib['affiliation'] = value
return self return self
def delAffiliation(self): def delAffiliation(self):
item = self.getXMLItem() item = self.getXMLItem()
#TODO set default affiliation #TODO set default affiliation
if 'affiliation' in item.attrib: del item.attrib['affiliation'] if 'affiliation' in item.attrib: del item.attrib['affiliation']
return self return self
def getJid(self): def getJid(self):
item = self.getXMLItem() item = self.getXMLItem()
return JID(item.get('jid', '')) return JID(item.get('jid', ''))
def setJid(self, value): def setJid(self, value):
item = self.getXMLItem() item = self.getXMLItem()
if not isinstance(value, str): if not isinstance(value, str):
value = str(value) value = str(value)
item.attrib['jid'] = value item.attrib['jid'] = value
return self return self
def delJid(self): def delJid(self):
item = self.getXMLItem() item = self.getXMLItem()
if 'jid' in item.attrib: del item.attrib['jid'] if 'jid' in item.attrib: del item.attrib['jid']
return self return self
def getRole(self): def getRole(self):
item = self.getXMLItem() item = self.getXMLItem()
#TODO get default role, set default role if none #TODO get default role, set default role if none
return item.get('role', '') return item.get('role', '')
def setRole(self, value): def setRole(self, value):
item = self.getXMLItem() item = self.getXMLItem()
#TODO check for valid role #TODO check for valid role
item.attrib['role'] = value item.attrib['role'] = value
return self return self
def delRole(self): def delRole(self):
item = self.getXMLItem() item = self.getXMLItem()
#TODO set default role #TODO set default role
if 'role' in item.attrib: del item.attrib['role'] if 'role' in item.attrib: del item.attrib['role']
return self return self
def getNick(self): def getNick(self):
return self.parent()['from'].resource return self.parent()['from'].resource
def getRoom(self): def getRoom(self):
return self.parent()['from'].bare return self.parent()['from'].bare
def setNick(self, value): def setNick(self, value):
log.warning("Cannot set nick through mucpresence plugin.") log.warning("Cannot set nick through mucpresence plugin.")
return self return self
def setRoom(self, value): def setRoom(self, value):
log.warning("Cannot set room through mucpresence plugin.") log.warning("Cannot set room through mucpresence plugin.")
return self return self
def delNick(self): def delNick(self):
log.warning("Cannot delete nick through mucpresence plugin.") log.warning("Cannot delete nick through mucpresence plugin.")
return self return self
def delRoom(self): def delRoom(self):
log.warning("Cannot delete room through mucpresence plugin.") log.warning("Cannot delete room through mucpresence plugin.")
return self return self
class xep_0045(base.base_plugin): class xep_0045(base.base_plugin):
""" """
Impliments XEP-0045 Multi User Chat Implements XEP-0045 Multi User Chat
""" """
def plugin_init(self): def plugin_init(self):
self.rooms = {} self.rooms = {}
self.ourNicks = {} self.ourNicks = {}
self.xep = '0045' self.xep = '0045'
self.description = 'Multi User Chat' self.description = 'Multi User Chat'
# load MUC support in presence stanzas # load MUC support in presence stanzas
registerStanzaPlugin(Presence, MUCPresence) registerStanzaPlugin(Presence, MUCPresence)
self.xmpp.registerHandler(Callback('MUCPresence', MatchXMLMask("<presence xmlns='%s' />" % self.xmpp.default_ns), self.handle_groupchat_presence)) self.xmpp.registerHandler(Callback('MUCPresence', MatchXMLMask("<presence xmlns='%s' />" % self.xmpp.default_ns), self.handle_groupchat_presence))
self.xmpp.registerHandler(Callback('MUCMessage', MatchXMLMask("<message xmlns='%s' type='groupchat'><body/></message>" % self.xmpp.default_ns), self.handle_groupchat_message)) self.xmpp.registerHandler(Callback('MUCMessage', MatchXMLMask("<message xmlns='%s' type='groupchat'><body/></message>" % self.xmpp.default_ns), self.handle_groupchat_message))
self.xmpp.registerHandler(Callback('MUCSubject', MatchXMLMask("<message xmlns='%s' type='groupchat'><subject/></message>" % self.xmpp.default_ns), self.handle_groupchat_subject)) self.xmpp.registerHandler(Callback('MUCSubject', MatchXMLMask("<message xmlns='%s' type='groupchat'><subject/></message>" % self.xmpp.default_ns), self.handle_groupchat_subject))
self.xmpp.registerHandler(Callback('MUCInvite', MatchXPath("{%s}message/{http://jabber.org/protocol/muc#user}x/invite" % self.xmpp.default_ns), self.handle_groupchat_invite))
def handle_groupchat_presence(self, pr): def handle_groupchat_invite(self, inv):
""" Handle a presence in a muc. """ Handle an invite into a muc.
""" """
got_offline = False logging.debug("MUC invite to %s from %s: %s" % (inv['from'], inv["from"], inv))
got_online = False if inv['from'] not in self.rooms.keys():
if pr['muc']['room'] not in self.rooms.keys(): self.xmpp.event("groupchat_invite", inv)
return
entry = pr['muc'].getStanzaValues()
entry['show'] = pr['show']
entry['status'] = pr['status']
if pr['type'] == 'unavailable':
if entry['nick'] in self.rooms[entry['room']]:
del self.rooms[entry['room']][entry['nick']]
got_offline = True
else:
if entry['nick'] not in self.rooms[entry['room']]:
got_online = True
self.rooms[entry['room']][entry['nick']] = entry
log.debug("MUC presence from %s/%s : %s" % (entry['room'],entry['nick'], entry))
self.xmpp.event("groupchat_presence", pr)
self.xmpp.event("muc::%s::presence" % entry['room'], pr)
if got_offline:
self.xmpp.event("muc::%s::got_offline" % entry['room'], pr)
if got_online:
self.xmpp.event("muc::%s::got_online" % entry['room'], pr)
def handle_groupchat_message(self, msg): def handle_groupchat_presence(self, pr):
""" Handle a message event in a muc. """ Handle a presence in a muc.
""" """
self.xmpp.event('groupchat_message', msg) got_offline = False
self.xmpp.event("muc::%s::message" % msg['from'].bare, msg) got_online = False
if pr['muc']['room'] not in self.rooms.keys():
return
entry = pr['muc'].getStanzaValues()
entry['show'] = pr['show']
entry['status'] = pr['status']
if pr['type'] == 'unavailable':
if entry['nick'] in self.rooms[entry['room']]:
del self.rooms[entry['room']][entry['nick']]
got_offline = True
else:
if entry['nick'] not in self.rooms[entry['room']]:
got_online = True
self.rooms[entry['room']][entry['nick']] = entry
log.debug("MUC presence from %s/%s : %s" % (entry['room'],entry['nick'], entry))
self.xmpp.event("groupchat_presence", pr)
self.xmpp.event("muc::%s::presence" % entry['room'], pr)
if got_offline:
self.xmpp.event("muc::%s::got_offline" % entry['room'], pr)
if got_online:
self.xmpp.event("muc::%s::got_online" % entry['room'], pr)
def handle_groupchat_subject(self, msg): def handle_groupchat_message(self, msg):
""" Handle a message coming from a muc indicating """ Handle a message event in a muc.
a change of subject (or announcing it when joining the room) """
""" self.xmpp.event('groupchat_message', msg)
self.xmpp.event('groupchat_subject', msg) self.xmpp.event("muc::%s::message" % msg['from'].bare, msg)
def jidInRoom(self, room, jid): def handle_groupchat_subject(self, msg):
for nick in self.rooms[room]: """ Handle a message coming from a muc indicating
entry = self.rooms[room][nick] a change of subject (or announcing it when joining the room)
if entry is not None and entry['jid'].full == jid: """
return True self.xmpp.event('groupchat_subject', msg)
return False
def getNick(self, room, jid): def jidInRoom(self, room, jid):
for nick in self.rooms[room]: for nick in self.rooms[room]:
entry = self.rooms[room][nick] entry = self.rooms[room][nick]
if entry is not None and entry['jid'].full == jid: if entry is not None and entry['jid'].full == jid:
return nick return True
return False
def getRoomForm(self, room, ifrom=None): def getNick(self, room, jid):
iq = self.xmpp.makeIqGet() for nick in self.rooms[room]:
iq['to'] = room entry = self.rooms[room][nick]
if ifrom is not None: if entry is not None and entry['jid'].full == jid:
iq['from'] = ifrom return nick
query = ET.Element('{http://jabber.org/protocol/muc#owner}query')
iq.append(query)
result = iq.send()
if result['type'] == 'error':
return False
xform = result.xml.find('{http://jabber.org/protocol/muc#owner}query/{jabber:x:data}x')
if xform is None: return False
form = self.xmpp.plugin['old_0004'].buildForm(xform)
return form
def configureRoom(self, room, form=None, ifrom=None): def getRoomForm(self, room, ifrom=None):
if form is None: iq = self.xmpp.makeIqGet()
form = self.getRoomForm(room, ifrom=ifrom) iq['to'] = room
#form = self.xmpp.plugin['old_0004'].makeForm(ftype='submit') if ifrom is not None:
#form.addField('FORM_TYPE', value='http://jabber.org/protocol/muc#roomconfig') iq['from'] = ifrom
iq = self.xmpp.makeIqSet() query = ET.Element('{http://jabber.org/protocol/muc#owner}query')
iq['to'] = room iq.append(query)
if ifrom is not None: result = iq.send()
iq['from'] = ifrom if result['type'] == 'error':
query = ET.Element('{http://jabber.org/protocol/muc#owner}query') return False
form = form.getXML('submit') xform = result.xml.find('{http://jabber.org/protocol/muc#owner}query/{jabber:x:data}x')
query.append(form) if xform is None: return False
iq.append(query) form = self.xmpp.plugin['old_0004'].buildForm(xform)
result = iq.send() return form
if result['type'] == 'error':
return False
return True
def joinMUC(self, room, nick, maxhistory="0", password='', wait=False, pstatus=None, pshow=None): def configureRoom(self, room, form=None, ifrom=None):
""" Join the specified room, requesting 'maxhistory' lines of history. if form is None:
""" form = self.getRoomForm(room, ifrom=ifrom)
stanza = self.xmpp.makePresence(pto="%s/%s" % (room, nick), pstatus=pstatus, pshow=pshow) #form = self.xmpp.plugin['old_0004'].makeForm(ftype='submit')
x = ET.Element('{http://jabber.org/protocol/muc}x') #form.addField('FORM_TYPE', value='http://jabber.org/protocol/muc#roomconfig')
if password: iq = self.xmpp.makeIqSet()
passelement = ET.Element('password') iq['to'] = room
passelement.text = password if ifrom is not None:
x.append(passelement) iq['from'] = ifrom
if maxhistory: query = ET.Element('{http://jabber.org/protocol/muc#owner}query')
history = ET.Element('history') form = form.getXML('submit')
if maxhistory == "0": query.append(form)
history.attrib['maxchars'] = maxhistory iq.append(query)
else: result = iq.send()
history.attrib['maxstanzas'] = maxhistory if result['type'] == 'error':
x.append(history) return False
stanza.append(x) return True
if not wait:
self.xmpp.send(stanza)
else:
#wait for our own room presence back
expect = ET.Element("{%s}presence" % self.xmpp.default_ns, {'from':"%s/%s" % (room, nick)})
self.xmpp.send(stanza, expect)
self.rooms[room] = {}
self.ourNicks[room] = nick
def destroy(self, room, reason='', altroom = '', ifrom=None): def joinMUC(self, room, nick, maxhistory="0", password='', wait=False, pstatus=None, pshow=None):
iq = self.xmpp.makeIqSet() """ Join the specified room, requesting 'maxhistory' lines of history.
if ifrom is not None: """
iq['from'] = ifrom stanza = self.xmpp.makePresence(pto="%s/%s" % (room, nick), pstatus=pstatus, pshow=pshow)
iq['to'] = room x = ET.Element('{http://jabber.org/protocol/muc}x')
query = ET.Element('{http://jabber.org/protocol/muc#owner}query') if password:
destroy = ET.Element('destroy') passelement = ET.Element('password')
if altroom: passelement.text = password
destroy.attrib['jid'] = altroom x.append(passelement)
xreason = ET.Element('reason') if maxhistory:
xreason.text = reason history = ET.Element('history')
destroy.append(xreason) if maxhistory == "0":
query.append(destroy) history.attrib['maxchars'] = maxhistory
iq.append(query) else:
r = iq.send() history.attrib['maxstanzas'] = maxhistory
if r is False or r['type'] == 'error': x.append(history)
return False stanza.append(x)
return True if not wait:
self.xmpp.send(stanza)
else:
#wait for our own room presence back
expect = ET.Element("{%s}presence" % self.xmpp.default_ns, {'from':"%s/%s" % (room, nick)})
self.xmpp.send(stanza, expect)
self.rooms[room] = {}
self.ourNicks[room] = nick
def setAffiliation(self, room, jid=None, nick=None, affiliation='member'): def destroy(self, room, reason='', altroom = '', ifrom=None):
""" Change room affiliation.""" iq = self.xmpp.makeIqSet()
if affiliation not in ('outcast', 'member', 'admin', 'owner', 'none'): if ifrom is not None:
raise TypeError iq['from'] = ifrom
query = ET.Element('{http://jabber.org/protocol/muc#admin}query') iq['to'] = room
if nick is not None: query = ET.Element('{http://jabber.org/protocol/muc#owner}query')
item = ET.Element('item', {'affiliation':affiliation, 'nick':nick}) destroy = ET.Element('destroy')
else: if altroom:
item = ET.Element('item', {'affiliation':affiliation, 'jid':jid}) destroy.attrib['jid'] = altroom
query.append(item) xreason = ET.Element('reason')
iq = self.xmpp.makeIqSet(query) xreason.text = reason
iq['to'] = room destroy.append(xreason)
result = iq.send() query.append(destroy)
if result is False or result['type'] != 'result': iq.append(query)
raise ValueError r = iq.send()
return True if r is False or r['type'] == 'error':
return False
return True
def invite(self, room, jid, reason=''): def setAffiliation(self, room, jid=None, nick=None, affiliation='member'):
""" Invite a jid to a room.""" """ Change room affiliation."""
msg = self.xmpp.makeMessage(room) if affiliation not in ('outcast', 'member', 'admin', 'owner', 'none'):
msg['from'] = self.xmpp.boundjid.bare raise TypeError
x = ET.Element('{http://jabber.org/protocol/muc#user}x') query = ET.Element('{http://jabber.org/protocol/muc#admin}query')
invite = ET.Element('{http://jabber.org/protocol/muc#user}invite', {'to': jid}) if nick is not None:
if reason: item = ET.Element('item', {'affiliation':affiliation, 'nick':nick})
rxml = ET.Element('reason') else:
rxml.text = reason item = ET.Element('item', {'affiliation':affiliation, 'jid':jid})
invite.append(rxml) query.append(item)
x.append(invite) iq = self.xmpp.makeIqSet(query)
msg.append(x) iq['to'] = room
self.xmpp.send(msg) result = iq.send()
if result is False or result['type'] != 'result':
raise ValueError
return True
def leaveMUC(self, room, nick, msg=''): def invite(self, room, jid, reason=''):
""" Leave the specified room. """ Invite a jid to a room."""
""" msg = self.xmpp.makeMessage(room)
if msg: msg['from'] = self.xmpp.boundjid.bare
self.xmpp.sendPresence(pshow='unavailable', pto="%s/%s" % (room, nick), pstatus=msg) x = ET.Element('{http://jabber.org/protocol/muc#user}x')
else: invite = ET.Element('{http://jabber.org/protocol/muc#user}invite', {'to': jid})
self.xmpp.sendPresence(pshow='unavailable', pto="%s/%s" % (room, nick)) if reason:
del self.rooms[room] rxml = ET.Element('reason')
rxml.text = reason
invite.append(rxml)
x.append(invite)
msg.append(x)
self.xmpp.send(msg)
def getRoomConfig(self, room): def leaveMUC(self, room, nick, msg=''):
iq = self.xmpp.makeIqGet('http://jabber.org/protocol/muc#owner') """ Leave the specified room.
iq['to'] = room """
iq['from'] = self.xmpp.boundjid.bare if msg:
result = iq.send() self.xmpp.sendPresence(pshow='unavailable', pto="%s/%s" % (room, nick), pstatus=msg)
if result is None or result['type'] != 'result': else:
raise ValueError self.xmpp.sendPresence(pshow='unavailable', pto="%s/%s" % (room, nick))
form = result.xml.find('{http://jabber.org/protocol/muc#owner}query/{jabber:x:data}x') del self.rooms[room]
if form is None:
raise ValueError
return self.xmpp.plugin['xep_0004'].buildForm(form)
def cancelConfig(self, room): def getRoomConfig(self, room):
query = ET.Element('{http://jabber.org/protocol/muc#owner}query') iq = self.xmpp.makeIqGet('http://jabber.org/protocol/muc#owner')
x = ET.Element('{jabber:x:data}x', type='cancel') iq['to'] = room
query.append(x) iq['from'] = self.xmpp.boundjid.bare
iq = self.xmpp.makeIqSet(query) result = iq.send()
iq.send() if result is None or result['type'] != 'result':
raise ValueError
form = result.xml.find('{http://jabber.org/protocol/muc#owner}query/{jabber:x:data}x')
if form is None:
raise ValueError
return self.xmpp.plugin['xep_0004'].buildForm(form)
def setRoomConfig(self, room, config): def cancelConfig(self, room):
query = ET.Element('{http://jabber.org/protocol/muc#owner}query') query = ET.Element('{http://jabber.org/protocol/muc#owner}query')
x = config.getXML('submit') x = ET.Element('{jabber:x:data}x', type='cancel')
query.append(x) query.append(x)
iq = self.xmpp.makeIqSet(query) iq = self.xmpp.makeIqSet(query)
iq['to'] = room iq.send()
iq['from'] = self.xmpp.boundjid.bare
iq.send()
def getJoinedRooms(self): def setRoomConfig(self, room, config):
return self.rooms.keys() query = ET.Element('{http://jabber.org/protocol/muc#owner}query')
x = config.getXML('submit')
query.append(x)
iq = self.xmpp.makeIqSet(query)
iq['to'] = room
iq['from'] = self.xmpp.boundjid.bare
iq.send()
def getOurJidInRoom(self, roomJid): def getJoinedRooms(self):
""" Return the jid we're using in a room. return self.rooms.keys()
"""
return "%s/%s" % (roomJid, self.ourNicks[roomJid])
def getJidProperty(self, room, nick, jidProperty): def getOurJidInRoom(self, roomJid):
""" Get the property of a nick in a room, such as its 'jid' or 'affiliation' """ Return the jid we're using in a room.
If not found, return None. """
""" return "%s/%s" % (roomJid, self.ourNicks[roomJid])
if room in self.rooms and nick in self.rooms[room] and jidProperty in self.rooms[room][nick]:
return self.rooms[room][nick][jidProperty]
else:
return None
def getRoster(self, room): def getJidProperty(self, room, nick, jidProperty):
""" Get the list of nicks in a room. """ Get the property of a nick in a room, such as its 'jid' or 'affiliation'
""" If not found, return None.
if room not in self.rooms.keys(): """
return None if room in self.rooms and nick in self.rooms[room] and jidProperty in self.rooms[room][nick]:
return self.rooms[room].keys() return self.rooms[room][nick][jidProperty]
else:
return None
def getRoster(self, room):
""" Get the list of nicks in a room.
"""
if room not in self.rooms.keys():
return None
return self.rooms[room].keys()