]> jfr.im git - irc/quakenet/qwebirc.git/blobdiff - qwebirc/ircclient.py
Support asynchronous DNS resolution in webirc/None WEBIRC modes.
[irc/quakenet/qwebirc.git] / qwebirc / ircclient.py
index 06589a44380a124d14117659890d60a1895e9db4..43f5665bc29650c30d14267fa47bd2939124332a 100644 (file)
@@ -1,4 +1,4 @@
-import twisted, sys
+import twisted, sys, codecs
 from twisted.words.protocols import irc
 from twisted.internet import reactor, protocol
 from twisted.web import resource, server
 from twisted.words.protocols import irc
 from twisted.internet import reactor, protocol
 from twisted.web import resource, server
@@ -6,31 +6,54 @@ from twisted.protocols import basic
 
 import hmac, time, config
 from config import HMACTEMPORAL
 
 import hmac, time, config
 from config import HMACTEMPORAL
-HMACKEY = hmac.HMAC(key=config.HMACKEY)
+
+if config.WEBIRC_MODE == "hmac":
+  HMACKEY = hmac.HMAC(key=config.HMACKEY)
 
 def hmacfn(*args):
   h = HMACKEY.copy()
   h.update("%d %s" % (int(time.time() / HMACTEMPORAL), " ".join(args)))
   return h.hexdigest()
 
 
 def hmacfn(*args):
   h = HMACKEY.copy()
   h.update("%d %s" % (int(time.time() / HMACTEMPORAL), " ".join(args)))
   return h.hexdigest()
 
+def utf8_iso8859_1(data, table=dict((x, x.decode("iso-8859-1")) for x in map(chr, range(0, 256)))):
+  return (table.get(data.object[data.start]), data.start+1)
+
+codecs.register_error("mixed-iso-8859-1", utf8_iso8859_1)
+
+def irc_decode(x):
+  try:
+    return x.decode("utf-8", "mixed-iso-8859-1")
+  except UnicodeDecodeError:
+    return x.decode("iso-8859-1", "ignore")
+
 class QWebIRCClient(basic.LineReceiver):
   delimiter = "\n"
 class QWebIRCClient(basic.LineReceiver):
   delimiter = "\n"
-  
+  def __init__(self, *args, **kwargs):
+    self.__nickname = "(unregistered)"
+    
   def dataReceived(self, data):
     basic.LineReceiver.dataReceived(self, data.replace("\r", ""))
 
   def lineReceived(self, line):
   def dataReceived(self, data):
     basic.LineReceiver.dataReceived(self, data.replace("\r", ""))
 
   def lineReceived(self, line):
-    line = irc.lowDequote(line)
-    try:
-      line = line.decode("utf-8")
-    except UnicodeDecodeError:
-      line = line.decode("iso-8859-1", "ignore")
+    line = irc_decode(irc.lowDequote(line))
     
     try:
       prefix, command, params = irc.parsemsg(line)
       self.handleCommand(command, prefix, params)
     except irc.IRCBadMessage:
       self.badMessage(line, *sys.exc_info())
     
     try:
       prefix, command, params = irc.parsemsg(line)
       self.handleCommand(command, prefix, params)
     except irc.IRCBadMessage:
       self.badMessage(line, *sys.exc_info())
+      
+    if command == "001":
+      self.__nickname = params[0]
+      
+      if self.__perform is not None:
+        for x in self.__perform:
+          self.write(x)
+        self.__perform = None
+    elif command == "NICK":
+      nick = prefix.split("!", 1)[0]
+      if nick == self.__nickname:
+        self.__nickname = params[0]
         
   def badMessage(self, args):
     self("badmessage", args)
         
   def badMessage(self, args):
     self("badmessage", args)
@@ -47,20 +70,50 @@ class QWebIRCClient(basic.LineReceiver):
   def connectionMade(self):
     basic.LineReceiver.connectionMade(self)
     
   def connectionMade(self):
     basic.LineReceiver.connectionMade(self)
     
+    self.lastError = None
     f = self.factory.ircinit
     f = self.factory.ircinit
-    nick, ident, ip, realname = f["nick"], f["ident"], f["ip"], f["realname"]
-    
-    hmac = hmacfn(ident, ip)
-    self.write("USER %s bleh bleh %s %s :%s" % (ident, ip, hmac, realname))
+    nick, ident, ip, realname, hostname = f["nick"], f["ident"], f["ip"], f["realname"], f["hostname"]
+    self.__nickname = nick
+    self.__perform = f.get("perform")
+
+    if config.WEBIRC_MODE == "hmac":
+      hmac = hmacfn(ident, ip)
+      self.write("USER %s bleh bleh %s %s :%s" % (ident, ip, hmac, realname))
+    elif config.WEBIRC_MODE == "webirc":
+      self.write("WEBIRC %s qwebirc %s %s" % (config.WEBIRC_PASSWORD, ip, hostname))
+      self.write("USER %s bleh %s :%s" % (ident, ip, realname))
+    else:
+      if ip == hostname:
+        dispip = ip
+      else:
+        dispip = "%s/%s" % (hostname, ip)
+
+      self.write("USER %s bleh bleh :%s - %s" % (ident, dispip, realname))
+
     self.write("NICK %s" % nick)
     
     self.factory.client = self
     self("connect")
 
     self.write("NICK %s" % nick)
     
     self.factory.client = self
     self("connect")
 
+  def __str__(self):
+    return "<QWebIRCClient: %s!%s@%s>" % (self.__nickname, self.factory.ircinit["ident"], self.factory.ircinit["ip"])
+    
   def connectionLost(self, reason):
   def connectionLost(self, reason):
+    if self.lastError:
+      self.disconnect("Connection to IRC server lost: %s" % self.lastError)
+    else:
+      self.disconnect("Connection to IRC server lost.")
     self.factory.client = None
     basic.LineReceiver.connectionLost(self, reason)
     self.factory.client = None
     basic.LineReceiver.connectionLost(self, reason)
-    self("disconnect")
+
+  def error(self, message):
+    self.lastError = message
+    self.write("QUIT :qwebirc exception: %s" % message)
+    self.transport.loseConnection()
+
+  def disconnect(self, reason):
+    self("disconnect", reason)
+    self.factory.publisher.disconnect()
     
 class QWebIRCFactory(protocol.ClientFactory):
   protocol = QWebIRCClient
     
 class QWebIRCFactory(protocol.ClientFactory):
   protocol = QWebIRCClient
@@ -71,12 +124,20 @@ class QWebIRCFactory(protocol.ClientFactory):
     
   def write(self, data):
     self.client.write(data)
     
   def write(self, data):
     self.client.write(data)
-    
+
+  def error(self, reason):
+    self.client.error(reason)
+
+  def clientConnectionFailed(self, connector, reason):
+    protocol.ClientFactory.clientConnectionFailed(self, connector, reason)
+    self.publisher.event(["disconnect", "Connection to IRC server failed."])
+    self.publisher.disconnect()
+
 def createIRC(*args, **kwargs):
   f = QWebIRCFactory(*args, **kwargs)
   reactor.connectTCP(config.IRCSERVER, config.IRCPORT, f)
   return f
 
 if __name__ == "__main__":
 def createIRC(*args, **kwargs):
   f = QWebIRCFactory(*args, **kwargs)
   reactor.connectTCP(config.IRCSERVER, config.IRCPORT, f)
   return f
 
 if __name__ == "__main__":
-  e = createIRC(lambda x: 2, nick="slug__moo", ident="mooslug", ip="1.2.3.6", realname="mooooo")
-  reactor.run()
\ No newline at end of file
+  e = createIRC(lambda x: 2, nick="slug__moo", ident="mooslug", ip="1.2.3.6", realname="mooooo", hostname="1.2.3.4")
+  reactor.run()