#!/usr/bin/env python
#
# Copyright (c) 2007 Per von Zweigbergk <pvz@pvz.pp.se>
# 
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation
# files (the "Software"), to deal in the Software without
# restriction, including without limitation the rights to use,
# copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following
# conditions:
# 
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
# 
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
# OTHER DEALINGS IN THE SOFTWARE.

import asyncore, asynchat, socket, threading

class RecoderHalfChannel(asynchat.async_chat):
	def __init__(self, sock, enc, enc_fallback = None):
		asynchat.async_chat.__init__(self, sock)
		self.set_terminator("\n")
		self.data = ""
		self.enc = enc
		if (enc_fallback != None):
			self.enc_fallback = enc_fallback
		else:
			self.enc_fallback = enc
	def collect_incoming_data(self, data):
		self.data += data
	def found_terminator(self):
		try:
			uline = self.data.decode(self.enc, 'strict')
		except UnicodeError:
			uline = self.data.decode(self.enc_fallback, 'replace')
		uline += "\n"
		self.data = ""
		self.rhc_other.push(uline.encode(self.rhc_other.enc, 'replace'))
	def pair(self, other):
		self.rhc_other = other
		other.rhc_other = self
	def handle_connect(self):
		pass
	def handle_close(self):
		self.close()
		self.rhc_other.close_when_done()

class RecoderServer(asyncore.dispatcher):
	def __init__(self, listen_port, client_enc, server_addr, server_port, webirc_pass, server_enc, server_enc_fallback = None):
		asyncore.dispatcher.__init__(self)
		self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
		self.bind(("", listen_port))
		self.listen(5)
		self.server_addr = server_addr
		self.server_port = server_port
		self.client_enc = client_enc
		self.server_enc = server_enc
		self.server_enc_fallback = server_enc_fallback
		self.webirc_pass = webirc_pass
	def handle_accept(self):
		client_sock, (client_addr, client_port) = self.accept()
		self.rhc_client = RecoderHalfChannel(client_sock, self.client_enc)
		self.rhc_server = RecoderHalfChannel(None, self.server_enc, self.server_enc_fallback)
		self.rhc_server.create_socket(socket.AF_INET, socket.SOCK_STREAM)
		self.rhc_server.pair(self.rhc_client)
		ResolverThread(self, client_addr)
	def handle_resolved(self, ip, hostname):
		self.rhc_server.connect((self.server_addr, self.server_port))
		self.rhc_server.push("WEBIRC "+self.webirc_pass+" ircrecoder "+hostname+" "+ip+"\n")

class ResolverThread(threading.Thread):
	def __init__(self, handler, addr):
		hostname, aliaslist, ipaddrlist = socket.gethostbyaddr(addr)
		if (len(ipaddrlist) == 1 and addr == ipaddrlist[0]):
			handler.handle_resolved(addr, hostname)
		else:
			handler.handle_resolved(addr, addr)

webirc_pass = 'put_your_cgiirc_password_here'
RecoderServer(6666, 'iso8859-1', 'localhost', 6667, webirc_pass, 'utf-8', 'iso8859-1')
RecoderServer(6668, 'utf-8', 'localhost', 6667, webirc_pass, 'utf-8', 'iso8859-1')
asyncore.loop()