summaryrefslogtreecommitdiff
path: root/bouncer.py
diff options
context:
space:
mode:
authorBrian Sherson <caretaker82@euclid.shersonb.net>2013-12-04 01:35:44 -0800
committerBrian Sherson <caretaker82@euclid.shersonb.net>2013-12-04 01:35:44 -0800
commit0d802dab5b586d511a6291248702c910502acaf7 (patch)
treef370db15b1a29c2fa8b6699188d28923b1361462 /bouncer.py
parent5cf8d2185f89aaf30e856bd0dbca88fbb51789ba (diff)
Significant changes
Diffstat (limited to 'bouncer.py')
-rw-r--r--bouncer.py513
1 files changed, 314 insertions, 199 deletions
diff --git a/bouncer.py b/bouncer.py
index c367dfd..9cfc786 100644
--- a/bouncer.py
+++ b/bouncer.py
@@ -8,31 +8,35 @@ import sys
import string
import hashlib
import traceback
+import irc
from threading import Thread, Lock
import Queue
class Bouncer (Thread):
- def __init__(self, addr="", port=16667, ssl=False, certfile=None, keyfile=None, ignore=None, debug=False, log=sys.stderr, timeout=300):
+ 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):
self.__name__ = "Bouncer for pyIRC"
- self.__version__ = "1.0.0rc2"
+ self.__version__ = "1.1"
self.__author__ = "Brian Sherson"
- self.__date__ = "August 26, 2013"
- #print "Initializing ListenThread..."
+ self.__date__ = "December 1, 2013"
+
self.addr = addr
self.port = port
self.servers = {}
self.passwd = {}
- self.socket = s = socket.socket()
+ self.socket = socket.socket(
+ socket.AF_INET6 if ipv6 else socket.AF_INET)
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.ssl = ssl
+ self.ipv6 = ipv6
self.certfile = certfile
self.keyfile = keyfile
- s.bind((self.addr, self.port))
+ self.socket.bind((self.addr, self.port))
self.connections = []
self.ignore = ignore
self.debug = debug
self.timeout = timeout
+ self.autoaway = autoaway
### 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.
@@ -71,102 +75,13 @@ class Bouncer (Thread):
connection.settimeout(self.timeout)
bouncer = BouncerConnection(
self, connection, addr, debug=self.debug)
- #bouncer.daemon=True
- #self.connections.append(bouncer)
- #bouncer.start()
- #ccrecv.start()
time.sleep(0.5)
try:
self.socket.close()
except:
pass
- def onRecv(self, IRC, line, data):
- if type(self.ignore) not in (list, tuple) or all([not re.match(pattern, line) for pattern in self.ignore]):
- if data:
- (origin, ident, host, cmd, target, params, extinfo) = data
- #print data
- if re.match("^\\d+$", cmd):
- cmd = int(cmd) # Code is a numerical response
- if cmd in (352, 315, 304) or (cmd == 461 and params.upper() == "WHO"): # WHO reply
- if len(self.whoexpected[IRC]) and self.whoexpected[IRC][0] in self.connections:
- self.whoexpected[IRC][0].send(line+"\n")
- if cmd == 315 or (cmd == 461 and params.upper() == "WHO"): # End of WHO reply
- origin = self.whoexpected[IRC][0]
- del self.whoexpected[IRC][0]
- timestamp = reduce(lambda x, y: x+":"+y, [str(t).rjust(2, "0") for t in time.localtime()[0:6]])
- if self.debug:
- with IRC.loglock:
- if issubclass(type(origin), Thread):
- name = origin.name
- print >>IRC.log, "%(timestamp)s dbg [Bouncer.onRecv] Removing %(origin)s (%(name)s) from WHO expected list." % vars()
- else:
- print >>IRC.log, "%(timestamp)s dbg [Bouncer.onRecv] Removing %(origin)s from 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.onRecv] WHO expected: %(obj)s (%(name)s)" % vars()
- else:
- print >>IRC.log, "%(timestamp)s dbg [Bouncer.onRecv] WHO expected: %(obj)s" % vars()
- IRC.log.flush()
- elif cmd in (307, 311, 312, 313, 317, 318, 319, 330, 335, 336, 378, 379): # WHO reply
- if len(self.whoisexpected[IRC]) and self.whoisexpected[IRC][0] in self.connections:
- self.whoisexpected[IRC][0].send(line+"\n")
- if cmd == 318: # End of WHOIS reply
- del self.whoisexpected[IRC][0]
- elif cmd in (321, 322, 323): # LIST reply
- if len(self.listexpected[IRC]) and self.listexpected[IRC][0] in self.connections:
- self.listexpected[IRC][0].send(line+"\n")
- if cmd == 323: # End of LIST reply
- del self.listexpected[IRC][0]
- else:
- for bouncer in self.connections:
- #print bouncer.IRC
- #print IRC
- #print line
- if bouncer.IRC == IRC:
- bouncer.send(line+"\n")
-
- def onSend(self, IRC, line, data, origin):
- if type(self.ignore) not in (list, tuple) or all([not re.match(pattern, line) for pattern in self.ignore]):
- (cmd, target, params, extinfo) = data
- if cmd.upper() in ("PRIVMSG", "NOTICE"):
- for bouncerconnection in self.connections:
- if bouncerconnection == origin: # Do NOT send the message back to the originating client.
- continue
- if bouncerconnection.IRC == IRC: # Send the message to the other clients connected to the bouncer.
- ctcp = re.findall("^\x01(.*?)(?:\\s+(.*?)\\s*)?\x01$",
- extinfo)
- if ctcp:
- (ctcptype, ext) = ctcp[0]
- if ctcptype == "ACTION":
- bouncerconnection.send(":%s!%s@%s %s\n" % (bouncerconnection.IRC.identity.nick, bouncerconnection.IRC.identity.idnt, bouncerconnection.IRC.identity.host, line))
- ### Unless the message is a CTCP that is not ACTION.
- else:
- bouncerconnection.send(":%s!%s@%s %s\n" % (bouncerconnection.IRC.identity.nick, bouncerconnection.IRC.identity.idnt, bouncerconnection.IRC.identity.host, line))
- elif cmd.upper() == "WHO":
- self.whoexpected[IRC].append(origin)
- if self.debug:
- with IRC.loglock:
- timestamp = reduce(lambda x, y: x+":"+y, [str(t).rjust(2, "0") for t in time.localtime()[0:6]])
- 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()
- elif cmd.upper() == "WHOIS":
- self.whoisexpected[IRC].append(origin)
- elif cmd.upper() == "LIST":
- self.listexpected[IRC].append(origin)
-
- def onModuleAdd(self, IRC, label, passwd, hashtype="md5"):
+ def onAddonAdd(self, IRC, label, passwd, hashtype="md5"):
if IRC in [connection for (connection, passwd, hashtype) in self.servers.values()]:
return # Silently do nothing
if label in self.servers.keys():
@@ -174,15 +89,11 @@ class Bouncer (Thread):
self.servers[label] = (IRC, passwd, hashtype)
self.whoexpected[IRC] = []
if self.debug:
- with IRC.loglock:
- timestamp = reduce(lambda x, y: x+":"+y, [str(t).rjust(
- 2, "0") for t in time.localtime()[0:6]])
- print >>IRC.log, "%(timestamp)s dbg [Bouncer.onModuleAdd] Clearing WHO expected list." % vars()
- IRC.log.flush()
+ IRC.logwrite("dbg [Bouncer.onAddonAdd] Clearing WHO expected list." % vars())
self.whoisexpected[IRC] = []
self.listexpected[IRC] = []
- def onModuleRem(self, IRC):
+ def onAddonRem(self, IRC):
for bouncerconnection in self.connections:
if bouncerconnection.IRC == IRC:
bouncerconnection.quit(quitmsg="Bouncer extension removed")
@@ -197,32 +108,263 @@ class Bouncer (Thread):
for bouncerconnection in self.connections:
bouncerconnection.stop(quitmsg=quitmsg)
- def onDisconnect(self, IRC):
+ def onDisconnect(self, IRC, expected=False):
self.whoexpected[IRC] = []
if self.debug:
- with IRC.loglock:
- timestamp = reduce(lambda x, y: x+":"+y, [str(t).rjust(
- 2, "0") for t in time.localtime()[0:6]])
- print >>IRC.log, "%(timestamp)s dbg [Bouncer.onDisconnect] Clearing WHO expected list." % vars()
- IRC.log.flush()
+ 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")
+ 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.
+ 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))
+
+ def onSendChanAction(self, IRC, origin, channel, targetprefix, 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.
+ 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))
+
+ 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()
+ 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.
+ 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
+
+ def onWhoEnd(self, IRC, origin, param, endmsg):
+ ### 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]
+
+ def onListStart(self, IRC, origin, params, extinfo):
+ ### 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
+
+ def onListEntry(self, IRC, origin, channel, population, extinfo):
+ ### 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
+
+ def onListEnd(self, IRC, origin, endmsg):
+ ### 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]
+
+ def onWhoisStart(self, IRC, origin, user, nickname, username, host, realname):
+ ### 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
+
+ def onWhoisRegisteredNick(self, IRC, origin, user, nickname, msg):
+ ### 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
+
+ def onWhoisConnectingFrom(self, IRC, origin, user, nickname, msg):
+ ### 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
+
+ def onWhoisChannels(self, IRC, origin, user, nickname, chanlist):
+ ### 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
+
+ def onWhoisAvailability(self, IRC, origin, user, nickname, msg):
+ ### 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
+
+ def onWhoisServer(self, IRC, origin, user, nickname, server, servername):
+ ### 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
+
+ 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
+
+ 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
+
+ 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
+
+ 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
+
+ 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
+
+ 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
+
+ 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]
+
+ def onUnhandled(self, IRC, line, origin, cmd, target, params, extinfo):
+ for bouncerconnection in self.connections:
+ if bouncerconnection.IRC == IRC:
+ bouncerconnection.send("%s\n"%line)
+
class BouncerConnection (Thread):
def __init__(self, bouncer, connection, addr, debug=False):
#print "Initializing ListenThread..."
self.bouncer = bouncer
self.connection = connection
- self.host, self.port = self.addr = addr
+ if len(addr) == 4:
+ self.host, self.port = self.addr = addr[:2]
+ self.ipv6 = True
+ else:
+ self.host, self.port = self.addr = addr
+ self.ipv6 = False
self.IRC = None
self.pwd = None
self.nick = None
self.label = None
- self.idnt = None
+ self.username = None
self.realname = None
self.addr = addr
self.debug = debug
@@ -237,16 +379,10 @@ class BouncerConnection (Thread):
def send(self, data, flags=0):
try:
with self.lock:
- self.connection.send(data, flags=flags)
+ self.connection.send(data)
except socket.error:
- with self.IRC.loglock:
- timestamp = reduce(lambda x, y: x+":"+y, [str(t).rjust(
- 2, "0") for t in time.localtime()[0:6]])
- exc, excmsg, tb = sys.exc_info()
- print >>self.IRC.log, "%(timestamp)s !!! [BouncerConnection.send] Exception in module %(module)s" % vars()
- for tbline in traceback.format_exc().split("\n"):
- print >>self.IRC.log, "%(timestamp)s !!! [BouncerConnection.send] %(tbline)s" % vars()
- self.IRC.log.flush()
+ 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")])
self.quit(quitmsg=excmsg.message)
def __repr__(self):
@@ -254,7 +390,7 @@ class BouncerConnection (Thread):
port = self.IRC.port if self.IRC else "*"
if self.IRC and self.IRC.identity:
nick = self.IRC.identity.nick
- ident = self.IRC.identity.idnt if self.IRC.identity.idnt else "*"
+ ident = self.IRC.identity.username if self.IRC.identity.username else "*"
host = self.IRC.identity.host if self.IRC.identity.host else "*"
else:
nick = "*"
@@ -282,7 +418,12 @@ class BouncerConnection (Thread):
def run(self):
### Add connection to connection list.
- listnumerics = dict(b=(367, 368, "channel ban list"), e=(348, 349, "Channel Exception List"), I=(346, 347, "Channel Invite Exception List"), w=(910, 911, "Channel Access List"), g=(941, 940, "chanel spamfilter list"), X=(954, 953, "channel exemptchanops list"))
+ listnumerics = dict(b=(367, 368, "channel ban list"),
+ e=(348, 349, "Channel Exception List"),
+ I=(346, 347, "Channel Invite Exception List"),
+ w=(910, 911, "Channel Access List"),
+ g=(941, 940, "chanel spamfilter list"),
+ X=(954, 953, "channel exemptchanops list"))
passwd = None
nick = None
@@ -296,7 +437,7 @@ class BouncerConnection (Thread):
while True:
### Read data (appending) into readbuf, then break lines and append lines to linebuf
while len(linebuf) == 0:
- timestamp = reduce(lambda x, y: x+":"+y, [str(t).rjust(2, "0") for t in time.localtime()[0:6]])
+ timestamp = irc.timestamp()
read = self.connection.recv(512)
if read == "" and len(linebuf) == 0: # No more data to process.
#self.quitmsg="Connection Closed"
@@ -330,38 +471,31 @@ class BouncerConnection (Thread):
self.quit("Access Denied")
break
- elif not self.idnt: # Bouncer expects a USER command to finish registration
+ elif not self.username: # Bouncer expects a USER command to finish registration
if cmd.upper() == "USER":
- self.idnt = target
- #print self.idnt
- if self.idnt in self.bouncer.servers.keys():
- self.IRC, passwdhash, hashtype = self.bouncer.servers[self.idnt]
+ self.username = target
+ #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
with self.IRC.lock:
- with self.IRC.loglock:
- timestamp = reduce(lambda x, y: x+":"+y, [str(t).rjust(2, "0") for t in time.localtime()[0:6]])
- print >>self.IRC.log, "%s *** [BouncerConnection] Incoming connection from %s to %s." % (timestamp, self.host, self.IRC)
- self.IRC.log.flush()
+ 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:
- with self.IRC.loglock:
- timestamp = reduce(lambda x, y: x+":"+y, [str(t).rjust(2, "0") for t in time.localtime()[0:6]])
- print >>self.IRC.log, "%(timestamp)s dbg [BouncerConnection] Attempting to broadcast incoming connection %(self)s." % vars()
- self.IRC.log.flush()
+ self.IRC.logwrite("dbg [BouncerConnection] Attempting to broadcast incoming connection %(self)s." % vars())
for bouncerconnection in self.bouncer.connections:
+ if bouncerconnection.IRC != self.IRC:
+ continue
if self.debug:
- with self.IRC.loglock:
- timestamp = reduce(lambda x, y: x+":"+y, [str(t).rjust(2, "0") for t in time.localtime()[0:6]])
- print >>self.IRC.log, "%(timestamp)s dbg [BouncerConnection] Broadcasting to %(bouncerconnection)s." % vars()
- self.IRC.log.flush()
+ 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:
- with self.IRC.loglock:
- timestamp = reduce(lambda x, y: x+":"+y, [str(t).rjust(2, "0") for t in time.localtime()[0:6]])
- print >>self.IRC.log, "%(timestamp)s dbg [BouncerConnection] Success: %(bouncerconnection)s." % vars()
- self.IRC.log.flush()
+ 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.
+ 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):
@@ -371,9 +505,9 @@ class BouncerConnection (Thread):
### 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.idnt, n) in labels:
+ while "*%s_%d"%(self.username, n) in labels:
n += 1
- self.label = "*%s_%d"%(self.idnt, n)
+ self.label = "*%s_%d"%(self.username, n)
### Request Version info.
#self.connection.send(":$bouncer PRIVMSG %s :\x01VERSION\x01\n" % (self.IRC.identity.nick))
@@ -384,8 +518,8 @@ class BouncerConnection (Thread):
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.servinfo))
- self.connection.send(":%s 004 %s %s\n" % (self.IRC.serv, self.IRC.identity.nick, self.IRC.serv004))
+ 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()]
@@ -405,10 +539,16 @@ class BouncerConnection (Thread):
self.connection.send(":%s 005 %s %s :are supported by this server\n" % (self.IRC.serv, self.IRC.identity.nick, support))
### Send MOTD
- 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))
- self.connection.send(":%s 376 %s :%s\n" % (self.IRC.serv, self.IRC.identity.nick, self.IRC.motdend))
+ 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))
@@ -416,7 +556,7 @@ class BouncerConnection (Thread):
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.idnt, self.IRC.identity.host))
+ # 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))
@@ -435,7 +575,7 @@ class BouncerConnection (Thread):
### 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.idnt, self.IRC.identity.host, channel.name))
+ 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))
@@ -469,33 +609,18 @@ class BouncerConnection (Thread):
break
elif cmd.upper() == "PING":
- with self.lock:
- self.connection.send(":%s PONG %s :%s\n" % (self.IRC.serv, self.IRC.serv, self.IRC.identity.nick))
-
- elif cmd.upper() == "WHO" and target.lower() == "$bouncer":
- with self.lock:
- for bouncerconnection in self.bouncer.connections:
- self.connection.send(":$bouncer 352 %s $bouncer %s %s $bouncer %s H@ :0 %s\n" % (self.IRC.identity.nick, bouncerconnection.idnt, bouncerconnection.host, bouncerconnection.label, bouncerconnection.IRC))
- self.connection.send(":$bouncer 315 %s $bouncer :End if /WHO list.\n" % (self.IRC.identity.nick))
+ 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 target.lower() == "$bouncer": # Message to internal bouncer control channel
- if ctcp and cmd.upper() == "NOTICE":
- (ctcptype, ext) = ctcp[0] # Unpack CTCP info
- if ctcptype == "VERSION": # Client is sending back version reply
- reply = ":%s!%s@%s PRIVMSG $bouncer :Version reply: %s\n" % (self.label, self.idnt, self.addr[0], ext)
- for bouncerconnection in self.bouncer.connections:
- bouncerconnection.connection.send(reply)
- elif ctcp: # If CTCP, only want to
+ 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.
- with self.lock:
- self.connection.send(":%s!%s@%s %s\n" % (self.IRC.identity.nick, self.IRC.identity.idnt, self.IRC.identity.host, line))
+ 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:
@@ -509,8 +634,10 @@ class BouncerConnection (Thread):
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:
- self.connection.send(":%s 324 %s %s +%s %s\n" % (self.IRC.serv, self.IRC.identity.nick, channel.name, modestr, params))
- self.connection.send(":%s 329 %s %s %s\n" % (self.IRC.serv, self.IRC.identity.nick, channel.name, channel.created))
+ 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)
@@ -543,12 +670,8 @@ class BouncerConnection (Thread):
exc, excmsg, tb = sys.exc_info()
self.quitmsg = str(excmsg)
if self.IRC:
- with self.IRC.loglock:
- exc, excmsg, tb = sys.exc_info()
- print >>self.IRC.log, "%(timestamp)s !!! [BouncerConnection] Exception in module %(self)s" % vars()
- for tbline in traceback.format_exc().split("\n"):
- print >>self.IRC.log, "%(timestamp)s !!! [BouncerConnection] %(tbline)s" % vars()
- self.IRC.log.flush()
+ 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")])
finally:
### Juuuuuuust in case.
with self.lock:
@@ -559,36 +682,28 @@ class BouncerConnection (Thread):
pass
if self.IRC:
- with self.IRC.loglock:
- timestamp = reduce(lambda x, y: x+":"+y, [str(t).rjust(2, "0") for t in time.localtime()[0:6]])
- print >>self.IRC.log, "%s *** [BouncerConnection] Connection from %s terminated (%s)." % (timestamp, self.host, self.quitmsg)
- self.IRC.log.flush()
+ 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.debug:
- with self.IRC.loglock:
- timestamp = reduce(lambda x, y: x+":"+y, [str(t).rjust(2, "0") for t in time.localtime()[0:6]])
- print >>self.IRC.log, "%(timestamp)s dbg [BouncerConnection] Attempting to broadcast terminated connection %(self)s." % vars()
- self.IRC.log.flush()
+ self.IRC.logwrite("dbg [BouncerConnection] Attempting to broadcast terminated connection %(self)s." % vars())
for bouncerconnection in self.bouncer.connections:
- if self.debug:
- with self.IRC.loglock:
- timestamp = reduce(lambda x, y: x+":"+y, [str(t).rjust(2, "0") for t in time.localtime()[0:6]])
- print >>self.IRC.log, "%(timestamp)s dbg [BouncerConnection] Broadcasting to %(bouncerconnection)s." % vars()
- self.IRC.log.flush()
- 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))
+ if bouncerconnection.IRC == self.IRC:
if self.debug:
- with self.IRC.loglock:
- timestamp = reduce(lambda x, y: x+":"+y, [str(t).rjust(2, "0") for t in time.localtime()[0:6]])
- print >>self.IRC.log, "%(timestamp)s dbg [BouncerConnection] Success: %(bouncerconnection)s." % vars()
- self.IRC.log.flush()
+ 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))
+ 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.idnt, self.host, self.quitmsg))
+# bouncerconnection.connection.send(":%s!%s@%s QUIT :%s\n" % (self.label, self.username, self.host, self.quitmsg))
# except:
# pass