Skip to content

Instantly share code, notes, and snippets.

@Justasic
Created May 30, 2014 18:54
Show Gist options
  • Save Justasic/e6af83fbc705e8d202b8 to your computer and use it in GitHub Desktop.
Save Justasic/e6af83fbc705e8d202b8 to your computer and use it in GitHub Desktop.
from twisted.internet.protocol import Protocol, Factory
from twisted.internet import reactor, protocol
from twisted.protocols.basic import LineReceiver
from twisted.python import log
import sys, time
class Channel():
def __init__(self, name, ctime, modes):
self.name = name
if not ctime:
self.ctime = int(time.time())
else:
self.ctime = ctime
self.modes = modes
self.users = []
def AddUser(self, user):
self.users.append(user)
def RemoveUser(self, user):
del self.users[self.users.index(user)]
class User():
def __init__(self, server, UID, ctime, nick, host, vhost, ident, ip, ts, modes, real):
self.server = server
self.UUID = UID
self.ctime = ctime
self.nick = nick
self.host = host
self.vhost = vhost
self.ident = ident
self.ip = ip
self.ts = ts
self.modes = modes
self.real = real
class Server():
def __init__(self, host, passwd, wut, SID, desc):
self.host = host
self.passwd = passwd
self.wut = wut
self.SID = SID
self.desc = desc
self.channels = {}
self.users = {}
class PseudoClient():
def __init__(self, factory, UID, nick, host, ident, real, modes):
self.factory = factory
self.UUID = UID
self.nick = nick
self.host = host
self.ident = ident
self.real = real
# the mode 'I' is for pseudoclients only
self.modes = modes + "Ik"
self.timestamp = int(time.time())
def SendJoin(self, c):
# Send the join message
self.factory.SendNumeric("FJOIN %s %s %s :,%s" % (c.name, c.ctime, c.modes, self.UUID))
def SendIntroduction(self):
self.factory.SendNumeric("UID %s %d %s %s %s %s 0.0.0.0 %d +%s :%s" %
(self.UUID,
self.timestamp,
self.nick,
self.host,
self.host,
self.ident,
self.timestamp,
self.modes,
self.real
))
def SendMessage(self, c, message):
log.msg("< :%s PRIVMSG %s :%s" % (self.UUID, c.name, message))
self.factory.sendLine(":%s PRIVMSG %s :%s" % (self.UUID, c.name, message))
servers = {}
linked_server = None
class CommandHandler():
def __init__(self, _command, _proto):
self.proto = _proto
self.factory = _proto.factory
self._command = _command
commandargs = []
command, commandargs = self.ParseCommandString(_command)
self.HandleCommand(command, commandargs)
def ParseCommandString(self, _command):
# Get the command by itself
cmd = _command.split(':')
command = cmd[0].strip()
try:
commandargs = cmd[1].strip().split()
except:
commandargs = None
#log.msg("> ", command, commandargs)
log.msg("> ", _command)
return command, commandargs
def HandleCommand(self, command, commandargs):
# If a command was received then process it, otherwise skip to the command arguments
# and handle the :UID based commands there
if command.strip():
cmd = command.split()
# FIXME: Check version here
if cmd[0] == "CAPAB":
# Get the capabilities from the other server
if cmd[1] == "START":
self.sendCAPAB()
# Okay, we've sent the shit we support, now do a netburst
elif cmd[1] == "END":
self.sendServer()
# We received a server from somewhere.
if cmd[0] == "SERVER":
# Add the server to the list
s = Server(cmd[1], cmd[2], cmd[3], cmd[4], " ".join(commandargs))
servers[s.SID] = s
global linked_server
linked_server = s
# Continue to the netburst now
self.SendNumeric("BURST %d" % (int(time.time() + 125)))
self.SendNumeric("VERSION :Bot %s :Whatever bot 1.0.0" % self.factory.server)
# If we're sending via SID, this will almost always be true
if commandargs:
if commandargs[1] == "BURST":
if self.proto.isSyncing:
self.SendNumeric("ENDBURST")
if commandargs[1] == "ENDBURST":
self.proto.isSyncing = False
self.proto.serverSynced()
if commandargs[1] == "PING":
self.SendNumeric("PONG %s %s" % (commandargs[3], commandargs[2]))
# We're adding another server to the list
if commandargs[1] == "SERVER":
desc = self._command.split(':')[2]
#def __init__(self, host, passwd, wut, SID, desc):
s = Server(commandargs[2], commandargs[3], commandargs[4], commandargs[5], desc)
servers[s.SID] = s
#log.msg("NEW SERVER!", commandargs, desc)
if commandargs[1] == "UID":
# Add another user to the server.
server = servers[commandargs[0]]
uuid = commandargs[2]
ctime = commandargs[3]
nick = commandargs[4]
host = commandargs[5]
vhost = commandargs[6]
ident = commandargs[7]
ip = commandargs[8]
ts = commandargs[9]
modes = commandargs[10]
desc = self._command.split(':')[2]
u = User(server, uuid, ctime, nick, host, vhost, ident, ip, ts, modes, desc)
server.users[uuid] = u
if commandargs[1] == "FJOIN":
server = servers[commandargs[0]]
name = commandargs[2]
ctime = commandargs[3]
modes = commandargs[4]
# Create the new channel
c = Channel(name, ctime, modes)
# Get all the users joined in the channel
_users = self._command.split(':')[2].split(',')
# Lookup all the users
for u in _users:
if not u:
continue
u_s = u.split(' ')
uuid = u_s[0]
if 1 in u_s:
op = u_s[1]
else:
op = None
user = self.proto.FindUser(uuid)
if user:
c.AddUser(user)
server.channels[name] = c
def sendServer(self):
server = self.factory.server
pw = self.factory.sendpass
sid = self.factory.SID
# command name pw ? SID :Description
self.Send("SERVER %s %s 0 %s :Test Bot that links here" % (server, pw, sid))
def sendCAPAB(self):
self.Send("CAPAB START 1202")
self.Send("CAPAB CAPABILITIES :PROTOCOL=1202")
self.Send("CAPAB END")
def Send(self, line):
log.msg("< %s" % line)
self.proto.sendLine(line)
def SendNumeric(self, line):
self.Send(":%s %s" % (self.factory.SID, line))
# The Inspircd Protocol handling class
class InspircdProto(LineReceiver):
def __init__(self, factory):
self.factory = factory
self.connectionValid = False
self.isSyncing = True;
self.delimiter = '\n'
self.currentuid = 000000
# See: https://github.com/inspircd/inspircd/blob/master/src/server.cpp#L89
def genNextUUID(self):
self.currentuid += 1
# Rollover
if self.currentuid == 1000000:
self.currentuid = 0
return "%s%06d" % (self.factory.SID, self.currentuid)
def connectionMade(self):
log.startLogging(sys.stdout)
log.msg("Successfully connected to %s." % self.addr.host)
reactor.callLater(45, self.sendPing)
def connectionLost(self, reason):
log.msg("Lost connection to %s." % self.addr.host)
pass
def lineReceived(self, data):
""" Default handler for all incoming data """
if not data.strip():
# If the entered data is empty, ignore it
return
CommandHandler(data, self)
def serverSynced(self):
log.msg("Servers synced!");
self.bot1 = PseudoClient(self, self.genNextUUID(), "herp", "d.derp.com", "derp", "herp derp bot", "")
self.bot1.SendIntroduction()
c = linked_server.channels['#Computers']
self.bot1.SendJoin(c)
self.bot1.SendMessage(c, "Y'all're niggas.")
def FindUser(self, uuid):
if not uuid:
return None
# Iterate over all servers
for sid, s in servers.items():
# iterate over all users in that server
for uid, u in s.users.items():
# If the uuids match, we found our user.
if uid == uuid:
return u
return None
def SendNumeric(self, line):
log.msg("< :%s %s" % (self.factory.SID, line))
self.sendLine(":%s %s" % (self.factory.SID, line))
def sendPing(self):
self.SendNumeric("PING %s %s" % (self.factory.SID, linked_server.SID))
reactor.callLater(45, self.sendPing)
def sendQuit(self, reason):
self.SendNumeric("SQUIT: %s" % reason)
self.transport.loseConnection()
def sendError(self, error):
self.sendLine("ERROR: %s" % reason)
self.transport.loseConnection()
class InspircFactory(protocol.ClientFactory):
def __init__(self, SID, server, sendpass):
self.sendpass = sendpass
self.server = server
self.SID = SID
def buildProtocol(self, addr):
p = InspircdProto(self)
p.addr = addr
return p
def clientConnectionLost(self, connector, reason):
"""If we get disconnected, reconnect to server."""
connector.connect()
def clientConnectionFailed(self, connector, reason):
print ("connection failed:", reason)
reactor.stop()
import os
from twisted.application import service, internet
from twisted.web import static, server
#import Bot, TelnetServer
import inspircd
#channel = ["#Test"]
#channel = "#Test"
host = "15.0.1.10"
SID = "52R"
server = "justasic.vemnet.us"
pw = "polarbears"
port = 7000
application = service.Application("BasicINSPBot")
#tcpservice = TelnetServer.SubScribeFactory()
#botservice = Bot.BotFactory(channel, tcpservice)
inspservice = inspircd.InspircFactory(SID, server, pw)
service = internet.TCPClient(host, port, inspservice)
#listenservice = internet.TCPServer(7050, tcpservice)
#listenservice.setServiceParent(application)
service.setServiceParent(application)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment