summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bouncer.py783
-rw-r--r--irc.py2680
-rw-r--r--logger.py308
3 files changed, 2131 insertions, 1640 deletions
diff --git a/bouncer.py b/bouncer.py
index 3c321fa..0e351ac 100644
--- a/bouncer.py
+++ b/bouncer.py
@@ -9,16 +9,29 @@ import string
import hashlib
import traceback
import irc
+import getpass
from threading import Thread, Lock
import Queue
+def BouncerReload(BNC):
+ if BNC.isAlive():
+ BNC.stop()
+ newBNC = Bouncer(addr=BNC.addr, port=BNC.port, ssl=BNC.ssl, ipv6=BNC.ipv6,
+ certfile=BNC.certfile, keyfile=BNC.keyfile, timeout=BNC.timeout, autoaway=BNC.autoaway)
+ for label, (IRC, passwd, hashtype) in BNC.servers.items():
+ IRC.rmAddon(BNC)
+ IRC.addAddon(newBNC, label=label, passwd=passwd, hashtype=hashtype)
+ return newBNC
+
+
class Bouncer (Thread):
- def __init__(self, addr="", port=16667, ssl=False, ipv6=False, certfile=None, keyfile=None, ignore=None, debug=False, log=sys.stderr, timeout=300, BNC=None, autoaway=None):
+
+ def __init__(self, addr="", port=16667, ssl=False, ipv6=False, certfile=None, keyfile=None, ignore=None, debug=False, timeout=300, autoaway=None):
self.__name__ = "Bouncer for pyIRC"
- self.__version__ = "1.1"
+ self.__version__ = "1.2"
self.__author__ = "Brian Sherson"
- self.__date__ = "December 1, 2013"
+ self.__date__ = "December 26, 2013"
self.addr = addr
self.port = port
@@ -37,9 +50,10 @@ class Bouncer (Thread):
self.debug = debug
self.timeout = timeout
self.autoaway = autoaway
+ self._stopexpected = False
- ### Keep track of what extensions/connections are requesting WHO, WHOIS, and LIST, because we don't want to spam every bouncer connection with the server's replies.
- ### In the future, MAY implement this idea in the irc module.
+ # Keep track of what extensions/connections are requesting WHO, WHOIS, and LIST, because we don't want to spam every bouncer connection with the server's replies.
+ # In the future, MAY implement this idea in the irc module.
self.whoexpected = {}
self.whoisexpected = {}
self.listexpected = {}
@@ -59,13 +73,19 @@ class Bouncer (Thread):
try:
(connection, addr) = self.socket.accept()
if self.ssl:
- connection = ssl.wrap_socket(connection, server_side=True, certfile=self.certfile, keyfile=self.keyfile, ssl_version=ssl.PROTOCOL_SSLv23)
+ connection = ssl.wrap_socket(
+ connection, server_side=True, certfile=self.certfile, keyfile=self.keyfile, ssl_version=ssl.PROTOCOL_SSLv23)
#print ((self,"New client connecting from %s:%s"%addr))
except socket.error:
- #print "Shutting down Listener"
+ # print "Shutting down Listener"
self.socket.close()
- #raise
+ if not self._stopexpected:
+ raise
sys.exit()
+ except:
+ tb = traceback.format_exc()
+ print >>sys.stderr, tb
+ continue
connection.settimeout(self.timeout)
bouncer = BouncerConnection(
self, connection, addr, debug=self.debug)
@@ -75,15 +95,23 @@ class Bouncer (Thread):
except:
pass
- def onAddonAdd(self, IRC, label, passwd, hashtype="md5"):
- if IRC in [connection for (connection, passwd, hashtype) in self.servers.values()]:
+ def onAddonAdd(self, IRC, label, passwd=None, hashtype="sha512"):
+ if passwd == None:
+ while True:
+ passwd = getpass.getpass("Enter new password: ")
+ if passwd == getpass.getpass("Confirm new password: "):
+ break
+ print "Passwords do not match!"
+ passwd = hashlib.new(hashtype, passwd).hexdigest()
+ if IRC in [connection for (connection, p, h) in self.servers.values()]:
return # Silently do nothing
if label in self.servers.keys():
return
self.servers[label] = (IRC, passwd, hashtype)
self.whoexpected[IRC] = []
if self.debug:
- IRC.logwrite("dbg [Bouncer.onAddonAdd] Clearing WHO expected list." % vars())
+ IRC.logwrite(
+ "dbg [Bouncer.onAddonAdd] Clearing WHO expected list." % vars())
self.whoisexpected[IRC] = []
self.listexpected[IRC] = []
@@ -96,6 +124,7 @@ class Bouncer (Thread):
del self.servers[label]
def stop(self):
+ self._stopexpected = True
self.socket.shutdown(0)
def disconnectall(self, quitmsg="Disconnecting all sessions"):
@@ -104,248 +133,259 @@ class Bouncer (Thread):
def onDisconnect(self, IRC, expected=False):
self.whoexpected[IRC] = []
- if self.debug:
- IRC.logwrite("dbg [Bouncer.onDisconnect] Clearing WHO expected list.")
self.whoisexpected[IRC] = []
self.listexpected[IRC] = []
for bouncerconnection in self.connections:
if bouncerconnection.IRC == IRC:
- bouncerconnection.quit(quitmsg="IRC connection lost")
+ #bouncerconnection.quit(quitmsg="IRC connection lost")
+ for channel in IRC.identity.channels:
+ bouncerconnection.send(":%s!%s@%s PART %s :Bouncer Connection Lost\n" % (
+ IRC.identity.nick, IRC.identity.username, IRC.identity.host, channel.name))
+ bouncerconnection.send(
+ ":%s!%s@%s QUIT :Bouncer Connection Lost\n" %
+ (IRC.identity.nick, IRC.identity.username, IRC.identity.host))
+ bouncerconnection.send(
+ ":*Bouncer* NOTICE %s :Connection to %s:%s has been lost.\n" %
+ (bouncerconnection.nick, IRC.server, IRC.port))
+
+ def onQuit(self, IRC, user, quitmsg):
+ # For some odd reason, certain networks (*cough*Freenode*cough*) will send a quit message for the user, causing IRC.identity.channels to be cleared
+ # before onDisconnect can be executed. This is the remedy.
+ for bouncerconnection in self.connections:
+ if bouncerconnection.IRC == IRC:
+ if quitmsg:
+ bouncerconnection.send(":%s!%s@%s QUIT :%s\n" % (
+ user.nick, user.username, user.host, quitmsg))
+ else:
+ bouncerconnection.send(
+ ":%s!%s@%s QUIT\n" % (user.nick, user.username, user.host))
+ if user == IRC.identity:
+ for channel in IRC.identity.channels:
+ bouncerconnection.send(":%s!%s@%s PART %s :Bouncer Connection Lost\n" % (
+ IRC.identity.nick, IRC.identity.username, IRC.identity.host, channel.name))
+
+ def onConnectAttempt(self, IRC):
+ for bouncerconnection in self.connections:
+ if bouncerconnection.IRC == IRC:
+ bouncerconnection.send(
+ ":*Bouncer* NOTICE %s :Attempting connection to %s:%s.\n" %
+ (bouncerconnection.nick, IRC.server, IRC.port))
+
+ def onConnect(self, IRC):
+ for bouncerconnection in self.connections:
+ if bouncerconnection.IRC == IRC:
+ bouncerconnection.send(
+ ":*Bouncer* NOTICE %s :Connection to %s:%s established.\n" %
+ (bouncerconnection.nick, IRC.server, IRC.port))
+
+ def onMeNickChange(self, IRC, newnick):
+ for bouncerconnection in self.connections:
+ if bouncerconnection.IRC == IRC:
+ bouncerconnection.send(":%s!%s@%s NICK %s\n" %
+ (IRC.identity.nick, IRC.identity.username, IRC.identity.host, newnick))
+ bouncerconnection.nick = newnick
+
+ def onRegistered(self, IRC):
+ for bouncerconnection in self.connections:
+ if bouncerconnection.IRC == IRC:
+ if bouncerconnection.nick != IRC.identity.nick:
+ bouncerconnection.send(":%s!%s@%s NICK %s\n" % (
+ bouncerconnection.nick, bouncerconnection.username, bouncerconnection.host, IRC.identity.nick))
+ bouncerconnection.nick = IRC.identity.nick
+
+ def onConnectFail(self, IRC, exc, excmsg, tb):
+ for bouncerconnection in self.connections:
+ if bouncerconnection.IRC == IRC:
+ bouncerconnection.send(
+ ":*Bouncer* NOTICE %s :Connection to %s:%s failed: %s.\n" %
+ (bouncerconnection.nick, IRC.server, IRC.port, excmsg))
def onSendChanMsg(self, IRC, origin, channel, targetprefix, msg):
- ### Called when bot sends a PRIVMSG to channel.
- ### The variable origin refers to a class instance voluntarily identifying itself as that which requested data be sent.
+ # Called when bot sends a PRIVMSG to channel.
+ # The variable origin refers to a class instance voluntarily
+ # identifying itself as that which requested data be sent.
for bouncerconnection in self.connections:
if IRC == bouncerconnection.IRC and origin != bouncerconnection:
- bouncerconnection.send(":%s!%s@%s PRIVMSG %s%s :%s\n"%(IRC.identity.nick, IRC.identity.username, IRC.identity.host, targetprefix, channel.name, msg))
+ bouncerconnection.send(":%s!%s@%s PRIVMSG %s%s :%s\n" %
+ (IRC.identity.nick, IRC.identity.username, IRC.identity.host, targetprefix, channel.name, msg))
def onSendChanAction(self, IRC, origin, channel, targetprefix, action):
- self.onSendChanMsg(IRC, origin, channel, targetprefix,
- "\x01ACTION %s\x01"%action)
+ self.onSendChanMsg(
+ IRC, origin, channel, targetprefix, "\x01ACTION %s\x01" % action)
def onSendChanNotice(self, IRC, origin, channel, targetprefix, msg):
- ### Called when bot sends a NOTICE to channel.
- ### The variable origin refers to a class instance voluntarily identifying itself as that which requested data be sent.
+ # Called when bot sends a NOTICE to channel.
+ # The variable origin refers to a class instance voluntarily
+ # identifying itself as that which requested data be sent.
for bouncerconnection in self.connections:
if IRC == bouncerconnection.IRC and origin != bouncerconnection:
- bouncerconnection.send(":%s!%s@%s NOTICE %s%s :%s\n"%(IRC.identity.nick, IRC.identity.username, IRC.identity.host, targetprefix, channel.name, msg))
+ bouncerconnection.send(":%s!%s@%s NOTICE %s%s :%s\n" % (
+ IRC.identity.nick, IRC.identity.username, IRC.identity.host, targetprefix, channel.name, msg))
def onSend(self, IRC, origin, line, cmd, target, params, extinfo):
if cmd.upper() == "WHO":
self.whoexpected[IRC].append(origin)
if self.debug:
- with IRC.loglock:
- timestamp = irc.timestamp()
- if issubclass(type(origin), Thread):
- name = origin.name
- print >>IRC.log, "%(timestamp)s dbg [Bouncer.onSend] Adding %(origin)s (%(name)s) to WHO expected list." % vars()
- else:
- print >>IRC.log, "%(timestamp)s dbg [Bouncer.onSend] Adding %(origin)s to WHO expected list." % vars()
- for obj in self.whoexpected[IRC]:
- if issubclass(type(obj), Thread):
- name = obj.name
- print >>IRC.log, "%(timestamp)s dbg [Bouncer.onSend] WHO expected: %(obj)s (%(name)s)" % vars()
- else:
- print >>IRC.log, "%(timestamp)s dbg [Bouncer.onSend] WHO expected: %(obj)s" % vars()
- IRC.log.flush()
+ if issubclass(type(origin), Thread):
+ name = origin.name
+ IRC.logwrite(
+ "dbg [Bouncer.onSend] Adding %(origin)s (%(name)s) to WHO expected list." % vars())
+ else:
+ IRC.logwrite(
+ "dbg [Bouncer.onSend] Adding %(origin)s to WHO expected list." % vars())
+ IRC.logwrite(
+ "dbg [Bouncer.onSend] WHO expected list size: %d" %
+ len(self.whoexpected[IRC]))
elif cmd.upper() == "WHOIS":
self.whoisexpected[IRC].append(origin)
elif cmd.upper() == "LIST":
self.listexpected[IRC].append(origin)
def onWhoEntry(self, IRC, origin, channel, user, channame, username, host, serv, nick, flags, hops, realname):
- ### Called when a WHO list is received.
+ # Called when a WHO list is received.
if len(self.whoexpected[IRC]) and self.whoexpected[IRC][0] in self.connections:
bncconnection = self.whoexpected[IRC][0]
- try:
- bncconnection.send(":%s 352 %s %s %s %s %s %s %s :%s %s\n"%(origin, IRC.identity.nick, channame, username, host, serv, nick, flags, hops, realname))
- except socket.error:
- pass
+ bncconnection.send(":%s 352 %s %s %s %s %s %s %s :%s %s\n" %
+ (origin, IRC.identity.nick, channame, username, host, serv, nick, flags, hops, realname))
def onWhoEnd(self, IRC, origin, param, endmsg):
- ### Called when a WHO list is received.
+ # Called when a WHO list is received.
if len(self.whoexpected[IRC]) and self.whoexpected[IRC][0] in self.connections:
bncconnection = self.whoexpected[IRC][0]
- try:
- bncconnection.send(":%s 315 %s %s :%s\n"%(
- origin, IRC.identity.nick, param, endmsg))
- except socket.error:
- pass
- finally:
- del self.whoexpected[IRC][0]
-
- def onWho(self, IRC, params, wholist, endmsg):
- ### Called when a WHO list is received.
- if len(self.whoexpected[IRC]):
- try:
- if self.whoexpected[IRC][0] in self.connections:
- bncconnection = self.whoexpected[IRC][0]
- lines = [":%s 352 %s %s %s %s %s %s %s :%s %s\n"%(IRC.serv, IRC.identity.nick, channame, username, host, serv, nick, flags, hops, realname) for (channel, user, channame, username, host, serv, nick, flags, hops, realname) in wholist]+[":%s 315 %s %s :%s\n"%(IRC.serv, IRC.identity.nick, params, endmsg)]
- bncconnection.send("".join(lines))
- finally:
- del self.whoexpected[IRC][0]
+ bncconnection.send(":%s 315 %s %s :%s\n" %
+ (origin, IRC.identity.nick, param, endmsg))
+ if self.debug:
+ if issubclass(type(self.whoexpected[IRC][0]), Thread):
+ name = self.whoexpected[IRC][0].name
+ IRC.logwrite(
+ "dbg [Bouncer.onWhoEnd] Removing %s (%s) from WHO expected list." %
+ (self.whoexpected[IRC][0], name))
+ else:
+ IRC.logwrite(
+ "dbg [Bouncer.onWhoEnd] Removing %s from WHO expected list." % self.whoexpected[IRC][0])
+ del self.whoexpected[IRC][0]
+ if self.debug:
+ IRC.logwrite("dbg [Bouncer.onWhoEnd] WHO expected list size: %d" %
+ len(self.whoexpected[IRC]))
def onListStart(self, IRC, origin, params, extinfo):
- ### Called when a WHO list is received.
+ # Called when a WHO list is received.
if len(self.listexpected[IRC]) and self.listexpected[IRC][0] in self.connections:
bncconnection = self.listexpected[IRC][0]
- try:
- bncconnection.send(":%s 321 %s %s :%s\n"%(origin,
- IRC.identity.nick, params, extinfo))
- except socket.error:
- pass
+ bncconnection.send(":%s 321 %s %s :%s\n" %
+ (origin, IRC.identity.nick, params, extinfo))
def onListEntry(self, IRC, origin, channel, population, extinfo):
- ### Called when a WHO list is received.
+ # Called when a WHO list is received.
if len(self.listexpected[IRC]) and self.listexpected[IRC][0] in self.connections:
bncconnection = self.listexpected[IRC][0]
- try:
- bncconnection.send(":%s 322 %s %s %d :%s\n"%(origin, IRC.identity.nick, channel.name, population, extinfo))
- except socket.error:
- pass
+ bncconnection.send(":%s 322 %s %s %d :%s\n" %
+ (origin, IRC.identity.nick, channel.name, population, extinfo))
def onListEnd(self, IRC, origin, endmsg):
- ### Called when a WHO list is received.
+ # Called when a WHO list is received.
if len(self.listexpected[IRC]) and self.listexpected[IRC][0] in self.connections:
bncconnection = self.listexpected[IRC][0]
- try:
- bncconnection.send(":%s 323 %s :%s\n"%(
- origin, IRC.identity.nick, endmsg))
- except socket.error:
- pass
- finally:
- del self.listexpected[IRC][0]
+ bncconnection.send(":%s 323 %s :%s\n" %
+ (origin, IRC.identity.nick, endmsg))
+ del self.listexpected[IRC][0]
def onWhoisStart(self, IRC, origin, user, nickname, username, host, realname):
- ### Called when a WHOIS reply is received.
+ # Called when a WHOIS reply is received.
if len(self.whoisexpected[IRC]):
if self.whoisexpected[IRC][0] in self.connections:
bncconnection = self.whoisexpected[IRC][0]
- try:
- bncconnection.send(":%s 311 %s %s %s %s * :%s\n" % (origin, IRC.identity.nick, nickname, username, host, realname))
- except socket.error:
- pass
+ bncconnection.send(":%s 311 %s %s %s %s * :%s\n" %
+ (origin, IRC.identity.nick, nickname, username, host, realname))
def onWhoisRegisteredNick(self, IRC, origin, user, nickname, msg):
- ### Called when a WHOIS reply is received.
+ # Called when a WHOIS reply is received.
if len(self.whoisexpected[IRC]) and self.whoisexpected[IRC][0] in self.connections:
bncconnection = self.whoisexpected[IRC][0]
- try:
- bncconnection.send(":%s 307 %s %s :%s\n" % (
- origin, IRC.identity.nick, nickname, msg))
- except socket.error:
- pass
+ bncconnection.send(":%s 307 %s %s :%s\n" %
+ (origin, IRC.identity.nick, nickname, msg))
def onWhoisConnectingFrom(self, IRC, origin, user, nickname, msg):
- ### Called when a WHOIS reply is received.
+ # Called when a WHOIS reply is received.
if len(self.whoisexpected[IRC]) and self.whoisexpected[IRC][0] in self.connections:
bncconnection = self.whoisexpected[IRC][0]
- try:
- bncconnection.send(":%s 378 %s %s :%s\n" % (
- origin, IRC.identity.nick, nickname, msg))
- except socket.error:
- pass
+ bncconnection.send(":%s 378 %s %s :%s\n" %
+ (origin, IRC.identity.nick, nickname, msg))
def onWhoisChannels(self, IRC, origin, user, nickname, chanlist):
- ### Called when a WHOIS reply is received.
+ # Called when a WHOIS reply is received.
if len(self.whoisexpected[IRC]) and self.whoisexpected[IRC][0] in self.connections:
bncconnection = self.whoisexpected[IRC][0]
- try:
- bncconnection.send(":%s 319 %s %s :%s\n" % (origin, IRC.identity.nick, nickname, " ".join(chanlist)))
- except socket.error:
- pass
+ bncconnection.send(":%s 319 %s %s :%s\n" %
+ (origin, IRC.identity.nick, nickname, " ".join(chanlist)))
def onWhoisAvailability(self, IRC, origin, user, nickname, msg):
- ### Called when a WHOIS reply is received.
+ # Called when a WHOIS reply is received.
if len(self.whoisexpected[IRC]) and self.whoisexpected[IRC][0] in self.connections:
bncconnection = self.whoisexpected[IRC][0]
- try:
- bncconnection.send(":%s 310 %s %s :%s\n" % (
- origin, IRC.identity.nick, nickname, msg))
- except socket.error:
- pass
+ bncconnection.send(":%s 310 %s %s :%s\n" %
+ (origin, IRC.identity.nick, nickname, msg))
def onWhoisServer(self, IRC, origin, user, nickname, server, servername):
- ### Called when a WHOIS reply is received.
+ # Called when a WHOIS reply is received.
if len(self.whoisexpected[IRC]) and self.whoisexpected[IRC][0] in self.connections:
bncconnection = self.whoisexpected[IRC][0]
- try:
- bncconnection.send(":%s 312 %s %s %s :%s\n" % (origin, IRC.identity.nick, nickname, server, servername))
- except socket.error:
- pass
+ bncconnection.send(":%s 312 %s %s %s :%s\n" %
+ (origin, IRC.identity.nick, nickname, server, servername))
def onWhoisOp(self, IRC, origin, user, nickname, msg):
if len(self.whoisexpected[IRC]) and self.whoisexpected[IRC][0] in self.connections:
bncconnection = self.whoisexpected[IRC][0]
- try:
- bncconnection.send(":%s 313 %s %s :%s\n" % (
- origin, IRC.identity.nick, nickname, msg))
- except socket.error:
- pass
+ bncconnection.send(":%s 313 %s %s :%s\n" %
+ (origin, IRC.identity.nick, nickname, msg))
def onWhoisAway(self, IRC, origin, user, nickname, awaymsg):
if len(self.whoisexpected[IRC]) and self.whoisexpected[IRC][0] in self.connections:
bncconnection = self.whoisexpected[IRC][0]
- try:
- bncconnection.send(":%s 301 %s %s :%s\n" % (origin,
- IRC.identity.nick, nickname, awaymsg))
- except socket.error:
- pass
+ bncconnection.send(":%s 301 %s %s :%s\n" %
+ (origin, IRC.identity.nick, nickname, awaymsg))
def onWhoisTimes(self, IRC, origin, user, nickname, idletime, signontime, msg):
if len(self.whoisexpected[IRC]) and self.whoisexpected[IRC][0] in self.connections:
bncconnection = self.whoisexpected[IRC][0]
- try:
- bncconnection.send(":%s 317 %s %s %d %d :%s\n" % (origin, IRC.identity.nick, nickname, idletime, signontime, msg))
- except socket.error:
- pass
+ bncconnection.send(":%s 317 %s %s %d %d :%s\n" %
+ (origin, IRC.identity.nick, nickname, idletime, signontime, msg))
def onWhoisSSL(self, IRC, origin, user, nickname, msg):
if len(self.whoisexpected[IRC]) and self.whoisexpected[IRC][0] in self.connections:
bncconnection = self.whoisexpected[IRC][0]
- try:
- bncconnection.send(":%s 671 %s %s :%s\n" % (
- origin, IRC.identity.nick, nickname, msg))
- except socket.error:
- pass
+ bncconnection.send(":%s 671 %s %s :%s\n" %
+ (origin, IRC.identity.nick, nickname, msg))
def onWhoisModes(self, IRC, origin, user, nickname, msg):
if len(self.whoisexpected[IRC]) and self.whoisexpected[IRC][0] in self.connections:
bncconnection = self.whoisexpected[IRC][0]
- try:
- bncconnection.send(":%s 339 %s %s :%s\n" % (
- origin, IRC.identity.nick, nickname, msg))
- except socket.error:
- pass
+ bncconnection.send(":%s 339 %s %s :%s\n" %
+ (origin, IRC.identity.nick, nickname, msg))
def onWhoisLoggedInAs(self, IRC, origin, user, nickname, loggedinas, msg):
if len(self.whoisexpected[IRC]) and self.whoisexpected[IRC][0] in self.connections:
bncconnection = self.whoisexpected[IRC][0]
- try:
- bncconnection.send(":%s 330 %s %s %s :%s\n" % (origin, IRC.identity.nick, nickname, loggedinas, msg))
- except socket.error:
- pass
+ bncconnection.send(":%s 330 %s %s %s :%s\n" %
+ (origin, IRC.identity.nick, nickname, loggedinas, msg))
def onWhoisEnd(self, IRC, origin, user, nickname, msg):
if len(self.whoisexpected[IRC]) and self.whoisexpected[IRC][0] in self.connections:
bncconnection = self.whoisexpected[IRC][0]
- try:
- bncconnection.send(":%s 318 %s %s :%s\n" % (
- origin, IRC.identity.nick, nickname, msg))
- except socket.error:
- pass
- finally:
- del self.whoisexpected[IRC][0]
+ bncconnection.send(":%s 318 %s %s :%s\n" %
+ (origin, IRC.identity.nick, nickname, msg))
+ del self.whoisexpected[IRC][0]
def onUnhandled(self, IRC, line, origin, cmd, target, params, extinfo):
for bouncerconnection in self.connections:
if bouncerconnection.IRC == IRC:
- bouncerconnection.send("%s\n"%line)
+ bouncerconnection.send("%s\n" % line)
class BouncerConnection (Thread):
+
def __init__(self, bouncer, connection, addr, debug=False):
- #print "Initializing ListenThread..."
+ # print "Initializing ListenThread..."
self.bouncer = bouncer
self.connection = connection
self.host, self.port = self.addr = addr[:2]
@@ -371,7 +411,8 @@ class BouncerConnection (Thread):
self.connection.send(data)
except socket.error:
exc, excmsg, tb = sys.exc_info()
- print >>self.IRC.logwrite(*["!!! [BouncerConnection.send] Exception in thread %(self)s" % vars()]+["!!! [BouncerConnection.send] %(tbline)s" % vars() for tbline in traceback.format_exc().split("\n")])
+ print >>self.IRC.logwrite(*["!!! [BouncerConnection.send] Exception in thread %(self)s" % vars()] + [
+ "!!! [BouncerConnection.send] %(tbline)s" % vars() for tbline in traceback.format_exc().split("\n")])
self.quit(quitmsg=excmsg.message)
def __repr__(self):
@@ -401,18 +442,19 @@ class BouncerConnection (Thread):
self.quitmsg = quitmsg
with self.lock:
try:
- self.connection.send("ERROR :Closing link: (%s@%s) [%s]\n" % (self.IRC.identity.nick if self.IRC else "*", self.host, quitmsg))
+ self.connection.send("ERROR :Closing link: (%s@%s) [%s]\n" % (
+ self.IRC.identity.nick if self.IRC else "*", self.host, quitmsg))
except:
pass
try:
- self.connection.shutdown(1)
+ self.connection.shutdown(socket.SHUT_WR)
self.connection.close()
except:
pass
self.quitting = True
def run(self):
- ### Name loopup should happen here instead
+ # Name loopup should happen here instead
ipv4match = re.findall(
r"^::ffff:((\d+)\.(\d+)\.(\d+)\.(\d+))$", self.host)
if self.bouncer.ipv6 and ipv4match:
@@ -428,7 +470,7 @@ class BouncerConnection (Thread):
except:
pass
- ### Add connection to connection list.
+ # Add connection to connection list.
listnumerics = dict(b=(367, 368, "channel ban list"),
e=(348, 349, "Channel Exception List"),
@@ -447,7 +489,8 @@ class BouncerConnection (Thread):
try:
while True:
- ### Read data (appending) into readbuf, then break lines and append lines to linebuf
+ # Read data (appending) into readbuf, then break lines and
+ # append lines to linebuf
while len(linebuf) == 0:
timestamp = irc.timestamp()
read = self.connection.recv(512)
@@ -460,10 +503,11 @@ class BouncerConnection (Thread):
if lastlf >= 0:
linebuf.extend(string.split(readbuf[0:lastlf], "\n"))
- readbuf = readbuf[lastlf+1:]
+ readbuf = readbuf[lastlf + 1:]
line = string.rstrip(linebuf.pop(0))
- match = re.findall("^(.+?)(?:\\s+(.+?)(?:\\s+(.+?))??)??(?:\\s+:(.*))?$", line, re.I)
+ match = re.findall(
+ "^(.+?)(?:\\s+(.+?)(?:\\s+(.+?))??)??(?:\\s+:(.*))?$", line, re.I)
if len(match) == 0:
continue
@@ -474,146 +518,165 @@ class BouncerConnection (Thread):
passwd = target if target else extinfo
else:
self.quit("Access Denied")
+ print "*** [BouncerConnection] Incoming connection from %s failed: Expected PASS." % (self.host)
break
- elif not nick: # Bouncer expects a NICK command
+ elif not self.nick: # Bouncer expects a NICK command
if cmd.upper() == "NICK":
- nick = target if target else extinfo
+ self.nick = target if target else extinfo
else:
self.quit("Access Denied")
+ print "*** [BouncerConnection] Incoming connection from %s failed: Expected NICK." % (self.host)
break
elif not self.username: # Bouncer expects a USER command to finish registration
if cmd.upper() == "USER":
self.username = target
- #print self.username
+ # print self.username
if self.username in self.bouncer.servers.keys():
- self.IRC, passwdhash, hashtype = self.bouncer.servers[self.username]
- passmatch = hashlib.new(hashtype, passwd).hexdigest() == passwdhash
+ self.IRC, passwdhash, hashtype = self.bouncer.servers[
+ self.username]
+ passmatch = hashlib.new(
+ hashtype, passwd).hexdigest() == passwdhash
with self.IRC.lock:
- self.IRC.logwrite("*** [BouncerConnection] Incoming connection from %s to %s." % (self.host, self.IRC))
+ if not passmatch:
+ self.quit("Access Denied")
+ self.IRC.logwrite(
+ "*** [BouncerConnection] Incoming connection from %s to %s denied: Invalid password." % (self.host, self.IRC))
+ for bouncerconnection in self.bouncer.connections:
+ if bouncerconnection.IRC != self.IRC:
+ continue
+ if not bouncerconnection.quitting:
+ bouncerconnection.send(":*Bouncer* NOTICE %s :Incoming connection from %s to %s dened: Invalid password.\n" % (
+ bouncerconnection.IRC.identity.nick, self.host, self.IRC))
+ break
+
+ self.IRC.logwrite(
+ "*** [BouncerConnection] Incoming connection from %s to %s." % (self.host, self.IRC))
with self.bouncer.lock:
- ### Announce connection to all other bouncer connections.
- if self.debug:
- self.IRC.logwrite("dbg [BouncerConnection] Attempting to broadcast incoming connection %(self)s." % vars())
+ # Announce connection to all other bouncer
+ # connections.
for bouncerconnection in self.bouncer.connections:
if bouncerconnection.IRC != self.IRC:
continue
- if self.debug:
- self.IRC.logwrite("dbg [BouncerConnection] Broadcasting to %(bouncerconnection)s." % vars())
if not bouncerconnection.quitting:
- bouncerconnection.send(":*Bouncer* NOTICE %s :Incoming connection from %s to %s\n" % (bouncerconnection.IRC.identity.nick, self.host, self.IRC))
- if self.debug:
- self.IRC.logwrite("dbg [BouncerConnection] Success: %(bouncerconnection)s." % vars())
- if len([bncconnection for bncconnection in self.bouncer.connections if bncconnection.IRC == self.IRC]) == 0 and self.IRC.identity.away:
- ### Bouncer connection should automatically return from away status.
+ bouncerconnection.send(":*Bouncer* NOTICE %s :Incoming connection from %s to %s\n" % (
+ bouncerconnection.IRC.identity.nick, self.host, self.IRC))
+ if len([bncconnection for bncconnection in self.bouncer.connections if bncconnection.IRC == self.IRC]) == 0 and self.IRC.registered and type(self.IRC.identity) == irc.User and self.IRC.identity.away:
+ # Bouncer connection should
+ # automatically return from away
+ # status.
self.IRC.raw("AWAY")
self.bouncer.connections.append(self)
- if not (self.IRC.connected and self.IRC.registered and type(self.IRC.supports) == dict and "CHANMODES" in self.IRC.supports.keys() and passmatch):
- self.quit("Access Denied")
- break
-
- ### If we have made it to this point, then access has been granted.
- labels = [bouncerconnection.label for bouncerconnection in self.bouncer.connections if bouncerconnection.IRC == self.IRC and bouncerconnection.label]
- n = 1
- while "*%s_%d"%(self.username, n) in labels:
- n += 1
- self.label = "*%s_%d"%(self.username, n)
-
- ### Request Version info.
- #self.connection.send(":$bouncer PRIVMSG %s :\x01VERSION\x01\n" % (self.IRC.identity.nick))
-
- ### Log incoming connection
-
- ### Send Greeting.
- with self.lock:
- self.connection.send(":%s 001 %s :%s\n" % (self.IRC.serv, self.IRC.identity.nick, self.IRC.welcome))
- self.connection.send(":%s 002 %s :%s\n" % (self.IRC.serv, self.IRC.identity.nick, self.IRC.hostinfo))
- self.connection.send(":%s 003 %s :%s\n" % (self.IRC.serv, self.IRC.identity.nick, self.IRC.servcreated))
- self.connection.send(":%s 004 %s %s\n" % (self.IRC.serv, self.IRC.identity.nick, self.IRC.servinfo))
-
- ### Send 005 response.
- supports = ["CHANMODES=%s"%(",".join(value)) if name == "CHANMODES" else "PREFIX=(%s)%s"%value if name == "PREFIX" else "%s=%s"%(name, value) if value else name for name, value in self.IRC.supports.items()]
- supports.sort()
- supportsreply = []
- supportsstr = " ".join(supports)
- index = 0
- while True:
- if len(supportsstr)-index > 196:
- nextindex = supportsstr.rfind(" ", index, index+196)
- supportsreply.append(supportsstr[index:nextindex])
- index = nextindex+1
+ if self.IRC.registered:
+ # Send Greeting.
+ with self.lock:
+ if self.IRC.welcome:
+ self.connection.send(":%s 001 %s :%s\n" % (
+ self.IRC.serv, self.IRC.identity.nick, self.IRC.welcome))
+ if self.IRC.hostinfo:
+ self.connection.send(":%s 002 %s :%s\n" % (
+ self.IRC.serv, self.IRC.identity.nick, self.IRC.hostinfo))
+ if self.IRC.servcreated:
+ self.connection.send(":%s 003 %s :%s\n" % (
+ self.IRC.serv, self.IRC.identity.nick, self.IRC.servcreated))
+ if self.IRC.servinfo:
+ self.connection.send(":%s 004 %s %s\n" % (
+ self.IRC.serv, self.IRC.identity.nick, self.IRC.servinfo))
+
+ # Send 005 response.
+ if self.IRC.supports:
+ supports = ["CHANMODES=%s" % (",".join(value)) if name == "CHANMODES" else "PREFIX=(%s)%s" % value if name == "PREFIX" else "%s=%s" % (
+ name, value) if value else name for name, value in self.IRC.supports.items()]
+ supports.sort()
+ supportsreply = []
+ supportsstr = " ".join(supports)
+ index = 0
+ while True:
+ if len(supportsstr) - index > 196:
+ nextindex = supportsstr.rfind(
+ " ", index, index + 196)
+ supportsreply.append(
+ supportsstr[index:nextindex])
+ index = nextindex + 1
+ else:
+ supportsreply.append(
+ supportsstr[index:])
+ break
+ for support in supportsreply:
+ self.connection.send(":%s 005 %s %s :are supported by this server\n" % (
+ self.IRC.serv, self.IRC.identity.nick, support))
+
+ # Send MOTD
+ if self.IRC.motdgreet and self.IRC.motd and self.IRC.motdend:
+ self.connection.send(":%s 375 %s :%s\n" % (
+ self.IRC.serv, self.IRC.identity.nick, self.IRC.motdgreet))
+ for motdline in self.IRC.motd:
+ self.connection.send(":%s 372 %s :%s\n" % (
+ self.IRC.serv, self.IRC.identity.nick, motdline))
+ try:
+ self.connection.send(":%s 376 %s :%s\n" % (
+ self.IRC.serv, self.IRC.identity.nick, self.IRC.motdend))
+ except AttributeError:
+ self.connection.send(
+ ":%s 376 %s\n" % (self.IRC.serv, self.IRC.identity.nick))
else:
- supportsreply.append(supportsstr[index:])
- break
- for support in supportsreply:
- self.connection.send(":%s 005 %s %s :are supported by this server\n" % (self.IRC.serv, self.IRC.identity.nick, support))
-
- ### Send MOTD
- if self.IRC.motdgreet and self.IRC.motd and self.IRC.motdend:
- self.connection.send(":%s 375 %s :%s\n" % (self.IRC.serv, self.IRC.identity.nick, self.IRC.motdgreet))
- for motdline in self.IRC.motd:
- self.connection.send(":%s 372 %s :%s\n" % (self.IRC.serv, self.IRC.identity.nick, motdline))
- try:
- self.connection.send(":%s 376 %s :%s\n" % (self.IRC.serv, self.IRC.identity.nick, self.IRC.motdend))
- except AttributeError:
- self.connection.send(":%s 376 %s\n" % (self.IRC.serv, self.IRC.identity.nick))
- else:
- self.connection.send(":%s 422 %s :MOTD File is missing\n" % (self.IRC.serv, self.IRC.identity.nick))
-
- ### Send user modes and snomasks.
- self.connection.send(":%s 221 %s +%s\n" % (self.IRC.serv, self.IRC.identity.nick, self.IRC.identity.modes))
- if "s" in self.IRC.identity.modes and self.IRC.identity.snomask:
- self.connection.send(":%s 008 %s +%s :Server notice mask\n" % (self.IRC.server, self.IRC.identity.nick, self.IRC.identity.snomask))
-
- # ### Join user to internal bouncer channel.
- # self.connection.send(":%s!%s@%s JOIN :$bouncer\n" % (self.IRC.identity.nick, self.IRC.identity.username, self.IRC.identity.host))
-
- # ### Set internal bouncer topic.
- # self.connection.send(":$bouncer 332 %s $bouncer :Bouncer internal channel. Enter bouncer commands here.\n" % (self.IRC.identity.nick))
- # self.connection.send(":$bouncer 333 %s $bouncer $bouncer %s\n" % (self.IRC.identity.nick, self.bouncer.starttime))
-
- # ### Send NAMES for internal bouncer channel.
- # self.connection.send(":$bouncer 353 %s @ $bouncer :%s\n" % (
- # self.IRC.identity.nick,
- # string.join(["@*Bouncer*"]+["@%s"%bouncerconnection.label for bouncerconnection in self.bouncer.connections]))
- # )
- # self.connection.send(":$bouncer 366 %s $bouncer :End of /NAMES list.\n" % (self.IRC.identity.nick))
-
- # ### Give operator mode to user.
- # self.connection.send(":*Bouncer* MODE $bouncer +o %s\n" % (self.IRC.identity.nick))
-
- ### Join user to channels.
- for channel in self.IRC.identity.channels:
- ### JOIN command
- self.connection.send(":%s!%s@%s JOIN :%s\n" % (self.IRC.identity.nick, self.IRC.identity.username, self.IRC.identity.host, channel.name))
-
- ### Topic
- self.connection.send(":%s 332 %s %s :%s\n" % (self.IRC.serv, self.IRC.identity.nick, channel.name, channel.topic))
- self.connection.send(":%s 333 %s %s %s %s\n" % (self.IRC.serv, self.IRC.identity.nick, channel.name, channel.topicsetby, channel.topictime))
-
- ### Determine if +s or +p modes are set in channel
- secret = "s" in channel.modes.keys() and channel.modes["s"]
- private = "p" in channel.modes.keys() and channel.modes["p"]
-
- ### Construct NAMES for channel.
- namesusers = []
- modes, symbols = self.IRC.supports["PREFIX"]
- self.connection.send(":%s 353 %s %s %s :%s\n" % (
- self.IRC.serv,
- self.IRC.identity.nick,
- "@" if secret else ("*" if private else "="),
- channel.name,
- string.join([string.join([symbols[k] if modes[k] in channel.modes.keys() and user in channel.modes[modes[k]] else "" for k in xrange(len(modes))], "")+user.nick for user in channel.users]))
- )
- self.connection.send(":%s 366 %s %s :End of /NAMES list.\n" % (self.IRC.serv, self.IRC.identity.nick, channel.name))
-
+ self.connection.send(
+ ":%s 422 %s :MOTD File is missing\n" % (self.IRC.serv, self.IRC.identity.nick))
+
+ # Send user modes and snomasks.
+ self.connection.send(":%s 221 %s +%s\n" % (
+ self.IRC.serv, self.IRC.identity.nick, self.IRC.identity.modes))
+
+ if "s" in self.IRC.identity.modes and self.IRC.identity.snomask:
+ self.connection.send(":%s 008 %s +%s :Server notice mask\n" % (
+ self.IRC.serv, self.IRC.identity.nick, self.IRC.identity.snomask))
+
+ # Join user to channels.
+ for channel in self.IRC.identity.channels:
+ # JOIN command
+ self.connection.send(":%s!%s@%s JOIN :%s\n" % (
+ self.IRC.identity.nick, self.IRC.identity.username, self.IRC.identity.host, channel.name))
+
+ # Topic
+ self.connection.send(":%s 332 %s %s :%s\n" % (
+ self.IRC.serv, self.IRC.identity.nick, channel.name, channel.topic))
+ self.connection.send(":%s 333 %s %s %s %s\n" % (self.IRC.serv, self.IRC.identity.nick, channel.name, channel.topicsetby.nick if type(
+ channel.topicsetby) == irc.User else channel.topicsetby, channel.topictime))
+
+ # Determine if +s or +p modes are
+ # set in channel
+ secret = "s" in channel.modes.keys() and channel.modes[
+ "s"]
+ private = "p" in channel.modes.keys(
+ ) and channel.modes["p"]
+
+ # Construct NAMES for channel.
+ namesusers = []
+ modes, symbols = self.IRC.supports[
+ "PREFIX"]
+ self.connection.send(":%s 353 %s %s %s :%s\n" % (
+ self.IRC.serv,
+ self.IRC.identity.nick,
+ "@" if secret else (
+ "*" if private else "="),
+ channel.name,
+ string.join([string.join([symbols[k] if modes[k] in channel.modes.keys() and user in channel.modes[modes[k]] else "" for k in xrange(len(modes))], "") + user.nick for user in channel.users]))
+ )
+ self.connection.send(":%s 366 %s %s :End of /NAMES list.\n" % (
+ self.IRC.serv, self.IRC.identity.nick, channel.name))
+ else:
+ self.send(
+ ":*Bouncer* NOTICE %s :Not connected to server. Type /bncconnect to attempt connection.\n" % self.nick)
+ self.send(":%s 001 %s :Welcome to the Bouncer IRC Network %s!%s@%s\n" % (
+ "*Bouncer*", self.nick, self.nick, self.username, self.host))
else: # User not found
self.quit("Access Denied")
break
else: # Client did not send USER command when expected
self.quit("Access Denied")
+ print "*** [BouncerConnection] Incoming connection from %s failed: Expected USER." % (self.host)
break
elif cmd.upper() == "QUIT":
@@ -621,60 +684,98 @@ class BouncerConnection (Thread):
break
elif cmd.upper() == "PING":
- self.send(":%s PONG %s :%s\n" % (self.IRC.serv, self.IRC.serv, self.IRC.identity.nick))
-
- elif cmd.upper() in ("PRIVMSG", "NOTICE"):
- ### Check if CTCP
- ctcp = re.findall("^\x01(.*?)(?:\\s+(.*?)\\s*)?\x01$",
- extinfo)
-
- if ctcp: # If CTCP, only want to
- (ctcptype, ext) = ctcp[0] # Unpack CTCP info
-
- if ctcptype == "LAGCHECK": # Client is doing a lag check. No need to send to IRC network, just reply back.
- self.send(":%s!%s@%s %s\n" % (self.IRC.identity.nick, self.IRC.identity.username, self.IRC.identity.host, line))
+ self.send(":%s PONG %s :%s\n" %
+ (self.IRC.serv, self.IRC.serv, self.IRC.identity.nick if type(self.IRC.identity) == irc.User else "***"))
+
+ elif cmd.upper() == "BNCCONNECT":
+ with self.IRC.lock:
+ if self.IRC.isAlive() and self.IRC.connected:
+ self.send(
+ ":*Bouncer* NOTICE %s :Bouncer is already connected.\n" % self.nick)
else:
- self.IRC.raw(line, origin=self)
- else:
- self.IRC.raw(line, origin=self)
-
- elif cmd.upper() == "MODE": # Will want to determine is requesting modes, or attempting to modify modes.
- if target and "CHANTYPES" in self.IRC.supports.keys() and target[0] in self.IRC.supports["CHANTYPES"]:
- if params == "":
- channel = self.IRC.channel(target)
- modes = channel.modes.keys()
- modestr = "".join([mode for mode in modes if mode not in self.IRC.supports["CHANMODES"][0]+self.IRC.supports["PREFIX"][0] and channel.modes[mode]])
- params = " ".join([channel.modes[mode] for mode in modes if mode in self.IRC.supports["CHANMODES"][1]+self.IRC.supports["CHANMODES"][2] and channel.modes[mode]])
- with self.lock:
- if len(modestr):
- self.connection.send(":%s 324 %s %s +%s %s\n" % (self.IRC.serv, self.IRC.identity.nick, channel.name, modestr, params))
- if channel.created:
- self.connection.send(":%s 329 %s %s %s\n" % (self.IRC.serv, self.IRC.identity.nick, channel.name, channel.created))
- elif re.match("^\\+?[%s]+$"%self.IRC.supports["CHANMODES"][0], params) and extinfo == "":
- #print "ddd Mode List Request", params
- channel = self.IRC.channel(target)
- redundant = []
- for mode in params.lstrip("+"):
- if mode in redundant or mode not in listnumerics.keys():
- continue
- i, e, l = listnumerics[mode]
+ self.IRC.start()
+
+ elif cmd.upper() == "BNCQUIT":
+ with self.IRC.lock:
+ if self.IRC.isAlive() and self.IRC.connected and self.IRC.registered:
+ quitmsg = " ".join(
+ [word for word in [target, params, extinfo] if word])
+ self.IRC.quit(quitmsg)
+ else:
+ self.send(
+ ":*Bouncer* NOTICE %s :Bouncer is already disconnected.\n" % self.nick)
+
+ else:
+ with self.IRC.lock:
+ if not self.IRC.connected:
+ self.send(
+ ":*Bouncer* NOTICE %s :Not connected to server. Type /bncconnect to attempt connection.\n" % self.nick)
+ break
+ elif not self.IRC.registered:
+ self.send(
+ ":*Bouncer* NOTICE %s :Not registered.\n" % self.nick)
+ break
+ elif cmd.upper() in ("PRIVMSG", "NOTICE"):
+ # Check if CTCP
+ ctcp = re.findall(
+ "^\x01(.*?)(?:\\s+(.*?)\\s*)?\x01$", extinfo)
+
+ if ctcp: # If CTCP, only want to
+ (ctcptype, ext) = ctcp[0] # Unpack CTCP info
+
+ if ctcptype == "LAGCHECK": # Client is doing a lag check. No need to send to IRC network, just reply back.
+ self.send(":%s!%s@%s %s\n" % (
+ self.IRC.identity.nick, self.IRC.identity.username, self.IRC.identity.host, line))
+ else:
+ self.IRC.raw(line, origin=self)
+ else:
+ self.IRC.raw(line, origin=self)
+
+ elif cmd.upper() == "MODE": # Will want to determine is requesting modes, or attempting to modify modes.
+ if target and "CHANTYPES" in self.IRC.supports.keys() and target[0] in self.IRC.supports["CHANTYPES"]:
+ if params == "":
+ channel = self.IRC.channel(target)
+ modes = channel.modes.keys()
+ modestr = "".join([mode for mode in modes if mode not in self.IRC.supports[
+ "CHANMODES"][0] + self.IRC.supports["PREFIX"][0] and channel.modes[mode]])
+ params = " ".join([channel.modes[mode] for mode in modes if mode in self.IRC.supports[
+ "CHANMODES"][1] + self.IRC.supports["CHANMODES"][2] and channel.modes[mode]])
+ with self.lock:
+ if len(modestr):
+ self.connection.send(":%s 324 %s %s +%s %s\n" % (
+ self.IRC.serv, self.IRC.identity.nick, channel.name, modestr, params))
+ if channel.created:
+ self.connection.send(":%s 329 %s %s %s\n" % (
+ self.IRC.serv, self.IRC.identity.nick, channel.name, channel.created))
+ elif re.match("^\\+?[%s]+$" % self.IRC.supports["CHANMODES"][0], params) and extinfo == "":
+ # print "ddd Mode List Request", params
+ channel = self.IRC.channel(target)
+ redundant = []
+ for mode in params.lstrip("+"):
+ if mode in redundant or mode not in listnumerics.keys():
+ continue
+ i, e, l = listnumerics[mode]
+ with self.lock:
+ if mode in channel.modes.keys():
+ for (mask, setby, settime) in channel.modes[mode]:
+ self.connection.send(":%s %d %s %s %s %s %s\n" % (
+ self.IRC.serv, i, channel.context.identity.nick, channel.name, mask, setby, settime))
+ self.connection.send(":%s %d %s %s :End of %s\n" % (
+ self.IRC.serv, e, channel.context.identity.nick, channel.name, l))
+ redundant.append(mode)
+ else:
+ self.IRC.raw(line, origin=self)
+ elif params == "" and target.lower() == self.IRC.identity.nick.lower():
with self.lock:
- if mode in channel.modes.keys():
- for (mask, setby, settime) in channel.modes[mode]:
- self.connection.send(":%s %d %s %s %s %s %s\n" % (self.IRC.serv, i, channel.context.identity.nick, channel.name, mask, setby, settime))
- self.connection.send(":%s %d %s %s :End of %s\n" % (self.IRC.serv, e, channel.context.identity.nick, channel.name, l))
- redundant.append(mode)
+ self.connection.send(":%s 221 %s +%s\n" % (
+ self.IRC.serv, self.IRC.identity.nick, self.IRC.identity.modes))
+ if "s" in self.IRC.identity.modes and self.IRC.identity.snomask:
+ self.connection.send(":%s 008 %s +%s :Server notice mask\n" % (
+ self.IRC.serv, self.IRC.identity.nick, self.IRC.identity.snomask))
+ else:
+ self.IRC.raw(line, origin=self)
else:
self.IRC.raw(line, origin=self)
- elif params == "" and target.lower() == self.IRC.identity.nick.lower():
- with self.lock:
- self.connection.send(":%s 221 %s +%s\n" % (self.IRC.serv, self.IRC.identity.nick, self.IRC.identity.modes))
- if "s" in self.IRC.identity.modes and self.IRC.identity.snomask:
- self.connection.send(":%s 008 %s +%s :Server notice mask\n" % (self.IRC.serv, self.IRC.identity.nick, self.IRC.identity.snomask))
- else:
- self.IRC.raw(line, origin=self)
- else:
- self.IRC.raw(line, origin=self)
except SystemExit:
pass # No need to pass error message if break resulted from sys.exit()
@@ -683,9 +784,10 @@ class BouncerConnection (Thread):
self.quitmsg = str(excmsg)
if self.IRC:
exc, excmsg, tb = sys.exc_info()
- self.IRC.logwrite(*["!!! [BouncerConnection] Exception in thread %(self)s" % vars()]+["!!! [BouncerConnection] %(tbline)s" % vars() for tbline in traceback.format_exc().split("\n")])
+ self.IRC.logwrite(*["!!! [BouncerConnection] Exception in thread %(self)s" % vars()] + [
+ "!!! [BouncerConnection] %(tbline)s" % vars() for tbline in traceback.format_exc().split("\n")])
finally:
- ### Juuuuuuust in case.
+ # Juuuuuuust in case.
with self.lock:
try:
self.connection.shutdown(1)
@@ -694,28 +796,33 @@ class BouncerConnection (Thread):
pass
if self.IRC:
- self.IRC.logwrite("*** [BouncerConnection] Connection from %s terminated (%s)." % (self.host, self.quitmsg))
+ self.IRC.logwrite(
+ "*** [BouncerConnection] Connection from %s terminated (%s)." % (self.host, self.quitmsg))
if self in self.bouncer.connections:
with self.bouncer.lock:
self.bouncer.connections.remove(self)
- if self.IRC.connected and self.IRC.identity and len([bncconnection for bncconnection in self.bouncer.connections if bncconnection.IRC == self.IRC]) == 0 and not self.IRC.identity.away and self.bouncer.autoaway:
- ### Bouncer automatically sets away status.
- self.IRC.raw("AWAY :%s"%self.bouncer.autoaway)
+ if self.IRC.connected and self.IRC.identity and len([bncconnection for bncconnection in self.bouncer.connections if bncconnection.IRC == self.IRC]) == 0 and self.IRC.registered and type(self.IRC.identity) == irc.User and not self.IRC.identity.away and self.bouncer.autoaway:
+ # Bouncer automatically sets away status.
+ self.IRC.raw("AWAY :%s" % self.bouncer.autoaway)
if self.debug:
- self.IRC.logwrite("dbg [BouncerConnection] Attempting to broadcast terminated connection %(self)s." % vars())
+ self.IRC.logwrite(
+ "dbg [BouncerConnection] Attempting to broadcast terminated connection %(self)s." % vars())
for bouncerconnection in self.bouncer.connections:
if bouncerconnection.IRC == self.IRC:
if self.debug:
- self.IRC.logwrite("dbg [BouncerConnection] Broadcasting to %(bouncerconnection)s." % vars())
+ self.IRC.logwrite(
+ "dbg [BouncerConnection] Broadcasting to %(bouncerconnection)s." % vars())
if not bouncerconnection.quitting:
- bouncerconnection.connection.send(":*Bouncer* NOTICE %s :Connection from %s to %s terminated (%s)\n" % (bouncerconnection.IRC.identity.nick, self.host, self.IRC, self.quitmsg))
+ bouncerconnection.connection.send(":*Bouncer* NOTICE %s :Connection from %s to %s terminated (%s)\n" % (
+ bouncerconnection.IRC.identity.nick, self.host, self.IRC, self.quitmsg))
if self.debug:
- self.IRC.logwrite("dbg [BouncerConnection] Success: %(bouncerconnection)s." % vars())
-
-# ### Announce QUIT to other bouncer connections.
-# for bouncerconnection in self.bouncer.connections:
-# try:
-# bouncerconnection.connection.send(":%s!%s@%s QUIT :%s\n" % (self.label, self.username, self.host, self.quitmsg))
-# except:
-# pass
+ self.IRC.logwrite(
+ "dbg [BouncerConnection] Success: %(bouncerconnection)s." % vars())
+
+# Announce QUIT to other bouncer connections.
+# for bouncerconnection in self.bouncer.connections:
+# try:
+# bouncerconnection.connection.send(":%s!%s@%s QUIT :%s\n" % (self.label, self.username, self.host, self.quitmsg))
+# except:
+# pass
diff --git a/irc.py b/irc.py
index e5e4448..e542ae5 100644
--- a/irc.py
+++ b/irc.py
@@ -1,5 +1,5 @@
#!/usr/bin/python
-from threading import Thread, Condition, Lock
+from threading import Thread, Condition, Lock, currentThread
import re
import time
import sys
@@ -10,6 +10,7 @@ import platform
import traceback
import ssl
import glob
+from collections import deque
import iqueue as Queue
@@ -105,6 +106,10 @@ class AlreadyJoined(BaseException):
pass
+class AlreadyConnected(BaseException):
+ pass
+
+
class RegistrationRequired(BaseException):
pass
@@ -115,102 +120,164 @@ class RejoinDelay(BaseException):
_rfc1459casemapping = string.maketrans(string.ascii_uppercase + r'\[]~',
string.ascii_lowercase + r'|{}^')
-exceptcodes = {489: SSLOnly, 384: Cbaned, 403: NoSuchChannel, 405: TooManyChannels, 442: NotOnChannel, 470: RedirectedJoin, 471: ChannelFull, 473: InviteOnly, 474: BannedFromChannel, 475: BadChannelKey, 476: BadChannelMask, 520: OpersOnly, 437: Unavailable, 477: RegistrationRequired, 495: RejoinDelay, 530: OperCreateOnly}
+# The IRC RFC does not permit the first character in a nickname to be a
+# numeral. However, this is not always adhered to.
+_nickmatch = r"^[A-Za-z0-9\-\^\`\\\|\_\{\}\[\]]+$"
+
+_intmatch = r"^\d+$"
+_chanmatch = r"^[%%s][^%s\s\n]*$" % re.escape("\x07,")
+_targchanmatch = r"^([%%s]?)([%%s][^%s\s\n]*)$" % re.escape("\x07,")
+_usermatch = r"^[A-Za-z0-9\-\^\`\\\|\_\{\}\[\]]+$"
+_realnamematch = r"^[^\n]*$"
+_ircrecvmatch = r"^:(.+?)(?:!(.+?)@(.+?))?\s+(.+?)(?:\s+(.+?)(?:\s+(.+?))??)??(?:\s+:(.*))?$"
+_ircsendmatch = r"^(.+?)(?:\s+(.+?)(?:\s+(.+?))??)??(?:\s+:(.*))?$"
+_ctcpmatch = "^\x01(.*?)(?:\\s+(.*?)\\s*)?\x01$"
+_prefixmatch = r"\((.*)\)(.*)"
+
+_privmodeeventnames = dict(q=("Owner", "Deowner"), a=("Admin", "Deadmin"), o=(
+ "Op", "Deop"), h=("Halfop", "Dehalfop"), v=("Voice", "Devoice"))
+_maskmodeeventnames = dict(b=("Ban", "Unban"), e=(
+ "BanExcept", "UnbanExcept"), I=("Invite", "Uninvite"))
+
+exceptcodes = {489: SSLOnly, 384: Cbaned, 403: NoSuchChannel, 405: TooManyChannels, 442: NotOnChannel, 470: RedirectedJoin, 471: ChannelFull, 473: InviteOnly, 474:
+ BannedFromChannel, 475: BadChannelKey, 476: BadChannelMask, 520: OpersOnly, 437: Unavailable, 477: RegistrationRequired, 495: RejoinDelay, 530: OperCreateOnly}
def timestamp():
t = time.time()
- ms = 1000*t%1000
+ ms = 1000 * t % 1000
ymdhms = time.localtime(t)
tz = time.altzone if ymdhms.tm_isdst else time.timezone
sgn = "-" if tz >= 0 else "+"
- return "%04d-%02d-%02d %02d:%02d:%02d.%03d%s%02d:%02d"%(ymdhms[:6]+(1000*t%1000, sgn, abs(tz)/3600, abs(tz)/60%60))
+ return "%04d-%02d-%02d %02d:%02d:%02d.%03d%s%02d:%02d" % (ymdhms[:6] + (1000 * t % 1000, sgn, abs(tz) / 3600, abs(tz) / 60 % 60))
+
+class Connection(object):
-class Connection(Thread):
def __init__(self, server, nick="ircbot", username="python", realname="Python IRC Library", passwd=None, port=None, ipv6=False, ssl=False, autoreconnect=True, log=sys.stderr, timeout=300, retrysleep=5, maxretries=15, onlogin=None):
self.__name__ = "pyIRC"
- self.__version__ = "1.1"
+ self.__version__ = "1.2"
self.__author__ = "Brian Sherson"
- self.__date__ = "December 1, 2013"
+ self.__date__ = "December 28, 2013"
- if port is None:
+ if port == None:
self.port = 6667 if not ssl else 6697
else:
self.port = port
if type(nick) in (str, unicode):
- self.nick = [nick]
+ if re.match(_nickmatch, nick):
+ self.nick = [nick]
+ else:
+ raise InvalidCharacter
elif type(nick) in (list, tuple):
- self.nick = nick
+ if all([re.match(_nickmatch, n) for n in nick]):
+ self.nick = nick
+ else:
+ raise InvalidCharacter
+
+ if re.match(_realnamematch, realname):
+ self.realname = realname
+ else:
+ raise InvalidCharacter
+
+ if re.match(_usermatch, username):
+ self.username = username
+ else:
+ raise InvalidCharacter
+
+ if passwd == None or "\n" not in passwd:
+ self.passwd = passwd
+ else:
+ raise InvalidCharacter
- self.realname = realname
- self.username = username
- self.passwd = passwd
self.server = server
self.ssl = ssl
self.ipv6 = ipv6
- self.connected = False
- self.registered = False
- self.connection = None
-
self.autoreconnect = autoreconnect
self.maxretries = maxretries
self.timeout = timeout
self.retrysleep = retrysleep
- self.quitexpected = False
+ self._quitexpected = False
self.log = log
self.addons = []
- self.trusted = []
+ self.trusted = [] # To be implemented later
+
+ self.lock = Lock()
+
+ self._loglock = Lock()
+ self._outlock = Lock()
+ self._sendline = Condition(self._outlock)
+ self._outgoing = deque()
+
+ self._sendhandlerthread = None
+ self._recvhandlerthread = None
+
+ # Initialize IRC environment variables
+ self._init()
+
+ def _init(self):
+ self._connected = False
+ self._registered = False
+ self._connection = None
+ self.trynick = 0
- ### Initialize IRC environment variables
- self.motdgreet = None
- self.motd = None
- self.motdend = None
self.identity = None
self.users = []
self.channels = []
+
+ self.motdgreet = None
+ self.motd = None
+ self.motdend = None
+
+ self.serv = None
+ self.welcome = None
+ self.hostinfo = None
+ self.servcreated = None
+ self.servinfo = None
+ self.serv005 = None
self.supports = {}
+ self.throttledata = []
+ self.throttled = False
- self.lock = Lock()
- self._linereceived = Condition(self.lock)
- self.loglock = Lock()
- self.sendlock = Lock()
- self.outgoing = Queue.Queue()
- self.outgoingthread = None
+ @property
+ def connected(self):
+ return self._connected
- Thread.__init__(self)
+ @property
+ def registered(self):
+ return self._registered
def logwrite(self, *lines):
- with self.loglock:
+ with self._loglock:
ts = timestamp()
for line in lines:
- print >>self.log, "%s %s"%(ts, line)
+ print >>self.log, "%s %s" % (ts, line)
self.log.flush()
def logopen(self, filename):
- with self.loglock:
+ with self._loglock:
ts = timestamp()
newlog = open(filename, "a")
if type(self.log) == file and not self.log.closed:
- print >>self.log, "%s ### Log file closed" % (ts)
if self.log not in (sys.stdout, sys.stderr):
+ print >>self.log, "%s ### Log file closed" % (ts)
self.log.close()
self.log = newlog
print >>self.log, "%s ### Log file opened" % (ts)
self.log.flush()
- def event(self, method, modlist, exceptions=False, **params):
- timestamp = reduce(lambda x, y: x+":"+y, [str(t).rjust(2,
- "0") for t in time.localtime()[0:6]])
+ def _event(self, method, modlist, exceptions=False, **params):
+ # Used to call event handlers on all attached addons, when applicable.
handled = []
unhandled = []
errors = []
for k, addon in enumerate(modlist):
if modlist.index(addon) < k:
+ # Duplicate
continue
if method in dir(addon) and callable(getattr(addon, method)):
try:
@@ -218,7 +285,10 @@ class Connection(Thread):
except:
exc, excmsg, tb = sys.exc_info()
errors.append((addon, exc, excmsg, tb))
- self.logwrite(*["!!! Exception in addon %(addon)s" % vars()]+["!!! %s"%line for line in traceback.format_exc().split("\n")])
+
+ # Print to log AND stderr
+ self.logwrite(*["!!! Exception in addon %(addon)s" % vars()] + [
+ "!!! %s" % line for line in traceback.format_exc().split("\n")])
print >>sys.stderr, "Exception in addon %(addon)s" % vars()
print >>sys.stderr, traceback.format_exc()
if exceptions: # If set to true, we raise the exception.
@@ -231,969 +301,1400 @@ class Connection(Thread):
def addAddon(self, addon, trusted=False, **params):
if addon in self.addons:
- raise BaseException("Addon already added.")
+ raise BaseException, "Addon already added."
with self.lock:
- self.event("onAddonAdd", [addon], exceptions=True, **params)
+ self._event("onAddonAdd", [addon], exceptions=True, **params)
self.addons.append(addon)
+ self.logwrite("*** Addon %s added." % repr(addon))
if trusted:
self.trusted.append(addon)
def insertAddon(self, index, addon, trusted=False, **params):
if addon in self.addons:
- raise BaseException("Addon already added.")
+ raise BaseException, "Addon already added."
with self.lock:
- self.event("onAddonAdd", [addon], exceptions=True, **params)
+ self._event("onAddonAdd", [addon], exceptions=True, **params)
self.addons.insert(index, addon)
+ self.logwrite("*** Addon %s inserted into index %d." %
+ (repr(addon), index))
if trusted:
self.trusted.append(addon)
def rmAddon(self, addon, **params):
with self.lock:
self.addons.remove(addon)
- self.event("onAddonRem", [addon], exceptions=True, **params)
+ self.logwrite("*** Addon %s removed." % repr(addon))
+ self._event("onAddonRem", [addon], exceptions=True, **params)
if addon in self.trusted:
self.trusted.remove(addon)
- def run(self):
- privmodeeventnames = dict(q=("Owner", "Deowner"), a=("Admin", "Deadmin"), o=("Op", "Deop"), h=("Halfop", "Dehalfop"), v=("Voice", "Devoice"))
- maskmodeeventnames = dict(b=("Ban", "Unban"), e=(
- "BanExcept", "UnbanExcept"), I=("Invite", "Uninvite"))
- self.quitexpected = False
- whoisstarted = False
- nameslist = []
- wholist = []
- lists = {}
- nameschan = None
+ def connect(self):
+ if self.isAlive():
+ raise AlreadyConnected
+ with self.lock:
+ self._recvhandlerthread = Thread(target=self._recvhandler)
+ self._sendhandlerthread = Thread(target=self._sendhandler)
+ self._recvhandlerthread.start()
+ self._sendhandlerthread.start()
+
+ def _connect(self):
+ with self.lock:
+ if self._connected:
+ raise AlreadyConnected
server = self.server
if self.ipv6 and ":" in server:
- server = "[%s]"%server
+ server = "[%s]" % server
port = self.port
+
+ with self.lock:
+ self.logwrite(
+ "*** Attempting connection to %(server)s:%(port)s." % vars())
+ self._event("onConnectAttempt", self.addons + reduce(
+ lambda x, y: x + y, [chan.addons for chan in self.channels], []))
try:
+ if self.ssl:
+ connection = socket.socket(
+ socket.AF_INET6 if self.ipv6 else socket.AF_INET, socket.SOCK_STREAM)
+ connection.settimeout(self.timeout)
+ self._connection = ssl.wrap_socket(
+ connection, cert_reqs=ssl.CERT_NONE)
+ else:
+ self._connection = socket.socket(
+ socket.AF_INET6 if self.ipv6 else socket.AF_INET, socket.SOCK_STREAM)
+ self._connection.settimeout(self.timeout)
+ self._connection.connect(
+ (self.server, self.port, 0, 0) if self.ipv6 else (self.server, self.port))
+ except socket.error:
+ exc, excmsg, tb = sys.exc_info()
with self.lock:
- self.event("onSessionOpen", self.addons+reduce(lambda x, y: x+y, [chan.addons for chan in self.channels], []))
+ self.logwrite(
+ "*** Connection to %(server)s:%(port)s failed: %(excmsg)s." % vars())
+ self._event("onConnectFail", self.addons + reduce(
+ lambda x, y: x + y, [chan.addons for chan in self.channels], []), exc=exc, excmsg=excmsg, tb=tb)
+ raise
- self.logwrite("### Log session started")
+ with self.lock:
+ # Run onConnect on all addons to signal connection was established.
+ self._event("onConnect", self.addons + reduce(
+ lambda x, y: x + y, [chan.addons for chan in self.channels], []))
+ self.logwrite(
+ "*** Connection to %(server)s:%(port)s established." % vars())
+ self._connected = True
+
+ def _procrecvline(self, line):
+ # If received PING, then just pong back transparently, bypassing
+ # _outgoingthread.
+ ping = re.findall("^PING :?(.*)$", line)
+ if len(ping):
+ with self.lock:
+ self._connection.send("PONG :%s\n" % ping[0])
+ return
- attempt = 1
- while True: # An entire connection lives within this while loop. When the connection fails, will try to reestablish, unless self.autoreconnect is set to False.
- while True: # Enter retry loop
- self.logwrite("*** Attempting connection to %(server)s:%(port)s." % vars())
+ self.logwrite("<<< %s" % line)
- with self.lock:
- self.event("onConnectAttempt", self.addons+reduce(lambda x, y: x+y, [chan.addons for chan in self.channels], []))
+ # Attempts to match against pattern ":src cmd target params :extinfo"
+ matches = re.findall(_ircrecvmatch, line)
+
+ # We have a match!
+ if len(matches):
+ parsed = (origin, username, host, cmd,
+ target, params, extinfo) = matches[0]
+ unhandled = []
+
+ if re.match(_intmatch, cmd):
+ cmd = int(cmd) # Code is a numerical response
+ else:
+ cmd = cmd.upper()
- try:
- if self.ssl:
- s = socket.socket(socket.AF_INET6 if self.ipv6 else socket.AF_INET, socket.SOCK_STREAM)
- s.settimeout(self.timeout)
- self.connection = ssl.wrap_socket(s, cert_reqs=ssl.CERT_NONE)
+ with self.lock:
+ if not self._registered:
+ if type(cmd) == int and cmd != 451 and target != "*": # Registration complete!
+ self.identity = self.user(target)
+ self.serv = origin
+ self._event("onRegistered", self.addons + reduce(
+ lambda x, y: x + y, [chan.addons for chan in self.channels], []))
+ self._registered = True
+
+ elif cmd == 433 and target == "*": # Server reports nick taken, so we need to try another.
+ self._trynick()
+ if not self._registered: # Registration is not yet complete
+ return
+
+ if username and host:
+ nickname = origin
+ origin = self.user(origin)
+ if origin.nick != nickname:
+ # Origin nickname has changed
+ origin.user = nickname
+ if origin.username != username:
+ # Origin username has changed
+ origin.username = username
+ if origin.host != host:
+ # Origin host has changed
+ origin.host = host
+
+ chanmatch = re.findall(
+ _targchanmatch % (re.escape(self.supports.get("PREFIX", ("ohv", "@%+"))[1]), re.escape(self.supports.get("CHANTYPES", "#"))), target)
+ if chanmatch:
+ targetprefix, channame = chanmatch[0]
+ target = self.channel(channame)
+ if target.name != channame:
+ # Target channel name has changed
+ target.name = channame
+ elif re.match(_nickmatch, target) and cmd != "NICK":
+ targetprefix = ""
+ target = self.user(target)
+ else:
+ targetprefix = ""
+
+ data = dict(origin=origin, cmd=cmd, target=target,
+ targetprefix=targetprefix, params=params, extinfo=extinfo)
+
+ # Major codeblock here! Track IRC state.
+ # Send line to addons having onRecv method first
+ self._event("onRecv", self.addons, line=line, **data)
+
+ # Support for further addon events is taken care of here. Each invocation of self._event will return (handled, unhandled, exceptions),
+ # where handled is the list of addons that have an event handler, and was executed without error, unhandled gives the list of addons
+ # not having the event handler, and exeptions giving the list of addons having an event handler, but an exception occurred.
+ # WARNING: When writing an addon, never, EVER attempt to aquire self.lock (IRC.lock from inside the method), or you will have a
+ # deadlock.
+
+ if cmd == 1:
+ (handled, unhandled, exceptions) = self._event("onWelcome", self.addons + reduce(
+ lambda x, y: x + y, [chan.addons for chan in self.channels], []), origin=origin, msg=extinfo)
+ self.welcome = extinfo # Welcome message
+ elif cmd == 2:
+ (handled, unhandled, exceptions) = self._event("onYourHost", self.addons + reduce(
+ lambda x, y: x + y, [chan.addons for chan in self.channels], []), origin=origin, msg=extinfo)
+ self.hostinfo = extinfo # Your Host
+ elif cmd == 3:
+ (handled, unhandled, exceptions) = self._event("onServerCreated", self.addons + reduce(
+ lambda x, y: x + y, [chan.addons for chan in self.channels], []), origin=origin, msg=extinfo)
+ self.servcreated = extinfo # Server Created
+ elif cmd == 4:
+ (handled, unhandled, exceptions) = self._event("onServInfo", self.addons + reduce(
+ lambda x, y: x + y, [chan.addons for chan in self.channels], []), origin=origin, servinfo=params)
+ self.servinfo = params # What is this code?
+ elif cmd == 5: # Server Supports
+ support = dict(
+ re.findall("([A-Za-z0-9]+)(?:=(\\S*))?", params))
+ if support.has_key("CHANMODES"):
+ support["CHANMODES"] = support["CHANMODES"].split(",")
+ if support.has_key("PREFIX"):
+ matches = re.findall(_prefixmatch, support["PREFIX"])
+ if matches:
+ support["PREFIX"] = matches[0]
+ else:
+ del support[
+ "PREFIX"] # Might as well delete the info if it doesn't match expected pattern
+ (handled, unhandled, exceptions) = self._event("onSupports", self.addons + reduce(
+ lambda x, y: x + y, [chan.addons for chan in self.channels], []), origin=origin, supports=support)
+ self.supports.update(support)
+ if "serv005" in dir(self) and type(self.serv005) == list:
+ self.serv005.append(params)
+ else:
+ self.serv005 = [params]
+ elif cmd == 8: # Snomask
+ snomask = params.lstrip("+")
+ (handled, unhandled, exceptions) = self._event("onSnoMask", self.addons + reduce(
+ lambda x, y: x + y, [chan.addons for chan in self.channels], []), origin=origin, snomask=snomask)
+ self.identity.snomask = snomask
+ if "s" not in self.identity.modes:
+ self.snomask = ""
+ elif cmd == 221: # User Modes
+ modes = (params if params else extinfo).lstrip("+")
+ (handled, unhandled, exceptions) = self._event("onUserModes", self.addons + reduce(
+ lambda x, y: x + y, [chan.addons for chan in self.channels], []), origin=origin, snomask=modes)
+ self.identity.modes = modes
+ if "s" not in self.identity.modes:
+ self.snomask = ""
+ elif cmd == 251: # Net Stats
+ (handled, unhandled, exceptions) = self._event(
+ "onNetStats", self.addons, origin=origin, netstats=extinfo)
+ self.netstats = extinfo
+ elif cmd == 252:
+ opcount = int(params)
+ (handled, unhandled, exceptions) = self._event(
+ "onOpCount", self.addons, origin=origin, opcount=opcount)
+ self.opcount = opcount
+ elif cmd == 254:
+ chancount = int(params)
+ (handled, unhandled, exceptions) = self._event(
+ "onChanCount", self.addons, origin=origin, chancount=chancount)
+ self.chancount = chancount
+
+ elif cmd == 305: # Returned from away status
+ (handled, unhandled, exceptions) = self._event(
+ "onReturn", self.addons, origin=origin, msg=extinfo)
+ self.identity.away = False
+
+ elif cmd == 306: # Entered away status
+ (handled, unhandled, exceptions) = self._event(
+ "onAway", self.addons, origin=origin, msg=extinfo)
+ self.identity.away = True
+
+ elif cmd == 311: # Start of WHOIS data
+ nickname, username, host, star = params.split()
+ user = self.user(nickname)
+ (handled, unhandled, exceptions) = self._event("onWhoisStart", self.addons, origin=origin,
+ user=user, nickname=nickname, username=username, host=host, realname=extinfo)
+ user.nick = nickname
+ user.username = username
+ user.host = host
+
+ elif cmd == 301: # Away Message
+ user = self.user(params)
+ (handled, unhandled, exceptions) = self._event(
+ "onWhoisAway", self.addons, origin=origin, user=user, nickname=params, awaymsg=extinfo)
+ user.away = True
+ user.awaymsg = extinfo
+
+ elif cmd == 303: # ISON Reply
+ users = [self.user(user) for user in extinfo.split(" ")]
+ (handled, unhandled, exceptions) = self._event(
+ "onIsonReply", self.addons, origin=origin, isonusers=users)
+
+ elif cmd == 307: # Is a registered nick
+ (handled, unhandled, exceptions) = self._event("onWhoisRegisteredNick",
+ self.addons, origin=origin, user=self.user(params), nickname=params, msg=extinfo)
+ elif cmd == 378: # Connecting From
+ (handled, unhandled, exceptions) = self._event("onWhoisConnectingFrom",
+ self.addons, origin=origin, user=self.user(params), nickname=params, msg=extinfo)
+ elif cmd == 319: # Channels
+ (handled, unhandled, exceptions) = self._event("onWhoisChannels", self.addons,
+ origin=origin, user=self.user(params), nickname=params, chanlist=extinfo.split(" "))
+ elif cmd == 310: # Availability
+ (handled, unhandled, exceptions) = self._event("onWhoisAvailability",
+ self.addons, origin=origin, user=self.user(params), nickname=params, msg=extinfo)
+ elif cmd == 312: # Server
+ nickname, server = params.split(" ")
+ user = self.user(nickname)
+ (handled, unhandled, exceptions) = self._event("onWhoisServer", self.addons,
+ origin=origin, user=user, nickname=nickname, server=server, servername=extinfo)
+ user.server = server
+ elif cmd == 313: # IRC Op
+ user = self.user(params)
+ (handled, unhandled, exceptions) = self._event(
+ "onWhoisOp", self.addons, origin=origin, user=user, nickname=params, msg=extinfo)
+ user.ircop = True
+ user.ircopmsg = extinfo
+ elif cmd == 317: # Idle and Signon times
+ nickname, idletime, signontime = params.split(" ")
+ user = self.user(nickname)
+ (handled, unhandled, exceptions) = self._event("onWhoisTimes", self.addons, origin=origin,
+ user=user, nickname=nickname, idletime=int(idletime), signontime=int(signontime), msg=extinfo)
+ user.idlesince = int(time.time()) - int(idletime)
+ user.signontime = int(signontime)
+ elif cmd == 671: # SSL
+ user = self.user(params)
+ (handled, unhandled, exceptions) = self._event(
+ "onWhoisSSL", self.addons, origin=origin, user=user, nickname=params, msg=extinfo)
+ user.ssl = True
+ elif cmd == 379: # User modes
+ (handled, unhandled, exceptions) = self._event("onWhoisModes", self.addons,
+ origin=origin, user=self.user(params), nickname=params, msg=extinfo)
+ elif cmd == 330: # Logged in as
+ nickname, loggedinas = params.split(" ")
+ user = self.user(nickname)
+ (handled, unhandled, exceptions) = self._event("onWhoisLoggedInAs", self.addons,
+ origin=origin, user=user, nickname=nickname, loggedinas=loggedinas, msg=extinfo)
+ user.loggedinas = loggedinas
+ elif cmd == 318: # End of WHOIS
+ (handled, unhandled, exceptions) = self._event("onWhoisEnd", self.addons,
+ origin=origin, user=self.user(params), nickname=params, msg=extinfo)
+
+ elif cmd == 321: # Start LIST
+ (handled, unhandled, exceptions) = self._event(
+ "onListStart", self.addons, origin=origin, params=params, extinfo=extinfo)
+ elif cmd == 322: # LIST item
+ (chan, pop) = params.split(" ", 1)
+ (handled, unhandled, exceptions) = self._event("onListEntry", self.addons,
+ origin=origin, channel=self.channel(chan), population=int(pop), extinfo=extinfo)
+ elif cmd == 323: # End of LIST
+ (handled, unhandled, exceptions) = self._event(
+ "onListEnd", self.addons, origin=origin, endmsg=extinfo)
+
+ elif cmd == 324: # Channel Modes
+ modeparams = params.split()
+ channame = modeparams.pop(0)
+ channel = self.channel(channame)
+ self._event("onRecv", channel.addons, line=line, **data)
+ if channel.name != channame:
+ channel.name = channame # Server seems to have changed the idea of the case of the channel name
+ setmodes = modeparams.pop(0)
+ modedelta = []
+ for mode in setmodes:
+ if mode == "+":
+ continue
+ elif mode in self.supports["CHANMODES"][2]:
+ param = modeparams.pop(0)
+ modedelta.append(("+%s" % mode, param))
+ elif mode in self.supports["CHANMODES"][3]:
+ modedelta.append(("+%s" % mode, None))
+ (handled, unhandled, exceptions) = self._event(
+ "onChannelModes", self.addons + channel.addons, channel=channel, modedelta=modedelta)
+ for ((modeset, mode), param) in modedelta:
+ if mode in self.supports["CHANMODES"][2]:
+ channel.modes[mode] = param
+ elif mode in self.supports["CHANMODES"][3]:
+ channel.modes[mode] = True
+
+ elif cmd == 329: # Channel created
+ channame, created = params.split()
+ created = int(created)
+ channel = self.channel(channame)
+ self._event("onRecv", channel.addons, line=line, **data)
+ (handled, unhandled, exceptions) = self._event(
+ "onChanCreated", self.addons + channel.addons, channel=channel, created=created)
+ channel.created = int(created)
+
+ elif cmd == 332: # Channel Topic
+ channame = params
+ channel = self.channel(channame)
+ self._event("onRecv", channel.addons, line=line, **data)
+ (handled, unhandled, exceptions) = self._event(
+ "onTopic", self.addons + channel.addons, origin=origin, channel=channel, topic=extinfo)
+ channel.topic = extinfo
+
+ elif cmd == 333: # Channel Topic info
+ (channame, nick, dt) = params.split()
+ channel = self.channel(channame)
+ self._event("onRecv", channel.addons, line=line, **data)
+ (handled, unhandled, exceptions) = self._event("onTopicInfo", self.addons +
+ channel.addons, origin=origin, channel=channel, topicsetby=nick, topictime=int(dt))
+ channel.topicsetby = nick
+ channel.topictime = int(dt)
+
+ elif cmd == 352: # WHO reply
+ (channame, username, host, serv,
+ nick, flags) = params.split()
+ try:
+ (hops, realname) = extinfo.split(" ", 1)
+ except ValueError:
+ hops = extinfo
+ realname = None
+
+ chantypes = self.supports.get("CHANTYPES", "&#+!")
+ if re.match(_chanmatch % re.escape(chantypes), channame):
+ channel = self.channel(channame)
+ else:
+ channel = None
+
+ user = self.user(nick)
+
+ self._event("onRecv", channel.addons, line=line, **data)
+ (handled, unhandled, exceptions) = self._event("onWhoEntry", self.addons + channel.addons, origin=origin, channel=channel,
+ user=user, channame=channame, username=username, host=host, serv=serv, nick=nick, flags=flags, hops=int(hops), realname=realname)
+ user.hops = hops
+ user.realname = realname
+ user.username = username
+ user.host = host
+ user.server = serv
+ user.away = "G" in flags
+ user.ircop = "*" in flags
+ if type(channel) == Channel:
+ if user not in channel.users:
+ channel.users.append(user)
+ if channel not in user.channels:
+ user.channels.append(channel)
+ for (mode, prefix) in zip(*self.supports["PREFIX"]):
+ if prefix in flags:
+ if mode in channel.modes.keys() and user not in channel.modes[mode]:
+ channel.modes[mode].append(user)
+ elif mode not in channel.modes.keys():
+ channel.modes[mode] = [user]
+
+ elif cmd == 315: # End of WHO reply
+ chantypes = self.supports.get("CHANTYPES", "&#+!")
+ if re.match(_chanmatch % re.escape(chantypes), params):
+ channel = self.channel(params)
+ (handled, unhandled, exceptions) = self._event(
+ "onWhoEnd", self.addons + channel.addons, origin=origin, param=params, endmsg=extinfo)
+ else:
+ (handled, unhandled, exceptions) = self._event(
+ "onWhoEnd", self.addons, origin=origin, param=params, endmsg=extinfo)
+
+ elif cmd == 353: # NAMES reply
+ (flag, channame) = params.split()
+ channel = self.channel(channame)
+ self._event("onRecv", channel.addons, line=line, **data)
+
+ if self.supports.has_key("PREFIX"):
+ names = re.findall(
+ r"([%s]*)([^@!\s]+)(?:!(\S+)@(\S+))?" %
+ re.escape(self.supports["PREFIX"][1]), extinfo)
+ else:
+ names = re.findall(
+ r"()([^@!\s]+)(?:!(\S+)@(\S+))?", extinfo)
+ # Still put it into tuple form for
+ # compatibility in the next
+ # structure
+ (handled, unhandled, exceptions) = self._event("onNames", self.addons + channel.addons,
+ origin=origin, channel=channel, flag=flag, channame=channame, nameslist=names)
+
+ for (symbs, nick, username, host) in names:
+ user = self.user(nick)
+ if user.nick != nick:
+ user.nick = nick
+ if username and user.username != username:
+ user.username = username
+ if host and user.host != host:
+ user.host = host
+ with channel.lock:
+ if channel not in user.channels:
+ user.channels.append(channel)
+ if user not in channel.users:
+ channel.users.append(user)
+ if self.supports.has_key("PREFIX"):
+ for symb in symbs:
+ mode = self.supports["PREFIX"][0][
+ self.supports["PREFIX"][1].index(symb)]
+ if not channel.modes.has_key(mode):
+ channel.modes[mode] = [user]
+ elif user not in channel.modes[mode]:
+ channel.modes[mode].append(user)
+
+ elif cmd == 366: # End of NAMES reply
+ channel = self.channel(params)
+ (handled, unhandled, exceptions) = self._event("onNamesEnd", self.addons +
+ channel.addons, origin=origin, channel=channel, channame=params, endmsg=extinfo)
+
+ elif cmd == 372: # MOTD line
+ (handled, unhandled, exceptions) = self._event(
+ "onMOTDLine", self.addons, origin=origin, motdline=extinfo)
+ self.motd.append(extinfo)
+ elif cmd == 375: # Begin MOTD
+ (handled, unhandled, exceptions) = self._event(
+ "onMOTDStart", self.addons, origin=origin, motdgreet=extinfo)
+ self.motdgreet = extinfo
+ self.motd = []
+ elif cmd == 376:
+ (handled, unhandled, exceptions) = self._event(
+ "onMOTDEnd", self.addons, origin=origin, motdend=extinfo)
+ self.motdend = extinfo # End of MOTD
+
+ elif cmd == 386 and "q" in self.supports["PREFIX"][0]: # Channel Owner (Unreal)
+ (channame, owner) = params.split()
+ channel = self.channel(channame)
+ self._event("onRecv", channel.addons, line=line, **data)
+ if channel.name != channame:
+ channel.name = channame # Server seems to have changed the idea of the case of the channel name
+ user = self.user(owner)
+ if user.nick != owner:
+ user.nick = owner
+ if channel.modes.has_key("q"):
+ if user not in channel.modes["q"]:
+ channel.modes["q"].append(user)
+ else:
+ channel.modes["q"] = [user]
+
+ elif cmd == 388 and "a" in self.supports["PREFIX"][0]: # Channel Admin (Unreal)
+ (channame, admin) = params.split()
+ channel = self.channel(channame)
+ self._event("onRecv", channel.addons, line=line, **data)
+ if channel.name != channame:
+ channel.name = channame # Server seems to have changed the idea of the case of the channel name
+ user = self.user(admin)
+ if user.nick != admin:
+ user.nick = admin
+ if channel.modes.has_key("a"):
+ if user not in channel.modes["a"]:
+ channel.modes["a"].append(user)
+ else:
+ channel.modes["a"] = [user]
+
+ elif cmd == "NICK":
+ newnick = extinfo if len(extinfo) else target
+
+ addons = reduce(
+ lambda x, y: x + y, [chan.addons for chan in origin.channels], [])
+ self._event("onRecv", addons, line=line, **data)
+ (handled, unhandled, exceptions) = self._event(
+ "onNickChange", self.addons + addons, user=origin, newnick=newnick)
+ if origin == self.identity:
+ (handled, unhandled, exceptions) = self._event(
+ "onMeNickChange", self.addons + addons, newnick=newnick)
+
+ for u in self.users:
+ if u.nick.lower() == newnick.lower():
+ self.users.remove(
+ u) # Nick collision, safe to assume this orphaned user is offline, so we shall remove the old instance.
+ for channel in self.channels:
+ # If for some odd reason, the old user still
+ # appears common channels, then we will remove
+ # the user anyway.
+ if u in channel.users:
+ channel.users.remove(u)
+ origin.nick = newnick
+
+ elif cmd == "JOIN":
+ channel = target if type(
+ target) == Channel else self.channel(extinfo)
+ self._event("onRecv", channel.addons, line=line, **data)
+ (handled, unhandled, exceptions) = self._event(
+ "onJoin", self.addons + channel.addons, user=origin, channel=channel)
+
+ if origin == self.identity: # This means the bot is entering the room,
+ # and will reset all the channel data, on the assumption that such data may have changed.
+ # Also, the bot must request modes
+ with channel._joining:
+ if channel._joinrequested:
+ channel._joinreply = cmd
+ channel._joining.notify()
+ channel.topic = ""
+ channel.topicmod = ""
+ channel.modes = {}
+ channel.users = []
+ self._event(
+ "onMeJoin", self.addons + channel.addons, channel=channel)
+ self.raw("MODE %s" % channel.name)
+ self.raw("WHO %s" % channel.name)
+ if "CHANMODES" in self.supports.keys():
+ self.raw(
+ "MODE %s :%s" % (channel.name, self.supports["CHANMODES"][0]))
+
+ if channel not in origin.channels:
+ origin.channels.append(channel)
+ if origin not in channel.users:
+ channel.users.append(origin)
+
+ elif cmd == "KICK":
+ kicked = self.user(params)
+ if kicked.nick != params:
+ kicked.nick = params
+
+ self._event("onRecv", target.addons, line=line, **data)
+ if origin == self.identity:
+ self._event(
+ "onMeKick", self.addons + target.addons, channel=target, kicked=kicked, kickmsg=extinfo)
+ if kicked == self.identity:
+ self._event("onMeKicked", self.addons + target.addons,
+ kicker=origin, channel=target, kickmsg=extinfo)
+ (handled, unhandled, exceptions) = self._event("onKick", self.addons +
+ target.addons, kicker=origin, channel=target, kicked=kicked, kickmsg=extinfo)
+
+ if target in kicked.channels:
+ kicked.channels.remove(target)
+ if kicked in target.users:
+ target.users.remove(kicked)
+ if self.supports.has_key("PREFIX"):
+ for mode in self.supports["PREFIX"][0]:
+ if target.modes.has_key(mode) and kicked in target.modes[mode]:
+ target.modes[mode].remove(kicked)
+
+ elif cmd == "PART":
+ try:
+ self._event("onRecv", target.addons, line=line, **data)
+ if origin == self.identity:
+ with target ._parting:
+ if target._partrequested:
+ target._partreply = cmd
+ target._parting.notify()
+ self._event(
+ "onMePart", self.addons + target.addons, channel=target, partmsg=extinfo)
+ (handled, unhandled, exceptions) = self._event(
+ "onPart", self.addons + target.addons, user=origin, channel=target, partmsg=extinfo)
+
+ if target in origin.channels:
+ origin.channels.remove(target)
+ if origin in target.users:
+ target.users.remove(origin)
+ if self.supports.has_key("PREFIX"):
+ for mode in self.supports["PREFIX"][0]:
+ if target.modes.has_key(mode) and origin in target.modes[mode]:
+ target.modes[mode].remove(origin)
+ except:
+ print target
+ raise
+ elif cmd == "QUIT":
+ channels = list(origin.channels)
+ addons = reduce(
+ lambda x, y: x + y, [chan.addons for chan in origin.channels], [])
+ self._event("onRecv", addons, line=line, **data)
+ (handled, unhandled, exceptions) = self._event(
+ "onQuit", self.addons + addons, user=origin, quitmsg=extinfo)
+ for channel in origin.channels:
+ with channel.lock:
+ if origin in channel.users:
+ channel.users.remove(origin)
+ if self.supports.has_key("PREFIX"):
+ for mode in self.supports["PREFIX"][0]:
+ if channel.modes.has_key(mode) and origin in channel.modes[mode]:
+ channel.modes[mode].remove(origin)
+ origin.channels = []
+
+ elif cmd == "MODE":
+ if type(target) == Channel:
+ self._event("onRecv", target.addons, line=line, **data)
+ modedelta = []
+ modeparams = params.split()
+ setmodes = modeparams.pop(0)
+ modeset = "+"
+ for mode in setmodes:
+ if mode in "+-":
+ modeset = mode
else:
- self.connection = socket.socket(socket.AF_INET6 if self.ipv6 else socket.AF_INET, socket.SOCK_STREAM)
- self.connection.connect((self.server, self.port, 0, 0) if self.ipv6 else (self.server, self.port))
- except socket.error:
- exc, excmsg, tb = sys.exc_info()
- self.event("onConnectFail", self.addons+reduce(lambda x, y: x+y, [chan.addons for chan in self.channels], []), exc=exc, excmsg=excmsg, tb=tb)
- self.logwrite("*** Connection to %(server)s:%(port)s failed: %(excmsg)s." % vars())
+ if mode in self.supports["CHANMODES"][0] + self.supports["CHANMODES"][1]:
+ param = modeparams.pop(0)
+ modedelta.append(
+ ("%s%s" % (modeset, mode), param))
+ if mode in _maskmodeeventnames.keys():
+ if modeset == "+":
+ eventname = _maskmodeeventnames[
+ mode][0]
+ if modeset == "-":
+ eventname = _maskmodeeventnames[
+ mode][1]
+ matchesbot = glob.fnmatch.fnmatch(
+ "%s!%s@%s".lower() % (self.identity.nick, self.identity.username, self.identity.host), param.lower())
+ self._event(
+ "on%s" % eventname, self.addons + target.addons, user=origin, channel=target, banmask=param)
+ if matchesbot:
+ self._event(
+ "onMe%s" % eventname, self.addons + target.addons, user=origin, channel=target, banmask=param)
+ elif mode in self.supports["CHANMODES"][2]:
+ if modeset == "+":
+ param = modeparams.pop(0)
+ modedelta.append(
+ ("%s%s" % (modeset, mode), param))
+ else:
+ modedelta.append(
+ ("%s%s" % (modeset, mode), None))
+ elif mode in self.supports["CHANMODES"][3]:
+ modedelta.append(
+ ("%s%s" % (modeset, mode), None))
+ elif self.supports.has_key("PREFIX") and mode in self.supports["PREFIX"][0]:
+ modenick = modeparams.pop(0)
+ modeuser = self.user(modenick)
+ if mode in _privmodeeventnames.keys():
+ if modeset == "+":
+ eventname = _privmodeeventnames[
+ mode][0]
+ if modeset == "-":
+ eventname = _privmodeeventnames[
+ mode][1]
+ self._event(
+ "on%s" % eventname, self.addons + target.addons, user=origin, channel=target, modeuser=modeuser)
+ if modeuser == self.identity:
+ self._event(
+ "onMe%s" % eventname, self.addons + target.addons, user=origin, channel=target)
+ modedelta.append(
+ ("%s%s" % (modeset, mode), modeuser))
+ (handled, unhandled, exceptions) = self._event(
+ "onChanModeSet", self.addons + target.addons, user=origin, channel=target, modedelta=modedelta)
+ with target.lock:
+ for ((modeset, mode), param) in modedelta:
+ if mode in self.supports["CHANMODES"][0]:
+ if modeset == "+":
+ if target.modes.has_key(mode):
+ if param.lower() not in [mask.lower() for (mask, setby, settime) in target.modes[mode]]:
+ target.modes[mode].append(
+ (param, origin, int(time.time())))
+ else:
+ target.modes[mode] = [
+ (param, origin, int(time.time()))]
+ else:
+ if mode in target.modes.keys():
+ if mode == "b": # Inspircd mode is case insentive when unsetting the mode
+ masks = [
+ mask.lower() for (mask, setby, settime) in target.modes[mode]]
+ if param.lower() in masks:
+ index = masks.index(
+ param.lower())
+ # print "Index: %d"%index
+ del target.modes[
+ mode][index]
+ else:
+ masks = [
+ mask for (mask, setby, settime) in target.modes[mode]]
+ if param in masks:
+ index = masks.index(param)
+ del target.modes[
+ mode][index]
+ elif mode in self.supports["CHANMODES"][1]:
+ if modeset == "+":
+ target.modes[mode] = param
+ else:
+ target.modes[mode] = None
+ elif mode in self.supports["CHANMODES"][2]:
+ if modeset == "+":
+ target.modes[mode] = param
+ else:
+ target.modes[mode] = None
+ elif mode in self.supports["CHANMODES"][3]:
+ if modeset == "+":
+ target.modes[mode] = True
+ else:
+ target.modes[mode] = False
+ elif self.supports.has_key("PREFIX") and mode in self.supports["PREFIX"][0]:
+ if modeset == "+":
+ if target.modes.has_key(mode) and param not in target.modes[mode]:
+ target.modes[mode].append(param)
+ if not target.modes.has_key(mode):
+ target.modes[mode] = [param]
+ elif target.modes.has_key(mode) and param in target.modes[mode]:
+ target.modes[mode].remove(param)
+ elif type(target) == User:
+ modeparams = (params if params else extinfo).split()
+ setmodes = modeparams.pop(0)
+ modeset = "+"
+ for mode in setmodes:
+ if mode in "+-":
+ modeset = mode
+ continue
+ if modeset == "+":
+ if mode not in target.modes:
+ target.modes += mode
+ if mode == "s" and len(modeparams):
+ snomask = modeparams.pop(0)
+ for snomode in snomask:
+ if snomode in "+-":
+ snomodeset = snomode
+ continue
+ if snomodeset == "+" and snomode not in target.snomask:
+ target.snomask += snomode
+ if snomodeset == "-" and snomode in target.snomask:
+ target.snomask = target.snomask.replace(
+ snomode, "")
+ if modeset == "-":
+ if mode in target.modes:
+ target.modes = target.modes.replace(
+ mode, "")
+ if mode == "s":
+ target.snomask = ""
+
+ elif cmd == "TOPIC":
+ self._event("onRecv", target.addons, line=line, **data)
+ (handled, unhandled, exceptions) = self._event(
+ "onTopicSet", self.addons + target.addons, user=origin, channel=target, topic=extinfo)
+
+ with target.lock:
+ target.topic = extinfo
+ target.topicsetby = origin
+ target.topictime = int(time.time())
+
+ elif cmd == "INVITE":
+ channel = self.channel(extinfo if extinfo else params)
+ self._event("onRecv", channel.addons, line=line, **data)
+ (handled, unhandled, exceptions) = self._event(
+ "onInvite", self.addons + channel.addons, user=origin, channel=channel)
+
+ elif cmd == "PRIVMSG":
+ if type(target) == Channel:
+ self._event("onRecv", target.addons, line=line, **data)
+
+ # CTCP handling
+ ctcp = re.findall(_ctcpmatch, extinfo)
+ if ctcp:
+ (ctcptype, ext) = ctcp[0]
+ if ctcptype.upper() == "ACTION":
+ if type(target) == Channel:
+ (handled, unhandled, exceptions) = self._event(
+ "onChanAction", self.addons + target.addons, user=origin, channel=target, targetprefix=targetprefix, action=ext)
+ elif target == self.identity:
+ (handled, unhandled, exceptions) = self._event(
+ "onPrivAction", self.addons, user=origin, action=ext)
else:
- self.connected = True
- self.connection.settimeout(self.timeout)
+ if type(target) == Channel:
+ (handled, unhandled, exceptions) = self._event("onChanCTCP", self.addons + target.addons,
+ user=origin, channel=target, targetprefix=targetprefix, ctcptype=ctcptype, params=ext)
+ elif target == self.identity:
+ (handled, unhandled, exceptions) = self._event(
+ "onPrivCTCP", self.addons, user=origin, ctcptype=ctcptype, params=ext)
+ if ctcptype.upper() == "VERSION":
+ origin.ctcpreply("VERSION", self.ctcpversion())
+ if ctcptype.upper() == "TIME":
+ tformat = time.ctime()
+ tz = time.tzname[0]
+ origin.ctcpreply(
+ "TIME", "%(tformat)s %(tz)s" % vars())
+ if ctcptype.upper() == "PING":
+ origin.ctcpreply("PING", "%(ext)s" % vars())
+ if ctcptype.upper() == "FINGER":
+ origin.ctcpreply("FINGER", "%(ext)s" % vars())
+ else:
+ if type(target) == Channel:
+ (handled, unhandled, exceptions) = self._event(
+ "onChanMsg", self.addons + target.addons, user=origin, channel=target, targetprefix=targetprefix, msg=extinfo)
+ elif target == self.identity:
+ (handled, unhandled, exceptions) = self._event(
+ "onPrivMsg", self.addons, user=origin, msg=extinfo)
+
+ elif cmd == "NOTICE":
+ if type(target) == Channel:
+ self._event("onRecv", target.addons, line=line, **data)
+
+ # CTCP handling
+ ctcp = re.findall(_ctcpmatch, extinfo)
+ if ctcp and target == self.identity:
+ (ctcptype, ext) = ctcp[0]
+ (handled, unhandled, exceptions) = self._event(
+ "onCTCPReply", self.addons, origin=origin, ctcptype=ctcptype, params=ext)
+ else:
+ if type(target) == Channel:
+ (handled, unhandled, exceptions) = self._event(
+ "onChanNotice", self.addons + target.addons, origin=origin, channel=target, targetprefix=targetprefix, msg=extinfo)
+ elif target == self.identity:
+ (handled, unhandled, exceptions) = self._event(
+ "onPrivNotice", self.addons, origin=origin, msg=extinfo)
+
+ elif cmd == 367: # Channel Ban list
+ (channame, mask, setby, settime) = params.split()
+ channel = self.channel(channame)
+ self._event("onRecv", channel.addons, line=line, **data)
+ (handled, unhandled, exceptions) = self._event("onBanListEntry", self.addons + channel.addons,
+ origin=origin, channel=channel, mask=mask, setby=setby, settime=int(settime))
+ if "b" in channel.modes.keys():
+ if mask.lower() not in [m.lower() for (m, s, t) in channel.modes["b"]]:
+ channel.modes["b"].append(
+ (mask, setby, int(settime)))
+ else:
+ channel.modes["b"] = [(mask, setby, int(settime))]
+ elif cmd == 368:
+ channel = self.channel(params)
+ self._event("onRecv", channel.addons, line=line, **data)
+ (handled, unhandled, exceptions) = self._event(
+ "onBanListEnd", self.addons + channel.addons, origin=origin, channel=channel, endmsg=extinfo)
+
+ elif cmd == 346: # Channel Invite list
+ (channame, mask, setby, settime) = params.split()
+ channel = self.channel(channame)
+ self._event("onRecv", channel.addons, line=line, **data)
+ (handled, unhandled, exceptions) = self._event("onInviteListEntry", self.addons +
+ channel.addons, origin=origin, channel=channel, mask=mask, setby=setby, settime=int(settime))
+ if "I" in channel.modes.keys():
+ if mask.lower() not in [m.lower() for (m, s, t) in channel.modes["I"]]:
+ channel.modes["I"].append(
+ (mask, setby, int(settime)))
+ else:
+ channel.modes["I"] = [(mask, setby, int(settime))]
+ elif cmd == 347:
+ channel = self.channel(params)
+ self._event("onRecv", channel.addons, line=line, **data)
+ (handled, unhandled, exceptions) = self._event(
+ "onInviteListEnd", self.addons + channel.addons, origin=origin, channel=channel, endmsg=extinfo)
+
+ elif cmd == 348: # Channel Ban Exception list
+ (channame, mask, setby, settime) = params.split()
+ channel = self.channel(channame)
+ self._event("onRecv", channel.addons, line=line, **data)
+ (handled, unhandled, exceptions) = self._event("onBanExceptListEntry", self.addons +
+ channel.addons, origin=origin, channel=channel, mask=mask, setby=setby, settime=int(settime))
+ if "e" in channel.modes.keys():
+ if mask.lower() not in [m.lower() for (m, s, t) in channel.modes["e"]]:
+ channel.modes["e"].append(
+ (mask, setby, int(settime)))
+ else:
+ channel.modes["e"] = [(mask, setby, int(settime))]
+ elif cmd == 349:
+ channel = self.channel(params)
+ self._event("onRecv", channel.addons, line=line, **data)
+ (handled, unhandled, exceptions) = self._event("onBanExceptListEnd",
+ self.addons + channel.addons, origin=origin, channel=channel, endmsg=extinfo)
+
+ elif cmd == 910: # Channel Access List
+ (channame, mask, setby, settime) = params.split()
+ channel = self.channel(channame)
+ self._event("onRecv", channel.addons, line=line, **data)
+ (handled, unhandled, exceptions) = self._event("onAccessListEntry", self.addons +
+ channel.addons, origin=origin, channel=channel, mask=mask, setby=setby, settime=int(settime))
+ if "w" in channel.modes.keys():
+ if mask.lower() not in [m.lower() for (m, s, t) in channel.modes["b"]]:
+ channel.modes["w"].append(
+ (mask, setby, int(settime)))
+ else:
+ channel.modes["w"] = [(mask, setby, int(settime))]
+ elif cmd == 911:
+ channel = self.channel(params)
+ self._event("onRecv", channel.addons, line=line, **data)
+ (handled, unhandled, exceptions) = self._event(
+ "onAccessListEnd", self.addons + channel.addons, origin=origin, channel=channel, endmsg=extinfo)
+
+ elif cmd == 941: # Spam Filter list
+ (channame, mask, setby, settime) = params.split()
+ channel = self.channel(channame)
+ self._event("onRecv", channel.addons, line=line, **data)
+ (handled, unhandled, exceptions) = self._event("onSpamfilterListEntry", self.addons +
+ channel.addons, origin=origin, channel=channel, mask=mask, setby=setby, settime=int(settime))
+ if "g" in channel.modes.keys():
+ if mask.lower() not in [m.lower() for (m, s, t) in channel.modes["g"]]:
+ channel.modes["g"].append(
+ (mask, setby, int(settime)))
+ else:
+ channel.modes["g"] = [(mask, setby, int(settime))]
+ elif cmd == 940:
+ channel = self.channel(params)
+ self._event("onRecv", channel.addons, line=line, **data)
+ (handled, unhandled, exceptions) = self._event("onSpamfilterListEnd",
+ self.addons + channel.addons, origin=origin, channel=channel, endmsg=extinfo)
+
+ elif cmd == 954: # Channel exemptchanops list
+ (channame, mask, setby, settime) = params.split()
+ channel = self.channel(channame)
+ self._event("onRecv", channel.addons, line=line, **data)
+ (handled, unhandled, exceptions) = self._event("onExemptChanOpsListEntry", self.addons +
+ channel.addons, origin=origin, channel=channel, mask=mask, setby=setby, settime=int(settime))
+ if "X" in channel.modes.keys():
+ if mask.lower() not in [m.lower() for (m, s, t) in channel.modes["X"]]:
+ channel.modes["X"].append(
+ (mask, setby, int(settime)))
+ else:
+ channel.modes["X"] = [(mask, setby, int(settime))]
+ elif cmd == 953:
+ channel = self.channel(params)
+ self._event("onRecv", channel.addons, line=line, **data)
+ (handled, unhandled, exceptions) = self._event("onExemptChanOpsListEnd",
+ self.addons + channel.addons, origin=origin, channel=channel, endmsg=extinfo)
+
+ elif cmd == 728: # Channel quiet list
+ (channame, modechar, mask, setby, settime) = params.split()
+ channel = self.channel(channame)
+ self._event("onRecv", channel.addons, line=line, **data)
+ (handled, unhandled, exceptions) = self._event("onQuietListEntry", self.addons + channel.addons,
+ origin=origin, channel=channel, modechar=modechar, mask=mask, setby=setby, settime=int(settime))
+ if "q" in channel.modes.keys():
+ if mask.lower() not in [m.lower() for (m, s, t) in channel.modes["q"]]:
+ channel.modes["q"].append(
+ (mask, setby, int(settime)))
+ else:
+ channel.modes["q"] = [(mask, setby, int(settime))]
+ elif cmd == 729:
+ channame, modechar = params.split()
+ channel = self.channel(channame)
+ self._event("onRecv", channel.addons, line=line, **data)
+ (handled, unhandled, exceptions) = self._event(
+ "onQuietListEnd", self.addons + channel.addons, channel=channel, endmsg=extinfo)
+
+ elif cmd in (495, 384, 385, 386, 468, 470, 366, 315, 482, 484, 953, 368, 482, 349, 940, 911, 489, 490, 492, 520, 530): # Channels which appear in params
+ for param in params.split():
+ if len(param) and param[0] in self.supports["CHANTYPES"]:
+ channel = self.channel(param)
+ self._event(
+ "onRecv", channel.addons, line=line, **data)
+
+ elif type(cmd) == int:
+ (handled, unhandled, exceptions) = self._event("on%03d" %
+ cmd, self.addons, line=line, origin=origin, target=target, params=params, extinfo=extinfo)
+ else:
+ (handled, unhandled, exceptions) = self._event("on%s" %
+ cmd, self.addons, line=line, origin=origin, cmd=cmd, target=target, params=params, extinfo=extinfo)
- ### Setting up thread responsible for sending data back to IRC server.
- self.outgoing._interrupted = False
- self.outgoingthread = Outgoing(self)
- self.outgoingthread.daemon = True
- self.outgoingthread.start()
+ if cmd in (384, 403, 405, 471, 473, 474, 475, 476, 520, 477, 489, 495): # Channel Join denied
+ try:
+ channel = self.channel(params)
+ except InvalidName:
+ pass
+ else:
+ with channel._joining:
+ if channel._joinrequested:
+ channel._joinreply = (cmd, extinfo)
+ channel._joining.notify()
- ### Run onConnect on all addons to signal connection was established.
- self.event("onConnect", self.addons+reduce(lambda x, y: x+y, [chan.addons for chan in self.channels], []))
- self.logwrite("*** Connection to %(server)s:%(port)s established." % vars())
- break
+ elif cmd == 470: # Channel Join denied due to redirect
+ channelname, redirect = params.split()
+ try:
+ channel = self.channel(channelname)
+ except InvalidName:
+ pass
+ else:
+ with channel._joining:
+ if channel._joinrequested:
+ channel._joinreply = (
+ cmd, "%s (%s)" % (extinfo, redirect))
+ channel._joining.notify()
+
+ # Handle events that were not handled.
+ self._event("onUnhandled", unhandled, line=line, origin=origin,
+ cmd=cmd, target=target, params=params, extinfo=extinfo)
+
+ def _trynick(self):
+ (q, s) = divmod(self.trynick, len(self.nick))
+ nick = self.nick[s]
+ if q > 0:
+ nick = "%s%d" % (nick, q)
+ self._send("NICK %s" % nick)
+ self.trynick += 1
+
+ def _recvhandler(self):
+ # Enforce that this function must only be run from within
+ # self._sendhandlerthread.
+ if currentThread() != self._recvhandlerthread:
+ raise RuntimeError, "This function is designed to run in its own thread."
+ server = self.server
+ if self.ipv6 and ":" in server:
+ server = "[%s]" % server
+ port = self.port
- if self.quitexpected:
- sys.exit()
- if attempt < self.maxretries or self.maxretries == -1:
- time.sleep(self.retrysleep)
- if self.quitexpected:
+ try:
+ with self.lock:
+ self._event("onSessionOpen", self.addons + reduce(
+ lambda x, y: x + y, [chan.addons for chan in self.channels], []))
+
+ self.logwrite("### Log session started")
+ while True: # Autoreconnect loop
+ attempt = 1
+ while True: # Autoretry loop
+ try:
+ self._connect()
+ break
+ except socket.error:
+ if self._quitexpected:
+ sys.exit()
+ if attempt < self.maxretries or self.maxretries < 0:
+ if self.retrysleep > 0:
+ time.sleep(self.retrysleep)
+ if self._quitexpected:
+ sys.exit()
+ attempt += 1
+ else:
+ self.logwrite(
+ "*** Maximum number of attempts reached. Giving up. (%(server)s:%(port)s)" % vars())
sys.exit()
- attempt += 1
- else:
- self.logwrite("*** Maximum number of attempts reached. Giving up. (%(server)s:%(port)s)" % vars())
- sys.exit()
- ### Connection succeeded
+ # Connection succeeded
try:
- ### Attempt initial registration.
+ with self._sendline:
+ self._sendline.notify()
+
+ # Attempt initial registration.
nick = self.nick[0]
- trynick = 0
if self.passwd:
- self.raw("PASS :%s" % self.passwd.split(
- "\n")[0].rstrip())
- self.raw("NICK :%s" % nick.split("\n")[0].rstrip())
- self.raw("USER %s * * :%s" % (self.username.split("\n")[0].rstrip(), self.realname.split("\n")[0].rstrip()))
+ self._send("PASS %s" % self.passwd)
+ self._trynick()
+ self._send("USER %s * * :%s" %
+ (self.username.split("\n")[0].rstrip(), self.realname.split("\n")[0].rstrip()))
- ### Initialize buffers
+ # Initialize buffers
linebuf = []
readbuf = ""
while True: # Main loop of IRC connection.
while len(linebuf) == 0: # Need Moar Data
- read = self.connection.recv(512)
+ read = self._connection.recv(512)
- ### If read was empty, connection is terminated.
+ # If read was empty, connection is terminated.
if read == "":
sys.exit()
- ### If read was successful, parse away!
+ # If read was successful, parse away!
readbuf += read
lastlf = readbuf.rfind("\n")
if lastlf >= 0:
- linebuf.extend(string.split(readbuf[0:lastlf],
- "\n"))
- readbuf = readbuf[lastlf+1:]
+ linebuf.extend(
+ string.split(readbuf[0:lastlf], "\n"))
+ readbuf = readbuf[lastlf + 1:]
line = string.rstrip(linebuf.pop(0))
+ self._procrecvline(line)
- ### If received PING, then just pong back transparently.
- ping = re.findall("^PING :?(.*)$", line)
- if len(ping):
- with self.lock:
- self.connection.send("PONG :%s\n" % ping[0])
- continue
-
- self.logwrite("<<< %(line)s" % vars())
-
- ### Attempts to match against pattern ":src cmd target params :extinfo"
- matches = re.findall(r"^:(.+?)(?:!(.+?)@(.+?))?\s+(.+?)(?:\s+(.+?)(?:\s+(.+?))??)??(?:\s+:(.*))?$", line)
-
- ### We have a match!
- if len(matches):
- parsed = (origin, username, host, cmd, target, params, extinfo) = matches[0]
- unhandled = []
-
- if re.match("^\\d+$", cmd):
- cmd = int(cmd) # Code is a numerical response
- else:
- cmd = cmd.upper()
-
- with self._linereceived:
- if not self.registered:
- if type(cmd) == int and cmd != 451 and target != "*": # Registration complete!
- self.registered = True
- self.identity = self.user(target)
- self.serv = origin
- self.event("onRegistered", self.addons+reduce(lambda x, y: x+y, [chan.addons for chan in self.channels], []))
-
- elif cmd == 433 and target == "*": # Server reports nick taken, so we need to try another.
- trynick += 1
- (q, s) = divmod(trynick, len(self.nick))
- nick = self.nick[s]
- if q > 0:
- nick += str(q)
- self.raw("NICK :%s" % nick.split("\n")[0].rstrip())
- if not self.registered: # Registration is not yet complete
- continue
-
- if username and host:
- nickname = origin
- origin = self.user(origin)
- if origin.nick != nickname:
- ### Origin nickname has changed
- origin.user = nickname
- if origin.username != username:
- ### Origin username has changed
- origin.username = username
- if origin.host != host:
- ### Origin host has changed
- origin.host = host
-
- chanmatch = re.findall(r"([%s]?)([%s]\S*)"%(re.escape(self.supports.get("PREFIX", ("ohv", "@%+"))[1]), re.escape(self.supports.get("CHANTYPES", "#"))), target)
- if chanmatch:
- targetprefix, channame = chanmatch[0]
- target = self.channel(channame)
- if target.name != channame:
- ### Target channel name has changed
- target.name = channame
- elif len(target) and target[0] != "$" and cmd != "NICK":
- targetprefix = ""
- target = self.user(target)
-
- self.data = data = dict(origin=origin, cmd=cmd, target=target, targetprefix=targetprefix, params=params, extinfo=extinfo)
- self._linereceived.notifyAll()
-
- ### Major codeblock here! Track IRC state.
- ### Send line to addons first
- self.event("onRecv", self.addons, line=line,
- **data)
- if cmd == 1:
- (handled, unhandled, exceptions) = self.event("onWelcome", self.addons+reduce(lambda x, y: x+y, [chan.addons for chan in self.channels], []), origin=origin, msg=extinfo)
- self.welcome = extinfo # Welcome message
- elif cmd == 2:
- (handled, unhandled, exceptions) = self.event("onYourHost", self.addons+reduce(lambda x, y: x+y, [chan.addons for chan in self.channels], []), origin=origin, msg=extinfo)
- self.hostinfo = extinfo # Your Host
- elif cmd == 3:
- (handled, unhandled, exceptions) = self.event("onServerCreated", self.addons+reduce(lambda x, y: x+y, [chan.addons for chan in self.channels], []), origin=origin, msg=extinfo)
- self.servcreated = extinfo # Server Created
- elif cmd == 4:
- (handled, unhandled, exceptions) = self.event("onServInfo", self.addons+reduce(lambda x, y: x+y, [chan.addons for chan in self.channels], []), origin=origin, servinfo=params)
- self.servinfo = params # What is this code?
- elif cmd == 5: # Server Supports
- support = dict(re.findall("([A-Za-z0-9]+)(?:=(\\S*))?", params))
- if "CHANMODES" in support:
- support["CHANMODES"] = support["CHANMODES"].split(",")
- if "PREFIX" in support:
- matches = re.findall("\\((.*)\\)(.*)", support["PREFIX"])
- if matches:
- support["PREFIX"] = matches[0]
- else:
- del support["PREFIX"] # Might as well delete the info if it doesn't match expected pattern
- (handled, unhandled, exceptions) = self.event("onSupports", self.addons+reduce(lambda x, y: x+y, [chan.addons for chan in self.channels], []), origin=origin, supports=support)
- self.supports.update(support)
- if "serv005" in dir(self) and type(self.serv005) == list:
- self.serv005.append(params)
- else:
- self.serv005 = [params]
- elif cmd == 8: # Snomask
- snomask = params.lstrip("+")
- (handled, unhandled, exceptions) = self.event("onSnoMask", self.addons+reduce(lambda x, y: x+y, [chan.addons for chan in self.channels], []), origin=origin, snomask=snomask)
- self.identity.snomask = snomask
- if "s" not in self.identity.modes:
- self.snomask = ""
- elif cmd == 221: # User Modes
- modes = (params if params else extinfo).lstrip("+")
- (handled, unhandled, exceptions) = self.event("onUserModes", self.addons+reduce(lambda x, y: x+y, [chan.addons for chan in self.channels], []), origin=origin, snomask=modes)
- self.identity.modes = modes
- if "s" not in self.identity.modes:
- self.snomask = ""
- elif cmd == 251: # Net Stats
- (handled, unhandled, exceptions) = self.event("onNetStats", self.addons, origin=origin, netstats=extinfo)
- self.netstats = extinfo
- elif cmd == 252:
- opcount = int(params)
- (handled, unhandled, exceptions) = self.event("onOpCount", self.addons, origin=origin, opcount=opcount)
- self.opcount = opcount
- elif cmd == 254:
- chancount = int(params)
- (handled, unhandled, exceptions) = self.event("onChanCount", self.addons, origin=origin, chancount=chancount)
- self.chancount = chancount
-
- elif cmd == 305: # Returned from away status
- (handled, unhandled, exceptions) = self.event("onReturn", self.addons, origin=origin, msg=extinfo)
- self.identity.away = False
-
- elif cmd == 306: # Entered away status
- (handled, unhandled, exceptions) = self.event("onAway", self.addons, origin=origin, msg=extinfo)
- self.identity.away = True
-
- elif cmd == 311: # Start of WHOIS data
- nickname, username, host, star = params.split()
- user = self.user(nickname)
- (handled, unhandled, exceptions) = self.event("onWhoisStart", self.addons, origin=origin, user=user, nickname=nickname, username=username, host=host, realname=extinfo)
- user.nick = nickname
- user.username = username
- user.host = host
-
- elif cmd == 301: # Away Message
- user = self.user(params)
- (handled, unhandled, exceptions) = self.event("onWhoisAway", self.addons, origin=origin, user=user, nickname=params, awaymsg=extinfo)
- user.away = True
- user.awaymsg = extinfo
-
- elif cmd == 303: # ISON Reply
- users = [self.user(user) for user in extinfo.split(" ")]
- (handled, unhandled, exceptions) = self.event("onIsonReply", self.addons, origin=origin, isonusers=users)
-
- elif cmd == 307: # Is a registered nick
- (handled, unhandled, exceptions) = self.event("onWhoisRegisteredNick", self.addons, origin=origin, user=self.user(params), nickname=params, msg=extinfo)
- elif cmd == 378: # Connecting From
- (handled, unhandled, exceptions) = self.event("onWhoisConnectingFrom", self.addons, origin=origin, user=self.user(params), nickname=params, msg=extinfo)
- elif cmd == 319: # Channels
- (handled, unhandled, exceptions) = self.event("onWhoisChannels", self.addons, origin=origin, user=self.user(params), nickname=params, chanlist=extinfo.split(" "))
- elif cmd == 310: # Availability
- (handled, unhandled, exceptions) = self.event("onWhoisAvailability", self.addons, origin=origin, user=self.user(params), nickname=params, msg=extinfo)
- elif cmd == 312: # Server
- nickname, server = params.split(" ")
- user = self.user(nickname)
- (handled, unhandled, exceptions) = self.event("onWhoisServer", self.addons, origin=origin, user=user, nickname=nickname, server=server, servername=extinfo)
- user.server = server
- elif cmd == 313: # IRC Op
- user = self.user(params)
- (handled, unhandled, exceptions) = self.event("onWhoisOp", self.addons, origin=origin, user=user, nickname=params, msg=extinfo)
- user.ircop = True
- user.ircopmsg = extinfo
- elif cmd == 317: # Idle and Signon times
- nickname, idletime, signontime = params.split(" ")
- user = self.user(nickname)
- (handled, unhandled, exceptions) = self.event("onWhoisTimes", self.addons, origin=origin, user=user, nickname=nickname, idletime=int(idletime), signontime=int(signontime), msg=extinfo)
- user.idlesince = int(time.time())-int(idletime)
- user.signontime = int(signontime)
- elif cmd == 671: # SSL
- user = self.user(params)
- (handled, unhandled, exceptions) = self.event("onWhoisSSL", self.addons, origin=origin, user=user, nickname=params, msg=extinfo)
- user.ssl = True
- elif cmd == 379: # User modes
- (handled, unhandled, exceptions) = self.event("onWhoisModes", self.addons, origin=origin, user=self.user(params), nickname=params, msg=extinfo)
- elif cmd == 330: # Logged in as
- nickname, loggedinas = params.split(" ")
- user = self.user(nickname)
- (handled, unhandled, exceptions) = self.event("onWhoisLoggedInAs", self.addons, origin=origin, user=user, nickname=nickname, loggedinas=loggedinas, msg=extinfo)
- user.loggedinas = loggedinas
- elif cmd == 318: # End of WHOIS
- (handled, unhandled, exceptions) = self.event("onWhoisEnd", self.addons, origin=origin, user=self.user(params), nickname=params, msg=extinfo)
-
- elif cmd == 321: # Start LIST
- (handled, unhandled, exceptions) = self.event("onListStart", self.addons, origin=origin, params=params, extinfo=extinfo)
- elif cmd == 322: # LIST item
- (chan, pop) = params.split(" ", 1)
- (handled, unhandled, exceptions) = self.event("onListEntry", self.addons, origin=origin, channel=self.channel(chan), population=int(pop), extinfo=extinfo)
- elif cmd == 323: # End of LIST
- (handled, unhandled, exceptions) = self.event("onListEnd", self.addons, origin=origin, endmsg=extinfo)
-
- elif cmd == 324: # Channel Modes
- modeparams = params.split()
- channame = modeparams.pop(0)
- channel = self.channel(channame)
- self.event("onRecv", channel.addons, line=line, **data)
- if channel.name != channame:
- channel.name = channame # Server seems to have changed the idea of the case of the channel name
- setmodes = modeparams.pop(0)
- modedelta = []
- for mode in setmodes:
- if mode == "+":
- continue
- elif mode in self.supports["CHANMODES"][2]:
- param = modeparams.pop(0)
- modedelta.append(("+%s"%mode, param))
- elif mode in self.supports["CHANMODES"][3]:
- modedelta.append(("+%s"%mode, None))
- (handled, unhandled, exceptions) = self.event("onChannelModes", self.addons+channel.addons, channel=channel, modedelta=modedelta)
- for ((modeset, mode), param) in modedelta:
- if mode in self.supports["CHANMODES"][2]:
- channel.modes[mode] = param
- elif mode in self.supports["CHANMODES"][3]:
- channel.modes[mode] = True
-
- elif cmd == 329: # Channel created
- channame, created = params.split()
- created = int(created)
- channel = self.channel(channame)
- self.event("onRecv", channel.addons, line=line, **data)
- (handled, unhandled, exceptions) = self.event("onChanCreated", self.addons+channel.addons, channel=channel, created=created)
- channel.created = int(created)
-
- elif cmd == 332: # Channel Topic
- channame = params
- channel = self.channel(channame)
- self.event("onRecv", channel.addons, line=line, **data)
- (handled, unhandled, exceptions) = self.event("onTopic", self.addons+channel.addons, origin=origin, channel=channel, topic=extinfo)
- channel.topic = extinfo
-
- elif cmd == 333: # Channel Topic info
- (channame, nick, dt) = params.split()
- channel = self.channel(channame)
- self.event("onRecv", channel.addons, line=line, **data)
- (handled, unhandled, exceptions) = self.event("onTopicInfo", self.addons+channel.addons, origin=origin, channel=channel, topicsetby=nick, topictime=int(dt))
- channel.topicsetby = nick
- channel.topictime = int(dt)
-
- elif cmd == 352: # WHO reply
- (channame, username, host, serv, nick, flags) = params.split()
- try:
- (hops, realname) = extinfo.split(" ", 1)
- except ValueError:
- hops = extinfo
- realname = None
-
- if channame[0] in self.supports.get("CHANTYPES", "#"):
- channel = self.channel(channame)
- else:
- channel = None
-
- user = self.user(nick)
-
- self.event("onRecv", channel.addons, line=line, **data)
- (handled, unhandled, exceptions) = self.event("onWhoEntry", self.addons+channel.addons, origin=origin, channel=channel, user=user, channame=channame, username=username, host=host, serv=serv, nick=nick, flags=flags, hops=int(hops), realname=realname)
- user.hops = hops
- user.realname = realname
- user.username = username
- user.host = host
- user.server = serv
- user.away = "G" in flags
- user.ircop = "*" in flags
- if type(channel) == Channel:
- if user not in channel.users:
- channel.users.append(user)
- if channel not in user.channels:
- user.channels.append(channel)
- for (mode, prefix) in zip(*self.supports["PREFIX"]):
- if prefix in flags:
- if mode in channel.modes.keys() and user not in channel.modes[mode]:
- channel.modes[mode].append(user)
- elif mode not in channel.modes.keys():
- channel.modes[mode] = [user]
-
- elif cmd == 315: # End of WHO reply
- (handled, unhandled, exceptions) = self.event("onWhoEnd", self.addons+channel.addons, origin=origin, param=params, endmsg=extinfo)
-
- elif cmd == 353: # NAMES reply
- (flag, channame) = params.split()
- channel = self.channel(channame)
- self.event("onRecv", channel.addons, line=line, **data)
-
- if "PREFIX" in self.supports:
- names = re.findall(r"([%s]*)([^@!\s]+)(?:!(\S+)@(\S+))?"%re.escape(self.supports["PREFIX"][1]), extinfo)
- else:
- names = re.findall(r"()([^@!\s]+)(?:!(\S+)@(\S+))?", extinfo) # Still put it into tuple form for compatibility in the next structure
- (handled, unhandled, exceptions) = self.event("onNames", self.addons+channel.addons, origin=origin, channel=channel, flag=flag, channame=channame, nameslist=names)
-
- for (symbs, nick, username, host) in names:
- user = self.user(nick)
- if user.nick != nick:
- user.nick = nick
- if username and user.username != username:
- user.username = username
- if host and user.host != host:
- user.host = host
- with channel.lock:
- if channel not in user.channels:
- user.channels.append(channel)
- if user not in channel.users:
- channel.users.append(user)
- if "PREFIX" in self.supports:
- for symb in symbs:
- mode = self.supports["PREFIX"][0][self.supports["PREFIX"][1].index(symb)]
- if mode not in channel.modes:
- channel.modes[mode] = [user]
- elif user not in channel.modes[mode]:
- channel.modes[mode].append(user)
-
- elif cmd == 366: # End of NAMES reply
- channel = self.channel(params)
- (handled, unhandled, exceptions) = self.event("onNamesEnd", self.addons+channel.addons, origin=origin, channel=channel, channame=params, endmsg=extinfo)
-
- elif cmd == 372: # MOTD line
- (handled, unhandled, exceptions) = self.event("onMOTDLine", self.addons, origin=origin, motdline=extinfo)
- self.motd.append(extinfo)
- elif cmd == 375: # Begin MOTD
- (handled, unhandled, exceptions) = self.event("onMOTDStart", self.addons, origin=origin, motdgreet=extinfo)
- self.motdgreet = extinfo
- self.motd = []
- elif cmd == 376:
- (handled, unhandled, exceptions) = self.event("onMOTDEnd", self.addons, origin=origin, motdend=extinfo)
- self.motdend = extinfo # End of MOTD
-
- elif cmd == 386 and "q" in self.supports["PREFIX"][0]: # Channel Owner (Unreal)
- (channame, owner) = params.split()
- channel = self.channel(channame)
- self.event("onRecv", channel.addons, line=line, **data)
- if channel.name != channame:
- channel.name = channame # Server seems to have changed the idea of the case of the channel name
- user = self.user(owner)
- if user.nick != owner:
- user.nick = owner
- if "q" in channel.modes:
- if user not in channel.modes["q"]:
- channel.modes["q"].append(user)
- else:
- channel.modes["q"] = [user]
-
- elif cmd == 388 and "a" in self.supports["PREFIX"][0]: # Channel Admin (Unreal)
- (channame, admin) = params.split()
- channel = self.channel(channame)
- self.event("onRecv", channel.addons, line=line, **data)
- if channel.name != channame:
- channel.name = channame # Server seems to have changed the idea of the case of the channel name
- user = self.user(admin)
- if user.nick != admin:
- user.nick = admin
- if "a" in channel.modes:
- if user not in channel.modes["a"]:
- channel.modes["a"].append(user)
- else:
- channel.modes["a"] = [user]
-
- elif cmd == "NICK":
- newnick = extinfo if len(extinfo) else target
-
- addons = reduce(lambda x, y: x+y, [chan.addons for chan in origin.channels], [])
- self.event("onRecv", addons, line=line, **data)
- (handled, unhandled, exceptions) = self.event("onNickChange", self.addons+addons, user=origin, newnick=newnick)
- if origin == self.identity:
- (handled, unhandled, exceptions) = self.event("onMeNickChange", self.addons+addons, newnick=newnick)
-
- for u in self.users:
- if u.nick.lower() == newnick.lower():
- self.users.remove(u) # Nick collision, safe to assume this orphaned user is offline, so we shall remove the old instance.
- for channel in self.channels:
- ### If for some odd reason, the old user still appears common channels, then we will remove the user anyway.
- if u in channel.users:
- channel.users.remove(u)
- origin.nick = newnick
-
- elif cmd == "JOIN":
- channel = target if type(target) == Channel else self.channel(extinfo)
- self.event("onRecv", channel.addons, line=line, **data)
- (handled, unhandled, exceptions) = self.event("onJoin", self.addons+channel.addons, user=origin, channel=channel)
-
- if origin == self.identity: # This means the bot is entering the room,
- # and will reset all the channel data, on the assumption that such data may have changed.
- # Also, the bot must request modes
- with channel._joining:
- if channel._joinrequested:
- channel._joinreply = cmd
- channel._joining.notify()
- channel.topic = ""
- channel.topicmod = ""
- channel.modes = {}
- channel.users = []
- self.event("onMeJoin", self.addons+channel.addons, channel=channel)
- self.raw("MODE %s" % channel.name)
- self.raw("WHO %s" % channel.name)
- if "CHANMODES" in self.supports.keys():
- self.raw("MODE %s :%s" % (channel.name, self.supports["CHANMODES"][0]))
-
- if channel not in origin.channels:
- origin.channels.append(channel)
- if origin not in channel.users:
- channel.users.append(origin)
-
- elif cmd == "KICK":
- kicked = self.user(params)
- if kicked.nick != params:
- kicked.nick = params
-
- self.event("onRecv", target.addons, line=line, **data)
- if origin == self.identity:
- self.event("onMeKick", self.addons+target.addons, channel=target, kicked=kicked, kickmsg=extinfo)
- if kicked == self.identity:
- self.event("onMeKicked", self.addons+target.addons, kicker=origin, channel=target, kickmsg=extinfo)
- (handled, unhandled, exceptions) = self.event("onKick", self.addons+target.addons, kicker=origin, channel=target, kicked=kicked, kickmsg=extinfo)
-
- if target in kicked.channels:
- kicked.channels.remove(target)
- if kicked in target.users:
- target.users.remove(kicked)
- if "PREFIX" in self.supports:
- for mode in self.supports["PREFIX"][0]:
- if mode in target.modes and kicked in target.modes[mode]:
- target.modes[mode].remove(kicked)
-
- elif cmd == "PART":
- self.event("onRecv", target.addons, line=line, **data)
- if origin == self.identity:
- with target ._parting:
- if target._partrequested:
- target._partreply = cmd
- target._parting.notify()
- self.event("onMePart", self.addons+target.addons, channel=target, partmsg=extinfo)
- (handled, unhandled, exceptions) = self.event("onPart", self.addons+target.addons, user=origin, channel=target, partmsg=extinfo)
-
- if target in origin.channels:
- origin.channels.remove(target)
- if origin in target.users:
- target.users.remove(origin)
- if "PREFIX" in self.supports:
- for mode in self.supports["PREFIX"][0]:
- if mode in target.modes and origin in target.modes[mode]:
- target.modes[mode].remove(origin)
-
- elif cmd == "QUIT":
- channels = list(origin.channels)
- addons = reduce(lambda x, y: x+y, [chan.addons for chan in origin.channels], [])
- self.event("onRecv", addons, line=line, **data)
- (handled, unhandled, exceptions) = self.event("onQuit", self.addons+addons, user=origin, quitmsg=extinfo)
- for channel in origin.channels:
- with channel.lock:
- if origin in channel.users:
- channel.users.remove(origin)
- if "PREFIX" in self.supports:
- for mode in self.supports["PREFIX"][0]:
- if mode in channel.modes and origin in channel.modes[mode]:
- channel.modes[mode].remove(origin)
- origin.channels = []
-
- elif cmd == "MODE":
- if type(target) == Channel:
- self.event("onRecv", target.addons, line=line, **data)
- modedelta = []
- modeparams = params.split()
- setmodes = modeparams.pop(0)
- modeset = "+"
- for mode in setmodes:
- if mode in "+-":
- modeset = mode
- else:
- if mode in self.supports["CHANMODES"][0]+self.supports["CHANMODES"][1]:
- param = modeparams.pop(0)
- modedelta.append(("%s%s"%(modeset, mode), param))
- if mode in maskmodeeventnames.keys():
- if modeset == "+":
- eventname = maskmodeeventnames[mode][0]
- if modeset == "-":
- eventname = maskmodeeventnames[mode][1]
- matchesbot = glob.fnmatch.fnmatch("%s!%s@%s".lower()%(self.identity.nick, self.identity.username, self.identity.host), param.lower())
- self.event("on%s"%eventname, self.addons+target.addons, user=origin, channel=target, banmask=param)
- if matchesbot:
- self.event("onMe%s"%eventname, self.addons+target.addons, user=origin, channel=target, banmask=param)
- elif mode in self.supports["CHANMODES"][2]:
- if modeset == "+":
- param = modeparams.pop(0)
- modedelta.append(("%s%s"%(modeset, mode), param))
- else:
- modedelta.append(("%s%s"%(modeset, mode), None))
- elif mode in self.supports["CHANMODES"][3]:
- modedelta.append(("%s%s"%(modeset, mode), None))
- elif "PREFIX" in self.supports and mode in self.supports["PREFIX"][0]:
- modenick = modeparams.pop(0)
- modeuser = self.user(modenick)
- if mode in privmodeeventnames.keys():
- if modeset == "+":
- eventname = privmodeeventnames[mode][0]
- if modeset == "-":
- eventname = privmodeeventnames[mode][1]
- self.event("on%s"%eventname, self.addons+target.addons, user=origin, channel=target, modeuser=modeuser)
- if modeuser == self.identity:
- self.event("onMe%s"%eventname, self.addons+target.addons, user=origin, channel=target)
- modedelta.append(("%s%s"%(modeset, mode), modeuser))
- (handled, unhandled, exceptions) = self.event("onChanModeSet", self.addons+target.addons, user=origin, channel=target, modedelta=modedelta)
- with target.lock:
- for ((modeset, mode), param) in modedelta:
- if mode in self.supports["CHANMODES"][0]:
- if modeset == "+":
- if mode in target.modes:
- if param.lower() not in [mask.lower() for (mask, setby, settime) in target.modes[mode]]:
- target.modes[mode].append((param, origin, int(time.time())))
- else:
- target.modes[mode] = [(param, origin, int(time.time()))]
- else:
- if mode in target.modes.keys():
- if mode == "b": # Inspircd mode is case insentive when unsetting the mode
- masks = [mask.lower() for (mask, setby, settime) in target.modes[mode]]
- if param.lower() in masks:
- index = masks.index(param.lower())
- #print "Index: %d"%index
- del target.modes[mode][index]
- else:
- masks = [mask for (mask, setby, settime) in target.modes[mode]]
- if param in masks:
- index = masks.index(param)
- del target.modes[mode][index]
- elif mode in self.supports["CHANMODES"][1]:
- if modeset == "+":
- target.modes[mode] = param
- else:
- target.modes[mode] = None
- elif mode in self.supports["CHANMODES"][2]:
- if modeset == "+":
- target.modes[mode] = param
- else:
- target.modes[mode] = None
- elif mode in self.supports["CHANMODES"][3]:
- if modeset == "+":
- target.modes[mode] = True
- else:
- target.modes[mode] = False
- elif "PREFIX" in self.supports and mode in self.supports["PREFIX"][0]:
- if modeset == "+":
- if mode in target.modes and param not in target.modes[mode]:
- target.modes[mode].append(param)
- if mode not in target.modes:
- target.modes[mode] = [param]
- elif mode in target.modes and param in target.modes[mode]:
- target.modes[mode].remove(param)
- elif type(target) == User:
- modeparams = (params if params else extinfo).split()
- setmodes = modeparams.pop(0)
- modeset = "+"
- for mode in setmodes:
- if mode in "+-":
- modeset = mode
- continue
- if modeset == "+":
- if mode not in target.modes:
- target.modes += mode
- if mode == "s" and len(modeparams):
- snomask = modeparams.pop(0)
- for snomode in snomask:
- if snomode in "+-":
- snomodeset = snomode
- continue
- if snomodeset == "+" and snomode not in target.snomask:
- target.snomask += snomode
- if snomodeset == "-" and snomode in target.snomask:
- target.snomask = target.snomask.replace(snomode, "")
- if modeset == "-":
- if mode in target.modes:
- target.modes = target.modes.replace(mode, "")
- if mode == "s":
- target.snomask = ""
-
- elif cmd == "TOPIC":
- self.event("onRecv", target.addons, line=line, **data)
- (handled, unhandled, exceptions) = self.event("onTopicSet", self.addons+target.addons, user=origin, channel=target, topic=extinfo)
-
- with target.lock:
- target.topic = extinfo
- target.topicsetby = origin
- target.topictime = int(time.time())
-
- elif cmd == "INVITE":
- channel = self.channel(extinfo if extinfo else params)
- self.event("onRecv", channel.addons, line=line, **data)
- (handled, unhandled, exceptions) = self.event("onInvite", self.addons+channel.addons, user=origin, channel=channel)
-
- elif cmd == "PRIVMSG":
- if type(target) == Channel:
- self.event("onRecv", target.addons, line=line, **data)
-
- ### CTCP handling
- ctcp = re.findall("^\x01(.*?)(?:\\s+(.*?)\\s*)?\x01$", extinfo)
- if ctcp:
- (ctcptype, ext) = ctcp[0]
- if ctcptype.upper() == "ACTION":
- if type(target) == Channel:
- (handled, unhandled, exceptions) = self.event("onChanAction", self.addons+target.addons, user=origin, channel=target, targetprefix=targetprefix, action=ext)
- elif target == self.identity:
- (handled, unhandled, exceptions) = self.event("onPrivAction", self.addons, user=origin, action=ext)
- else:
- if type(target) == Channel:
- (handled, unhandled, exceptions) = self.event("onChanCTCP", self.addons+target.addons, user=origin, channel=target, targetprefix=targetprefix, ctcptype=ctcptype, params=ext)
- elif target == self.identity:
- (handled, unhandled, exceptions) = self.event("onPrivCTCP", self.addons, user=origin, ctcptype=ctcptype, params=ext)
- if ctcptype.upper() == "VERSION":
- origin.ctcpreply("VERSION", self.ctcpversion())
- if ctcptype.upper() == "TIME":
- tformat = time.ctime()
- tz = time.tzname[0]
- origin.ctcpreply("TIME", "%(tformat)s %(tz)s" % vars())
- if ctcptype.upper() == "PING":
- origin.ctcpreply("PING", "%(ext)s" % vars())
- if ctcptype.upper() == "FINGER":
- origin.ctcpreply("FINGER", "%(ext)s" % vars())
- else:
- if type(target) == Channel:
- (handled, unhandled, exceptions) = self.event("onChanMsg", self.addons+target.addons, user=origin, channel=target, targetprefix=targetprefix, msg=extinfo)
- elif target == self.identity:
- (handled, unhandled, exceptions) = self.event("onPrivMsg", self.addons, user=origin, msg=extinfo)
-
- elif cmd == "NOTICE":
- if type(target) == Channel:
- self.event("onRecv", target.addons, line=line, **data)
-
- ### CTCP handling
- ctcp = re.findall("^\x01(.*?)(?:\\s+(.*?)\\s*)?\x01$", extinfo)
- if ctcp and target == self.identity:
- (ctcptype, ext) = ctcp[0]
- (handled, unhandled, exceptions) = self.event("onCTCPReply", self.addons, origin=origin, ctcptype=ctcptype, params=ext)
- else:
- if type(target) == Channel:
- (handled, unhandled, exceptions) = self.event("onChanNotice", self.addons+target.addons, origin=origin, channel=target, targetprefix=targetprefix, msg=extinfo)
- elif target == self.identity:
- (handled, unhandled, exceptions) = self.event("onPrivNotice", self.addons, origin=origin, msg=extinfo)
-
- elif cmd == 367: # Channel Ban list
- (channame, mask, setby, settime) = params.split()
- channel = self.channel(channame)
- self.event("onRecv", channel.addons, line=line, **data)
- (handled, unhandled, exceptions) = self.event("onBanListEntry", self.addons+channel.addons, origin=origin, channel=channel, mask=mask, setby=setby, settime=int(settime))
- if "b" in channel.modes.keys():
- if mask.lower() not in [m.lower() for (m, s, t) in channel.modes["b"]]:
- channel.modes["b"].append((mask, setby, int(settime)))
- else:
- channel.modes["b"] = [(mask, setby, int(settime))]
- elif cmd == 368:
- channel = self.channel(params)
- self.event("onRecv", channel.addons, line=line, **data)
- (handled, unhandled, exceptions) = self.event("onBanListEnd", self.addons+channel.addons, origin=origin, channel=channel, endmsg=extinfo)
-
- elif cmd == 346: # Channel Invite list
- (channame, mask, setby, settime) = params.split()
- channel = self.channel(channame)
- self.event("onRecv", channel.addons, line=line, **data)
- (handled, unhandled, exceptions) = self.event("onInviteListEntry", self.addons+channel.addons, origin=origin, channel=channel, mask=mask, setby=setby, settime=int(settime))
- if "I" in channel.modes.keys():
- if mask.lower() not in [m.lower() for (m, s, t) in channel.modes["I"]]:
- channel.modes["I"].append((mask, setby, int(settime)))
- else:
- channel.modes["I"] = [(mask, setby, int(settime))]
- elif cmd == 347:
- channel = self.channel(params)
- self.event("onRecv", channel.addons, line=line, **data)
- (handled, unhandled, exceptions) = self.event("onInviteListEnd", self.addons+channel.addons, origin=origin, channel=channel, endmsg=extinfo)
-
- elif cmd == 348: # Channel Ban Exception list
- (channame, mask, setby, settime) = params.split()
- channel = self.channel(channame)
- self.event("onRecv", channel.addons, line=line, **data)
- (handled, unhandled, exceptions) = self.event("onBanExceptListEntry", self.addons+channel.addons, origin=origin, channel=channel, mask=mask, setby=setby, settime=int(settime))
- if "e" in channel.modes.keys():
- if mask.lower() not in [m.lower() for (m, s, t) in channel.modes["e"]]:
- channel.modes["e"].append((mask, setby, int(settime)))
- else:
- channel.modes["e"] = [(mask, setby, int(settime))]
- elif cmd == 349:
- channel = self.channel(params)
- self.event("onRecv", channel.addons, line=line, **data)
- (handled, unhandled, exceptions) = self.event("onBanExceptListEnd", self.addons+channel.addons, origin=origin, channel=channel, endmsg=extinfo)
-
- elif cmd == 910: # Channel Access List
- (channame, mask, setby, settime) = params.split()
- channel = self.channel(channame)
- self.event("onRecv", channel.addons, line=line, **data)
- (handled, unhandled, exceptions) = self.event("onAccessListEntry", self.addons+channel.addons, origin=origin, channel=channel, mask=mask, setby=setby, settime=int(settime))
- if "w" in channel.modes.keys():
- if mask.lower() not in [m.lower() for (m, s, t) in channel.modes["b"]]:
- channel.modes["w"].append((mask, setby, int(settime)))
- else:
- channel.modes["w"] = [(mask, setby, int(settime))]
- elif cmd == 911:
- channel = self.channel(params)
- self.event("onRecv", channel.addons, line=line, **data)
- (handled, unhandled, exceptions) = self.event("onAccessListEnd", self.addons+channel.addons, origin=origin, channel=channel, endmsg=extinfo)
-
- elif cmd == 941: # Spam Filter list
- (channame, mask, setby, settime) = params.split()
- channel = self.channel(channame)
- self.event("onRecv", channel.addons, line=line, **data)
- (handled, unhandled, exceptions) = self.event("onSpamfilterListEntry", self.addons+channel.addons, origin=origin, channel=channel, mask=mask, setby=setby, settime=int(settime))
- if "g" in channel.modes.keys():
- if mask.lower() not in [m.lower() for (m, s, t) in channel.modes["g"]]:
- channel.modes["g"].append((mask, setby, int(settime)))
- else:
- channel.modes["g"] = [(mask, setby, int(settime))]
- elif cmd == 940:
- channel = self.channel(params)
- self.event("onRecv", channel.addons, line=line, **data)
- (handled, unhandled, exceptions) = self.event("onSpamfilterListEnd", self.addons+channel.addons, origin=origin, channel=channel, endmsg=extinfo)
-
- elif cmd == 954: # Channel exemptchanops list
- (channame, mask, setby, settime) = params.split()
- channel = self.channel(channame)
- self.event("onRecv", channel.addons, line=line, **data)
- (handled, unhandled, exceptions) = self.event("onExemptChanOpsListEntry", self.addons+channel.addons, origin=origin, channel=channel, mask=mask, setby=setby, settime=int(settime))
- if "X" in channel.modes.keys():
- if mask.lower() not in [m.lower() for (m, s, t) in channel.modes["X"]]:
- channel.modes["X"].append((mask, setby, int(settime)))
- else:
- channel.modes["X"] = [(mask, setby, int(settime))]
- elif cmd == 953:
- channel = self.channel(params)
- self.event("onRecv", channel.addons, line=line, **data)
- (handled, unhandled, exceptions) = self.event("onExemptChanOpsListEnd", self.addons+channel.addons, origin=origin, channel=channel, endmsg=extinfo)
-
- elif cmd == 728: # Channel quiet list
- (channame, modechar, mask, setby, settime) = params.split()
- channel = self.channel(channame)
- self.event("onRecv", channel.addons, line=line, **data)
- (handled, unhandled, exceptions) = self.event("onQuietListEntry", self.addons+channel.addons, origin=origin, channel=channel, modechar=modechar, mask=mask, setby=setby, settime=int(settime))
- if "q" in channel.modes.keys():
- if mask.lower() not in [m.lower() for (m, s, t) in channel.modes["q"]]:
- channel.modes["q"].append((mask, setby, int(settime)))
- else:
- channel.modes["q"] = [(mask, setby, int(settime))]
- elif cmd == 729:
- channame, modechar = params.split()
- channel = self.channel(channame)
- self.event("onRecv", channel.addons, line=line, **data)
- (handled, unhandled, exceptions) = self.event("onQuietListEnd", self.addons+channel.addons, channel=channel, endmsg=extinfo)
-
- elif cmd in (495, 384, 385, 386, 468, 470, 366, 315, 482, 484, 953, 368, 482, 349, 940, 911, 489, 490, 492, 520, 530): # Channels which appear in params
- for param in params.split():
- if len(param) and param[0] in self.supports["CHANTYPES"]:
- channel = self.channel(param)
- self.event("onRecv", channel.addons, line=line, **data)
-
- elif type(cmd) == int:
- (handled, unhandled, exceptions) = self.event("on%03d"%cmd, self.addons, line=line, origin=origin, target=target, params=params, extinfo=extinfo)
- else:
- (handled, unhandled, exceptions) = self.event("on%s"%cmd, self.addons, line=line, origin=origin, cmd=cmd, target=target, params=params, extinfo=extinfo)
-
- if cmd in (384, 403, 405, 471, 473, 474, 475, 476, 520, 477, 489, 495): # Channel Join denied
- try:
- channel = self.channel(params)
- except InvalidName:
- pass
- else:
- with channel._joining:
- if channel._joinrequested:
- channel._joinreply = (cmd, extinfo)
- channel._joining.notify()
-
- elif cmd == 470: # Channel Join denied due to redirect
- channelname, redirect = params.split()
- try:
- channel = self.channel(channelname)
- except InvalidName:
- pass
- else:
- with channel._joining:
- if channel._joinrequested:
- channel._joinreply = (cmd, "%s (%s)"%(extinfo, redirect))
- channel._joining.notify()
-
- self.event("onUnhandled", unhandled, line=line, origin=origin, cmd=cmd, target=target, params=params, extinfo=extinfo)
-
- else: # Line does NOT match ":origin cmd target params :extinfo"
- self.event("onRecv", self.addons, line=line)
except SystemExit: # Connection lost normally.
pass
+
except socket.error: # Connection lost due to either ping timeout or connection reset by peer. Not a fatal error.
exc, excmsg, tb = sys.exc_info()
- self.logwrite("*** Connection to %(server)s:%(port)s failed: %(excmsg)s." % vars())
+ with self.lock:
+ self.logwrite(
+ "*** Connection to %(server)s:%(port)s failed: %(excmsg)s." % vars())
+ self._event("onConnectFail", self.addons + reduce(
+ lambda x, y: x + y, [chan.addons for chan in self.channels], []), exc=exc, excmsg=excmsg, tb=tb)
+
except: # Unknown exception, treated as FATAL. Try to quit IRC and terminate thread with exception.
- ### Quit with a (hopefully) useful quit message, or die trying.
- self.quitexpected = True
+ # Quit with a (hopefully) useful quit message, or die
+ # trying.
+ self._quitexpected = True
try:
- self.quit("%s" % traceback.format_exc()
- .rstrip().split("\n")[-1])
+ self.quit(
+ "%s" % traceback.format_exc().rstrip().split("\n")[-1])
except:
pass
raise
+
finally: # Post-connection operations after connection is lost, and must be executed, even if exception occurred.
+ with self._sendline:
+ self._outgoing.clear()
+ self._sendline.notify()
with self.lock:
- (handled, unhandled, exceptions) = self.event("onDisconnect", self.addons+reduce(lambda x, y: x+y, [chan.addons for chan in self.channels], []), expected=self.quitexpected)
- self.connected = False
- self.registered = False
- self.identity = None
-
- ### Tell outgoing thread to quit.
- self.outgoing.interrupt()
+ (handled, unhandled, exceptions) = self._event("onDisconnect", self.addons + reduce(
+ lambda x, y: x + y, [chan.addons for chan in self.channels], []), expected=self._quitexpected)
+ self._init()
- ### Wait until the outgoing thread dies.
- if self.outgoingthread and self.outgoingthread.isAlive():
- self.outgoingthread.join()
- self.outgoingthread = None
+ # Notify _outgoingthread that the connection has been
+ # terminated.
+ with self._sendline:
+ self._sendline.notify()
try:
- self.connection.close()
+ self._connection.close()
except:
pass
self.logwrite("*** Connection Terminated.")
- if self.quitexpected or not self.autoreconnect:
+ if self._quitexpected or not self.autoreconnect:
+ self._quitexpected = False
sys.exit()
- ### If we make it to this point, then it is because connection was lost unexpectedly, and will attempt to reconnect if self.autoreconnect is True.
- time.sleep(self.retrysleep)
-
except SystemExit:
pass
except: # Print exception to log file
- self.logwrite(*["!!! FATAL Exception"]+["!!! %s"%line for line in traceback.format_exc().split("\n")])
- print >>sys.stderr, "FATAL Exception" % vars()
+ self.logwrite(*["!!! FATAL Exception"] + ["!!! %s" %
+ line for line in traceback.format_exc().split("\n")])
+ print >>sys.stderr, "FATAL Exception"
print >>sys.stderr, traceback.format_exc()
sys.exit()
finally:
self.logwrite("### Log session ended")
- (handled, unhandled, exceptions) = self.event("onSessionClose", self.addons+reduce(lambda x, y: x+y, [chan.addons for chan in self.channels], []))
- Thread.__init__(self) # Makes thread restartable
+ (handled, unhandled, exceptions) = self._event("onSessionClose", self.addons +
+ reduce(lambda x, y: x + y, [chan.addons for chan in self.channels], []))
+
+ # Tell _sendhandler to quit
+ with self._sendline:
+ self._outgoing.append("quit")
+ self._sendline.notify()
+
+ def _send(self, line, origin=None):
+ if "\r" in line or "\n" in line:
+ raise InvalidCharacter
+ cmd = line.split(" ")[0].upper()
+
+ T = time.time()
+ if cmd == "PRIVMSG":
+ # Hard-coding a throttling mechanism for PRIVMSGs only here. Will later build support for custom throttlers.
+ # The throttle will be triggered when it attempts to send a sixth PRIVMSG in a four-second interval.
+ # When the throttle is active, PRIVMSGs will be sent in at least one-second intervals.
+ # The throttle is deactivated when three seconds elapse without
+ # sending a PRIVMSG.
+ while len(self.throttledata) and self.throttledata[0] < T - 4:
+ del self.throttledata[0]
+ if not self.throttled:
+ if len(self.throttledata) >= 5:
+ self.throttled = True
+ T = self.throttledata[-1] + 1
+ else:
+ if len(self.throttledata) == 0 or self.throttledata[-1] < T - 2:
+ self.throttled = False
+ else:
+ T = max(T, self.throttledata[-1] + 1)
+ self.throttledata.append(T)
+ with self._sendline:
+ self._outgoing.append((T, line, origin))
+ self._sendline.notify()
+
+ def _procsendline(self, line, origin=None):
+ match = re.findall(_ircsendmatch, line)
+ if len(match) == 0:
+ return
+ (cmd, target, params, extinfo) = match[0]
+ cmd = cmd.upper()
+ with self.lock:
+ if cmd == "QUIT":
+ self._quitexpected = True
+ self._connection.send("%s\n" % line)
+
+ # Modify line if it contains a password so that the password is not
+ # logged or sent to any potentially untrustworthy addons
+ if cmd == "PRIVMSG":
+ if target.upper() == "NICKSERV":
+ nscmd = re.findall(
+ r"^\s*(\S+)\s+(\S+)(?:\s*(\S+)(?:\s*(.+))?)?$", extinfo, re.I)
+ if nscmd:
+ nscmd = nscmd[0]
+ if nscmd[0].upper() in ("IDENTIFY", "REGISTER"):
+ extinfo = "%s ********" % nscmd[0]
+ line = "%s %s :%s" % (cmd, target, extinfo)
+ elif nscmd[0].upper() in ("GROUP", "GHOST", "RECOVER", "RELEASE"):
+ extinfo = "%s %s ********" % nscmd[:2]
+ line = "%s %s :%s" % (cmd, target, extinfo)
+ elif nscmd[0].upper() == "SET":
+ if nscmd[1].upper() == "PASSWORD":
+ extinfo = "%s %s ********" % nscmd[:2]
+ line = "%s %s :%s" % (cmd, target, extinfo)
+ elif nscmd[0].upper() not in ("GLIST", "ACCESS", "SASET", "DROP", "SENDPASS", "ALIST", "INFO", "LIST", "LOGOUT", "STATUS", "UPDATE", "GETPASS", "FORBID", "SUSPEND", "UNSUSPEND", "OINFO"):
+ extinfo = "********"
+ line = "%s %s :%s" % (cmd, target, extinfo)
+ if target.upper() == "CHANSERV":
+ cscmd = re.findall(
+ r"^\s*(\S+)\s+(\S+)\s+(\S+)(?:\s*(\S+)(?:\s*(.+))?)?$", extinfo, re.I)
+ if cscmd:
+ cscmd = cscmd[0]
+ if cscmd[0].upper() in ("IDENTIFY", "REGISTER"):
+ extinfo = "%s %s ********" % cscmd[:2]
+ line = "%s %s :%s" % (cmd, target, extinfo)
+ elif cscmd[0].upper() in ("GROUP", "GHOST", "RECOVER", "RELEASE"):
+ extinfo = "%s %s %s ********" % cscmd[:3]
+ line = "%s %s :%s" % (cmd, target, extinfo)
+ elif cscmd[0].upper() == "SET":
+ if cscmd[2].upper() == "PASSWORD":
+ extinfo = "%s %s %s ********" % cscmd[:3]
+ line = "%s %s :%s" % (cmd, target, extinfo)
+ elif cscmd[0].upper() not in ("GLIST", "ACCESS", "SASET", "DROP", "SENDPASS", "ALIST", "INFO", "LIST", "LOGOUT", "STATUS", "UPDATE", "GETPASS", "FORBID", "SUSPEND", "UNSUSPEND", "OINFO"):
+ extinfo = "********"
+ line = "%s %s :%s" % (cmd, target, extinfo)
+
+ chanmatch = re.findall(
+ _targchanmatch % (re.escape(self.supports.get("PREFIX", ("ohv", "@%+"))[1]), re.escape(self.supports.get("CHANTYPES", "#"))), target)
+ if chanmatch:
+ targetprefix, channame = chanmatch[0]
+ target = self.channel(channame)
+ if target.name != channame:
+ # Target channel name has changed
+ target.name = channame
+ elif re.match(_nickmatch, target) and cmd != "NICK":
+ targetprefix = ""
+ target = self.user(target)
+
+ ctcp = re.findall(_ctcpmatch, extinfo)
+ if ctcp:
+ (ctcptype, ext) = ctcp[0]
+ if ctcptype.upper() == "ACTION":
+ if type(target) == Channel:
+ self._event(
+ "onSendChanAction", self.addons +
+ target.addons,
+ origin=origin, channel=target, targetprefix=targetprefix, action=ext)
+ elif type(target) == User:
+ self._event(
+ "onSendPrivAction", self.addons, origin=origin, user=target, action=ext)
+ else:
+ if type(target) == Channel:
+ self._event(
+ "onSendChanCTCP", self.addons + target.addons, origin=origin,
+ channel=target, targetprefix=targetprefix, ctcptype=ctcptype, params=ext)
+ elif type(target) == User:
+ self._event(
+ "onSendPrivCTCP", self.addons, origin=origin, user=target, ctcptype=ctcptype, params=ext)
+ else:
+ if type(target) == Channel:
+ self._event(
+ "onSendChanMsg", self.addons + target.addons, origin=origin,
+ channel=target, targetprefix=targetprefix, msg=extinfo)
+ elif type(target) == User:
+ self._event(
+ "onSendPrivMsg", self.addons, origin=origin, user=target, msg=extinfo)
+
+ # elif target.upper()=="CHANSERV":
+ #msg=extinfo.split(" ")
+ # if msg[0].upper() in ("IDENTIFY", "REGISTER") and len(msg)>2:
+ # msg[2]="********"
+ #extinfo=" ".join(msg)
+ #line="%s %s :%s"%(cmd, target, extinfo)
+ elif cmd.upper() in ("NS", "NICKSERV"):
+ if target.upper() in ("IDENTIFY", "REGISTER"):
+ params = params.split(" ")
+ while "" in params:
+ params.remove("")
+ if len(params):
+ params[0] = "********"
+ params = " ".join(params)
+ line = "%s %s %s" % (cmd, target, params)
+ elif target.upper() in ("GROUP", "GHOST", "RECOVER", "RELEASE"):
+ params = params.split(" ")
+ while "" in params:
+ params.remove("")
+ if len(params) > 1:
+ params[1] = "********"
+ params = " ".join(params)
+ line = "%s %s %s" % (cmd, target, params)
+ elif target.upper() not in ("GLIST", "ACCESS", "SASET", "DROP", "SENDPASS", "ALIST", "INFO", "LIST", "LOGOUT", "STATUS", "UPDATE", "GETPASS", "FORBID", "SUSPEND", "UNSUSPEND", "OINFO"):
+ params = ""
+ target = "********"
+ line = "%s %s" % (cmd, target)
+ elif cmd.upper() == "OPER":
+ params = "********"
+ line = "%s %s %s" % (cmd, target, params)
+ elif cmd.upper() == "PASS":
+ extinfo = "********"
+ target = ""
+ line = "%s :%s" % (cmd, extinfo)
+ elif cmd.upper() == "IDENTIFY":
+ target = "********"
+ line = "%s %s" % (cmd, target)
+ self._event("onSend", self.addons, origin=origin, line=line,
+ cmd=cmd, target=target, params=params, extinfo=extinfo)
+ self.logwrite(">>> %s" % line)
+
+ def _sendhandler(self):
+ # Enforce that this function must only be run from within
+ # self._sendhandlerthread.
+ if currentThread() != self._sendhandlerthread:
+ raise RuntimeError, "This function is designed to run in its own thread."
+
+ try:
+ while True:
+ # Wait for one of the following:
+ # (1) An item placed into _outgoing
+ # (2) Connection is lost
+ # (3) self._recvhandlerthread is set to None
+
+ with self._sendline:
+ if "quit" in self._outgoing:
+ sys.exit()
+ S = time.time()
+ if len(self._outgoing):
+ T, line, origin = min(self._outgoing)
+ if T > S:
+ self._sendline.wait(T - S)
+ continue
+ else:
+ self._outgoing.remove((T, line, origin))
+ else:
+ self._sendline.wait()
+ continue
+
+ try:
+ self._procsendline(line, origin=origin)
+ except socket.error:
+ exc, excmsg, tb = sys.exc_info()
+ with self.lock:
+ self.logwrite(
+ "*** Connection to %(server)s:%(port)s failed: %(excmsg)s." % vars())
+ self._event("onConnectFail", self.addons + reduce(
+ lambda x, y: x + y, [chan.addons for chan in self.channels], []), exc=exc, excmsg=excmsg, tb=tb)
+ with self._sendline:
+ self._outgoing.clear()
+ try:
+ self._connection.close()
+ except:
+ pass
+
+ except SystemExit:
+ pass
+
+ except:
+ tb = traceback.format_exc()
+ self._quitexpected = True
+ self.logwrite(*["!!! FATAL Exception"] + [
+ "!!! %s" % line for line in tb.split("\n")])
+ print >>sys.stderr, "FATAL Exception"
+ print >>sys.stderr, tb
+ with self._sendline:
+ try:
+ self._connection.send(
+ "QUIT :%s\n" % tb.rstrip().split("\n")[-1])
+ self._connection.shutdown(socket.SHUT_WR)
+ except:
+ pass
+ finally:
+ with self._sendline:
+ self._outgoing.clear() # Clear out _outgoing.
+
+ # For compatibility, when modules still expect irc.Connection to be a
+ # subclass of threading.Thread
+ def isAlive(self):
+ return type(self._recvhandlerthread) == Thread and self._recvhandlerthread.isAlive() and type(self._sendhandlerthread) == Thread and self._sendhandlerthread.isAlive()
+
+ # For compatibility, when modules still expect irc.Connection to be a
+ # subclass of threading.Thread
+ def start(self):
+ return self.connect()
def __repr__(self):
server = self.server
if self.ipv6 and ":" in server:
- server = "[%s]"%server
+ server = "[%s]" % server
port = self.port
if self.identity:
nick = self.identity.nick
@@ -1212,61 +1713,60 @@ class Connection(Thread):
else:
protocol = "irc"
return "<IRC Context: %(nick)s!%(user)s@%(host)s on %(protocol)s://%(server)s:%(port)s>" % locals()
- #else: return "<IRC Context: irc%(ssl)s://%(server)s:%(port)s>" % locals()
+ # else: return "<IRC Context: irc%(ssl)s://%(server)s:%(port)s>" %
+ # locals()
def oper(self, name, passwd, origin=None):
- self.raw("OPER %s %s" % (re.findall("^([^\r\n\\s]*)", name)[0],
- re.findall("^([^\r\n\\s]*)", passwd)[0]), origin=origin)
+ self.raw("OPER %s %s" %
+ (re.findall("^([^\r\n\\s]*)", name)[0], re.findall("^([^\r\n\\s]*)", passwd)[0]), origin=origin)
def list(self, params="", origin=None):
if len(re.findall("^([^\r\n\\s]*)", params)[0]):
- self.raw("LIST %s" % (re.findall(
- "^([^\r\n\\s]*)", params)[0]), origin=origin)
+ self.raw("LIST %s" %
+ (re.findall("^([^\r\n\\s]*)", params)[0]), origin=origin)
else:
self.raw("LIST", origin=origin)
def getmotd(self, target="", origin=None):
if len(re.findall("^([^\r\n\\s]*)", target)[0]):
- self.raw("MOTD %s" % (re.findall(
- "^([^\r\n\\s]*)", target)[0]), origin=origin)
+ self.raw("MOTD %s" %
+ (re.findall("^([^\r\n\\s]*)", target)[0]), origin=origin)
else:
self.raw("MOTD", origin=origin)
def version(self, target="", origin=None):
if len(re.findall("^([^\r\n\\s]*)", target)[0]):
- self.raw("VERSION %s" % (re.findall(
- "^([^\r\n\\s]*)", target)[0]), origin=origin)
+ self.raw("VERSION %s" %
+ (re.findall("^([^\r\n\\s]*)", target)[0]), origin=origin)
else:
self.raw("VERSION", origin=origin)
def stats(self, query, target="", origin=None):
if len(re.findall("^([^\r\n\\s]*)", target)[0]):
- self.raw("STATS %s %s" % (query, re.findall(
- "^([^\r\n\\s]*)", target)[0]), origin=origin)
+ self.raw("STATS %s %s" %
+ (query, re.findall("^([^\r\n\\s]*)", target)[0]), origin=origin)
else:
- self.raw("STATS %s"%query, origin=origin)
+ self.raw("STATS %s" % query, origin=origin)
def quit(self, msg="", origin=None):
- with self.lock:
- if self.connected:
- if len(re.findall("^([^\r\n]*)", msg)[0]):
- self.raw("QUIT :%s" % re.findall("^([^\r\n]*)",
- msg)[0], origin=origin)
- else:
- self.raw("QUIT", origin=origin)
+ if len(re.findall("^([^\r\n]*)", msg)[0]):
+ self._send("QUIT :%s" %
+ re.findall("^([^\r\n]*)", msg)[0], origin=origin)
+ else:
+ self._send("QUIT", origin=origin)
def ctcpversion(self):
reply = []
- ### Prepare reply for addon
- reply.append("%(__name__)s %(__version__)s, %(__author__)s" %
- vars(self))
+ # Prepare reply for addon
+ reply.append(
+ "%(__name__)s %(__version__)s, %(__author__)s" % vars(self))
- ### Prepare reply for Python and OS versions
+ # Prepare reply for Python and OS versions
pyver = sys.version.split("\n")
- pyver[0] = "Python "+pyver[0]
+ pyver[0] = "Python " + pyver[0]
reply.extend(pyver)
reply.extend(platform.platform().split("\n"))
- ### Prepare reply for extension addons
+ # Prepare reply for extension addons
for addon in self.addons:
try:
r = "%(__name__)s %(__version__)s" % vars(addon)
@@ -1278,46 +1778,47 @@ class Connection(Thread):
return reduce(lambda x, y: "%s; %s" % (x, y), reply)
def raw(self, line, origin=None):
- if "\r" in line or "\n" in line:
- raise InvalidCharacter
- self.outgoing.put((line, origin))
+ self._send(line, origin=origin)
def user(self, nick):
if self.supports.get("CASEMAPPING", "rfc1459") == "ascii":
- users = [user for user in self.users if user.nick.lower(
- ) == nick.lower()]
+ users = [
+ user for user in self.users if user.nick.lower() == nick.lower()]
else:
- users = [user for user in self.users if user.nick.translate(_rfc1459casemapping) == nick.translate(_rfc1459casemapping)]
+ users = [user for user in self.users if user.nick.translate(
+ _rfc1459casemapping) == nick.translate(_rfc1459casemapping)]
if len(users):
return users[0]
else:
user = User(nick, self)
self.users.append(user)
- timestamp = reduce(lambda x, y: x+":"+y, [str(
- t).rjust(2, "0") for t in time.localtime()[0:6]])
+ timestamp = reduce(lambda x, y: x + ":" + y, [
+ str(t).rjust(2, "0") for t in time.localtime()[0:6]])
return user
def channel(self, name):
if self.supports.get("CASEMAPPING", "rfc1459") == "ascii":
- channels = [chan for chan in self.channels if chan.name.lower(
- ) == name.lower()]
+ channels = [
+ chan for chan in self.channels if chan.name.lower() == name.lower()]
else:
- channels = [chan for chan in self.channels if chan.name.translate(_rfc1459casemapping) == name.translate(_rfc1459casemapping)]
+ channels = [chan for chan in self.channels if chan.name.translate(
+ _rfc1459casemapping) == name.translate(_rfc1459casemapping)]
if len(channels):
return channels[0]
else:
- timestamp = reduce(lambda x, y: x+":"+y, [str(
- t).rjust(2, "0") for t in time.localtime()[0:6]])
+ timestamp = reduce(lambda x, y: x + ":" + y, [
+ str(t).rjust(2, "0") for t in time.localtime()[0:6]])
chan = Channel(name, self)
self.channels.append(chan)
return chan
class Channel(object):
+
def __init__(self, name, context):
chantypes = context.supports.get("CHANTYPES", "&#+!")
- if not re.match(r"^[%s][^%s\s]*$" % (re.escape(chantypes), re.escape("\x07,")), name):
- raise InvalidName(repr(name))
+ if not re.match(_chanmatch % re.escape(chantypes), name):
+ raise InvalidName, repr(name)
self.name = name
self.context = context
self.addons = []
@@ -1340,37 +1841,37 @@ class Channel(object):
if target and target not in self.context.supports.get("PREFIX", ("ohv", "@%+"))[1]:
raise InvalidPrefix
for line in re.findall("([^\r\n]+)", msg):
- self.context.raw("PRIVMSG %s%s :%s" % (target,
- self.name, line), origin=origin)
+ self.context._send("PRIVMSG %s%s :%s" %
+ (target, self.name, line), origin=origin)
def who(self, origin=None):
- self.context.raw("WHO %s" % (self.name), origin=origin)
+ self.context._send("WHO %s" % (self.name), origin=origin)
def names(self, origin=None):
- self.context.raw("NAMES %s" % (self.name), origin=origin)
+ self.context._send("NAMES %s" % (self.name), origin=origin)
def notice(self, msg, target="", origin=None):
if target and target not in self.context.supports.get("PREFIX", ("ohv", "@%+"))[1]:
raise InvalidPrefix
for line in re.findall("([^\r\n]+)", msg):
- self.context.raw("NOTICE %s%s :%s" % (target,
- self.name, line), origin=origin)
+ self.context._send("NOTICE %s%s :%s" %
+ (target, self.name, line), origin=origin)
def settopic(self, msg, origin=None):
- self.context.raw("TOPIC %s :%s" % (self.name, re.findall(
- "^([^\r\n]*)", msg)[0]), origin=origin)
+ self.context._send("TOPIC %s :%s" %
+ (self.name, re.findall("^([^\r\n]*)", msg)[0]), origin=origin)
def ctcp(self, act, msg="", origin=None):
if len(re.findall("^([^\r\n]*)", msg)[0]):
- self.msg("\01%s %s\01" % (act.upper(), re.findall(
- "^([^\r\n]*)", msg)[0]), origin=origin)
+ self.msg("\01%s %s\01" %
+ (act.upper(), re.findall("^([^\r\n]*)", msg)[0]), origin=origin)
else:
self.msg("\01%s\01" % act.upper())
def ctcpreply(self, act, msg="", origin=None):
if len(re.findall("^([^\r\n]*)", msg)[0]):
- self.notice("\01%s %(msg)s\01" % (act.upper(),
- re.findall("^([^\r\n]*)", msg)[0]), origin=origin)
+ self.notice("\01%s %(msg)s\01" %
+ (act.upper(), re.findall("^([^\r\n]*)", msg)[0]), origin=origin)
else:
self.notice("\01%s\01" % act.upper(), origin=origin)
@@ -1380,7 +1881,7 @@ class Channel(object):
def part(self, msg="", blocking=False, timeout=30, origin=None):
with self.context.lock:
if self.context.identity not in self.users:
- ### Bot is not on the channel
+ # Bot is not on the channel
raise NotOnChannel
with self._parting:
try:
@@ -1388,19 +1889,20 @@ class Channel(object):
raise ActionAlreadyRequested
self._partrequested = True
if len(re.findall("^([^\r\n]*)", msg)[0]):
- self.context.raw("PART %s :%s" % (self.name, re.findall("^([^\r\n]*)", msg)[0]), origin=origin)
+ self.context._send(
+ "PART %s :%s" % (self.name, re.findall("^([^\r\n]*)", msg)[0]), origin=origin)
else:
- self.context.raw("PART %s" % self.name, origin=origin)
+ self.context._send("PART %s" % self.name, origin=origin)
- ### Anticipated Numeric Replies:
+ # Anticipated Numeric Replies:
- ### ERR_NEEDMOREPARAMS ERR_NOSUCHCHANNEL
- ### ERR_NOTONCHANNEL
+ # ERR_NEEDMOREPARAMS ERR_NOSUCHCHANNEL
+ # ERR_NOTONCHANNEL
if blocking:
endtime = time.time() + timeout
while True:
- self._parting.wait(max(0, endtime-time.time()))
+ self._parting.wait(max(0, endtime - time.time()))
t = time.time()
if not self.context.connected:
raise NotConnected
@@ -1408,7 +1910,7 @@ class Channel(object):
return
elif type(self._partreply) == tuple and len(self._partreply) == 2:
cmd, extinfo = self._partreply
- raise exceptcodes[cmd](extinfo)
+ raise exceptcodes[cmd], extinfo
if t > endtime:
raise RequestTimedOut
finally:
@@ -1420,12 +1922,13 @@ class Channel(object):
user) == User else re.findall("^([^\r\n\\s]*)", user)[0]
if nickname == "":
raise InvalidName
- self.context.raw("INVITE %s %s" % (nickname, self.name), origin=origin)
+ self.context._send("INVITE %s %s" %
+ (nickname, self.name), origin=origin)
def join(self, key="", blocking=False, timeout=30, origin=None):
with self.context.lock:
if self.context.identity in self.users:
- ### Bot is already on the channel
+ # Bot is already on the channel
raise AlreadyJoined
with self._joining:
try:
@@ -1433,22 +1936,23 @@ class Channel(object):
raise ActionAlreadyRequested
self._joinrequested = True
if len(re.findall("^([^\r\n\\s]*)", key)[0]):
- self.context.raw("JOIN %s %s" % (self.name, re.findall("^([^\r\n\\s]*)", key)[0]), origin=origin)
+ self.context._send(
+ "JOIN %s %s" % (self.name, re.findall("^([^\r\n\\s]*)", key)[0]), origin=origin)
else:
- self.context.raw("JOIN %s" % self.name, origin=origin)
+ self.context._send("JOIN %s" % self.name, origin=origin)
- ### Anticipated Numeric Replies:
+ # Anticipated Numeric Replies:
- ### ERR_NEEDMOREPARAMS ERR_BANNEDFROMCHAN
- ### ERR_INVITEONLYCHAN ERR_BADCHANNELKEY
- ### ERR_CHANNELISFULL ERR_BADCHANMASK
- ### ERR_NOSUCHCHANNEL ERR_TOOMANYCHANNELS
- ### ERR_TOOMANYTARGETS ERR_UNAVAILRESOURCE
+ # ERR_NEEDMOREPARAMS ERR_BANNEDFROMCHAN
+ # ERR_INVITEONLYCHAN ERR_BADCHANNELKEY
+ # ERR_CHANNELISFULL ERR_BADCHANMASK
+ # ERR_NOSUCHCHANNEL ERR_TOOMANYCHANNELS
+ # ERR_TOOMANYTARGETS ERR_UNAVAILRESOURCE
if blocking:
endtime = time.time() + timeout
while True:
- self._joining.wait(max(0, endtime-time.time()))
+ self._joining.wait(max(0, endtime - time.time()))
t = time.time()
if not self.context.connected:
raise NotConnected
@@ -1456,7 +1960,7 @@ class Channel(object):
return
elif type(self._joinreply) == tuple and len(self._joinreply) == 2:
cmd, extinfo = self._joinreply
- raise exceptcodes[cmd](extinfo)
+ raise exceptcodes[cmd], extinfo
if t > endtime:
raise RequestTimedOut
finally:
@@ -1469,19 +1973,20 @@ class Channel(object):
if nickname == "":
raise InvalidName
if len(re.findall("^([^\r\n]*)", msg)[0]):
- self.context.raw("KICK %s %s :%s" % (self.name, nickname,
- re.findall("^([^\r\n]*)", msg)[0]), origin=origin)
+ self.context._send("KICK %s %s :%s" %
+ (self.name, nickname, re.findall("^([^\r\n]*)", msg)[0]), origin=origin)
else:
- self.context.raw("KICK %s %s" % (self.name,
- nickname), origin=origin)
+ self.context._send("KICK %s %s" %
+ (self.name, nickname), origin=origin)
def __repr__(self):
- return "<Channel: "+self.name+"@"+self.context.server+"/"+str(self.context.port)+">"
+ return "<Channel: " + self.name + "@" + self.context.server + "/" + str(self.context.port) + ">"
class User(object):
+
def __init__(self, nick, context):
- if not re.match(r"^[A-Za-z\^\`\\\|\_\{\}\[\]][A-Za-z0-9\-\^\`\\\|\_\{\}\[\]]*$", nick):
+ if not re.match(_nickmatch, nick):
raise InvalidName
self.nick = nick
self.username = ""
@@ -1504,202 +2009,27 @@ class User(object):
def msg(self, msg, origin=None):
for line in re.findall("([^\r\n]+)", msg):
- self.context.raw("PRIVMSG %s :%s" % (self.nick,
- line), origin=origin)
+ self.context._send("PRIVMSG %s :%s" %
+ (self.nick, line), origin=origin)
def notice(self, msg, origin=None):
for line in re.findall("([^\r\n]+)", msg):
- self.context.raw("NOTICE %s :%s" % (self.nick,
- line), origin=origin)
+ self.context._send("NOTICE %s :%s" %
+ (self.nick, line), origin=origin)
def ctcp(self, act, msg="", origin=None):
if len(re.findall("^([^\r\n]*)", msg)[0]):
- self.msg("\01%s %s\01" % (act.upper(), re.findall(
- "^([^\r\n]*)", msg)[0]), origin=origin)
+ self.msg("\01%s %s\01" %
+ (act.upper(), re.findall("^([^\r\n]*)", msg)[0]), origin=origin)
else:
self.msg("\01%s\01" % act.upper())
def ctcpreply(self, act, msg="", origin=None):
if len(re.findall("^([^\r\n]*)", msg)[0]):
- self.notice("\01%s %s\01" % (act.upper(),
- re.findall("^([^\r\n]*)", msg)[0]), origin=origin)
+ self.notice("\01%s %s\01" %
+ (act.upper(), re.findall("^([^\r\n]*)", msg)[0]), origin=origin)
else:
self.notice("\01%s\01" % act.upper(), origin=origin)
def me(self, msg="", origin=None):
self.ctcp("ACTION", msg, origin=origin)
-
-
-class Outgoing(Thread):
- def __init__(self, IRC, throttle=0.25, lines=10, t=5):
- self.IRC = IRC
- self.throttle = throttle
- self.lines = lines
- self.time = t
- #self.queue=Queue()
- Thread.__init__(self)
-
- def run(self):
- try:
- throttled = False
- timestamps = []
- while True:
- try:
- q = self.IRC.outgoing.get()
- except Queue.Interrupted:
- break
- if q == "quit" or not self.IRC.connected:
- break
- line, origin = q
- match = re.findall("^(.+?)(?:\\s+(.+?)(?:\\s+(.+?))??)??(?:\\s+:(.*))?$", line, re.I)
- (cmd, target, params, extinfo) = match[0]
- timestamp = reduce(lambda x, y: x+":"+y, [str(t).rjust(
- 2, "0") for t in time.localtime()[0:6]])
- with self.IRC.lock:
- try:
- self.IRC.connection.send("%(line)s\n" % vars())
- except socket.error:
- try:
- self.IRC.connection.shutdown(0)
- except:
- pass
- raise
-
- ### Modify line if it contains a password so that the password is not logged or sent to any potentially untrustworthy addons
- #if re.match("^(.+?)(?:\\s+(.+?)(?:\\s+(.+?))??)??(?:\\s+:(.*))?$", line, re.I):
- if cmd.upper() == "PRIVMSG":
- if target.upper() == "NICKSERV":
- nscmd = re.findall(r"^\s*(\S+)\s+(\S+)(?:\s*(\S+)(?:\s*(.+))?)?$", extinfo, re.I)
- if nscmd:
- nscmd = nscmd[0]
- if nscmd[0].upper() in ("IDENTIFY", "REGISTER"):
- extinfo = "%s ********"%nscmd[0]
- line = "%s %s :%s"%(cmd, target, extinfo)
- elif nscmd[0].upper() in ("GROUP", "GHOST", "RECOVER", "RELEASE"):
- extinfo = "%s %s ********"%nscmd[:2]
- line = "%s %s :%s"%(cmd, target, extinfo)
- elif nscmd[0].upper() == "SET":
- if nscmd[1].upper() == "PASSWORD":
- extinfo = "%s %s ********"%nscmd[:2]
- line = "%s %s :%s"%(cmd, target, extinfo)
- elif nscmd[0].upper() not in ("GLIST", "ACCESS", "SASET", "DROP", "SENDPASS", "ALIST", "INFO", "LIST", "LOGOUT", "STATUS", "UPDATE", "GETPASS", "FORBID", "SUSPEND", "UNSUSPEND", "OINFO"):
- extinfo = "********"
- line = "%s %s :%s"%(cmd, target, extinfo)
- if target.upper() == "CHANSERV":
- cscmd = re.findall(r"^\s*(\S+)\s+(\S+)\s+(\S+)(?:\s*(\S+)(?:\s*(.+))?)?$", extinfo, re.I)
- if cscmd:
- cscmd = cscmd[0]
- if cscmd[0].upper() in ("IDENTIFY", "REGISTER"):
- extinfo = "%s %s ********"%cscmd[:2]
- line = "%s %s :%s"%(cmd, target, extinfo)
- elif cscmd[0].upper() in ("GROUP", "GHOST", "RECOVER", "RELEASE"):
- extinfo = "%s %s %s ********"%cscmd[:3]
- line = "%s %s :%s"%(cmd, target, extinfo)
- elif cscmd[0].upper() == "SET":
- if cscmd[2].upper() == "PASSWORD":
- extinfo = "%s %s %s ********"%cscmd[:3]
- line = "%s %s :%s"%(cmd, target, extinfo)
- elif cscmd[0].upper() not in ("GLIST", "ACCESS", "SASET", "DROP", "SENDPASS", "ALIST", "INFO", "LIST", "LOGOUT", "STATUS", "UPDATE", "GETPASS", "FORBID", "SUSPEND", "UNSUSPEND", "OINFO"):
- extinfo = "********"
- line = "%s %s :%s"%(cmd, target, extinfo)
-
- chanmatch = re.findall("([%s]?)([%s].+)"%(re.escape(self.IRC.supports.get("PREFIX", ("ohv", "@%+"))[1]), re.escape(self.IRC.supports.get("CHANTYPES", "#"))), target)
- if chanmatch:
- targetprefix, channame = chanmatch[0]
- target = self.IRC.channel(channame)
- if target.name != channame:
- ### Target channel name has changed
- target.name = channame
- elif len(target) and target[0] != "$" and cmd != "NICK":
- targetprefix = ""
- target = self.IRC.user(target)
-
- ctcp = re.findall("^\x01(.*?)(?:\\s+(.*?)\\s*)?\x01$",
- extinfo)
- if ctcp:
- (ctcptype, ext) = ctcp[0]
- if ctcptype.upper() == "ACTION":
- if type(target) == Channel:
- self.IRC.event("onSendChanAction", self.IRC.addons+target.addons, origin=origin, channel=target, targetprefix=targetprefix, action=ext)
- elif type(target) == User:
- self.IRC.event("onSendPrivAction", self.IRC.addons, origin=origin, user=target, action=ext)
- else:
- if type(target) == Channel:
- self.IRC.event("onSendChanCTCP", self.IRC.addons+target.addons, origin=origin, channel=target, targetprefix=targetprefix, ctcptype=ctcptype, params=ext)
- elif type(target) == User:
- self.IRC.event("onSendPrivCTCP", self.IRC.addons, origin=origin, user=target, ctcptype=ctcptype, params=ext)
- else:
- if type(target) == Channel:
- self.IRC.event("onSendChanMsg", self.IRC.addons+target.addons, origin=origin, channel=target, targetprefix=targetprefix, msg=extinfo)
- elif type(target) == User:
- self.IRC.event("onSendPrivMsg", self.IRC.addons, origin=origin, user=target, msg=extinfo)
-
- #elif target.upper()=="CHANSERV":
- #msg=extinfo.split(" ")
- #if msg[0].upper() in ("IDENTIFY", "REGISTER") and len(msg)>2:
- #msg[2]="********"
- #extinfo=" ".join(msg)
- #line="%s %s :%s"%(cmd, target, extinfo)
- elif cmd.upper() == "NS":
- if target.upper() in ("IDENTIFY", "REGISTER"):
- params = params.split(" ")
- while "" in params:
- params.remove("")
- if len(params):
- params[0] = "********"
- params = " ".join(params)
- line = "%s %s %s"%(cmd, target, params)
- elif target.upper() in ("GROUP", "GHOST", "RECOVER", "RELEASE"):
- params = params.split(" ")
- while "" in params:
- params.remove("")
- if len(params) > 1:
- params[1] = "********"
- params = " ".join(params)
- line = "%s %s %s"%(cmd, target, params)
- elif target.upper() not in ("GLIST", "ACCESS", "SASET", "DROP", "SENDPASS", "ALIST", "INFO", "LIST", "LOGOUT", "STATUS", "UPDATE", "GETPASS", "FORBID", "SUSPEND", "UNSUSPEND", "OINFO"):
- params = ""
- target = "********"
- line = "%s %s"%(cmd, target)
- elif cmd.upper() == "OPER":
- params = "********"
- line = "%s %s %s"%(cmd, target, params)
- elif cmd.upper() == "PASS":
- extinfo = "********"
- target = ""
- line = "%s :%s"%(cmd, extinfo)
- elif cmd.upper() == "IDENTIFY":
- target = "********"
- line = "%s %s"%(cmd, target)
- self.IRC.event("onSend", self.IRC.addons, origin=origin, line=line, cmd=cmd, target=target, params=params, extinfo=extinfo)
- self.IRC.logwrite(">>> %(line)s" % vars())
- if cmd.upper() == "QUIT":
- self.IRC.quitexpected = True
- timestamps.append(time.time())
- while timestamps[0] < timestamps[-1]-self.time-0.1:
- del timestamps[0]
- if throttled:
- if len(timestamps) < 2:
- throttled = False
- else:
- if len(timestamps) >= self.lines:
- throttled = True
- if throttled:
- time.sleep(max(timestamps[-1] +
- self.throttle-time.time(), 0))
- except:
- self.IRC.connection.send("QUIT :%s\n" %
- traceback.format_exc().rstrip().split("\n")[-1])
- self.IRC.connection.close()
- self.IRC.connection.shutdown(0)
-
-
-class Pinger(Thread):
- def __init__(self, connection, lock=None):
- self.connection = connection
- self.lock = lock
- self.daemon = True
- Thread.__init__(self)
-
- def run(self):
- pass
diff --git a/logger.py b/logger.py
index 01f2bc1..848bb33 100644
--- a/logger.py
+++ b/logger.py
@@ -14,11 +14,20 @@ import ssl
import urllib2
import irc
-modemapping = dict(
- Y="ircop", q="owner", a="admin", o="op", h="halfop", v="voice")
+modemapping = dict(Y="ircop", q="owner",
+ a="admin", o="op", h="halfop", v="voice")
+
+
+def LoggerReload(log):
+ newlog = Logger(logroot=log.logroot)
+ for IRC, label in log.labels.items():
+ IRC.rmAddon(log)
+ IRC.addAddon(newlog, label=label)
+ return newlog
class Logger(Thread):
+
def __init__(self, logroot):
self.logroot = logroot
path = [logroot]
@@ -31,7 +40,7 @@ class Logger(Thread):
while len(path) > 1:
path[0] = os.path.join(*path[:2])
del path[1]
- #print path
+ # print path
os.mkdir(path[0])
self.logs = {}
@@ -45,10 +54,10 @@ class Logger(Thread):
def run(self):
try:
Y, M, D, h, m, s, w, d, dst = time.localtime()
- nextrotate = int(time.mktime((Y, M, D+1, 0, 0, 0, 0, 0, -1)))
+ nextrotate = int(time.mktime((Y, M, D + 1, 0, 0, 0, 0, 0, -1)))
while True:
while nextrotate > time.time(): # May need to do this in a loop in case the following time.sleep command wakes up a second too early.
- time.sleep(max(0.1, min((nextrotate-time.time(), 3600))))
+ time.sleep(max(0.1, min((nextrotate - time.time(), 3600))))
with self.rotatelock:
if all([not log or log.closed for log in self.logs.values()]):
break
@@ -60,31 +69,36 @@ class Logger(Thread):
self.rotateLog(IRC)
except:
exc, excmsg, tb = sys.exc_info()
- IRC.logwrite(*["!!! [Logger] Exception in module %(module)s" % vars()]+["!!! [Logger] %s" % tbline for tbline in traceback.format_exc().split("\n")])
+ IRC.logwrite(*["!!! [Logger] Exception in module %(module)s" % vars()] + [
+ "!!! [Logger] %s" % tbline for tbline in traceback.format_exc().split("\n")])
if IRC.identity:
for channel in IRC.identity.channels:
try:
self.rotateLog(channel)
except:
exc, excmsg, tb = sys.exc_info()
- IRC.logwrite(*["!!! [Logger] Exception in module %(module)s" % vars()]+["!!! [Logger] %s" % tbline for tbline in traceback.format_exc().split("\n")])
+ IRC.logwrite(*["!!! [Logger] Exception in module %(module)s" % vars()] + [
+ "!!! [Logger] %s" % tbline for tbline in traceback.format_exc().split("\n")])
for user in IRC.users:
if user in self.logs.keys():
try:
self.closeLog(user)
except:
exc, excmsg, tb = sys.exc_info()
- IRC.logwrite(*["!!! [Logger] Exception in module %(module)s" % vars()]+["!!! [Logger] %s" % tbline for tbline in traceback.format_exc().split("\n")])
- IRC.logopen(os.path.join(self.logroot, self.labels[IRC], "rawdata-%04d.%02d.%02d.log"%now[:3]))
- nextrotate = int(time.mktime((Y, M, D+1, 0, 0, 0, 0, 0, -1)))
+ IRC.logwrite(*["!!! [Logger] Exception in module %(module)s" % vars()] + [
+ "!!! [Logger] %s" % tbline for tbline in traceback.format_exc().split("\n")])
+ IRC.logopen(
+ os.path.join(self.logroot, self.labels[IRC], "rawdata-%04d.%02d.%02d.log" % now[:3]))
+ nextrotate = int(time.mktime((Y, M, D + 1, 0, 0, 0, 0, 0, -1)))
finally:
Thread.__init__(self)
+ self.daemon = True
def onAddonAdd(self, IRC, label):
if label in self.labels.values():
- raise BaseException("Label already exists")
+ raise BaseException, "Label already exists"
if IRC in self.labels.keys():
- raise BaseException("Network already exists")
+ raise BaseException, "Network already exists"
if not os.path.isdir(os.path.join(self.logroot, label)):
os.mkdir(os.path.join(self.logroot, label))
self.labels[IRC] = label
@@ -94,10 +108,10 @@ class Logger(Thread):
for channel in IRC.identity.channels:
self.openLog(channel)
now = time.localtime()
- timestamp = reduce(lambda x, y: x+":"+y, [str(t).rjust(2,
- "0") for t in now[0:6]])
- IRC.logopen(os.path.join(self.logroot, self.labels[IRC],
- "rawdata-%04d.%02d.%02d.log"%now[:3]))
+ timestamp = reduce(lambda x, y: x + ":" + y, [
+ str(t).rjust(2, "0") for t in now[0:6]])
+ IRC.logopen(
+ os.path.join(self.logroot, self.labels[IRC], "rawdata-%04d.%02d.%02d.log" % now[:3]))
def onAddonRem(self, IRC):
if IRC.connected:
@@ -118,21 +132,25 @@ class Logger(Thread):
if not self.isAlive():
self.start()
now = time.localtime()
- timestamp = reduce(lambda x, y: x+":"+y, [str(t).rjust(2,
- "0") for t in now[0:6]])
+ timestamp = reduce(lambda x, y: x + ":" + y, [
+ str(t).rjust(2, "0") for t in now[0:6]])
if type(window) == irc.Connection:
- log = self.logs[window] = open(os.path.join(self.logroot, self.labels[window], "console-%04d.%02d.%02d.log"%now[:3]), "a")
+ log = self.logs[window] = open(
+ os.path.join(self.logroot, self.labels[window], "console-%04d.%02d.%02d.log" % now[:3]), "a")
print >>log, "%s ### Log file opened" % (irc.timestamp())
elif type(window) == irc.Channel:
label = self.labels[window.context]
- log = self.logs[window] = open(os.path.join(self.logroot, label, "channel-%s-%04d.%02d.%02d.log"%((urllib2.quote(window.name.lower()).replace("/", "%2f"),)+now[:3])), "a")
+ log = self.logs[window] = open(os.path.join(self.logroot, label, "channel-%s-%04d.%02d.%02d.log" % (
+ (urllib2.quote(window.name.lower()).replace("/", "%2f"),) + now[:3])), "a")
print >>log, "%s ### Log file opened" % (irc.timestamp())
self.logs[window].flush()
if window.context.identity in window.users:
if window.topic:
- print >>log, "%s <<< :%s 332 %s %s :%s" % (irc.timestamp(), window.context.serv, window.context.identity.nick, window.name, window.topic)
+ print >>log, "%s <<< :%s 332 %s %s :%s" % (
+ irc.timestamp(), window.context.serv, window.context.identity.nick, window.name, window.topic)
if window.topicsetby and window.topictime:
- print >>log, "%s <<< :%s 333 %s %s %s %s" % (irc.timestamp(), window.context.serv, window.context.identity.nick, window.name, window.topicsetby, window.topictime)
+ print >>log, "%s <<< :%s 333 %s %s %s %s" % (
+ irc.timestamp(), window.context.serv, window.context.identity.nick, window.name, window.topicsetby, window.topictime)
if window.users:
secret = "s" in window.modes.keys() and window.modes["s"]
private = "p" in window.modes.keys() and window.modes["p"]
@@ -141,18 +159,24 @@ class Logger(Thread):
print >>log, "%s <<< :%s 353 %s %s %s :%s" % (irc.timestamp(),
window.context.serv,
window.context.identity.nick,
- "@" if secret else ("*" if private else "="),
+ "@" if secret else (
+ "*" if private else "="),
window.name,
- " ".join(["".join([symbols[k] if modes[k] in window.modes.keys() and user in window.modes[modes[k]] else "" for k in xrange(len(modes))])+user.nick for user in window.users]))
+ " ".join(["".join([symbols[k] if modes[k] in window.modes.keys() and user in window.modes[modes[k]] else "" for k in xrange(len(modes))]) + user.nick for user in window.users]))
if window.modes:
modes = window.modes.keys()
- modestr = "".join([mode for mode in modes if mode not in window.context.supports["CHANMODES"][0]+window.context.supports["PREFIX"][0] and window.modes[mode]])
- params = " ".join([window.modes[mode] for mode in modes if mode in window.context.supports["CHANMODES"][1]+window.context.supports["CHANMODES"][2] and window.modes[mode]])
- print >>log, "%s <<< :%s 324 %s %s +%s %s" % (irc.timestamp(), window.context.serv, window.context.identity.nick, window.name, modestr, params)
+ modestr = "".join([mode for mode in modes if mode not in window.context.supports[
+ "CHANMODES"][0] + window.context.supports["PREFIX"][0] and window.modes[mode]])
+ params = " ".join([window.modes[mode] for mode in modes if mode in window.context.supports[
+ "CHANMODES"][1] + window.context.supports["CHANMODES"][2] and window.modes[mode]])
+ print >>log, "%s <<< :%s 324 %s %s +%s %s" % (
+ irc.timestamp(), window.context.serv, window.context.identity.nick, window.name, modestr, params)
if window.created:
- print >>log, "%s <<< :%s 329 %s %s %s" % (irc.timestamp(), window.context.serv, window.context.identity.nick, window.name, window.created)
+ print >>log, "%s <<< :%s 329 %s %s %s" % (
+ irc.timestamp(), window.context.serv, window.context.identity.nick, window.name, window.created)
if type(window) == irc.User:
- logname = os.path.join(self.logroot, self.labels[window.context], "query-%s-%04d.%02d.%02d.log"%((urllib2.quote(window.nick.lower()).replace("/", "%2f"),)+now[:3]))
+ logname = os.path.join(self.logroot, self.labels[window.context], "query-%s-%04d.%02d.%02d.log" % (
+ (urllib2.quote(window.nick.lower()).replace("/", "%2f"),) + now[:3]))
for (other, log) in self.logs.items():
if other == window:
continue
@@ -169,8 +193,8 @@ class Logger(Thread):
def closeLog(self, window):
if window in self.logs.keys() and type(self.logs[window]) == file and not self.logs[window].closed:
- print >>self.logs[window], "%s ### Log file closed" % (
- irc.timestamp())
+ print >>self.logs[
+ window], "%s ### Log file closed" % (irc.timestamp())
self.logs[window].close()
if window in self.logs.keys():
del self.logs[window]
@@ -194,7 +218,7 @@ class Logger(Thread):
ts, IRC.server, IRC.port)
def onConnectFail(self, IRC, exc, excmsg, tb):
- ### Called when a connection attempt fails.
+ # Called when a connection attempt fails.
if IRC not in self.logs.keys() or (not self.logs[IRC]) or self.logs[IRC].closed:
self.openLog(IRC)
ts = irc.timestamp()
@@ -205,7 +229,8 @@ class Logger(Thread):
ts = irc.timestamp()
for window in self.logs.keys():
if type(window) in (irc.Channel, irc.User) and window.context == IRC:
- print >>self.logs[window], "%s *** Connection to %s:%s terminated." % (ts, IRC.server, IRC.port)
+ print >>self.logs[window], "%s *** Connection to %s:%s terminated." % (
+ ts, IRC.server, IRC.port)
self.logs[window].flush()
self.closeLog(window)
print >>self.logs[IRC], "%s *** Connection %s:%s terminated." % (
@@ -214,7 +239,7 @@ class Logger(Thread):
self.closeLog(IRC)
def onJoin(self, IRC, user, channel):
- ### Called when somebody joins a channel, includes bot.
+ # Called when somebody joins a channel, includes bot.
ts = irc.timestamp()
if user == IRC.identity:
self.openLog(channel)
@@ -223,95 +248,111 @@ class Logger(Thread):
self.logs[channel].flush()
def onChanMsg(self, IRC, user, channel, targetprefix, msg):
- ### Called when someone sends a PRIVMSG to channel.
+ # Called when someone sends a PRIVMSG to channel.
ts = irc.timestamp()
if type(user) == irc.User:
- classes = " ".join([modemapping[mode] for mode in IRC.supports["PREFIX"][0] if mode in channel.modes.keys() and user in channel.modes[mode]])
+ classes = " ".join([modemapping[mode]
+ for mode in IRC.supports["PREFIX"][0] if mode in channel.modes.keys() and user in channel.modes[mode]])
if classes:
- print >>self.logs[channel], "%s %s <<< :%s!%s@%s PRIVMSG %s%s :%s" % (ts, classes, user.nick, user.username, user.host, targetprefix, channel.name, msg)
+ print >>self.logs[channel], "%s %s <<< :%s!%s@%s PRIVMSG %s%s :%s" % (
+ ts, classes, user.nick, user.username, user.host, targetprefix, channel.name, msg)
else:
- print >>self.logs[channel], "%s <<< :%s!%s@%s PRIVMSG %s%s :%s" % (ts, user.nick, user.username, user.host, targetprefix, channel.name, msg)
+ print >>self.logs[channel], "%s <<< :%s!%s@%s PRIVMSG %s%s :%s" % (
+ ts, user.nick, user.username, user.host, targetprefix, channel.name, msg)
elif type(user) in (str, unicode):
classes = "server"
- print >>self.logs[channel], "%s %s <<< :%s PRIVMSG %s%s :%s" % (ts,
- classes, user, targetprefix, channel.name, msg)
+ print >>self.logs[channel], "%s %s <<< :%s PRIVMSG %s%s :%s" % (
+ ts, classes, user, targetprefix, channel.name, msg)
self.logs[channel].flush()
def onChanAction(self, IRC, user, channel, targetprefix, action):
- self.onChanMsg(IRC, user, channel, targetprefix,
- "\x01ACTION %s\x01"%action)
+ self.onChanMsg(
+ IRC, user, channel, targetprefix, "\x01ACTION %s\x01" % action)
def onChanNotice(self, IRC, origin, channel, targetprefix, msg):
- ### Called when someone sends a NOTICE to channel.
+ # Called when someone sends a NOTICE to channel.
ts = irc.timestamp()
if type(origin) == irc.User:
- classes = " ".join([modemapping[mode] for mode in IRC.supports["PREFIX"][0] if mode in channel.modes.keys() and origin in channel.modes[mode]])
+ classes = " ".join([modemapping[mode]
+ for mode in IRC.supports["PREFIX"][0] if mode in channel.modes.keys() and origin in channel.modes[mode]])
if classes:
- print >>self.logs[channel], "%s %s <<< :%s!%s@%s NOTICE %s%s :%s" % (ts, classes, origin.nick, origin.username, origin.host, targetprefix, channel.name, msg)
+ print >>self.logs[channel], "%s %s <<< :%s!%s@%s NOTICE %s%s :%s" % (
+ ts, classes, origin.nick, origin.username, origin.host, targetprefix, channel.name, msg)
else:
- print >>self.logs[channel], "%s <<< :%s!%s@%s NOTICE %s%s :%s" % (ts, origin.nick, origin.username, origin.host, targetprefix, channel.name, msg)
+ print >>self.logs[channel], "%s <<< :%s!%s@%s NOTICE %s%s :%s" % (
+ ts, origin.nick, origin.username, origin.host, targetprefix, channel.name, msg)
elif type(origin) in (str, unicode):
classes = "server"
- print >>self.logs[channel], "%s %s <<< :%s NOTICE %s%s :%s" % (ts,
- classes, origin, targetprefix, channel.name, msg)
+ print >>self.logs[channel], "%s %s <<< :%s NOTICE %s%s :%s" % (
+ ts, classes, origin, targetprefix, channel.name, msg)
self.logs[channel].flush()
def onPart(self, IRC, user, channel, partmsg):
- ### Called when somebody parts the channel, includes bot.
+ # Called when somebody parts the channel, includes bot.
ts = irc.timestamp()
if partmsg:
- print >>self.logs[channel], "%s <<< :%s!%s@%s PART %s :%s" % (ts, user.nick, user.username, user.host, channel.name, partmsg)
+ print >>self.logs[channel], "%s <<< :%s!%s@%s PART %s :%s" % (
+ ts, user.nick, user.username, user.host, channel.name, partmsg)
else:
- print >>self.logs[channel], "%s <<< :%s!%s@%s PART %s" % (ts,
- user.nick, user.username, user.host, channel.name)
+ print >>self.logs[channel], "%s <<< :%s!%s@%s PART %s" % (
+ ts, user.nick, user.username, user.host, channel.name)
self.logs[channel].flush()
if user == IRC.identity:
self.closeLog(channel)
def onKick(self, IRC, kicker, channel, kicked, kickmsg):
- ### Called when somebody is kicked from the channel, includes bot.
+ # Called when somebody is kicked from the channel, includes bot.
ts = irc.timestamp()
if kickmsg:
- print >>self.logs[channel], "%s <<< :%s!%s@%s KICK %s %s :%s" % (ts, kicker.nick, kicker.username, kicker.host, channel.name, kicked.nick, kickmsg)
+ print >>self.logs[channel], "%s <<< :%s!%s@%s KICK %s %s :%s" % (
+ ts, kicker.nick, kicker.username, kicker.host, channel.name, kicked.nick, kickmsg)
else:
- print >>self.logs[channel], "%s <<< :%s!%s@%s KICK %s %s" % (ts, user.nick, user.username, user.host, channel.name, kicked.nick)
+ print >>self.logs[channel], "%s <<< :%s!%s@%s KICK %s %s" % (
+ ts, user.nick, user.username, user.host, channel.name, kicked.nick)
self.logs[channel].flush()
- if user == IRC.identity:
+ if kicked == IRC.identity:
self.closeLog(channel)
def onSendChanMsg(self, IRC, origin, channel, targetprefix, msg):
- ### Called when bot sends a PRIVMSG to channel.
- ### The variable origin refers to a class instance voluntarily identifying itself as that which requested data be sent.
+ # Called when bot sends a PRIVMSG to channel.
+ # The variable origin refers to a class instance voluntarily
+ # identifying itself as that which requested data be sent.
ts = irc.timestamp()
- classes = " ".join([modemapping[mode] for mode in IRC.supports["PREFIX"][0] if mode in channel.modes.keys() and IRC.identity in channel.modes[mode]])
+ classes = " ".join([modemapping[mode]
+ for mode in IRC.supports["PREFIX"][0] if mode in channel.modes.keys() and IRC.identity in channel.modes[mode]])
if classes:
- print >>self.logs[channel], "%s %s >>> :%s!%s@%s PRIVMSG %s%s :%s" % (ts, classes, IRC.identity.nick, IRC.identity.username, IRC.identity.host, targetprefix, channel.name, msg)
+ print >>self.logs[channel], "%s %s >>> :%s!%s@%s PRIVMSG %s%s :%s" % (
+ ts, classes, IRC.identity.nick, IRC.identity.username, IRC.identity.host, targetprefix, channel.name, msg)
else:
- print >>self.logs[channel], "%s >>> :%s!%s@%s PRIVMSG %s%s :%s" % (ts, IRC.identity.nick, IRC.identity.username, IRC.identity.host, targetprefix, channel.name, msg)
+ print >>self.logs[channel], "%s >>> :%s!%s@%s PRIVMSG %s%s :%s" % (
+ ts, IRC.identity.nick, IRC.identity.username, IRC.identity.host, targetprefix, channel.name, msg)
self.logs[channel].flush()
def onSendChanAction(self, IRC, origin, channel, targetprefix, action):
- ### origin is the source of the channel message
- ### Called when bot sends an action (/me) to channel.
- ### The variable origin refers to a class instance voluntarily identifying itself as that which requested data be sent.
- self.onSendChanMsg(IRC, origin, channel, targetprefix,
- "\x01ACTION %s\x01"%action)
+ # origin is the source of the channel message
+ # Called when bot sends an action (/me) to channel.
+ # The variable origin refers to a class instance voluntarily
+ # identifying itself as that which requested data be sent.
+ self.onSendChanMsg(
+ IRC, origin, channel, targetprefix, "\x01ACTION %s\x01" % action)
def onPrivMsg(self, IRC, user, msg):
- ### Called when someone sends a PRIVMSG to the bot.
+ # Called when someone sends a PRIVMSG to the bot.
if user not in self.logs.keys():
self.openLog(user)
ts = irc.timestamp()
- print >>self.logs[user], "%s <<< :%s!%s@%s PRIVMSG %s :%s" % (ts, user.nick, user.username, user.host, IRC.identity.nick, msg)
+ print >>self.logs[user], "%s <<< :%s!%s@%s PRIVMSG %s :%s" % (
+ ts, user.nick, user.username, user.host, IRC.identity.nick, msg)
self.logs[user].flush()
def onPrivNotice(self, IRC, origin, msg):
- ### Called when someone sends a NOTICE to the bot.
+ # Called when someone sends a NOTICE to the bot.
ts = irc.timestamp()
if type(origin) == irc.User:
if origin not in self.logs.keys():
self.openLog(origin)
- print >>self.logs[origin], "%s <<< :%s!%s@%s NOTICE %s :%s" % (ts, origin.nick, origin.username, origin.host, IRC.identity.nick, msg)
+ print >>self.logs[origin], "%s <<< :%s!%s@%s NOTICE %s :%s" % (
+ ts, origin.nick, origin.username, origin.host, IRC.identity.nick, msg)
self.logs[origin].flush()
else:
print >>self.logs[IRC], "%s <<< :%s NOTICE %s :%s" % (
@@ -319,53 +360,57 @@ class Logger(Thread):
self.logs[IRC].flush()
def onPrivAction(self, IRC, user, action):
- ### Called when someone sends an action (/me) to the bot.
- self.onPrivMsg(IRC, user, "\x01ACTION %s\x01"%action)
+ # Called when someone sends an action (/me) to the bot.
+ self.onPrivMsg(IRC, user, "\x01ACTION %s\x01" % action)
def onSendPrivMsg(self, IRC, origin, user, msg):
- ### Called when bot sends a PRIVMSG to a user.
- ### The variable origin refers to a class instance voluntarily identifying itself as that which requested data be sent.
+ # Called when bot sends a PRIVMSG to a user.
+ # The variable origin refers to a class instance voluntarily
+ # identifying itself as that which requested data be sent.
if user not in self.logs.keys():
self.openLog(user)
ts = irc.timestamp()
- print >>self.logs[user], "%s >>> :%s!%s@%s PRIVMSG %s :%s" % (ts, IRC.identity.nick, IRC.identity.username, IRC.identity.host, user.nick, msg)
+ print >>self.logs[user], "%s >>> :%s!%s@%s PRIVMSG %s :%s" % (
+ ts, IRC.identity.nick, IRC.identity.username, IRC.identity.host, user.nick, msg)
self.logs[user].flush()
def onSendPrivAction(self, IRC, origin, user, action):
- ### Called when bot sends an action (/me) to a user.
- ### The variable origin refers to a class instance voluntarily identifying itself as that which requested data be sent.
- self.onSendPrivMsg(IRC, origin, user, "\x01ACTION %s\x01"%action)
+ # Called when bot sends an action (/me) to a user.
+ # The variable origin refers to a class instance voluntarily
+ # identifying itself as that which requested data be sent.
+ self.onSendPrivMsg(IRC, origin, user, "\x01ACTION %s\x01" % action)
def onNickChange(self, IRC, user, newnick):
- ### Called when somebody changes nickname.
+ # Called when somebody changes nickname.
ts = irc.timestamp()
line = "%s <<< :%s!%s@%s NICK %s" % (
ts, user.nick, user.username, user.host, newnick)
- ### Print nick change in each channel the user is in.
+ # Print nick change in each channel the user is in.
for channel in user.channels:
print >>self.logs[channel], line
self.logs[channel].flush()
- ### And in the query if open.
+ # And in the query if open.
if user in self.logs.keys():
print >>self.logs[user], line
self.logs[user].flush()
def onMeNickChange(self, IRC, newnick):
- ### Called when the bot changes nickname.
+ # Called when the bot changes nickname.
- ### Print nick change to all open queries, except for query with self (already done with onNickChange).
+ # Print nick change to all open queries, except for query with self
+ # (already done with onNickChange).
ts = irc.timestamp()
- line = "%s <<< :%s!%s@%s NICK %s" % (ts, IRC.identity.nick,
- IRC.identity.username, IRC.identity.host, newnick)
+ line = "%s <<< :%s!%s@%s NICK %s" % (
+ ts, IRC.identity.nick, IRC.identity.username, IRC.identity.host, newnick)
for (window, log) in self.logs.items():
if type(window) == irc.User and window != IRC.identity:
print >>log, line
log.flush()
def onQuit(self, IRC, user, quitmsg):
- ### Called when somebody quits IRC.
+ # Called when somebody quits IRC.
ts = irc.timestamp()
if quitmsg:
line = "%s <<< :%s!%s@%s QUIT :%s" % (
@@ -374,20 +419,20 @@ class Logger(Thread):
line = "%s <<< :%s!%s@%s QUIT" % (
ts, user.nick, user.username, user.host)
- ### Print quit in each channel the user was in.
+ # Print quit in each channel the user was in.
for channel in user.channels:
if channel in self.logs.keys() and not self.logs[channel].closed:
print >>self.logs[channel], line
self.logs[channel].flush()
- ### And in the query if open.
+ # And in the query if open.
if user in self.logs.keys():
print >>self.logs[user], line
self.logs[user].flush()
self.closeLog(user)
def onNames(self, IRC, origin, channel, flag, channame, nameslist):
- ### Called when a NAMES list is received.
+ # Called when a NAMES list is received.
if channel in self.logs.keys() and not self.logs[channel].closed:
log = self.logs[channel]
else:
@@ -398,7 +443,7 @@ class Logger(Thread):
private = "p" in channel.modes.keys() and channel.modes["p"]
modes, symbols = channel.context.supports["PREFIX"]
print >>log, "%s <<< :%s 353 %s %s %s :%s" % (ts, origin, IRC.identity.nick, flag, channame,
- " ".join(["%s%s!%s@%s"%(prefix, nick, username, host) if username and host else "%s%s"%(prefix, nick) for (prefix, nick, username, host) in nameslist]))
+ " ".join(["%s%s!%s@%s" % (prefix, nick, username, host) if username and host else "%s%s" % (prefix, nick) for (prefix, nick, username, host) in nameslist]))
log.flush()
def onNamesEnd(self, IRC, origin, channel, channame, endmsg):
@@ -412,51 +457,53 @@ class Logger(Thread):
log.flush()
def onWhoisStart(self, IRC, origin, user, nickname, username, host, realname):
- ### Called when a WHOIS reply is received.
+ # Called when a WHOIS reply is received.
if user not in self.logs.keys():
self.openLog(user)
- print >>self.logs[user], "%s <<< :%s 311 %s %s %s %s * :%s" % (irc.timestamp(), origin, IRC.identity.nick, nickname, username, host, realname)
+ print >>self.logs[user], "%s <<< :%s 311 %s %s %s %s * :%s" % (
+ irc.timestamp(), origin, IRC.identity.nick, nickname, username, host, realname)
def onWhoisRegisteredNick(self, IRC, origin, user, nickname, msg):
- ### Called when a WHOIS reply is received.
+ # Called when a WHOIS reply is received.
if user not in self.logs.keys():
self.openLog(user)
print >>self.logs[user], "%s <<< :%s 307 %s %s :%s" % (
irc.timestamp(), origin, IRC.identity.nick, nickname, msg)
def onWhoisAway(self, IRC, origin, user, nickname, awaymsg):
- ### Called when a WHOIS reply is received.
+ # Called when a WHOIS reply is received.
if user not in self.logs.keys():
self.openLog(user)
- print >>self.logs[user], "%s <<< :%s 301 %s %s :%s" % (irc.timestamp(
- ), origin, IRC.identity.nick, nickname, awaymsg)
+ print >>self.logs[user], "%s <<< :%s 301 %s %s :%s" % (
+ irc.timestamp(), origin, IRC.identity.nick, nickname, awaymsg)
def onWhoisConnectingFrom(self, IRC, origin, user, nickname, msg):
- ### Called when a WHOIS reply is received.
+ # Called when a WHOIS reply is received.
if user not in self.logs.keys():
self.openLog(user)
print >>self.logs[user], "%s <<< :%s 378 %s %s :%s" % (
irc.timestamp(), origin, IRC.identity.nick, nickname, msg)
def onWhoisChannels(self, IRC, origin, user, nickname, chanlist):
- ### Called when a WHOIS reply is received.
+ # Called when a WHOIS reply is received.
if user not in self.logs.keys():
self.openLog(user)
- print >>self.logs[user], "%s <<< :%s 319 %s %s :%s" % (irc.timestamp(),
- origin, IRC.identity.nick, nickname, " ".join(chanlist))
+ print >>self.logs[user], "%s <<< :%s 319 %s %s :%s" % (
+ irc.timestamp(), origin, IRC.identity.nick, nickname, " ".join(chanlist))
def onWhoisAvailability(self, IRC, origin, user, nickname, msg):
- ### Called when a WHOIS reply is received.
+ # Called when a WHOIS reply is received.
if user not in self.logs.keys():
self.openLog(user)
print >>self.logs[user], "%s <<< :%s 310 %s %s :%s" % (
irc.timestamp(), origin, IRC.identity.nick, nickname, msg)
def onWhoisServer(self, IRC, origin, user, nickname, server, servername):
- ### Called when a WHOIS reply is received.
+ # Called when a WHOIS reply is received.
if user not in self.logs.keys():
self.openLog(user)
- print >>self.logs[user], "%s <<< :%s 312 %s %s %s :%s" % (irc.timestamp(), origin, IRC.identity.nick, nickname, server, servername)
+ print >>self.logs[user], "%s <<< :%s 312 %s %s %s :%s" % (
+ irc.timestamp(), origin, IRC.identity.nick, nickname, server, servername)
def onWhoisOp(self, IRC, origin, user, nickname, msg):
if user not in self.logs.keys():
@@ -467,7 +514,8 @@ class Logger(Thread):
def onWhoisTimes(self, IRC, origin, user, nickname, idletime, signontime, msg):
if user not in self.logs.keys():
self.openLog(user)
- print >>self.logs[user], "%s <<< :%s 317 %s %s %d %d :%s" % (irc.timestamp(), origin, IRC.identity.nick, nickname, idletime, signontime, msg)
+ print >>self.logs[user], "%s <<< :%s 317 %s %s %d %d :%s" % (
+ irc.timestamp(), origin, IRC.identity.nick, nickname, idletime, signontime, msg)
def onWhoisSSL(self, IRC, origin, user, nickname, msg):
if user not in self.logs.keys():
@@ -484,7 +532,8 @@ class Logger(Thread):
def onWhoisLoggedInAs(self, IRC, origin, user, nickname, loggedinas, msg):
if user not in self.logs.keys():
self.openLog(user)
- print >>self.logs[user], "%s <<< :%s 330 %s %s %s :%s" % (irc.timestamp(), origin, IRC.identity.nick, nickname, loggedinas, msg)
+ print >>self.logs[user], "%s <<< :%s 330 %s %s %s :%s" % (
+ irc.timestamp(), origin, IRC.identity.nick, nickname, loggedinas, msg)
def onWhoisEnd(self, IRC, origin, user, nickname, msg):
if user not in self.logs.keys():
@@ -494,19 +543,19 @@ class Logger(Thread):
self.logs[user].flush()
def onWhoEntry(self, IRC, **kwargs):
- ### Called when a WHO list is received.
+ # Called when a WHO list is received.
pass
def onWhoEnd(self, IRC, **kwargs):
- ### Called when a WHO list is received.
+ # Called when a WHO list is received.
pass
def onList(self, IRC, chanlistbegin, chanlist, endmsg):
- ### Called when a channel list is received.
+ # Called when a channel list is received.
pass
def onTopic(self, IRC, origin, channel, topic):
- ### Called when channel topic is received via 332 response.
+ # Called when channel topic is received via 332 response.
ts = irc.timestamp()
if channel in self.logs.keys() and not self.logs[channel].closed:
log = self.logs[channel]
@@ -517,26 +566,27 @@ class Logger(Thread):
log.flush()
def onTopicInfo(self, IRC, origin, channel, topicsetby, topictime):
- ### Called when channel topic info is received via 333 response.
+ # Called when channel topic info is received via 333 response.
ts = irc.timestamp()
if channel in self.logs.keys() and not self.logs[channel].closed:
log = self.logs[channel]
else:
log = self.logs[IRC]
- print >>log, "%s <<< :%s 333 %s %s %s %d" % (ts, origin,
- IRC.identity.nick, channel.name, topicsetby, topictime)
+ print >>log, "%s <<< :%s 333 %s %s %s %d" % (
+ ts, origin, IRC.identity.nick, channel.name, topicsetby, topictime)
log.flush()
def onTopicSet(self, IRC, user, channel, topic):
- ### Called when channel topic is changed.
+ # Called when channel topic is changed.
ts = irc.timestamp()
- print >>self.logs[channel], "%s <<< :%s!%s@%s TOPIC %s :%s" % (ts,
- user.nick, user.username, user.host, channel.name, topic)
+ print >>self.logs[channel], "%s <<< :%s!%s@%s TOPIC %s :%s" % (
+ ts, user.nick, user.username, user.host, channel.name, topic)
self.logs[channel].flush()
def onChanModeSet(self, IRC, user, channel, modedelta):
- ### Called when channel modes are changed.
- ### modedelta is a list of tuples of the format ("+x", parameter), ("+x", None) if no parameter is provided.
+ # Called when channel modes are changed.
+ # modedelta is a list of tuples of the format ("+x", parameter), ("+x",
+ # None) if no parameter is provided.
ts = irc.timestamp()
modestr = ""
params = []
@@ -546,23 +596,26 @@ class Logger(Thread):
modestr += sgn
sign = sgn
modestr += modechar
- if param is not None:
+ if param != None:
params.append(param.nick if type(param) == irc.User else param)
if len(params):
if type(user) == irc.User:
- print >>self.logs[channel], "%s <<< :%s!%s@%s MODE %s %s %s" % (ts, user.nick, user.username, user.host, channel.name, modestr, " ".join(params))
+ print >>self.logs[channel], "%s <<< :%s!%s@%s MODE %s %s %s" % (
+ ts, user.nick, user.username, user.host, channel.name, modestr, " ".join(params))
else:
- print >>self.logs[channel], "%s <<< :%s MODE %s %s %s" % (ts, user, channel.name, modestr, " ".join(params))
+ print >>self.logs[channel], "%s <<< :%s MODE %s %s %s" % (
+ ts, user, channel.name, modestr, " ".join(params))
else:
if type(user) == irc.User:
- print >>self.logs[channel], "%s <<< :%s!%s@%s MODE %s %s" % (ts, user.nick, user.username, user.host, channel.name, modestr)
+ print >>self.logs[channel], "%s <<< :%s!%s@%s MODE %s %s" % (
+ ts, user.nick, user.username, user.host, channel.name, modestr)
else:
print >>self.logs[channel], "%s <<< :%s MODE %s %s" % (
ts, user, channel.name, modestr)
self.logs[channel].flush()
def onChannelModes(self, IRC, channel, modedelta):
- ### Called when channel modes are received via 324 response.
+ # Called when channel modes are received via 324 response.
ts = irc.timestamp()
if channel in self.logs.keys() and not self.logs[channel].closed:
log = self.logs[channel]
@@ -576,17 +629,18 @@ class Logger(Thread):
modestr += sgn
sign = sgn
modestr += modechar
- if param is not None:
+ if param != None:
params.append(param)
if len(params):
- print >>log, "%s <<< :%s 324 %s %s %s %s" % (ts, IRC.serv, IRC.identity.nick, channel.name, modestr, " ".join(params))
+ print >>log, "%s <<< :%s 324 %s %s %s %s" % (
+ ts, IRC.serv, IRC.identity.nick, channel.name, modestr, " ".join(params))
else:
- print >>log, "%s <<< :%s 324 %s %s %s" % (ts, IRC.serv,
- IRC.identity.nick, channel.name, modestr)
+ print >>log, "%s <<< :%s 324 %s %s %s" % (
+ ts, IRC.serv, IRC.identity.nick, channel.name, modestr)
log.flush()
def onChanCreated(self, IRC, channel, created):
- ### Called when a 329 response is received.
+ # Called when a 329 response is received.
ts = irc.timestamp()
if channel in self.logs.keys() and not self.logs[channel].closed:
log = self.logs[channel]