summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrian Sherson <caretaker82@euclid.shersonb.net>2014-02-09 13:20:22 -0800
committerBrian Sherson <caretaker82@euclid.shersonb.net>2014-02-09 13:20:22 -0800
commit235f8e0964503bbb71a1a9fba17b9c9b7aa791e9 (patch)
treea4e50ffb4156929f8491e323d40a7f495b6d4d54
parent382dbd56681b21c9d64afb9678fdc488604f76b8 (diff)
Unicode support, channel name translation, channel show/hide.
-rw-r--r--bouncer.py1004
1 files changed, 643 insertions, 361 deletions
diff --git a/bouncer.py b/bouncer.py
index 0e351ac..6333e2d 100644
--- a/bouncer.py
+++ b/bouncer.py
@@ -12,16 +12,27 @@ import irc
import getpass
from threading import Thread, Lock
import Queue
+import chardet
+
+# TODO: Rewrite this *entire* module and make more efficient.
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)
+ if BNC.__version__ == "1.2":
+ 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, (context, passwd, hashtype) in BNC.servers.items():
+ context.rmAddon(BNC)
+ context.addAddon(
+ newBNC, label=label, passwd=passwd, hashtype=hashtype)
+ else:
+ newBNC = Bouncer(**BNC.__options__)
+ for context, conf in BNC.conf.items():
+ context.rmAddon(BNC)
+ context.addAddon(newBNC, **conf.__dict__)
return newBNC
@@ -29,13 +40,16 @@ class Bouncer (Thread):
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.2"
+ self.__version__ = "1.3"
self.__author__ = "Brian Sherson"
- self.__date__ = "December 26, 2013"
+ self.__date__ = "February 9, 2014"
+ self.__options__ = dict(
+ addr=addr, port=port, ssl=ssl, ipv6=ipv6, certfile=certfile,
+ keyfile=keyfile, ignore=ignore, debug=debug, timeout=timeout, autoaway=autoaway)
self.addr = addr
self.port = port
- self.servers = {}
+ self.conf = {}
self.passwd = {}
self.socket = socket.socket(
socket.AF_INET6 if ipv6 else socket.AF_INET)
@@ -54,9 +68,9 @@ class Bouncer (Thread):
# 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 = {}
+ self._whoexpected = {}
+ self._whoisexpected = {}
+ self._listexpected = {}
self.lock = Lock()
self.starttime = int(time.time())
Thread.__init__(self)
@@ -95,7 +109,12 @@ class Bouncer (Thread):
except:
pass
- def onAddonAdd(self, IRC, label, passwd=None, hashtype="sha512"):
+ def onAddonAdd(self, context, label, passwd=None, hashtype="sha512", ignore=None, autoaway=None, translations=None, hidden=None):
+ for (context2, conf2) in self.conf.items():
+ if context == context2:
+ raise ValueError, "Context already exists in config."
+ if label == conf2.label:
+ raise ValueError, "Unique label required."
if passwd == None:
while True:
passwd = getpass.getpass("Enter new password: ")
@@ -103,25 +122,24 @@ class Bouncer (Thread):
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] = []
+ conf = irc.Config(
+ label=label, passwd=passwd, hashtype=hashtype, ignore=ignore, autoaway=autoaway,
+ translations={} if translations == None else translations, hidden=irc.ChanList(hidden, context=context))
+ self.conf[context] = conf
+ self._whoexpected[context] = []
if self.debug:
- IRC.logwrite(
+ context.logwrite(
"dbg [Bouncer.onAddonAdd] Clearing WHO expected list." % vars())
- self.whoisexpected[IRC] = []
- self.listexpected[IRC] = []
+ self._whoisexpected[context] = []
+ self._listexpected[context] = []
- def onAddonRem(self, IRC):
+ def onAddonRem(self, context):
for bouncerconnection in self.connections:
- if bouncerconnection.IRC == IRC:
+ if bouncerconnection.context == context:
bouncerconnection.quit(quitmsg="Bouncer extension removed")
- for (label, (connection, passwd, hashtype)) in self.servers.items():
- if connection == IRC:
- del self.servers[label]
+ del self.conf[context]
+ del self._whoexpected[context], self._whoisexpected[
+ context], self._listexpected[context]
def stop(self):
self._stopexpected = True
@@ -129,256 +147,340 @@ class Bouncer (Thread):
def disconnectall(self, quitmsg="Disconnecting all sessions"):
for bouncerconnection in self.connections:
- bouncerconnection.stop(quitmsg=quitmsg)
+ bouncerconnection.quit(quitmsg=quitmsg)
- def onDisconnect(self, IRC, expected=False):
- self.whoexpected[IRC] = []
- self.whoisexpected[IRC] = []
- self.listexpected[IRC] = []
+ def onDisconnect(self, context, expected=False):
+ self._whoexpected[context] = []
+ self._whoisexpected[context] = []
+ self._listexpected[context] = []
for bouncerconnection in self.connections:
- if bouncerconnection.IRC == IRC:
- #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))
+ if bouncerconnection.context == context:
+ #bouncerconnection.quit(quitmsg="context connection lost")
+ if context.identity:
+ for channel in context.identity.channels:
+ bouncerconnection.send(":%s!%s@%s PART %s :Bouncer Connection Lost\n" % (
+ context.identity.nick, context.identity.username, context.identity.host, channel.name))
+ bouncerconnection.send(":%s!%s@%s QUIT :Bouncer Connection Lost\n" % (
+ context.identity.nick, context.identity.username, context.identity.host))
bouncerconnection.send(
":*Bouncer* NOTICE %s :Connection to %s:%s has been lost.\n" %
- (bouncerconnection.nick, IRC.server, IRC.port))
+ (bouncerconnection.nick, context.server, context.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
+ def onQuit(self, context, user, quitmsg):
+ # For some odd reason, certain networks (*cough*Freenode*cough*) will send a quit message for the user, causing context.identity.channels to be cleared
# before onDisconnect can be executed. This is the remedy.
for bouncerconnection in self.connections:
- if bouncerconnection.IRC == IRC:
+ if bouncerconnection.context == context:
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:
+ if user == context.identity:
+ for channel in context.identity.channels:
bouncerconnection.send(":%s!%s@%s PART %s :Bouncer Connection Lost\n" % (
- IRC.identity.nick, IRC.identity.username, IRC.identity.host, channel.name))
+ context.identity.nick, context.identity.username, context.identity.host, channel.name))
- def onConnectAttempt(self, IRC):
+ def onConnectAttempt(self, context):
for bouncerconnection in self.connections:
- if bouncerconnection.IRC == IRC:
+ if bouncerconnection.context == context:
bouncerconnection.send(
":*Bouncer* NOTICE %s :Attempting connection to %s:%s.\n" %
- (bouncerconnection.nick, IRC.server, IRC.port))
+ (bouncerconnection.nick, context.server, context.port))
- def onConnect(self, IRC):
+ def onConnect(self, context):
for bouncerconnection in self.connections:
- if bouncerconnection.IRC == IRC:
+ if bouncerconnection.context == context:
bouncerconnection.send(
":*Bouncer* NOTICE %s :Connection to %s:%s established.\n" %
- (bouncerconnection.nick, IRC.server, IRC.port))
+ (bouncerconnection.nick, context.server, context.port))
+
+ def onMeNickChange(self, context, newnick):
+ for bouncerconnection in self.connections:
+ if bouncerconnection.context == context:
+ bouncerconnection.send(":%s!%s@%s NICK %s\n" %
+ (context.identity.nick, context.identity.username, context.identity.host, newnick))
+ bouncerconnection.nick = newnick
- def onMeNickChange(self, IRC, newnick):
+ def onNickChange(self, context, user, newnick):
for bouncerconnection in self.connections:
- if bouncerconnection.IRC == IRC:
+ if bouncerconnection.context == context:
bouncerconnection.send(":%s!%s@%s NICK %s\n" %
- (IRC.identity.nick, IRC.identity.username, IRC.identity.host, newnick))
+ (user.nick, user.username, user.host, newnick))
bouncerconnection.nick = newnick
- def onRegistered(self, IRC):
+ def onRegistered(self, context):
for bouncerconnection in self.connections:
- if bouncerconnection.IRC == IRC:
- if bouncerconnection.nick != IRC.identity.nick:
+ if bouncerconnection.context == context:
+ if bouncerconnection.nick != context.identity.nick:
bouncerconnection.send(":%s!%s@%s NICK %s\n" % (
- bouncerconnection.nick, bouncerconnection.username, bouncerconnection.host, IRC.identity.nick))
- bouncerconnection.nick = IRC.identity.nick
+ bouncerconnection.nick, bouncerconnection.username, bouncerconnection.host, context.identity.nick))
+ bouncerconnection.nick = context.identity.nick
- def onConnectFail(self, IRC, exc, excmsg, tb):
+ def onConnectFail(self, context, exc, excmsg, tb):
for bouncerconnection in self.connections:
- if bouncerconnection.IRC == IRC:
+ if bouncerconnection.context == context:
bouncerconnection.send(
":*Bouncer* NOTICE %s :Connection to %s:%s failed: %s.\n" %
- (bouncerconnection.nick, IRC.server, IRC.port, excmsg))
+ (bouncerconnection.nick, context.server, context.port, excmsg))
- def onSendChanMsg(self, IRC, origin, channel, targetprefix, msg):
+ def onSendChanMsg(self, context, 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.
+ conf = self.conf[context]
+ if channel in conf.translations.keys():
+ channame = conf.translations[channel]
+ else:
+ channame = channel.name
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))
+ if context == bouncerconnection.context and origin != bouncerconnection and channel not in bouncerconnection.hidden:
+ bouncerconnection.send(":%s!%s@%s PRIVMSG %s%s :%s\n" % (
+ context.identity.nick, context.identity.username, context.identity.host, targetprefix, channame, msg))
- def onSendChanAction(self, IRC, origin, channel, targetprefix, action):
+ def onSendChanAction(self, context, origin, channel, targetprefix, action):
self.onSendChanMsg(
- IRC, origin, channel, targetprefix, "\x01ACTION %s\x01" % action)
+ context, origin, channel, targetprefix, "\x01ACTION %s\x01" % action)
- def onSendChanNotice(self, IRC, origin, channel, targetprefix, msg):
+ def onSendChanNotice(self, context, 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.
+ conf = self.conf[context]
+ if channel in conf.translations.keys():
+ channame = conf.translations[channel]
+ else:
+ channame = channel.name
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))
+ if context == bouncerconnection.context and origin != bouncerconnection:
+ bouncerconnection.send(":%s!%s@%s NOTICE %s%s :%s\n" %
+ (context.identity.nick, context.identity.username, context.identity.host, targetprefix, channame, msg))
- def onSend(self, IRC, origin, line, cmd, target, params, extinfo):
+ def onSend(self, context, origin, line, cmd, target, params, extinfo):
if cmd.upper() == "WHO":
- self.whoexpected[IRC].append(origin)
+ self._whoexpected[context].append(origin)
if self.debug:
if issubclass(type(origin), Thread):
name = origin.name
- IRC.logwrite(
+ context.logwrite(
"dbg [Bouncer.onSend] Adding %(origin)s (%(name)s) to WHO expected list." % vars())
else:
- IRC.logwrite(
+ context.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]))
+ context.logwrite(
+ "dbg [Bouncer.onSend] WHO expected list size: %d" % len(self._whoexpected[context]))
elif cmd.upper() == "WHOIS":
- self.whoisexpected[IRC].append(origin)
+ self._whoisexpected[context].append(origin)
elif cmd.upper() == "LIST":
- self.listexpected[IRC].append(origin)
+ self._listexpected[context].append(origin)
- def onWhoEntry(self, IRC, origin, channel, user, channame, username, host, serv, nick, flags, hops, realname):
+ def onWhoEntry(self, context, 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]
+ conf = self.conf[context]
+ if context.channel(channame) in conf.translations.keys():
+ channame = conf.translations[context.channel(channame)]
+ if len(self._whoexpected[context]) and self._whoexpected[context][0] in self.connections:
+ bncconnection = self._whoexpected[context][0]
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))
+ (origin, context.identity.nick, channame, username, host, serv, nick, flags, hops, realname))
- def onWhoEnd(self, IRC, origin, param, endmsg):
+ def onWhoEnd(self, context, 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:
+ conf = self.conf[context]
+ chantypes = context.supports.get("CHANTYPES", "&#+!")
+ if re.match(irc._chanmatch % re.escape(chantypes), param) and context[param] in conf.translations.keys():
+ param = conf.translations[context.channel(param)]
+ except:
+ pass
+ if len(self._whoexpected[context]) and self._whoexpected[context][0] in self.connections:
+ bncconnection = self._whoexpected[context][0]
bncconnection.send(":%s 315 %s %s :%s\n" %
- (origin, IRC.identity.nick, param, endmsg))
+ (origin, context.identity.nick, param, endmsg))
if self.debug:
- if issubclass(type(self.whoexpected[IRC][0]), Thread):
- name = self.whoexpected[IRC][0].name
- IRC.logwrite(
+ if issubclass(type(self._whoexpected[context][0]), Thread):
+ name = self._whoexpected[context][0].name
+ context.logwrite(
"dbg [Bouncer.onWhoEnd] Removing %s (%s) from WHO expected list." %
- (self.whoexpected[IRC][0], name))
+ (self._whoexpected[context][0], name))
else:
- IRC.logwrite(
- "dbg [Bouncer.onWhoEnd] Removing %s from WHO expected list." % self.whoexpected[IRC][0])
- del self.whoexpected[IRC][0]
+ context.logwrite(
+ "dbg [Bouncer.onWhoEnd] Removing %s from WHO expected list." % self._whoexpected[context][0])
+ del self._whoexpected[context][0]
if self.debug:
- IRC.logwrite("dbg [Bouncer.onWhoEnd] WHO expected list size: %d" %
- len(self.whoexpected[IRC]))
+ context.logwrite(
+ "dbg [Bouncer.onWhoEnd] WHO expected list size: %d" %
+ len(self._whoexpected[context]))
- def onListStart(self, IRC, origin, params, extinfo):
+ def onListStart(self, context, 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]
+ if len(self._listexpected[context]) and self._listexpected[context][0] in self.connections:
+ bncconnection = self._listexpected[context][0]
bncconnection.send(":%s 321 %s %s :%s\n" %
- (origin, IRC.identity.nick, params, extinfo))
+ (origin, context.identity.nick, params, extinfo))
- def onListEntry(self, IRC, origin, channel, population, extinfo):
+ def onListEntry(self, context, 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]
+ conf = self.conf[context]
+ if channel in conf.translations.keys():
+ channame = conf.translations[channel]
+ else:
+ channame = channel.name
+ if len(self._listexpected[context]) and self._listexpected[context][0] in self.connections:
+ bncconnection = self._listexpected[context][0]
bncconnection.send(":%s 322 %s %s %d :%s\n" %
- (origin, IRC.identity.nick, channel.name, population, extinfo))
+ (origin, context.identity.nick, channame, population, extinfo))
- def onListEnd(self, IRC, origin, endmsg):
+ def onListEnd(self, context, 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]
+ if len(self._listexpected[context]) and self._listexpected[context][0] in self.connections:
+ bncconnection = self._listexpected[context][0]
bncconnection.send(":%s 323 %s :%s\n" %
- (origin, IRC.identity.nick, endmsg))
- del self.listexpected[IRC][0]
+ (origin, context.identity.nick, endmsg))
+ del self._listexpected[context][0]
- def onWhoisStart(self, IRC, origin, user, nickname, username, host, realname):
+ def onWhoisStart(self, context, 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]
+ if len(self._whoisexpected[context]):
+ if self._whoisexpected[context][0] in self.connections:
+ bncconnection = self._whoisexpected[context][0]
bncconnection.send(":%s 311 %s %s %s %s * :%s\n" %
- (origin, IRC.identity.nick, nickname, username, host, realname))
+ (origin, context.identity.nick, nickname, username, host, realname))
- def onWhoisRegisteredNick(self, IRC, origin, user, nickname, msg):
+ def onWhoisRegisteredNick(self, context, 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]
+ if len(self._whoisexpected[context]) and self._whoisexpected[context][0] in self.connections:
+ bncconnection = self._whoisexpected[context][0]
bncconnection.send(":%s 307 %s %s :%s\n" %
- (origin, IRC.identity.nick, nickname, msg))
+ (origin, context.identity.nick, nickname, msg))
- def onWhoisConnectingFrom(self, IRC, origin, user, nickname, msg):
+ def onWhoisConnectingFrom(self, context, 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]
+ if len(self._whoisexpected[context]) and self._whoisexpected[context][0] in self.connections:
+ bncconnection = self._whoisexpected[context][0]
bncconnection.send(":%s 378 %s %s :%s\n" %
- (origin, IRC.identity.nick, nickname, msg))
+ (origin, context.identity.nick, nickname, msg))
- def onWhoisChannels(self, IRC, origin, user, nickname, chanlist):
+ def onWhoisChannels(self, context, 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]
+ # TODO: Translations implementation
+ if len(self._whoisexpected[context]) and self._whoisexpected[context][0] in self.connections:
+ bncconnection = self._whoisexpected[context][0]
bncconnection.send(":%s 319 %s %s :%s\n" %
- (origin, IRC.identity.nick, nickname, " ".join(chanlist)))
+ (origin, context.identity.nick, nickname, " ".join(chanlist)))
- def onWhoisAvailability(self, IRC, origin, user, nickname, msg):
+ def onWhoisAvailability(self, context, 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]
+ if len(self._whoisexpected[context]) and self._whoisexpected[context][0] in self.connections:
+ bncconnection = self._whoisexpected[context][0]
bncconnection.send(":%s 310 %s %s :%s\n" %
- (origin, IRC.identity.nick, nickname, msg))
+ (origin, context.identity.nick, nickname, msg))
- def onWhoisServer(self, IRC, origin, user, nickname, server, servername):
+ def onWhoisServer(self, context, 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]
+ if len(self._whoisexpected[context]) and self._whoisexpected[context][0] in self.connections:
+ bncconnection = self._whoisexpected[context][0]
bncconnection.send(":%s 312 %s %s %s :%s\n" %
- (origin, IRC.identity.nick, nickname, server, servername))
+ (origin, context.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]
+ def onWhoisOp(self, context, origin, user, nickname, msg):
+ if len(self._whoisexpected[context]) and self._whoisexpected[context][0] in self.connections:
+ bncconnection = self._whoisexpected[context][0]
bncconnection.send(":%s 313 %s %s :%s\n" %
- (origin, IRC.identity.nick, nickname, msg))
+ (origin, context.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]
+ def onWhoisAway(self, context, origin, user, nickname, awaymsg):
+ if len(self._whoisexpected[context]) and self._whoisexpected[context][0] in self.connections:
+ bncconnection = self._whoisexpected[context][0]
bncconnection.send(":%s 301 %s %s :%s\n" %
- (origin, IRC.identity.nick, nickname, awaymsg))
+ (origin, context.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]
+ def onWhoisTimes(self, context, origin, user, nickname, idletime, signontime, msg):
+ if len(self._whoisexpected[context]) and self._whoisexpected[context][0] in self.connections:
+ bncconnection = self._whoisexpected[context][0]
bncconnection.send(":%s 317 %s %s %d %d :%s\n" %
- (origin, IRC.identity.nick, nickname, idletime, signontime, msg))
+ (origin, context.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]
+ def onWhoisSSL(self, context, origin, user, nickname, msg):
+ if len(self._whoisexpected[context]) and self._whoisexpected[context][0] in self.connections:
+ bncconnection = self._whoisexpected[context][0]
bncconnection.send(":%s 671 %s %s :%s\n" %
- (origin, IRC.identity.nick, nickname, msg))
+ (origin, context.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]
+ def onWhoisModes(self, context, origin, user, nickname, msg):
+ if len(self._whoisexpected[context]) and self._whoisexpected[context][0] in self.connections:
+ bncconnection = self._whoisexpected[context][0]
bncconnection.send(":%s 339 %s %s :%s\n" %
- (origin, IRC.identity.nick, nickname, msg))
+ (origin, context.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]
+ def onWhoisLoggedInAs(self, context, origin, user, nickname, loggedinas, msg):
+ if len(self._whoisexpected[context]) and self._whoisexpected[context][0] in self.connections:
+ bncconnection = self._whoisexpected[context][0]
bncconnection.send(":%s 330 %s %s %s :%s\n" %
- (origin, IRC.identity.nick, nickname, loggedinas, msg))
+ (origin, context.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]
+ def onWhoisEnd(self, context, origin, user, nickname, msg):
+ if len(self._whoisexpected[context]) and self._whoisexpected[context][0] in self.connections:
+ bncconnection = self._whoisexpected[context][0]
bncconnection.send(":%s 318 %s %s :%s\n" %
- (origin, IRC.identity.nick, nickname, msg))
- del self.whoisexpected[IRC][0]
+ (origin, context.identity.nick, nickname, msg))
+ del self._whoisexpected[context][0]
- def onUnhandled(self, IRC, line, origin, cmd, target, params, extinfo):
+ def onJoin(self, context, user, channel):
+ conf = self.conf[context]
+ if channel in conf.translations.keys():
+ channame = conf.translations[channel]
+ else:
+ channame = channel.name
+ line = ":%s!%s@%s JOIN %s" % (
+ user.nick, user.username, user.host, channame)
for bouncerconnection in self.connections:
- if bouncerconnection.IRC == IRC:
+ if bouncerconnection.context == context and channel not in bouncerconnection.hidden:
+ bouncerconnection.send("%s\n" % line)
+
+ def onUnhandled(self, context, line, origin, cmd, target, params, extinfo, targetprefix):
+ conf = self.conf[context]
+
+ if type(origin) == irc.User:
+ origin = "%s!%s@%s" % (origin.nick, origin.username, origin.host)
+
+ if target in conf.translations.keys():
+ target = conf.translations[target]
+
+ chantarg = None
+
+ if type(target) == irc.User:
+ target = target.nick
+ elif type(target) == irc.Channel:
+ chantarg = target
+ target = target.name
+
+ if params: # Channels which appear in params
+ oldparams = params
+ params = []
+ for param in oldparams.split():
+ chantypes = context.supports.get("CHANTYPES", "&#+!")
+ if re.match(irc._chanmatch % re.escape(chantypes), param) and context[param] in conf.translations.keys():
+ params.append(conf.translations[context[param]])
+ else:
+ params.append(param)
+
+ if target:
+ if type(cmd) == int:
+ cmd = "%03d" % cmd
+ if params and extinfo:
+ line = ":%s %s %s %s :%s" % (
+ origin, cmd, target, " ".join(params), extinfo)
+ elif params:
+ line = ":%s %s %s %s" % (origin, cmd, target, " ".join(params))
+ elif extinfo:
+ line = ":%s %s %s :%s" % (origin, cmd, target, extinfo)
+ else:
+ line = ":%s %s %s" % (origin, cmd, target)
+
+ for bouncerconnection in self.connections:
+ if bouncerconnection.context == context and chantarg not in bouncerconnection.hidden:
bouncerconnection.send("%s\n" % line)
@@ -389,7 +491,7 @@ class BouncerConnection (Thread):
self.bouncer = bouncer
self.connection = connection
self.host, self.port = self.addr = addr[:2]
- self.IRC = None
+ self.context = None
self.pwd = None
self.nick = None
self.label = None
@@ -400,6 +502,7 @@ class BouncerConnection (Thread):
self.lock = Lock()
self.quitmsg = "Connection Closed"
self.quitting = False
+ self.hidden = irc.ChanList()
Thread.__init__(self)
self.daemon = True
@@ -408,29 +511,29 @@ class BouncerConnection (Thread):
def send(self, data, flags=0):
try:
with self.lock:
- self.connection.send(data)
+ self.connection.send(data.encode("utf8"))
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.context.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):
- server = self.IRC.server if self.IRC else "*"
- port = self.IRC.port if self.IRC else "*"
- if self.IRC and self.IRC.identity:
- nick = self.IRC.identity.nick
- ident = self.IRC.identity.username if self.IRC.identity.username else "*"
- host = self.IRC.identity.host if self.IRC.identity.host else "*"
+ server = self.context.server if self.context else "*"
+ port = self.context.port if self.context else "*"
+ if self.context and self.context.identity:
+ nick = self.context.identity.nick
+ ident = self.context.identity.username if self.context.identity.username else "*"
+ host = self.context.identity.host if self.context.identity.host else "*"
else:
nick = "*"
ident = "*"
host = "*"
- if self.IRC.ssl and self.IRC.ipv6:
+ if self.context.ssl and self.context.ipv6:
protocol = "ircs6"
- elif self.IRC.ssl:
+ elif self.context.ssl:
protocol = "ircs"
- elif self.IRC.ipv6:
+ elif self.context.ipv6:
protocol = "irc6"
else:
protocol = "irc"
@@ -443,7 +546,7 @@ class BouncerConnection (Thread):
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.context.identity.nick if self.context else "*", self.host, quitmsg))
except:
pass
try:
@@ -506,8 +609,15 @@ class BouncerConnection (Thread):
readbuf = readbuf[lastlf + 1:]
line = string.rstrip(linebuf.pop(0))
+ try:
+ line = line.decode("utf8")
+ except UnicodeDecodeError:
+ # Attempt to figure encoding
+ charset = chardet.detect(line)['encoding']
+ line = line.decode(charset)
match = re.findall(
"^(.+?)(?:\\s+(.+?)(?:\\s+(.+?))??)??(?:\\s+:(.*))?$", line, re.I)
+ # print match
if len(match) == 0:
continue
@@ -532,118 +642,206 @@ class BouncerConnection (Thread):
elif not self.username: # Bouncer expects a USER command to finish registration
if cmd.upper() == "USER":
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:
- 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:
+ contextfound = False
+ for self.context, conf in self.bouncer.conf.items():
+ # print conf.label, self.username
+ if conf.label == self.username:
+ contextfound = True
+ break
+ if not contextfound:
+ with self.context.lock:
+ self.quit("Access Denied")
+ self.context.logwrite(
+ "*** [BouncerConnection] Incoming connection from %s to %s denied: Invalid password." % (self.host, self.context))
+ for bouncerconnection in self.bouncer.connections:
+ if bouncerconnection.context != self.context:
+ continue
+ if not bouncerconnection.quitting:
+ bouncerconnection.send(":*Bouncer* NOTICE %s :Incoming connection from %s to %s dened: Invalid password.\n" % (
+ bouncerconnection.context.identity.nick, self.host, self.context))
+ break
+ passmatch = hashlib.new(
+ conf.hashtype, passwd).hexdigest() == conf.passwd
+ with self.context.lock:
+ if not passmatch:
+ self.quit("Access Denied")
+ self.context.logwrite(
+ "*** [BouncerConnection] Incoming connection from %s to %s denied: Invalid password." % (self.host, self.context))
+ for bouncerconnection in self.bouncer.connections:
+ if bouncerconnection.context != self.context:
+ continue
+ if not bouncerconnection.quitting:
+ bouncerconnection.send(":*Bouncer* NOTICE %s :Incoming connection from %s to %s dened: Invalid password.\n" % (
+ bouncerconnection.context.identity.nick, self.host, self.context))
+ break
+
+ self.context.logwrite(
+ "*** [BouncerConnection] Incoming connection from %s to %s." % (self.host, self.context))
+ with self.bouncer.lock:
+ # Announce connection to all other bouncer
+ # connections.
+ for bouncerconnection in self.bouncer.connections:
+ if bouncerconnection.context != self.context:
+ continue
+ if not bouncerconnection.quitting:
+ bouncerconnection.send(":*Bouncer* NOTICE %s :Incoming connection from %s to %s\n" % (
+ bouncerconnection.context.identity.nick, self.host, self.context))
+ if len([bncconnection for bncconnection in self.bouncer.connections if bncconnection.context == self.context]) == 0 and self.context.registered and type(self.context.identity) == irc.User and self.context.identity.away:
+ # Bouncer connection should automatically
+ # return from away status.
+ self.context.raw("AWAY")
+ self.hidden = irc.ChanList(
+ self.bouncer.conf[self.context].hidden, context=self.context)
+ self.bouncer.connections.append(self)
+
+ if self.context.registered:
+ # Send Greeting.
+ with self.lock:
+ if self.context.welcome:
+ self.connection.send(
+ (u":%s 001 %s :%s\n" % (self.context.serv, self.context.identity.nick, self.context.welcome)).encode("utf8"))
+ if self.context.hostinfo:
+ self.connection.send(
+ (u":%s 002 %s :%s\n" % (self.context.serv, self.context.identity.nick, self.context.hostinfo)).encode("utf8"))
+ if self.context.servcreated:
+ self.connection.send(
+ (u":%s 003 %s :%s\n" % (self.context.serv, self.context.identity.nick, self.context.servcreated)).encode("utf8"))
+ if self.context.servinfo:
+ self.connection.send(
+ (u":%s 004 %s %s\n" % (self.context.serv, self.context.identity.nick, self.context.servinfo)).encode("utf8"))
+
+ # Send 005 response.
+ if self.context.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.context.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((u":%s 005 %s %s :are supported by this server\n" % (
+ self.context.serv, self.context.identity.nick, support)).encode("utf8"))
+
+ # Send MOTD
+ if self.context.motdgreet and self.context.motd and self.context.motdend:
+ self.connection.send(
+ (u":%s 375 %s :%s\n" % (self.context.serv, self.context.identity.nick, self.context.motdgreet)).encode("utf8"))
+ for motdline in self.context.motd:
+ self.connection.send(
+ (u":%s 372 %s :%s\n" % (self.context.serv, self.context.identity.nick, motdline)).encode("utf8"))
+ try:
+ self.connection.send(
+ (u":%s 376 %s :%s\n" % (self.context.serv, self.context.identity.nick, self.context.motdend)).encode("utf8"))
+ except AttributeError:
+ self.connection.send(
+ (u":%s 376 %s\n" % (self.context.serv, self.context.identity.nick)).encode("utf8"))
+ else:
+ self.connection.send((u":%s 422 %s :MOTD File is missing\n" % (
+ self.context.serv, self.context.identity.nick)).encode("utf8"))
+
+ # Send user modes and snomasks.
+ self.connection.send(
+ (u":%s 221 %s +%s\n" % (self.context.serv, self.context.identity.nick, self.context.identity.modes)).encode("utf8"))
+
+ if "s" in self.context.identity.modes and self.context.identity.snomask:
+ self.connection.send((u":%s 008 %s +%s :Server notice mask\n" % (
+ self.context.serv, self.context.identity.nick, self.context.identity.snomask)).encode("utf8"))
+
+ # Join user to channels.
+ for channel in self.context.identity.channels:
+ if channel in self.hidden:
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.
- 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\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 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))
+ if channel in conf.translations.keys():
+ channame = conf.translations[
+ channel]
else:
- self.connection.send(
- ":%s 422 %s :MOTD File is missing\n" % (self.IRC.serv, self.IRC.identity.nick))
+ channame = channel.name
+ # JOIN command
+ self.connection.send(
+ (u":%s!%s@%s JOIN :%s\n" % (self.context.identity.nick, self.context.identity.username, self.context.identity.host, channame)).encode("utf8"))
+
+ # Topic
+ self.connection.send(
+ (u":%s 332 %s %s :%s\n" % (self.context.serv, self.context.identity.nick, channame, channel.topic)).encode("utf8"))
+ self.connection.send((u":%s 333 %s %s %s %s\n" % (self.context.serv, self.context.identity.nick, channame, channel.topicsetby.nick if type(
+ channel.topicsetby) == irc.User else channel.topicsetby, channel.topictime)).encode("utf8"))
+
+ # 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.context.supports[
+ "PREFIX"]
+ self.connection.send((u":%s 353 %s %s %s :%s\n" % (
+ self.context.serv,
+ self.context.identity.nick,
+ "@" if secret else (
+ "*" if private else "="),
+ channame,
+ u" ".join([u"".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]))
+ ).encode("utf8"))
+ self.connection.send((u":%s 366 %s %s :End of /NAMES list.\n" % (
+ self.context.serv, self.context.identity.nick, channame)).encode("utf8"))
+ else:
+ self.send(
+ u":*Bouncer* NOTICE %s :Not connected to server. Type /bncconnect to attempt connection.\n" % self.nick)
+ self.send(
+ u":%s 001 %s :Welcome to the Bouncer context Network %s!%s@%s\n" %
+ ("*Bouncer*", self.nick, self.nick, self.username, self.host))
+ 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
- # Send user modes and snomasks.
- self.connection.send(":%s 221 %s +%s\n" % (
- self.IRC.serv, self.IRC.identity.nick, self.IRC.identity.modes))
+ elif cmd.upper() == "QUIT":
+ self.quit(extinfo)
+ break
- 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))
+ elif cmd.upper() == "SHOW":
+ if target:
+ for chan in target.split(","):
+ chantypes = self.context.supports.get(
+ "CHANTYPES", "&#+!")
+ if re.match(irc._chanmatch % re.escape(chantypes), target):
+ translationfound = False
+ for channel, channame in conf.translations.items():
+ if translation.lower() == chan.lower():
+ translationfound = True
+ if not translationfound:
+ channel = self.context[chan]
+ channame = channel.name
+
+ if channel in self.hidden:
+ with self.lock:
+ self.hidden.remove(channel)
- # Join user to channels.
- for channel in self.IRC.identity.channels:
+ if channel in self.context.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))
+ self.connection.send(
+ (u":%s!%s@%s JOIN :%s\n" % (self.context.identity.nick, self.context.identity.username, self.context.identity.host, channame)).encode("utf8"))
# 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))
+ self.connection.send(
+ (u":%s 332 %s %s :%s\n" % (self.context.serv, self.context.identity.nick, channame, channel.topic)).encode("utf8"))
+ self.connection.send((u":%s 333 %s %s %s %s\n" % (self.context.serv, self.context.identity.nick, channame, channel.topicsetby.nick if type(
+ channel.topicsetby) == irc.User else channel.topicsetby, channel.topictime)).encode("utf8"))
# Determine if +s or +p modes are
# set in channel
@@ -654,67 +852,140 @@ class BouncerConnection (Thread):
# Construct NAMES for channel.
namesusers = []
- modes, symbols = self.IRC.supports[
+ modes, symbols = self.context.supports[
"PREFIX"]
- self.connection.send(":%s 353 %s %s %s :%s\n" % (
- self.IRC.serv,
- self.IRC.identity.nick,
+ self.connection.send((u":%s 353 %s %s %s :%s\n" % (
+ self.context.serv,
+ self.context.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
+ channame,
+ u" ".join([u"".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]))
+ ).encode("utf8"))
+ self.connection.send((u":%s 366 %s %s :End of /NAMES list.\n" % (
+ self.context.serv, self.context.identity.nick, channame)).encode("utf8"))
+ else:
+ self.connection.send((u":%s 442 %s %s :You are not on that channel.\n" % (
+ self.context.serv, self.context.identity.nick, channame)).encode("utf8"))
+ else:
+ self.connection.send((u":%s 403 %s %s :Invalid channel name.\n" % (
+ self.context.serv, self.context.identity.nick, chan)).encode("utf8"))
+ else:
+ self.connection.send((u":%s 461 %s SHOW :Not enough parameters.\n" % (
+ self.context.serv, self.context.identity.nick)).encode("utf8"))
+ self.connection.send((u":%s 304 %s :SYNTAX SHOW <channel>{,<channel>}\n" % (
+ self.context.serv, self.context.identity.nick)).encode("utf8"))
+ elif cmd.upper() == "HIDE":
+ if target:
+ for chan in target.split(","):
+ chantypes = self.context.supports.get(
+ "CHANTYPES", "&#+!")
+ if re.match(irc._chanmatch % re.escape(chantypes), target):
+ translationfound = False
+ for channel, channame in conf.translations.items():
+ if translation.lower() == chan.lower():
+ translationfound = True
+ if not translationfound:
+ channel = self.context[chan]
+ channame = channel.name
+
+ if channel not in self.hidden:
+ with self.lock:
+ self.hidden.append(channel)
- elif cmd.upper() == "QUIT":
- self.quit(extinfo)
- break
+ if channel in self.context.identity.channels:
+ # PART command
+ self.connection.send((u":%s!%s@%s PART %s :Hiding channel\n" % (
+ self.context.identity.nick, self.context.identity.username, self.context.identity.host, channame)).encode("utf8"))
+ else:
+ self.connection.send((u":%s 442 %s %s :You are not on that channel.\n" % (
+ self.context.serv, self.context.identity.nick, channame)).encode("utf8"))
+ else:
+ self.connection.send((u":%s 403 %s %s :Invalid channel name.\n" % (
+ self.context.serv, self.context.identity.nick, chan)).encode("utf8"))
+ else:
+ self.connection.send((u":%s 461 %s HIDE :Not enough parameters.\n" % (
+ self.context.serv, self.context.identity.nick)).encode("utf8"))
+ self.connection.send((u":%s 304 %s :SYNTAX HIDE <channel>{,<channel>}\n" % (
+ self.context.serv, self.context.identity.nick)).encode("utf8"))
elif cmd.upper() == "PING":
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 "***"))
+ (self.context.serv, self.context.serv, self.context.identity.nick if type(self.context.identity) == irc.User else "***"))
elif cmd.upper() == "BNCCONNECT":
- with self.IRC.lock:
- if self.IRC.isAlive() and self.IRC.connected:
+ with self.context.lock:
+ if self.context.isAlive() and self.context.connected:
self.send(
":*Bouncer* NOTICE %s :Bouncer is already connected.\n" % self.nick)
- else:
- self.IRC.start()
+ self.context.start()
elif cmd.upper() == "BNCQUIT":
- with self.IRC.lock:
- if self.IRC.isAlive() and self.IRC.connected and self.IRC.registered:
+ with self.context.lock:
+ if self.context.isAlive() and self.context.connected and self.context.registered:
quitmsg = " ".join(
[word for word in [target, params, extinfo] if word])
- self.IRC.quit(quitmsg)
+ self.context.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:
+ if target:
+ targetlist = []
+ for targ in target.split(","):
+ translationfound = False
+ for (channel, translation) in conf.translations.items():
+ if translation.lower() == targ.lower():
+ # print channel
+ targetlist.append(channel.name)
+ translationfound = True
+ break
+ if not translationfound:
+ targetlist.append(targ)
+ target = ",".join(targetlist)
+
+ oldparams = params
+ params = []
+ for param in oldparams.split():
+ translationfound = False
+ for (channel, translation) in conf.translations.items():
+ # print target, (channel, translation)
+ if translation.lower() == param.lower():
+ # print channel
+ params.append(channel.name)
+ translationfound = True
+ break
+ if not translationfound:
+ params.append(param)
+ params = " ".join(params)
+
+ #print (cmd, target, params, extinfo)
+
+ if params and extinfo:
+ line = "%s %s %s :%s" % (
+ cmd, target, params, extinfo)
+ elif params:
+ line = "%s %s %s" % (cmd, target, params)
+ elif extinfo:
+ line = "%s %s :%s" % (cmd, target, extinfo)
+ else:
+ line = "%s %s" % (cmd, target)
+
+ with self.context.lock:
+ # print "Locked"
+ # print self.context.connected,
+ # self.context.registered, cmd.upper()
+ if not self.context.connected:
self.send(
":*Bouncer* NOTICE %s :Not connected to server. Type /bncconnect to attempt connection.\n" % self.nick)
break
- elif not self.IRC.registered:
+
+ elif not self.context.registered:
self.send(
":*Bouncer* NOTICE %s :Not registered.\n" % self.nick)
break
+
elif cmd.upper() in ("PRIVMSG", "NOTICE"):
# Check if CTCP
ctcp = re.findall(
@@ -723,33 +994,42 @@ class BouncerConnection (Thread):
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.
+ if ctcptype == "LAGCHECK": # Client is doing a lag check. No need to send to context 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.context.identity.nick, self.context.identity.username, self.context.identity.host, line))
else:
- self.IRC.raw(line, origin=self)
+ self.context.raw(line, origin=self)
else:
- self.IRC.raw(line, origin=self)
+ self.context.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 target and "CHANTYPES" in
+ # self.context.supports.keys() and target[0] in
+ # self.context.supports["CHANTYPES"]:
+ chantypes = self.context.supports.get(
+ "CHANTYPES", "&#+!")
+ if re.match(irc._chanmatch % re.escape(chantypes), target):
+ channel = self.context[target]
+ if channel in conf.translations.keys():
+ channame = conf.translations[channel]
+ else:
+ channame = channel.name
+
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]])
+ modestr = "".join([mode for mode in modes if mode not in self.context.supports[
+ "CHANMODES"][0] + self.context.supports["PREFIX"][0] and channel.modes[mode]])
+ params = " ".join([channel.modes[mode] for mode in modes if mode in self.context.supports[
+ "CHANMODES"][1] + self.context.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))
+ self.connection.send(
+ (u":%s 324 %s %s +%s %s\n" % (self.context.serv, self.context.identity.nick, channame, modestr, params)).encode("utf8"))
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 == "":
+ self.connection.send(
+ (u":%s 329 %s %s %s\n" % (self.context.serv, self.context.identity.nick, channame, channel.created)).encode("utf8"))
+ elif re.match("^\\+?[%s]+$" % self.context.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():
@@ -758,34 +1038,36 @@ class BouncerConnection (Thread):
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))
+ self.connection.send(
+ (u":%s %d %s %s %s %s %s\n" % (self.context.serv, i, channel.context.identity.nick, channame, mask, setby, settime)).encode("utf8"))
+ self.connection.send(
+ (u":%s %d %s %s :End of %s\n" % (self.context.serv, e, channel.context.identity.nick, channame, l)).encode("utf8"))
redundant.append(mode)
else:
- self.IRC.raw(line, origin=self)
- elif params == "" and target.lower() == self.IRC.identity.nick.lower():
+ self.context.raw(line, origin=self)
+ elif params == "" and target.lower() == self.context.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))
+ self.connection.send(
+ (u":%s 221 %s +%s\n" % (self.context.serv, self.context.identity.nick, self.context.identity.modes)).encode("utf8"))
+ if "s" in self.context.identity.modes and self.context.identity.snomask:
+ self.connection.send((u":%s 008 %s +%s :Server notice mask\n" % (
+ self.context.serv, self.context.identity.nick, self.context.identity.snomask)).encode("utf8"))
else:
- self.IRC.raw(line, origin=self)
+ self.context.raw(line, origin=self)
else:
- self.IRC.raw(line, origin=self)
+ self.context.raw(line, origin=self)
except SystemExit:
pass # No need to pass error message if break resulted from sys.exit()
except:
exc, excmsg, tb = sys.exc_info()
self.quitmsg = str(excmsg)
- if self.IRC:
+ if self.context:
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.context.logwrite(*["!!! [BouncerConnection] Exception in thread %(self)s" % vars()] + [
+ "!!! [BouncerConnection] %(tbline)s" % vars() for tbline in traceback.format_exc().split("\n")])
+ print >>sys.stderr, "Exception in thread %(self)s" % vars()
+ print >>sys.stderr, traceback.format_exc()
finally:
# Juuuuuuust in case.
with self.lock:
@@ -795,29 +1077,29 @@ class BouncerConnection (Thread):
except:
pass
- if self.IRC:
- self.IRC.logwrite(
+ if self.context:
+ self.context.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 self.IRC.registered and type(self.IRC.identity) == irc.User and not self.IRC.identity.away and self.bouncer.autoaway:
+ if self.context.connected and self.context.identity and len([bncconnection for bncconnection in self.bouncer.connections if bncconnection.context == self.context]) == 0 and self.context.registered and type(self.context.identity) == irc.User and not self.context.identity.away and self.bouncer.autoaway:
# Bouncer automatically sets away status.
- self.IRC.raw("AWAY :%s" % self.bouncer.autoaway)
+ self.context.raw("AWAY :%s" % self.bouncer.autoaway)
if self.debug:
- self.IRC.logwrite(
+ self.context.logwrite(
"dbg [BouncerConnection] Attempting to broadcast terminated connection %(self)s." % vars())
for bouncerconnection in self.bouncer.connections:
- if bouncerconnection.IRC == self.IRC:
+ if bouncerconnection.context == self.context:
if self.debug:
- self.IRC.logwrite(
+ self.context.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.context.identity.nick, self.host, self.context, self.quitmsg))
if self.debug:
- self.IRC.logwrite(
+ self.context.logwrite(
"dbg [BouncerConnection] Success: %(bouncerconnection)s." % vars())
# Announce QUIT to other bouncer connections.