diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..e152ff0
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,2 @@
+# normalize text files to use lf
+text eol=lf
diff --git a/.gitignore b/.gitignore
index 2f78cf5..84416d1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,2 @@
*.pyc
-
+mysettings.conf
\ No newline at end of file
diff --git a/Flea/Flea.py b/Flea/Flea.py
new file mode 100644
index 0000000..b52d335
--- /dev/null
+++ b/Flea/Flea.py
@@ -0,0 +1,221 @@
+# 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 config
+import irclib
+
+# Built-in to Python 2.7
+import __builtin__
+import socket
+import ssl
+import sys
+import os
+import re
+
+
+# Allows reimporting modules
+class ImportRollback:
+ def __init__(self, plugins_folder="/plugins"):
+ # Dictionary of loaded modules
+ self.curMods = sys.modules.copy()
+ self.newImport = __builtin__.__import__
+
+ self.plugins = os.path.join(os.getcwd(), plugins_folder)
+
+ # Add the plugins location to the path variable
+ sys.path.append(self.plugins)
+
+ # Override builtin import function with install()
+ __builtin__.__import__ = self.install
+ self.newMods = {}
+
+ # Import modules
+ def install(self, mod, globals=None, locals=None, fromlist=[]):
+ self.newMods[mod] = 1
+ return apply(self.newImport, (mod, globals, locals, fromlist))
+
+ # Delete modules
+ def reset(self):
+ for mod in self.newMods.keys():
+ if not self.curMods.has_key(mod):
+ del(sys.modules[mod])
+
+ __builtin__.__import__ = self.newImport
+
+
+# Print and log to logfile
+def printlog(message, log=None):
+ print message
+ if log is not None:
+ log.write(message+"\n")
+
+
+def PluginsImport(log=None, plugins_folder="/plugins"):
+ plugins = os.path.join(os.getcwd(), plugins_folder)
+ plugin_list = []
+
+ if os.path.exists(plugins):
+ os.chdir(plugins)
+
+ for item in os.listdir(plugins):
+ if os.path.isdir(os.path.join(plugins, item)):
+ printlog("[Plugins] Initializing " + item, log)
+ plugin = __import__(item+".main")
+ plugin_list.append(plugin)
+
+ else:
+ return None
+
+ os.chdir(os.getcwd())
+ return plugin_list
+
+
+def init_connection(config_file="settings.conf"):
+ irc_conn = irclib.irc()
+ irc_conn.config = config.cfgParser(config_file)
+
+ if irc_conn.config["logging"]:
+ log = open("log.txt", 'a')
+ irc_conn.log = log
+ else:
+ log = None
+
+ irc_conn.debug = irc_conn.config["debug"]
+
+ # Keep track of modules for a rollback
+ importctrl = ImportRollback()
+
+ # Import /plugins
+ if irc_conn.config["plugins"]:
+ plugins = PluginsImport(log)
+ else:
+ plugins = None
+
+ if plugins is not None:
+ # TODO: Add more debugging messages, sporadatic.
+ printlog("[Plugins] Failed to load.", log)
+
+ # Create socket object and wrap with SSL object, then connect.
+ irc_conn.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ irc_conn.sock = ssl.wrap_socket(irc_conn.sock)
+
+ server = (irc_conn.config["host"], irc_conn.config["port"])
+ try:
+ printlog("Connecting to " + server[0] + ':' + str(server[1]))
+ irc_conn.sock.connect(server)
+ except:
+ printlog("Connection failed.", log)
+ return (None, None)
+
+ # Display SSL inforation to the user
+ ssl_info = irc_conn.sock.cipher()
+ if ssl_info is not None:
+ printlog("[SSL] Cipher: " + ssl_info[0], log)
+ printlog("[SSL] Version: " + ssl_info[1], log)
+ printlog("[SSL] Bits: " + str(ssl_info[2]), log)
+
+ # Establish identity on server
+ identity = (irc_conn.config["ident"], irc_conn.config["mode"],
+ irc_conn.config["unused"], irc_conn.config["realname"])
+ irc_conn.User(*identity)
+ irc_conn.Nick(irc_conn.config["nick"])
+
+ return (irc_conn, plugins)
+
+
+def client_loop(irc_conn, plugins, log=None):
+ wait = None
+ if irc_conn is None:
+ print "No connection established."
+ sys.exit(0)
+
+ while True:
+ # Buffer to store data from server
+ data = ''
+
+ while True:
+ # Receive data from connection
+ tmpdata = irc_conn.sock.recv(4096)
+ data = data + tmpdata
+
+ if len(tmpdata) < 4096:
+ break
+
+ # If no incoming data exists then connection has closed
+ if len(tmpdata) == 0:
+ print "Connection closed."
+ raw_input()
+ sys.exit(0)
+
+ # Split data to easily deal with it
+ data = tmpdata.split("\r\n")
+
+ # Parse IRC line by line
+ for line in data:
+
+ # Ignore empty lines
+ if len(line) > 0:
+ printlog(line, log)
+ irc_conn.pack = irc_conn.Parser(line)
+
+ # Run all plugins main() function
+ wait = None
+ if irc_conn.config["plugins"]:
+ if plugins is not None:
+ for plugin in plugins:
+ wait = plugin.main.main(irc_conn)
+ if wait == "QUIT":
+ break
+
+ # Ping Pong, keep the connection alive.
+ if irc_conn.pack["cmd"] == "PING":
+ irc_conn.Pong(irc_conn.pack["text"])
+
+ # Send user mode message after command 001
+ elif irc_conn.pack["cmd"] == "001":
+ irc_conn.Mode(irc_conn.config["nick"], irc_conn.config["mode"])
+
+ elif irc_conn.pack["cmd"] == "NOTICE":
+ if irc_conn.pack["ident"] == "NickServ":
+ # Send password after NickServ informs you
+ # that your nick is registered
+ pattern = r"[Tt]his nickname is registered"
+ if re.search(pattern, irc_conn.pack["text"]):
+ irc_conn.Identify(irc_conn.config["password"])
+ irc_conn.Join(irc_conn.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_conn.Quit("Fleabot https://github.com/Kris619/Flea")
+ irc_conn.sock.close()
+ if log:
+ log.close()
+
+ print "Press the [ENTER] key to close."
+ raw_input()
+ sys.exit(0)
+
+
+def main():
+ (irc_conn, plugins) = init_connection()
+ client_loop(irc_conn, plugins)
+
+if __name__ == "__main__":
+ main()
diff --git a/core/__init__.py b/Flea/__init__.py
similarity index 100%
rename from core/__init__.py
rename to Flea/__init__.py
diff --git a/core/config.py b/Flea/config.py
similarity index 100%
rename from core/config.py
rename to Flea/config.py
diff --git a/core/irclib.py b/Flea/irclib.py
similarity index 96%
rename from core/irclib.py
rename to Flea/irclib.py
index dbf15cf..6988ffc 100644
--- a/core/irclib.py
+++ b/Flea/irclib.py
@@ -19,14 +19,15 @@ import socket
import re
class irc:
-
+ # TODO: Wrap in __init__
debug = False
- log = False
+ log = None
config = {}
pack = {}
sock = socket.socket()
- # IRC Parser. Parses by line
+ # IRC Parser. Parses by line Functions are
+ # lowercase, classes uppercase
def Parser(self, line):
packet = {"nick":None, "ident":None,
"host":None, "cmd":None,
@@ -95,7 +96,7 @@ class irc:
if self.debug:
print output
- if self.log:
+ if self.log is not None:
self.log.write(output+"\n")
def User(self, nick, mode, unused, owner):
diff --git a/Flea.py b/bin/Flea
similarity index 95%
rename from Flea.py
rename to bin/Flea
index 8b95b63..d040c7c 100644
--- a/Flea.py
+++ b/bin/Flea
@@ -1,3 +1,4 @@
+#!/bin/python
# An IRC bot named Flea
# Copyright (C) 2016 Kris Lamoureux
@@ -18,7 +19,7 @@ import traceback
import sys
try:
- import core.main
+ import Flea.Flea
except KeyboardInterrupt:
print "\nGoodbye!"
@@ -39,3 +40,4 @@ except:
raw_input()
sys.exit(0)
+Flea.Flea.main()
diff --git a/core/main.py b/core/main.py
deleted file mode 100644
index 4696757..0000000
--- a/core/main.py
+++ /dev/null
@@ -1,221 +0,0 @@
-# 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
-
-from core.config import *
-import core.irclib as irclib
-
-# Built-in to Python 2.7
-import __builtin__
-import socket
-import ssl
-import sys
-import os
-import re
-
-
-# Allows reimporting modules
-class ImportRollback:
- def __init__(self):
- # Dictionary of loaded modules
- self.curMods = sys.modules.copy()
- self.newImport = __builtin__.__import__
-
- # Directory of plugins
- self.plugins = os.getcwd()+"/plugins/"
-
- # Add the plugins location to the path variable
- # Helps the system find the plugin modules
- sys.path.append(self.plugins)
-
- # Override builtin import function with install()
- __builtin__.__import__ = self.install
- self.newMods = {}
-
- # Import modules
- def install(self, mod, globals=None, locals=None, fromlist=[]):
- self.newMods[mod] = 1
- return apply(self.newImport, (mod, globals, locals, fromlist))
-
- # Delete modules
- def reset(self):
- for mod in self.newMods.keys():
- if not self.curMods.has_key(mod):
- del(sys.modules[mod])
-
- __builtin__.__import__ = self.newImport
-
-
-# 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/
- plugins = current+"/plugins/"
-
- # List of plugins
- plugin_list = []
-
- # If /plugins/ exists change directory to it
- if os.path.exists(plugins):
- os.chdir(plugins)
-
- # Go through every item in /plugins/
- for item in os.listdir(plugins):
-
- # Only import directory plugins (no single files)
- if os.path.isdir(plugins+item):
- prntlog("[Plugins] Initializing "+item, log)
- plugin = __import__(item+".main")
- plugin_list.append(plugin)
-
- else:
- return False
-
- os.chdir(current)
- return plugin_list
-
-
-def main():
-
- # Create irclib irc object
- irc = irclib.irc()
-
- # 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(log)
-
- if not plugins:
- prntlog("[Plugins] Failed to load.", log)
-
- # Set debug to true/false inside irc() object
- irc.debug = irc.config["debug"]
-
- # Create socket object
- irc.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-
- # Wrap socket object to create SSLSocket object
- irc.sock = ssl.wrap_socket(irc.sock)
-
- # Connect to IRC server
- 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:
- 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"],
- irc.config["unused"], irc.config["realname"])
-
- irc.Nick(irc.config["nick"])
-
- while True:
- # Buffer to store data from server
- data = ''
-
- while True:
- # Receive data from connection
- tmpdata = irc.sock.recv(4096)
- data = data + tmpdata
-
- if len(tmpdata) < 4096:
- break
-
- # If no incoming data exists then connection has closed
- if len(tmpdata) == 0:
- print "Connection closed."
- raw_input()
- sys.exit(0)
-
- # Split data to easily deal with it
- data = tmpdata.split("\r\n")
-
- # Parse IRC line by line
- for line in data:
-
- # Ignore empty lines
- if len(line) > 0:
-
- # 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:
- wait = plugin.main.main(irc)
- if wait == "QUIT":
- break
-
- # Ping Pong, keep the connection alive.
- if irc.pack["cmd"] == "PING":
- irc.Pong(irc.pack["text"])
-
- # Send user mode message after command 001
- elif irc.pack["cmd"] == "001":
- irc.Mode(irc.config["nick"], irc.config["mode"])
-
- elif irc.pack["cmd"] == "NOTICE":
- if irc.pack["ident"] == "NickServ":
- # Send password after NickServ informs you
- # that your nick is registered
- pattern = r"[Tt]his nickname is registered"
- if re.search(pattern, irc.pack["text"]):
- 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()