#!/usr/bin/python
import socket,string,time,sys,StringIO

class irclink:
    def __init__(self,handlers={}):
        self.socket = None
        self.beginofline = ""
        self.handlers = handlers
    def connect(self,host,port):
        if self.socket: self.disconnect()
        self.socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
        self.socket.connect ((host,port))
        self.socket.setblocking (0)
    def register_as_client(self,user,nick):
        self.send ('USER %s\n'%user)
        self.send ('NICK %s\n'%nick)
    def register_as_server(self,password,myname,myhost):
        self.send ('PASS %s\n'%password)
        self.send ('SERVER %s :%s\n'%(myname,myhost))
    def disconnect (self):
        self.socket.close ()
        self.socket = None
    def update (self):
        try: data = self.socket.recv(1024)
        except socket.error,(errno,errms):
            if errno==11:
                return Ellipsis
            raise
        if not data:
            print "connection closed by peer"
            self.disconnect ()
            return Ellipsis
        self.receive(data)
        return None
    def receive (self,data):
        while '\n' in data:
            line,data = string.split(data,'\n',1)
            self.handle (self.beginofline+line.rstrip())
            self.beginofline = ""
        self.beginofline = data
    def handle (self,line):
        source,cmd,params="","",""
        try:
            if line[0]!=":": line=" "+line
            source,cmd = string.split (line," ",1)
            if " " in cmd:
                cmd,params = string.split (cmd," ",1)
            handler = self.handlers.get (cmd,self.handlers.get("",None))
            if handler: handler (self,source,cmd,params)
        except Exception,e:
            print "<<<Exception '%s' in handler ; line was '%s'>>>"%(e,line)
    def send (self,data):
        try: self.socket.send (data)
        except socket.error,(errno,errms):
            if errno==11:
                time.sleep(0.1)
                self.send(data)

def handler_ping(irclink,source,cmd,params):
    irclink.send("PONG %s\n"%params)
def handler_debug(irclink,source,cmd,params):
    print "src='%s', cmd='%s', params='%s'"%(source,cmd,params)
def handler_loginok(irclink,source,cmd,params):
    if not hasattr(irclink,'loginok'):
        irclink.loginok = 1
        irclink.send ('NICK Kicka 0 0 +i kicka ouhyeah.fr.librenet.net ouhyeah.fr.librenet.net 1 :The ouhyeah Kicka!\n')
        #irclink.send (':Kicka JOIN #nocturne\n')
        irclink.send (':Kicka JOIN #@\n')
        #irclink.send ('NICK Kicka 0 0 JOIN #nocturne\n')
def handler_squelch(irclink,source,cmd,params):
    pass
forbiddenchannels=["kiiillme","kiiillme2"]
def handler_join(irclink,source,cmd,params):
    global forbiddenchannels
    handler_logat(irclink,source,cmd,params)
    ts1,ts2,chan,junk,nicks=string.split(params," ",4)
    if nicks[0]==" ": nicks=nicks[1:]
    nicks=nicks[1:] # remove ":"
    nicks=string.split(nicks)
    for nick in nicks:
        if nick[0]=="@": nick=nick[1:]
        if nick[0]=="+": nick=nick[1:]
        #print "[%s] joining [%s]"%(nick,chan)
        if chan in forbiddenchannels:
            irclink.send('KILL %s :forbiddenchannel'%nick)
def handler_logat(irclink,source,cmd,params):
    irclink.send (':Kicka PRIVMSG #@ :[%s] %s => %s\n'%(source[1:],cmd,params))
def handler_nick(irclink,source,cmd,params):
    global suffixes
    if source=="": # new login
        nick,hopcount,ts,mode,username,host,server,junk,comment = \
           string.split (params," ",8)
        for s in suffixes:
            if host.endswith(s):
                irclink.send('CHATOPS :%s!%s@%s (%s) has logged in via %s.\n'%\
                             (nick,username,host,comment,server))
                break
    handler_logat(irclink,source,cmd,params)
def handler_privmsg(irclink,source,cmd,params):
    target,body=string.split(params," ",1)
    body=body[1:]
    if target.lower()=='kicka':
        if " " in body:
            password,command=string.split(body," ",1)
            if password=='ZZZ':
                irclink.send("NICK %s 0 0 +i kickasub ouhyeah.librenet.net ouhyeah.librenet.net 1 :Kickasub for %s\n"%(command,source[1:]))
                if not hasattr(irclink,'subs'): irclink.subs={}
                irclink.subs[command]=source[1:]
                irclink.send(":%s PRIVMSG %s :Master, I'm ready.\n"%(command,source[1:]))
            if password=='XXX':
                exec(command,globals(),globals())
            if password=='YYY':
                savestdout=sys.stdout
                sys.stdout=StringIO.StringIO()
                try: exec(command,globals(),globals())
                except Exception,e:
                    irclink.send(":Kicka PRIVMSG %s :<<<Exception '%s' in handler ; line was '%s'>>>\n"%(source[1:],e,command))
                    sys.stdout=savestdout
                    raise
                for line in string.split(sys.stdout.getvalue(),"\n"):
                    if line.strip():
                        irclink.send(':Kicka PRIVMSG %s :%s\n'%\
                                     (source[1:],line))
                sys.stdout=savestdout
        return
    if hasattr(irclink,"subs"):
        master=irclink.subs.get(target,None)
        if master:
            if source[1:]!=master:
                irclink.send(':%s PRIVMSG %s :I will not obey to thee!\n'%\
                             (target,source[1:]))
                return
            savestdout=sys.stdout
            sys.stdout=StringIO.StringIO()
            try: exec(body,globals(),globals())
            except Exception,e:
                irclink.send(":%s PRIVMSG %s :<<<Exception '%s' in handler ; line was '%s'>>>\n"%(target,source[1:],e,body))
                sys.stdout=savestdout
                raise
            for line in string.split(sys.stdout.getvalue(),"\n"):
                if line.strip():
                    irclink.send(':%s PRIVMSG %s :%s\n'%\
                                 (target,source[1:],line))
            sys.stdout=savestdout
            return
    print "<%s/%s> %s"%(source[1:],target,body)
handlers = {
    "AWAY": handler_logat,
    "CAPAB": handler_loginok,
    "GNOTICE": handler_squelch,
    "KICK": handler_logat,
    "MODE": handler_squelch,
    "NICK": handler_nick,
    "NOTICE": handler_squelch,
    "PART": handler_logat,
    "PASS": handler_squelch,
    "PING": handler_ping,
    "PONG": handler_squelch,
    "PRIVMSG": handler_privmsg,
    "QUIT": handler_logat,
    "SERVER": handler_squelch,
    "SJOIN": handler_join,
    "SQLINE": handler_squelch,
    "SVINFO": handler_squelch,
    "SVSMODE": handler_squelch,
    "TOPIC": handler_logat,
    "VERSION": handler_squelch,
    "251": handler_loginok,
    "252": handler_loginok,
    "254": handler_loginok,
    "255": handler_loginok,
    "265": handler_loginok,
    "266": handler_loginok,
    "": handler_debug
    }

suffixes=["univ-mlv.fr","aol.com"]
kicka=irclink(handlers)
kicka.connect('tezcatlipoca.isnpro.com',6667)
#kicka.register_as_client('k i c a','Kicka')
kicka.register_as_server('XXX',
                         'ouhyeah.fr.librenet.net','ouhyeah.fr.librenet.net')
while 1:
    sleep=kicka.update()
    if sleep: time.sleep(0.1)

