diff --git a/Flea.py b/Flea.py
index 46dd8f4..8b95b63 100644
--- a/Flea.py
+++ b/Flea.py
@@ -15,10 +15,27 @@
# along with this program. If not, see
import traceback
+import sys
try:
import core.main
-except:
- traceback.print_exc()
- input()
+
+except KeyboardInterrupt:
+ print "\nGoodbye!"
+ sys.exit()
+
+except SystemExit:
+ raise
+
+except:
+ # Print error, save it to error.txt
+ # then wait to be closed.
+ traceback.print_exc()
+
+ errorfile = open("error.txt", 'a')
+ traceback.print_exc(None, errorfile)
+ errorfile.close()
+
+ raw_input()
+ sys.exit(0)
diff --git a/core/irclib.py b/core/irclib.py
index 820e170..dbf15cf 100644
--- a/core/irclib.py
+++ b/core/irclib.py
@@ -16,10 +16,12 @@
# Built-in to Python 2.7
import socket
+import re
class irc:
- debug = False
+ debug = False
+ log = False
config = {}
pack = {}
sock = socket.socket()
@@ -79,10 +81,22 @@ class irc:
return packet
- # Basic message function to send any data
+ # Basic message function to send and log any data
def msg(self, message):
self.sock.send(message+"\r\n")
- if self.debug: print ">>> "+message
+
+ # Match messages containing private information
+ # then censors it to output to the terminal and log
+ pattern = r"^PRIVMSG NickServ :IDENTIFY *"
+ if re.search(pattern, message):
+ message = "PRIVMSG NickServ :IDENTIFY ****"
+
+ output = ">>> "+message
+
+ if self.debug:
+ print output
+ if self.log:
+ self.log.write(output+"\n")
def User(self, nick, mode, unused, owner):
self.msg("USER "+nick+' '+mode+' '+unused+" :"+owner)
diff --git a/core/main.py b/core/main.py
index e333db2..4696757 100644
--- a/core/main.py
+++ b/core/main.py
@@ -58,7 +58,14 @@ class ImportRollback:
__builtin__.__import__ = self.newImport
-def PluginsImport():
+# Print and log to logfile
+def prntlog(message, logfile):
+ print message
+ if logfile:
+ logfile.write(message+"\n")
+
+
+def PluginsImport(log=False):
# Get root of Flea
current = os.getcwd()
# Path to /plugins/ under /Flea/
@@ -76,7 +83,7 @@ def PluginsImport():
# Only import directory plugins (no single files)
if os.path.isdir(plugins+item):
- print "[Plugins] Initializing "+item
+ prntlog("[Plugins] Initializing "+item, log)
plugin = __import__(item+".main")
plugin_list.append(plugin)
@@ -87,7 +94,6 @@ def PluginsImport():
return plugin_list
-
def main():
# Create irclib irc object
@@ -96,14 +102,22 @@ def main():
# Parse main settings.conf file
irc.config = cfgParser("settings.conf")
+ # If logging is enabled, open log file.
+ if irc.config["logging"]:
+ log = open("log.txt", 'a')
+ irc.log = log
+ else:
+ log = False
+
# Keep track of modules for a rollback
importctrl = ImportRollback()
# Import /plugins/
if irc.config["plugins"]:
- plugins = PluginsImport()
+ plugins = PluginsImport(log)
+
if not plugins:
- print "[Plugins] Failed to load."
+ prntlog("[Plugins] Failed to load.", log)
# Set debug to true/false inside irc() object
irc.debug = irc.config["debug"]
@@ -115,15 +129,18 @@ def main():
irc.sock = ssl.wrap_socket(irc.sock)
# Connect to IRC server
- irc.sock.connect((irc.config["host"], irc.config["port"]))
- print "Connecting to "+irc.config["host"]+':'+str(irc.config["port"])
+ host = irc.config["host"]
+ port = irc.config["port"]
+
+ irc.sock.connect((host, port))
+ prntlog("Connecting to "+host+':'+str(port), log)
# Display SSL information to the user
ssl_info = irc.sock.cipher()
if ssl_info != None:
- print "[SSL] Cipher: "+ssl_info[0]
- print "[SSL] Version: "+ssl_info[1]
- print "[SSL] Bits: "+str(ssl_info[2])
+ prntlog("[SSL] Cipher: "+ssl_info[0], log)
+ prntlog("[SSL] Version: "+ssl_info[1], log)
+ prntlog("[SSL] Bits: "+str(ssl_info[2]), log)
# Send User/Nick message to establish user on the server
irc.User(irc.config["ident"], irc.config["mode"],
@@ -145,8 +162,9 @@ def main():
# If no incoming data exists then connection has closed
if len(tmpdata) == 0:
- input("Connection closed.")
- sys.exit()
+ print "Connection closed."
+ raw_input()
+ sys.exit(0)
# Split data to easily deal with it
data = tmpdata.split("\r\n")
@@ -157,14 +175,17 @@ def main():
# Ignore empty lines
if len(line) > 0:
- # Print line, parse it and respond
- print line
+ # Print/log line, parse it and respond
+ prntlog(line, log)
irc.pack = irc.Parser(line)
# Run all plugins main() function
+ wait = ''
if irc.config["plugins"]:
for plugin in plugins:
- plugin.main.main(irc)
+ wait = plugin.main.main(irc)
+ if wait == "QUIT":
+ break
# Ping Pong, keep the connection alive.
if irc.pack["cmd"] == "PING":
@@ -183,5 +204,18 @@ def main():
irc.Identify(irc.config["password"])
irc.Join(irc.config["channel"])
+ if log: log.flush()
+
+ # Wait for QUIT to be returned from any plugin's main() function
+ if wait == "QUIT":
+ # Quit, close connection and logfile.
+ irc.Quit("Fleabot https://github.com/Kris619/Flea")
+ irc.sock.close()
+ if log: log.close()
+
+ print "Press the [ENTER] key to close."
+ raw_input()
+ sys.exit(0)
+
main()
diff --git a/plugins/Control/main.py b/plugins/Control/main.py
index 72cbdad..e867123 100644
--- a/plugins/Control/main.py
+++ b/plugins/Control/main.py
@@ -1,3 +1,19 @@
+# An IRC bot named Flea
+# Copyright (C) 2016 Kris Lamoureux
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see
+
import re
# Init
@@ -11,7 +27,7 @@ def chkcontrol(irc):
global access
global queue
- nick = irc.pack["nick"]
+ nick = irc.pack["nick"].lower()
for person in access:
if nick == person:
@@ -33,13 +49,14 @@ def main(irc):
# Set control channel
controlchan = irc.config["channel"]
+ controlusr = irc.config["control"]
# NOTICEs are used to "control" Flea
if irc.pack["cmd"] == "NOTICE":
# Nick must match the nick in settings
# e.g. control = Kris
- if irc.pack["nick"] == irc.config["control"]:
+ if irc.pack["nick"].lower() == controlusr.lower():
# Split message by spaces, for functions with
# required parameters. e.g. " "
@@ -67,13 +84,10 @@ def main(irc):
if chkcontrol(irc):
irc.Notice("You already have access to Control.",
irc.pack["nick"])
- else:
- noaccess(irc)
if irc.pack["text"] == "quit":
if chkcontrol(irc):
- irc.Quit("Fleabot https://github.com/Kris619/Flea")
- quit()
+ return "QUIT"
else:
noaccess(irc)
@@ -81,32 +95,34 @@ def main(irc):
elif irc.pack["cmd"] == "307":
if irc.pack["text"] == "is identified for this nick":
+ usernick = irc.pack["params"][1]
+
# Check if Nick is in the queue for access list
- if queue.count(irc.pack["params"][1]) == 1:
+ if queue.count(usernick) == 1:
# Remove Nick from queue
- queue.remove(irc.pack["params"][1])
+ queue.remove(usernick)
# Check if user is set to control in settings
# e.g. control = Kris
- if irc.pack["params"][1] == irc.config["control"]:
+ if usernick.lower() == controlusr.lower():
# Is control user inside the control channel?
- if chans[controlchan].count(irc.pack["params"][1]) == 1:
+ if chans[controlchan.lower()].count(usernick) == 1:
# Grant access
- access.append(irc.pack["params"][1])
+ access.append(usernick)
- print irc.pack["params"][1]+" added to Access"
+ print usernick+" added to Access"
irc.Notice(
"You have been given access to Control.",
- irc.pack["params"][1])
+ usernick)
else:
irc.Notice(
"You are not in the Control channel: "+controlchan,
- irc.pack["params"][1])
+ usernick)
# Keep track of users in every channel
# "353" lists users to a channel
@@ -137,7 +153,7 @@ def main(irc):
if irc.pack["nick"] == irc.config["nick"]:
# Create channel user list if it doesn't exist
if chans.keys().count(irc.pack["text"]) == 0:
- chans[irc.pack["text"]] = []
+ chans[irc.pack["text"].lower()] = [irc.pack["text"]]
# Another user joined
else:
diff --git a/settings.conf b/settings.conf
index 44babd0..4756de4 100644
--- a/settings.conf
+++ b/settings.conf
@@ -1,4 +1,5 @@
debug = true
+logging = false
plugins = true
host = irc.example.net