2018-09-05 15:38:19 +02:00
|
|
|
|
#!/usr/bin/python -u
|
|
|
|
|
# -*- coding: utf-8 -1 -*-
|
|
|
|
|
|
|
|
|
|
# Import some necessary libraries.
|
|
|
|
|
import socket, sys, time, csv, Queue, random, re, pdb, select, os.path, datetime
|
|
|
|
|
from threading import Thread
|
|
|
|
|
import feedparser
|
|
|
|
|
import xml.dom.minidom
|
|
|
|
|
from time import mktime, localtime
|
|
|
|
|
|
|
|
|
|
import iso8601
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# IRC configuration
|
|
|
|
|
|
|
|
|
|
default_server = "irc.eu.freenode.net"
|
|
|
|
|
default_nickname = "bot-cop"
|
2018-09-14 14:48:55 +02:00
|
|
|
|
ban_list = ["fentanyl", "scams", "fraudster", "scams", "spam-shake", ":alla.\s", "һ", "ⅼ", "ⅾ", "і", "а", "ɑ", "ᥒ", "і", "ഠ", "ⅿ"]
|
2018-09-05 15:38:19 +02:00
|
|
|
|
|
|
|
|
|
#########################
|
|
|
|
|
### Class Definitions ###
|
|
|
|
|
#########################
|
|
|
|
|
|
|
|
|
|
class Project(object):
|
|
|
|
|
def __init__(self, project, channel):
|
|
|
|
|
self.name = project
|
|
|
|
|
self.channel = channel
|
|
|
|
|
self.bot_next = datetime.datetime.utcnow()
|
|
|
|
|
self.bot_latest = datetime.datetime.utcnow()
|
|
|
|
|
|
|
|
|
|
def set_ircsock ( self, ircsock ):
|
|
|
|
|
self.ircsock = ircsock
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Defines a bot
|
|
|
|
|
class Bot(object):
|
|
|
|
|
|
|
|
|
|
def __init__(self, server, botnick):
|
|
|
|
|
self.botnick = botnick
|
|
|
|
|
self.ban_regex = re.compile(self.get_regex(ban_list), re.I)
|
|
|
|
|
self.server = server
|
|
|
|
|
self.projects = [ ]
|
|
|
|
|
|
|
|
|
|
def connect(self):
|
|
|
|
|
self.ircsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
|
|
|
self.ircsock.connect((self.server, 6667))
|
|
|
|
|
self.ircsock.send("USER {0} {0} {0} :Robot Agir April"
|
|
|
|
|
".\n".format(self.botnick)) # bot authentication
|
|
|
|
|
self.ircsock.send("NICK {}\n".format(self.botnick)) # Assign the nick to the bot.
|
|
|
|
|
if os.path.isfile("password.txt"):
|
|
|
|
|
with open("password.txt", 'r') as f:
|
|
|
|
|
password = f.read()
|
|
|
|
|
if registered == True:
|
|
|
|
|
self.ircsock.send("PRIVMSG {} {} {} {}".format("NickServ","IDENTIFY", self.botnick, password))
|
|
|
|
|
|
|
|
|
|
def add_project(self, project):
|
|
|
|
|
project.set_ircsock ( self.ircsock )
|
|
|
|
|
self.ircsock.send("JOIN {} \n".format(project.channel)) # Joins channel
|
|
|
|
|
self.projects.append(project)
|
|
|
|
|
|
|
|
|
|
def get_project(self, name):
|
|
|
|
|
for project in self.projects:
|
|
|
|
|
if name[0] != '#' and project.name == name:
|
|
|
|
|
return project
|
|
|
|
|
elif name[0] == '#' and project.channel == name:
|
|
|
|
|
return project
|
|
|
|
|
|
|
|
|
|
# Main loop
|
|
|
|
|
def loop(self):
|
|
|
|
|
last_read = datetime.datetime.utcnow()
|
|
|
|
|
while 1: # Loop forever
|
|
|
|
|
ready_to_read, b, c = select.select([self.ircsock],[],[], 1)
|
|
|
|
|
if ready_to_read:
|
|
|
|
|
last_read = datetime.datetime.utcnow()
|
|
|
|
|
ircmsg = self.msg_handler()
|
|
|
|
|
ircmsg, actor, channel = self.parse_messages(ircmsg)
|
|
|
|
|
if ircmsg is not None:
|
|
|
|
|
self.message_response(ircmsg, actor, channel)
|
|
|
|
|
if datetime.datetime.utcnow() - last_read > datetime.timedelta(minutes=10):
|
|
|
|
|
raise Exception('timeout: nothing to read on socket since 10 minutes')
|
|
|
|
|
|
|
|
|
|
# Responds to server Pings.
|
|
|
|
|
def pong(self, ircmsg):
|
|
|
|
|
response = "PONG :" + ircmsg.split("PING :")[1] + "\n"
|
|
|
|
|
self.ircsock.send(response)
|
|
|
|
|
|
|
|
|
|
# Parses messages and responds to them appropriately.
|
|
|
|
|
def message_response(self, ircmsg, actor, channel):
|
|
|
|
|
# If someone talks to (or refers to) the bot.
|
|
|
|
|
if self.ban_regex.search(ircmsg):
|
|
|
|
|
self.bot_ban(channel,actor)
|
|
|
|
|
|
|
|
|
|
# If the server pings us then we've got to respond!
|
|
|
|
|
if ircmsg.find("PING :") != -1:
|
|
|
|
|
self.pong(ircmsg)
|
|
|
|
|
|
|
|
|
|
# Responds to a user that inputs "Ban Mybot".
|
|
|
|
|
def bot_ban(self, channel, fucker):
|
2018-09-14 14:48:55 +02:00
|
|
|
|
self.ircsock.send("KICK {0} {1} :Fesse-moi avec une pelle !\n".format(channel, fucker))
|
2018-09-05 15:38:19 +02:00
|
|
|
|
|
|
|
|
|
# Explains what the bot is when queried.
|
|
|
|
|
def bot_help(self, channel):
|
|
|
|
|
self.ircsock.send("PRIVMSG {} :Bonjour, je suis un bot qui reconnaît les options !help, !refresh et !bonjour\n".format(channel))
|
|
|
|
|
|
|
|
|
|
# Reads the messages from the server and adds them to the Queue and prints
|
|
|
|
|
# them to the console. This function will be run in a thread, see below.
|
|
|
|
|
def msg_handler(self): # pragma: no cover (this excludes this function from testing)
|
|
|
|
|
new_msg = self.ircsock.recv(2048) # receive data from the server
|
|
|
|
|
new_msg = new_msg.strip('\n\r') # removing any unnecessary linebreaks
|
|
|
|
|
|
|
|
|
|
if new_msg != '' and new_msg.find("PING :") == -1:
|
|
|
|
|
print(datetime.datetime.now().isoformat() + " " + new_msg)
|
|
|
|
|
return new_msg
|
|
|
|
|
|
|
|
|
|
# Checks for messages.
|
|
|
|
|
def parse_messages(self, ircmsg):
|
|
|
|
|
try:
|
|
|
|
|
actor = ircmsg.split(":")[1].split("!")[0]
|
|
|
|
|
try:
|
|
|
|
|
target = ircmsg.split(":")[1].split(" ")[2]
|
|
|
|
|
except:
|
|
|
|
|
target = None
|
|
|
|
|
return " ".join(ircmsg.split()), actor, target
|
|
|
|
|
except:
|
|
|
|
|
# print "Wrong message:", ircmsg
|
|
|
|
|
return None, None, None
|
|
|
|
|
|
|
|
|
|
# Compile regex
|
|
|
|
|
def get_regex(self, options):
|
|
|
|
|
pattern = "("
|
|
|
|
|
for s in options:
|
|
|
|
|
pattern += s
|
|
|
|
|
pattern += '|'
|
|
|
|
|
pattern = pattern[:-1]
|
|
|
|
|
pattern += ")"
|
|
|
|
|
return pattern
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
##########################
|
|
|
|
|
### The main function. ###
|
|
|
|
|
##########################
|
|
|
|
|
|
|
|
|
|
def main():
|
|
|
|
|
cop_bot = Bot(default_server, default_nickname)
|
|
|
|
|
cop_bot.connect()
|
|
|
|
|
cop_bot.add_project(Project('admins','#april-admin'))
|
|
|
|
|
cop_bot.add_project(Project('april','#april'))
|
|
|
|
|
return cop_bot.loop()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
|
sys.exit(main())
|