view muc.py @ 22:e2bd4de698e5

Solved an XMPP resource conflict that would have happened when someone on IRC changed its nickname and later its old nickname would be used again. In other words, the bot no longer uses nicknames as XMPP resources. Signed-off-by: Charly COSTE <changaco@changaco.net>
author Charly COSTE <changaco@changaco.net>
date Thu, 20 Aug 2009 17:49:40 +0200
parents 32a35f7eff70
children faa468731d8a
line wrap: on
line source

#!/usr/bin/env python
# -*- coding: utf-8 -*-

# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.


import xmppony as xmpp
from time import sleep


class muc:
	
	class PasswordNeeded(Exception): pass
	class MembersOnlyRoom(Exception): pass
	class BannedFromRoom(Exception): pass
	class NicknameConflict(Exception): pass
	class RoomIsFull(Exception): pass
	class RoomIsLocked(Exception): pass
	class ForgotNickname(Exception): pass
	class UnknownError(Exception): pass
	
	def __init__(self, room_jid):
		self.room_jid = room_jid
		self.connected = False
		self.participants = {}
	
	
	def join(self, xmpp_c, nickname, status=None, callback=None):
		"""Join room on xmpp_c connection using nickname"""
		self.jid = self.room_jid+'/'+nickname
		self.nickname = nickname
		self.xmpp_c = xmpp_c
		self.callback = callback
		self.xmpp_c.RegisterHandler('presence', self._xmpp_presence_handler)
		self.xmpp_c.send(xmpp.protocol.Presence(to=self.jid, status=status, payload=[xmpp.simplexml.Node(tag='x', attrs={'xmlns': 'http://jabber.org/protocol/muc'}, payload=[xmpp.simplexml.Node(tag='history', attrs={'maxchars': '0'})])]))
	
	
	def _xmpp_presence_handler(self, xmpp_c, presence):
		if presence.getFrom() == self.jid:
			errors = []
			if presence.getAttr('type') == 'error':
				for c in presence.getChildren():
					if c.getName() == 'error':
						for cc in c.getChildren():
							if cc.getNamespace() == 'urn:ietf:params:xml:ns:xmpp-stanzas' and cc.getName() != 'text':
								err = c.getAttr('type')+' '+cc.getName()
								if err == 'auth not-authorized':
									# password-protected room
									errors.append(self.__class__.PasswordNeeded())
								elif err == 'auth registration-required':
									# members-only room
									errors.append(self.__class__.MembersOnlyRoom())
								elif err == 'auth forbidden':
									# banned from room
									errors.append(self.__class__.BannedFromRoom())
								elif err == 'cancel conflict':
									# nickname conflict
									errors.append(self.__class__.NicknameConflict())
								elif err == 'wait service-unavailable':
									# room is full
									errors.append(self.__class__.RoomIsFull())
								elif err == 'cancel item-not-found':
									# room is locked
									errors.append(self.__class__.RoomIsLocked())
								elif err == 'modify jid-malformed':
									# forgot to give a nickname
									errors.append(self.__class__.ForgotNickname())
								else:
									errors.append(self.__class__.UnknownError(presence.__str__(fancy=1).decode('utf-8')))
						break
				if len(errors) == 0:
					errors.append(self.__class__.UnknownError(presence.__str__(fancy=1).decode('utf-8')))
			else:
				self.connected = True
				xmpp_c.UnregisterHandler('presence', self._xmpp_presence_handler)
			if self.callback != None:
				self.callback(errors)
	
	
	def say(self, message):
		"""Say message in the room"""
		self.xmpp_c.send(xmpp.protocol.Message(to=self.room_jid, typ='groupchat', body=message))
	
	
	def sayTo(self, to, message):
		"""Send a private message"""
		self.xmpp_c.send(xmpp.protocol.Message(to=self.room_jid+'/'+to, typ='chat', body=message))
	
	
	def change_nick(self, nickname, status=None, callback=None):
		"""Change nickname"""
		self.jid = self.room_jid+'/'+nickname
		self.callback = callback
		self.xmpp_c.RegisterHandler('presence', self._xmpp_presence_handler)
		self.xmpp_c.send(xmpp.protocol.Presence(to=self.jid, status=status))
	
	
	def leave(self, message=''):
		"""Leave the room"""
		self.xmpp_c.send(xmpp.protocol.Presence(to=self.jid, typ='unavailable', status=message))
		self.connected = False
	
	
	def __del__(self):
		if self.connected:
			self.leave()

xmpp.muc = muc