3
0
mirror of https://github.com/jlu5/PyLink.git synced 2024-11-27 21:19:31 +01:00

Initial Clientbot stub, with very rudimentary user handling (#144)

This commit is contained in:
James Lu 2016-07-16 22:42:17 -07:00
parent 1770058e1b
commit c52d542ed8
2 changed files with 139 additions and 0 deletions

121
protocols/clientbot.py Normal file
View File

@ -0,0 +1,121 @@
import time
from pylinkirc import utils, conf
from pylinkirc.log import log
from pylinkirc.classes import Protocol, IrcUser, IrcServer
class ClientbotWrapperProtocol(Protocol):
def __init__(self, irc):
super().__init__(irc)
# FIXME: Grab this from 005 / RPL_ISUPPORT instead of hardcoding.
self.casemapping = 'ascii'
self.caps = {}
# Initialize counter-based pseudo UID generators
self.uidgen = utils.PUIDGenerator('PUID')
self.sidgen = utils.PUIDGenerator('PSID')
def connect(self):
"""Initializes a connection to a server."""
ts = self.irc.start_ts
f = self.irc.send
# TODO: fetch channel/user/prefix modes from RPL_ISUPPORT.
#self.irc.prefixmodes = {'q': '~', 'a': '&', 'o': '@', 'h': '%', 'v': '+'}
# HACK: Replace the SID from the config options with our own.
old_sid = self.irc.sid
self.irc.sid = sid = self.sidgen.next_uid()
self.irc.servers[sid] = self.irc.servers[old_sid]
del self.irc.servers[old_sid]
sendpass = self.irc.serverdata.get("sendpass")
if sendpass:
f('PASS %s' % sendpass)
# This is a really gross hack to get the defined NICK/IDENT/HOST/GECOS.
# But this connection stuff is done before any of the spawnClient stuff in
# services_support fires.
f('NICK %s' % (self.irc.serverdata.get('pylink_nick') or conf.conf["bot"].get("nick", "PyLink")))
ident = self.irc.serverdata.get('pylink_ident') or conf.conf["bot"].get("ident", "pylink")
f('USER %s %s 0.0.0.0 %s' % (ident, ident,
# TODO: per net realnames or hostnames aren't implemented yet.
conf.conf["bot"].get("realname", "PyLink Clientbot")))
def spawnClient(self, nick, ident='null', host='null', realhost=None, modes=set(),
server=None, ip='0.0.0.0', realname=None, ts=None, opertype=None,
manipulatable=False):
"""
STUB: Pretends to spawn a new client with a subset of the given options.
"""
uid = self.uidgen.next_uid()
ts = ts or int(time.time())
realname = realname or ''
log.debug('(%s) spawnClient stub called, saving nick %s as PUID %s', self.irc.name, nick, uid)
u = self.irc.users[uid] = IrcUser(nick, ts, uid, ident=ident, host=host, realname=realname)
log.debug('(%s) self.irc.users: %s', self.irc.name, self.irc.users)
self.irc.servers[self.irc.sid].users.add(uid)
return u
def spawnServer(self, name, sid=None, uplink=None, desc=None, endburst_delay=0):
"""
STUB: Pretends to spawn a new server with a subset of the given options.
"""
name = name.lower()
sid = self.sidgen.next_sid()
self.irc.servers[sid] = IrcServer(uplink, name)
return sid
def join(self, *args):
return
def ping(self, *args):
return
def handle_events(self, data):
"""Event handler for the RFC1459 (clientbot) protocol.
"""
data = data.split(" ")
args = self.parsePrefixedArgs(data)
sender = args[0]
# PyLink as a services framework expects UIDs and SIDs for everythiung. Since we connect
# as a bot here, there's no explicit user introduction, so we're going to generate
# pseudo-uids and pseudo-sids as we see prefixes.
log.debug('(%s) handle_events: sender is %s', self.irc.name, sender)
if '!' not in sender:
# Sender is a server name.
idsource = self._getSid(sender)
if idsource not in self.irc.servers:
idsource = self.spawnServer(sender)
else:
# Sender is a nick!user@host prefix. Split it into its relevant parts.
nick, identhost = sender.split('!', 1)
idsource = self.irc.nickToUid(nick)
if not idsource:
ident, host = identhost.split('@', 1)
idsource = self.spawnClient(nick, ident, host).uid
log.debug('(%s) handle_events: idsource is %s', self.irc.name, idsource)
command = args[1]
args = args[2:]
try:
func = getattr(self, 'handle_'+command.lower())
except AttributeError: # unhandled command
pass
else:
parsed_args = func(idsource, command, args)
if parsed_args is not None:
return [idsource, command, parsed_args]
def handle_005(self, source, command, args):
"""
Handles 005 / RPL_ISUPPORT.
"""
return {'parse_as': 'ENDBURST'}
Class = ClientbotWrapperProtocol

View File

@ -64,6 +64,24 @@ class IncrementalUIDGenerator():
self.increment() self.increment()
return uid return uid
class PUIDGenerator():
"""
Pseudo UID Generator module, using a prefix and a simple counter.
"""
def __init__(self, prefix):
self.prefix = prefix
self.counter = 0
def next_uid(self):
"""
Generates the next PUID.
"""
uid = '%s@%s' % (self.prefix, self.counter)
self.counter += 1
return uid
next_sid = next_uid
def add_cmd(func, name=None, **kwargs): def add_cmd(func, name=None, **kwargs):
"""Binds an IRC command function to the given command name.""" """Binds an IRC command function to the given command name."""
world.services['pylink'].add_cmd(func, name=name, **kwargs) world.services['pylink'].add_cmd(func, name=name, **kwargs)