1
0
Fork 0

implemented basics

This commit is contained in:
fanir 2014-02-28 17:04:08 +01:00
parent cb46a86567
commit 9ca0509bb0

269
main.py
View file

@ -23,9 +23,25 @@
# #
import sys # SETTINGS CAN BE FOUND AT THE BOTTOM OF THE FILE
import socket
import string
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(): class pircbot():
@ -41,77 +57,195 @@ class pircbot():
except UnicodeDecodeError: continue except UnicodeDecodeError: continue
return textstring.decode(self.encodings[0], 'ignore') 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.nicknames = nicknames
self.server = server self.server = server
self.port = port self.port = port
self.ident = ident self.ident = ident
self.realname = realname self.realname = realname
self.encodings = encodings 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): def connect(self):
s=socket.socket( ) # connect
self.socket = socket.socket()
try: try:
s.connect((self.server, self.port)) self.socket.connect((self.server, self.port))
except socket.error as e: except socket.error as e:
print("Fehler: %s" % e) log.show(log.FATAL, "Fehler: %s" % e)
return 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: self.run = True
line=line.rstrip()
line=line.split(" ")
if(line[0]=="PING"): # start getting data
s.send(self.encode("PONG %s\r\n" % line[1])) 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: 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=""): 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): def join(self, channel):
pass print(channel)
self.socket.send(self.encode("JOIN %s\n" % channel))
def part(self, channel): def part(self, channel):
pass self.socket.send(self.encode("PART %s\n" % channel))
def on_command(self, prefix, origin, source, command, params):
"""
Executed when getting a PRIVMSG starting with self.cmdprefix
def startbot(): Prefix contains the optional prefix of the raw line.
bot = pircbot(nicknames=(NICKNAME, ALT_NICKNAME), server=SERVER, port=PORT, Origin is a map holding the parsed prefix, containing
ident=IDENT, realname=REALNAME, encodings=ENCODINGS) "nick", "ident" and "host" for users and "server" for servers.
bot.connect() Source is the first parameter after the irc-command, specifying
bot.quit() 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(): def parseargs():
"""
Parses comand line arguments
"""
import argparse import argparse
p = argparse.ArgumentParser( p = argparse.ArgumentParser(
description = "i think my desc is missing") description = "i think my desc is missing")
p.add_argument("action", default="help", choices = ["start", "stop"], help="What to do?") 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") #p.add_argument("--daemon", "-d", type = bool, choices = [1, 0], default=1, help="Daemonize, Default: 1")
return p.parse_args() return p.parse_args()
def KeyboardInterruptHandler(signum, frame):
global bot
print("Got Ctrl-C, dying now...")
bot.quit("")
sys.exit()
def main(): def main():
global bot
signal.signal(signal.SIGINT, KeyboardInterruptHandler)
args = parseargs() args = parseargs()
if args.action == "start": 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!") elif args.action == "stop": print("nope!")
return 0 return 0
@ -122,21 +256,56 @@ if __name__ == '__main__':
### SETTINGS ### ### 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" # Also known as username. Some IRC-internal.
PORT = 6667 # 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() main()