implemented basics
This commit is contained in:
parent
cb46a86567
commit
9ca0509bb0
1 changed files with 235 additions and 66 deletions
269
main.py
269
main.py
|
@ -23,9 +23,25 @@
|
|||
#
|
||||
|
||||
|
||||
import sys
|
||||
import socket
|
||||
import string
|
||||
# SETTINGS CAN BE FOUND AT THE BOTTOM OF THE FILE
|
||||
|
||||
|
||||
import sys, time, string, socket, re, signal
|
||||
from select import poll, POLLIN, POLLPRI, POLLOUT,\
|
||||
POLLERR, POLLHUP, POLLNVAL
|
||||
from threading import Thread#, Event
|
||||
|
||||
bot = None
|
||||
|
||||
class log():
|
||||
DEBUG, INFO, WARNING, ERROR, FATAL, SILENT =\
|
||||
0, 1, 2, 3, 4, 5
|
||||
|
||||
def show(level, msg):
|
||||
if level in range(log.DEBUG, log.SILENT):
|
||||
if LOGLEVEL <= level: print(msg)
|
||||
else:
|
||||
raise ValueError("That's not a loglevel!")
|
||||
|
||||
|
||||
class pircbot():
|
||||
|
@ -41,77 +57,195 @@ class pircbot():
|
|||
except UnicodeDecodeError: continue
|
||||
return textstring.decode(self.encodings[0], 'ignore')
|
||||
|
||||
connected = False
|
||||
|
||||
def __init__(self, nicknames, server, port=6667, ident="pircbot", realname="pircbot", encodings=("utf-8", "latin-1")):
|
||||
def __init__(self, nicknames, server, port=6667, ident="pircbot",
|
||||
realname="pircbot", encodings=("utf-8", "latin-1"),
|
||||
command_prefix=".", admins=""):
|
||||
self.nicknames = nicknames
|
||||
self.server = server
|
||||
self.port = port
|
||||
self.ident = ident
|
||||
self.realname = realname
|
||||
self.encodings = encodings
|
||||
self.admins = admins
|
||||
self.cmdprefix = command_prefix
|
||||
self.socket = None
|
||||
self.recvloop = None
|
||||
self.recvbuffer = bytearray(1024)
|
||||
self.run = False
|
||||
self.ready = False
|
||||
self.is_alive = False
|
||||
self.need_nick = True
|
||||
|
||||
def recv(self):
|
||||
"""
|
||||
Loop for reciving data
|
||||
"""
|
||||
parser = Thread(target=self.parse, name="parser")
|
||||
p = poll()
|
||||
p.register(self.socket.fileno(), POLLIN)
|
||||
while self.run:
|
||||
ap = p.poll(1000)
|
||||
if (self.socket.fileno(), POLLIN) in ap:
|
||||
self.recvbuffer.extend(self.socket.recv(1024))
|
||||
if not parser.is_alive():
|
||||
parser = Thread(target=self.parse, name="parser")
|
||||
parser.start()
|
||||
if parser.is_alive(): parser.join()
|
||||
|
||||
def connect(self):
|
||||
s=socket.socket( )
|
||||
# connect
|
||||
self.socket = socket.socket()
|
||||
try:
|
||||
s.connect((self.server, self.port))
|
||||
self.socket.connect((self.server, self.port))
|
||||
except socket.error as e:
|
||||
print("Fehler: %s" % e)
|
||||
log.show(log.FATAL, "Fehler: %s" % e)
|
||||
return
|
||||
s.send(self.encode("NICK %s\r\n" % self.nicknames[0]))
|
||||
s.send(self.encode("USER %s %s bla :%s\r\n" % (self.ident, self.server, self.realname)))
|
||||
self.connected = True
|
||||
readbuffer=""
|
||||
while 1:
|
||||
readbuffer=readbuffer+self.decode(s.recv(1024))
|
||||
temp=readbuffer.split("\n")
|
||||
readbuffer=temp.pop( )
|
||||
|
||||
for line in temp:
|
||||
line=line.rstrip()
|
||||
line=line.split(" ")
|
||||
self.run = True
|
||||
|
||||
if(line[0]=="PING"):
|
||||
s.send(self.encode("PONG %s\r\n" % line[1]))
|
||||
# start getting data
|
||||
self.recvloop = Thread(target=self.recv, name="recvloop")
|
||||
self.recvloop.start()
|
||||
|
||||
# get a nick
|
||||
self.socket.send(self.encode("NICK %s\r\n" % self.nicknames.pop(0)))
|
||||
|
||||
self.socket.send(self.encode("USER %s %s bla :%s\r\n" % (self.ident, self.server, self.realname)))
|
||||
|
||||
self.is_alive = True
|
||||
|
||||
def parse(self):
|
||||
"""
|
||||
Loop for parsing incoming data
|
||||
"""
|
||||
#line = ""
|
||||
origin = {}
|
||||
while self.run and self.recvbuffer != b"":
|
||||
# get and decode line from buffer
|
||||
rawline, _, self.recvbuffer = self.recvbuffer.partition(b"\r\n")
|
||||
rawline = self.decode(rawline)
|
||||
# prepare line
|
||||
line = rawline.split(" :", 1)
|
||||
head = line[0].lstrip("\x00").split(" ")
|
||||
larg = line[1] if len(line)>1 else ""
|
||||
# parse prefix
|
||||
if head[0].startswith(":"):
|
||||
prefix = head.pop(0)[1:]
|
||||
origin.clear()
|
||||
if "@" in prefix:
|
||||
origin["nick"], origin["ident"], origin["host"] = re.match(r"(\S+)!(\S+)@(\S+)", prefix).groups()
|
||||
else:
|
||||
origin["server"] = prefix
|
||||
else:
|
||||
print(" ".join(line))
|
||||
prefix = ""
|
||||
# parse command
|
||||
command = head.pop(0)
|
||||
# parse params
|
||||
params = head
|
||||
params.append(larg)
|
||||
|
||||
log.show(log.DEBUG, ">> %s" % rawline)
|
||||
|
||||
if command == "PING":
|
||||
self.socket.send(self.encode("PONG %s\r\n" % params[0]))
|
||||
elif command == "PRIVMSG":
|
||||
if params[1].startswith(self.cmdprefix):
|
||||
args = params[1].lstrip(self.cmdprefix).split(" ")
|
||||
sndline = self.on_command(prefix, origin, params[0], args[0], args[1:])
|
||||
if sndline != None:
|
||||
log.show(log.DEBUG, "<< %s" % sndline)
|
||||
self.socket.send(self.encode(sndline))
|
||||
elif command == "001":
|
||||
self.ready = True
|
||||
elif command == "433":
|
||||
self.socket.send(self.encode("NICK %s\r\n" % self.nicknames.pop(0)))
|
||||
elif command == "KILL":
|
||||
print("Got killed: %s", rawline)
|
||||
self.die()
|
||||
|
||||
def is_admin(self, user):
|
||||
for admin in self.admins:
|
||||
if re.search(admin, user) != None:
|
||||
return True
|
||||
return False
|
||||
|
||||
def die(self):
|
||||
self.run = False
|
||||
self.recvloop.join()
|
||||
self.is_alive = False
|
||||
sys.exit()
|
||||
|
||||
def quit(self, reason=""):
|
||||
pass
|
||||
self.socket.send(self.encode("QUIT :%s\n" % reason))
|
||||
self.run = False
|
||||
self.recvloop.join()
|
||||
self.is_alive = False
|
||||
|
||||
def join(self, channel):
|
||||
pass
|
||||
print(channel)
|
||||
self.socket.send(self.encode("JOIN %s\n" % channel))
|
||||
|
||||
def part(self, channel):
|
||||
pass
|
||||
self.socket.send(self.encode("PART %s\n" % channel))
|
||||
|
||||
|
||||
|
||||
|
||||
def startbot():
|
||||
bot = pircbot(nicknames=(NICKNAME, ALT_NICKNAME), server=SERVER, port=PORT,
|
||||
ident=IDENT, realname=REALNAME, encodings=ENCODINGS)
|
||||
bot.connect()
|
||||
bot.quit()
|
||||
def on_command(self, prefix, origin, source, command, params):
|
||||
"""
|
||||
Executed when getting a PRIVMSG starting with self.cmdprefix
|
||||
Prefix contains the optional prefix of the raw line.
|
||||
Origin is a map holding the parsed prefix, containing
|
||||
"nick", "ident" and "host" for users and "server" for servers.
|
||||
Source is the first parameter after the irc-command, specifying
|
||||
the channel or user, from where the line comes.
|
||||
Command is the command for the bot.
|
||||
Params contains a list of originally space separated parameters.
|
||||
"""
|
||||
print(params)
|
||||
if command.startswith("hello"):
|
||||
greeting = "".join(("Hi " + origin["nick"] +"!"))
|
||||
if source[0] in {"#", "+", "!", "&"}:
|
||||
return "PRIVMSG %s :%s\r\n" % (source, greeting)
|
||||
else:
|
||||
return "PRIVMSG %s :%s\r\n" % (origin["nick"], greeting)
|
||||
elif command.startswith("join") and len(params)>0:
|
||||
if self.is_admin(origin["nick"]): self.join(params[0])
|
||||
else: return "PRIVMSG %s :You can't do that!\r\n" % origin["nick"]
|
||||
elif command.startswith("part") and len(params)>0:
|
||||
if self.is_admin(origin["nick"]): self.part(params[0])
|
||||
else: return "PRIVMSG %s :You can't do that!\r\n" % origin["nick"]
|
||||
|
||||
|
||||
def parseargs():
|
||||
"""
|
||||
Parses comand line arguments
|
||||
"""
|
||||
import argparse
|
||||
p = argparse.ArgumentParser(
|
||||
description = "i think my desc is missing")
|
||||
p.add_argument("action", default="help", choices = ["start", "stop"], help="What to do?")
|
||||
#p.add_argument("--daemon", "-d", type = bool, choices = [1, 0], default=1, help="Daemonize, Default: 1")
|
||||
|
||||
return p.parse_args()
|
||||
|
||||
def KeyboardInterruptHandler(signum, frame):
|
||||
global bot
|
||||
print("Got Ctrl-C, dying now...")
|
||||
bot.quit("")
|
||||
sys.exit()
|
||||
|
||||
def main():
|
||||
global bot
|
||||
signal.signal(signal.SIGINT, KeyboardInterruptHandler)
|
||||
|
||||
args = parseargs()
|
||||
if args.action == "start":
|
||||
startbot()
|
||||
bot = pircbot(nicknames=NICKNAMES, ident=IDENT, realname=REALNAME,
|
||||
server=SERVER, port=PORT, encodings=ENCODINGS, command_prefix=COMMAND_PREFIX, admins=ADMINS)
|
||||
try:
|
||||
bot.connect()
|
||||
while bot.ready == False: time.sleep(1)
|
||||
for channel in CHANNELS:
|
||||
bot.join(channel)
|
||||
while 1:
|
||||
if bot.is_alive == False: print("X")
|
||||
time.sleep(10)
|
||||
except SystemExit:
|
||||
print("exiting...")
|
||||
elif args.action == "stop": print("nope!")
|
||||
return 0
|
||||
|
||||
|
@ -122,21 +256,56 @@ if __name__ == '__main__':
|
|||
### SETTINGS ###
|
||||
################
|
||||
|
||||
# With how much information do you want to be annoyed?
|
||||
# DEBUG spams most, FATAL least. WARNING should be a good tradeoff.
|
||||
# One of: log.DEBUG, log.INFO, log.WARNING, log.ERROR, log.FATAL
|
||||
LOGLEVEL = log.DEBUG
|
||||
|
||||
IDENT = "chalkbot"
|
||||
NICKNAME = "chalkbot"
|
||||
ALT_NICKNAME = "chalkbot_"
|
||||
REALNAME = "A ChalkBot Instance"
|
||||
# Command for registering with nickserv, without leading slash
|
||||
NICKSERVCMD = ""
|
||||
|
||||
SERVER = "fanir.de"
|
||||
PORT = 6667
|
||||
# Also known as username. Some IRC-internal.
|
||||
# By default, the nickname will be used as ident.
|
||||
IDENT = "chalkbot"
|
||||
|
||||
ENCODINGS = ('utf-8', 'latin-1', 'iso-8859-1', 'cp1252')
|
||||
# The list of nicknames to try. If the first one is not aviable, it will
|
||||
# try the second, and so on...
|
||||
# You should specfy at least two nicks.
|
||||
NICKNAMES = ["chalkbot", "chalkbot_", "chalkbot__"]
|
||||
|
||||
CHANNELS = ["#bots"]
|
||||
REALNAME = "A ChalkBot Instance"
|
||||
|
||||
# Command for registering with nickserv, without leading slash.
|
||||
NICKSERVCMD = ""
|
||||
|
||||
MODES = "+B"
|
||||
|
||||
|
||||
# The Server name to connect to. Duh!
|
||||
#SERVER = "fanir.de"
|
||||
SERVER = "localhost"
|
||||
|
||||
# "Default" is 6667. An often used port for SSL would be 6697, if SSL would be
|
||||
# supported. Maybe in a future, far far away...
|
||||
PORT = 6667
|
||||
|
||||
# A comma-seperated list of channels to join, enclosed by braces.
|
||||
CHANNELS = ["#bots", "#main"]
|
||||
|
||||
# The encodings to try when getting messages from IRC. Will be tried in the given order.
|
||||
# The first one is used to encode data when sending stuff.
|
||||
# The list given shoud do just fine in most networks, I assume.
|
||||
# Also comma seperated and enclosed by braces.
|
||||
ENCODINGS = ['utf-8', 'latin-1', 'iso-8859-1', 'cp1252']
|
||||
|
||||
|
||||
# List of users (hostmasks, will be parsed as regex) who can do important stuff,
|
||||
# like joining and parting channels and shutting down the bot.
|
||||
ADMINS = ["Fanir.*"]
|
||||
|
||||
COMMAND_PREFIX = "."
|
||||
|
||||
#######################
|
||||
### END OF SETTINGS ###
|
||||
#######################
|
||||
|
||||
|
||||
main()
|
||||
|
||||
|
|
Loading…
Reference in a new issue