209 lines
6.6 KiB
Python
Executable File
209 lines
6.6 KiB
Python
Executable File
#!/usr/bin/python3
|
|
#
|
|
# miniirc-based relay bot
|
|
#
|
|
# © 2018 by luk3yx
|
|
#
|
|
|
|
import miniirc, sys
|
|
from miniirc import IRC
|
|
|
|
# Variables
|
|
debug = True
|
|
|
|
# Network list
|
|
networks = {
|
|
# 'Network Name': {
|
|
# 'ip': 'irc.servers.ip',
|
|
# 'port': 6697,
|
|
# 'nick': 'testing-relay',
|
|
# 'ignored': {'lowercase-identifier'}, # Matched against nick, ident
|
|
# '#channel': 'local-routing-name', # and host.
|
|
# },
|
|
}
|
|
|
|
# Format strings
|
|
# formatstrings = {
|
|
# 'PRIVMSG': '<{host[0]}@{network}> {msg}',
|
|
# 'ACTION': '* {host[0]}@{network} {msg}',
|
|
# 'JOIN': '--> {host[0]}@{network} ({host[1]}@{host[2]}) has joined',
|
|
# 'PART': '<-- {host[0]}@{network} ({host[1]}@{host[2]}) has left ({msg})',
|
|
# 'KICK': '<-- {victim} has been kicked by {kicker} ({msg})',
|
|
# 'NICK': ' -- {host[0]}@{network} ({host[1]}@{host[2]}) is now known as'
|
|
# '{msg}',
|
|
# 'QUIT': '<-- {victim} ({host[1]}@{host[2]}) has quit ({msg})'
|
|
# }
|
|
|
|
# This looks messy, but it creates nice coloured/colored strings.
|
|
_uh = '\x036(\x0310{{host[1]}}@{{host[2]}}\x036)'
|
|
_ = '\x03{0}{1}\x03 {{host[0]}}@{{network}} ' + _uh + \
|
|
'\x03{0} has {2} \x036(\x0310{{msg}}\x036)'
|
|
_hn = '{host[0]}@{network}'
|
|
formatstrings = {
|
|
'PRIVMSG': '<' + _hn + '> {msg}',
|
|
'ACTION': '* ' + _hn + ' {msg}',
|
|
'JOIN': _.format(3, '-->', 'joined').replace(' \x036(\x0310{msg}\x036)',
|
|
''),
|
|
'PART': _.format(4, '<--', 'left'),
|
|
'KICK': _.format(4, '<--', 'been yaykicked by {kicker}').replace(' ' +
|
|
_uh.format(), '').replace('{host[0]}', '{victim}'),
|
|
'NICK': _.format(6, ' --', '{NICK}').replace('({msg})',
|
|
'{msg}').replace('has {NICK}', 'is now known as'),
|
|
'QUIT': _.format(4, '<--', 'quit IRC')
|
|
}
|
|
del _
|
|
del _hn
|
|
del _uh
|
|
|
|
# Welcome!
|
|
print('Welcome to miniirc-relay!', file=sys.stderr)
|
|
is_channel = lambda channel : type(channel) == str and not channel[:1].isalnum()
|
|
|
|
# Parse the networks list and connect to any new IRC networks
|
|
_ircs = {}
|
|
relayed = {}
|
|
def parse_networks():
|
|
print('Parsing networks...', file=sys.stderr)
|
|
relayed.clear()
|
|
for name in networks:
|
|
network = networks[name]
|
|
|
|
channels = set()
|
|
for channel in network:
|
|
if is_channel(channel):
|
|
lchan = channel.lower()
|
|
if channel != lchan:
|
|
network[lchan] = network[channel]
|
|
del network[channel]
|
|
channel = lchan
|
|
del lchan
|
|
channels.add(channel)
|
|
id = network[channel]
|
|
if id not in relayed:
|
|
relayed[id] = {}
|
|
relayed[id][name] = channel
|
|
|
|
if not network.get(IRC):
|
|
print('Connecting to {}...'.format(repr(name)), file=sys.stderr)
|
|
network[IRC] = IRC(network['ip'], network['port'], network['nick'],
|
|
channels, ns_identity = network.get('ns_identity'),
|
|
debug = debug)
|
|
network[IRC].debug('Channels on {}: {}'.format(repr(name),channels))
|
|
_ircs[network[IRC]] = name
|
|
print('Done.', file=sys.stderr)
|
|
|
|
# Check to see if a user is ignored.
|
|
def is_ignored(hostmask, network):
|
|
if not networks.get(network) or not networks[network].get('ignored'):
|
|
return
|
|
for name in hostmask:
|
|
if name.lower() in networks[network]['ignored']:
|
|
networks[network][IRC].debug('Ignoring message from ' +
|
|
repr(hostmask))
|
|
return True
|
|
return False
|
|
|
|
# Send a message to networks
|
|
def relay_message(irc, msg, channel=None):
|
|
if not msg:
|
|
return
|
|
network = _ircs.get(irc)
|
|
|
|
if channel:
|
|
channel = channel.lower()
|
|
irc.debug('Sending message from', channel, 'on', network)
|
|
if not is_channel(channel) or channel not in networks[network]:
|
|
return
|
|
id = networks[network][channel]
|
|
if id not in relayed:
|
|
print('WARNING: Non-existent channel ID detected!', file=sys.stderr)
|
|
parse_networks()
|
|
to_relay = relayed[id]
|
|
for n in to_relay:
|
|
if n != network and networks[n].get(IRC):
|
|
irc.debug('Relaying from', network, 'to', n, 'via', networks[n][IRC])
|
|
networks[n][IRC].msg(to_relay[n], msg)
|
|
else:
|
|
for n in networks:
|
|
if n != network and networks[n].get(IRC):
|
|
for channel in networks[n]:
|
|
if is_channel(channel):
|
|
networks[n][IRC].msg(channel, msg)
|
|
|
|
|
|
# Handle PRIVMSGs
|
|
@miniirc.Handler('PRIVMSG', colon=False)
|
|
def handle_privmsg(irc, hostmask, args):
|
|
text = args[-1]
|
|
msg = None
|
|
net = _ircs.get(irc)
|
|
if is_ignored(hostmask, net):
|
|
return
|
|
|
|
if text == '\x01ACTION\x01' or (text.startswith('\x01ACTION ')
|
|
and text.endswith('\x01')):
|
|
msg = formatstrings['ACTION'].format(host=hostmask, network=net,
|
|
msg=text[8:-1])
|
|
elif not text.startswith('\x01'):
|
|
msg = formatstrings['PRIVMSG'].format(host=hostmask, network=net,
|
|
msg=text)
|
|
|
|
relay_message(irc, msg, args[0])
|
|
|
|
# Handle JOINs
|
|
@miniirc.Handler('JOIN', colon=False)
|
|
def handle_join(irc, hostmask, args):
|
|
net = _ircs.get(irc)
|
|
if is_ignored(hostmask, net):
|
|
return
|
|
if net:
|
|
msg = formatstrings['JOIN'].format(host=hostmask, network=net)
|
|
relay_message(irc, msg, args[0])
|
|
|
|
# Handle PARTs
|
|
@miniirc.Handler('PART', colon=False)
|
|
def handle_part(irc, hostmask, args):
|
|
net = _ircs.get(irc)
|
|
if is_ignored(hostmask, net):
|
|
return
|
|
if net:
|
|
msg = formatstrings['PART'].format(host=hostmask, network=net,
|
|
msg=args[-1])
|
|
relay_message(irc, msg, args[0])
|
|
|
|
# Handle PARTs
|
|
@miniirc.Handler('KICK', colon=False)
|
|
def handle_part(irc, hostmask, args):
|
|
net = _ircs.get(irc)
|
|
if is_ignored(hostmask, net):
|
|
return
|
|
if net:
|
|
msg = formatstrings['KICK'].format(victim=args[-2], network=net,
|
|
kicker=hostmask[0], msg=args[-1])
|
|
relay_message(irc, msg, args[0])
|
|
|
|
# Handle QUITs
|
|
@miniirc.Handler('QUIT', colon=False)
|
|
def handle_quit(irc, hostmask, args):
|
|
net = _ircs.get(irc)
|
|
if is_ignored(hostmask, net):
|
|
return
|
|
if net:
|
|
msg = formatstrings['QUIT'].format(host=hostmask, network=net,
|
|
msg=args[-1] if args else '')
|
|
relay_message(irc, msg)
|
|
|
|
# Handle NICKs
|
|
@miniirc.Handler('NICK', colon=False)
|
|
def handle_quit(irc, hostmask, args):
|
|
net = _ircs.get(irc)
|
|
if is_ignored(hostmask, net):
|
|
return
|
|
if net:
|
|
msg = formatstrings['NICK'].format(host=hostmask, network=net,
|
|
newnick=args[0])
|
|
relay_message(irc, msg)
|
|
|
|
# Parse the network list
|
|
parse_networks()
|