changeset 172:64a0e9636ae6

removed encoding.py, charsets handling is now in irclib and custom charsets can be set per server in the configuration file Signed-off-by: Charly COSTE <changaco@changaco.net>
author Charly COSTE <changaco@changaco.net>
date Tue, 02 Feb 2010 20:19:50 +0100
parents 489c157d9e82
children 6c4aaf8f3733
files bot.py bridge.py encoding.py example_config.xml irclib.py participant.py start_bots_from_xml_config.py
diffstat 7 files changed, 42 insertions(+), 60 deletions(-) [+]
line wrap: on
line diff
--- a/bot.py
+++ b/bot.py
@@ -22,7 +22,6 @@ from time import sleep
 import traceback
 import xml.parsers.expat
 
-from encoding import *
 import irclib
 import muc
 xmpp = muc.xmpp
@@ -67,10 +66,7 @@ class Bot(threading.Thread):
 		if send_to_admins == True:
 			self._send_message_to_admins(s)
 		if not debug or debug and self.debug:
-			try:
-				self.error_fd.write(auto_encode(s)+"\n")
-			except EncodingException:
-				self.error_fd.write('Error message cannot be transcoded.\n')
+			self.error_fd.write(s.encode('utf-8')+"\n")
 	
 	
 	def _xmpp_loop(self):
@@ -478,7 +474,7 @@ class Bot(threading.Thread):
 		
 		
 		# A string representation of the event
-		event_str = '==> Debug: Received IRC event.\nconnection='+connection.__str__()+'\neventtype='+event.eventtype()+'\nsource='+auto_decode(event.source().__str__())+'\ntarget='+auto_decode(event.target().__str__())+'\narguments='+auto_decode(event.arguments().__str__())
+		event_str = '==> Debug: Received IRC event.\nconnection='+connection.__str__()+'\neventtype='+event.eventtype()+'\nsource='+repr(event.source())+'\ntarget='+repr(event.target())+'\narguments='+repr(event.arguments())
 		
 		
 		if event.eventtype() in ['pubmsg', 'action', 'privmsg', 'quit', 'part', 'nick', 'kick']:
@@ -676,9 +672,9 @@ class Bot(threading.Thread):
 				pass
 	
 	
-	def new_bridge(self, xmpp_room, irc_room, irc_server, mode, say_level, irc_port=6667, irc_connection_interval=1):
+	def new_bridge(self, xmpp_room, irc_room, irc_server, mode, say_level, irc_port=6667, irc_connection_interval=1, irc_charsets=None):
 		"""Create a bridge between xmpp_room and irc_room at irc_server."""
-		b = Bridge(self, xmpp_room, irc_room, irc_server, mode, say_level, irc_port=irc_port, irc_connection_interval=irc_connection_interval)
+		b = Bridge(self, xmpp_room, irc_room, irc_server, mode, say_level, irc_port=irc_port, irc_connection_interval=irc_connection_interval, irc_charsets=irc_charsets)
 		self.bridges.append(b)
 		return b
 	
--- a/bridge.py
+++ b/bridge.py
@@ -19,7 +19,6 @@ import re
 import threading
 import traceback
 
-from encoding import *
 from irclib import ServerConnection
 import muc
 xmpp = muc.xmpp
@@ -43,13 +42,14 @@ class Bridge:
 	class NoSuchParticipantException(Exception): pass
 	
 	
-	def __init__(self, owner_bot, xmpp_room_jid, irc_room, irc_server, mode, say_level, irc_port=6667, irc_connection_interval=1):
+	def __init__(self, owner_bot, xmpp_room_jid, irc_room, irc_server, mode, say_level, irc_port=6667, irc_connection_interval=1, irc_charsets=None):
 		"""Create a new bridge."""
 		self.bot = owner_bot
 		self.irc_server = irc_server
 		self.irc_port = irc_port
 		self.irc_room = irc_room.lower()
 		self.irc_connection_interval = irc_connection_interval
+		self.irc_charsets = irc_charsets
 		self.xmpp_room_jid = xmpp_room_jid
 		if hasattr(self.__class__, '_'+say_level):
 			self.say_level = getattr(self.__class__, '_'+say_level)
@@ -78,7 +78,7 @@ class Bridge:
 		try:
 			self.irc_connections_limit = -1
 			self.irc_connection = self.bot.irc.open_connection(self.irc_server, self.irc_port, self.bot.nickname)
-			self.irc_connection.connect(nick_callback=self._irc_nick_callback)
+			self.irc_connection.connect(nick_callback=self._irc_nick_callback, charsets=self.irc_charsets)
 		except:
 			self.bot.error('[Error] joining IRC room failed')
 			raise
deleted file mode 100644
--- a/encoding.py
+++ /dev/null
@@ -1,38 +0,0 @@
-#!/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/>.
-
-
-class EncodingException(Exception): pass
-
-
-def auto_encode(s):
-	for codec in ['utf-8', 'iso8859_15']:
-		try:
-			return s.encode(codec)
-		except (UnicodeEncodeError, UnicodeDecodeError) as e:
-			print e
-			pass
-	raise EncodingException('no suitable codec found')
-
-
-def auto_decode(s):
-	for codec in ['utf-8', 'iso8859_15']:
-		try:
-			return s.decode(codec)
-		except (UnicodeEncodeError, UnicodeDecodeError) as e:
-			print e
-			pass
-	raise EncodingException('no suitable codec found')
\ No newline at end of file
--- a/example_config.xml
+++ b/example_config.xml
@@ -6,11 +6,13 @@
 		<admin jid='admin2@example.net' />
 		<bridge mode='normal' say_level='all'>
 			<xmpp-room jid='dream-world@chat.example.com'/>
-			<irc chan='#dream-world' server='irc.example.org'/>
+			<irc chan='#dream-world' server='irc.example.org' charsets='utf-8 iso8859_15'/>
+				<!-- separate codecs by a space -->
+				<!-- see <http://docs.python.org/library/codecs.html#standard-encodings> for a list of codecs -->
 		</bridge>
 		<bridge mode='minimal' say_level='nothing'>
 			<xmpp-room jid='room@chat.example.com'/>
-			<irc chan='#chan' server='irc.example.org' connection_interval='2'/> <!-- connection_interval is in seconds -->
+			<irc chan='#chan' server='irc.example.net' connection_interval='2'/> <!-- connection_interval is in seconds -->
 		</bridge>
 	</bot>
 	<!-- WARNING: do NOT start two bots with the same JID or the same nickname -->
--- a/irclib.py
+++ b/irclib.py
@@ -163,6 +163,7 @@ class IRC:
         self.connections = []
         self.handlers = {}
         self.delayed_commands = [] # list of tuples in the format (time, function, arguments)
+        self.charsets = {'': ['utf-8']}
 
         self.add_global_handler("ping", _ping_ponger, -42)
 
@@ -424,7 +425,17 @@ class ServerConnection(Connection):
 
 
     def __str__(self):
-        return self.real_nickname+' at '+self.server+':'+str(self.port)
+        return self.real_nickname+' at '+self._server_str()
+
+
+    def _decode(self, bytes):
+        charsets = self.irclibobj.charsets[self._server_str()] or self.irclibobj.charsets['']
+        for codec in charsets:
+            try:
+                return bytes.decode(codec)
+            except (UnicodeEncodeError, UnicodeDecodeError):
+                pass
+        raise Exception, 'no suitable codec found for: '+repr(bytes)+'\ntried: '+' '.join(charsets)
 
 
     def _ping(self):
@@ -435,8 +446,12 @@ class ServerConnection(Connection):
         self.ping(self.get_server_name())
 
 
+    def _server_str(self):
+        return self.server+':'+str(self.port)
+
+
     def connect(self, password=None, username=None,
-                ircname=None, localaddress="", localport=0, ssl=False, ipv6=False, nick_callback=None):
+                ircname=None, localaddress="", localport=0, ssl=False, ipv6=False, nick_callback=None, charsets=None):
         """Connect to the server.
 
         Arguments:
@@ -473,6 +488,8 @@ class ServerConnection(Connection):
             return self
 
         if self.socket != 'closed':
+            if charsets or not self.irclibobj.charsets.has_key(self._server_str()):
+                self.irclibobj.charsets[self._server_str()] = charsets
             self.nick_callbacks = []
             self.irc_id = None
             self.previous_buffer = ""
@@ -600,6 +617,8 @@ class ServerConnection(Connection):
             if not line:
                 continue
 
+            line = self._decode(line)
+
             prefix = None
             command = None
             arguments = None
--- a/participant.py
+++ b/participant.py
@@ -18,7 +18,6 @@
 import re
 from time import sleep
 
-from encoding import *
 from irclib import ServerNotConnectedError, ServerConnection
 import muc
 xmpp = muc.xmpp
@@ -317,12 +316,12 @@ class Participant:
 	def sayOnXMPP(self, message):
 		try:
 			if isinstance(self.xmpp_c, xmpp.client.Client):
-				self.muc.say(auto_decode(message))
+				self.muc.say(message)
 			elif not isinstance(self.irc_connection, ServerConnection):
 				if message[:4] == '/me ':
-					self.bridge.xmpp_room.say('* '+self.nickname+' '+auto_decode(message[4:]))
+					self.bridge.xmpp_room.say('* '+self.nickname+' '+message[4:])
 				else:
-					self.bridge.xmpp_room.say('<'+self.nickname+'> '+auto_decode(message))
+					self.bridge.xmpp_room.say('<'+self.nickname+'> '+message)
 		except EncodingException:
 			self.bridge.say('[Warning] "'+self.nickname+'" is sending messages using an unknown encoding', log=True)
 	
@@ -330,7 +329,7 @@ class Participant:
 	def sayOnXMPPTo(self, to, message):
 		try:
 			if isinstance(self.xmpp_c, xmpp.client.Client):
-				self.muc.sayTo(to, auto_decode(message))
+				self.muc.sayTo(to, message)
 			elif not isinstance(self.irc_connection, ServerConnection):
 				if self.bridge.mode != 'normal':
 					self.bridge.getParticipant(to).sayOnXMPPTo(self.nickname, 'Sorry but cross-protocol private messages are disabled in '+self.bridge.mode+' mode.')
@@ -349,7 +348,7 @@ class Participant:
 	
 	def _close_xmpp_connection(self, message):
 		if isinstance(self.xmpp_c, xmpp.client.Client):
-			self.muc.leave(auto_decode(message))
+			self.muc.leave(message)
 			self.xmpp_c = None
 			self.bridge.bot.close_xmpp_connection(self.nickname)
 	
--- a/start_bots_from_xml_config.py
+++ b/start_bots_from_xml_config.py
@@ -65,6 +65,10 @@ for bot_el in config.getElementsByTagNam
 				irc_connection_interval = float(irc.getAttribute('connection_interval'))
 			except ValueError:
 				print '[Error] the value of connection_interval must be a number'
+		if irc.hasAttribute('charsets'):
+			irc_charsets = irc.getAttribute('charsets').split()
+		else:
+			irc_charsets = None
 		
 		if bridge_el.hasAttribute('say_level'):
 			say_level = bridge_el.getAttribute('say_level')
@@ -76,7 +80,7 @@ for bot_el in config.getElementsByTagNam
 		else:
 			mode = 'normal'
 		
-		bot.new_bridge(xmpp_room.getAttribute('jid'), irc.getAttribute('chan'), irc.getAttribute('server'), mode, say_level, irc_connection_interval=irc_connection_interval)
+		bot.new_bridge(xmpp_room.getAttribute('jid'), irc.getAttribute('chan'), irc.getAttribute('server'), mode, say_level, irc_connection_interval=irc_connection_interval, irc_charsets=irc_charsets)
 
 try:
 	if len(bots) == 0: