diff --git a/README.md b/README.md
index c28c838..dc5b6b3 100644
--- a/README.md
+++ b/README.md
@@ -1,11 +1,11 @@
# Flea
-Flea aims to be a modular Python IRC bot. This software was inspired from older
+Flea aims to be a modular Python IRC bot. This software was inspired from older
IRC bots I wrote.
## License
-Flea is released under the
-[GNU AGPLv3](https://www.gnu.org/licenses/why-affero-gpl.html), please **direct
-your attention to the LICENSE file in the root of the repository** before
+Flea is released under the
+[GNU AGPLv3](https://www.gnu.org/licenses/why-affero-gpl.html), please **direct
+your attention to the LICENSE file in the root of the repository** before
continuing.
## Requirements
@@ -14,7 +14,7 @@ Flea was written in [Python 2.7](http://www.python.org/download/releases/2.7/)
## Quick Start
1. Edit the *settings.conf* file to appropriate settings on the server you would
like to use
-
-2. Run the terminal/console in the root of the project and type:
+
+2. Run the terminal/console in the root of the project and type:
*python Flea.py*
diff --git a/core/irclib.py b/core/irclib.py
index fa6cda6..820e170 100644
--- a/core/irclib.py
+++ b/core/irclib.py
@@ -14,10 +14,14 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see
+# Built-in to Python 2.7
import socket
class irc:
debug = False
+
+ config = {}
+ pack = {}
sock = socket.socket()
# IRC Parser. Parses by line
@@ -114,7 +118,7 @@ class irc:
self.msg("NOTICE "+user+" :\001VERSION "+version+"\001")
def Whois(self, query):
- self.msg("WHOIS "+query+"\r\n")
+ self.msg("WHOIS "+query)
def SetMode(self, channel, nick, mode):
self.msg("MODE "+channel+" "+mode+" "+nick)
diff --git a/core/main.py b/core/main.py
index 71483a4..e333db2 100644
--- a/core/main.py
+++ b/core/main.py
@@ -23,6 +23,7 @@ import socket
import ssl
import sys
import os
+import re
# Allows reimporting modules
@@ -63,6 +64,9 @@ def PluginsImport():
# 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)
@@ -73,33 +77,36 @@ def PluginsImport():
# Only import directory plugins (no single files)
if os.path.isdir(plugins+item):
print "[Plugins] Initializing "+item
- __import__(item+".main")
+ plugin = __import__(item+".main")
+ plugin_list.append(plugin)
else:
return False
os.chdir(current)
- return True
+ return plugin_list
+
def main():
+ # Create irclib irc object
+ irc = irclib.irc()
+
# Parse main settings.conf file
- config = cfgParser("settings.conf")
+ irc.config = cfgParser("settings.conf")
# Keep track of modules for a rollback
importctrl = ImportRollback()
# Import /plugins/
- if config["plugins"]:
- if not PluginsImport():
+ if irc.config["plugins"]:
+ plugins = PluginsImport()
+ if not plugins:
print "[Plugins] Failed to load."
- # Create irclib irc object
- irc = irclib.irc()
-
# Set debug to true/false inside irc() object
- irc.debug = config["debug"]
+ irc.debug = irc.config["debug"]
# Create socket object
irc.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
@@ -108,8 +115,8 @@ def main():
irc.sock = ssl.wrap_socket(irc.sock)
# Connect to IRC server
- irc.sock.connect((config["host"], config["port"]))
- print "Connecting to "+config["host"]+':'+str(config["port"])
+ irc.sock.connect((irc.config["host"], irc.config["port"]))
+ print "Connecting to "+irc.config["host"]+':'+str(irc.config["port"])
# Display SSL information to the user
ssl_info = irc.sock.cipher()
@@ -119,10 +126,10 @@ def main():
print "[SSL] Bits: "+str(ssl_info[2])
# Send User/Nick message to establish user on the server
- irc.User(config["ident"], config["mode"],
- config["unused"], config["realname"])
+ irc.User(irc.config["ident"], irc.config["mode"],
+ irc.config["unused"], irc.config["realname"])
- irc.Nick(config["nick"])
+ irc.Nick(irc.config["nick"])
while True:
# Buffer to store data from server
@@ -152,24 +159,29 @@ def main():
# Print line, parse it and respond
print line
- pack = irc.Parser(line)
+ irc.pack = irc.Parser(line)
+
+ # Run all plugins main() function
+ if irc.config["plugins"]:
+ for plugin in plugins:
+ plugin.main.main(irc)
# Ping Pong, keep the connection alive.
- if pack["cmd"] == "PING":
- irc.Pong(pack["text"])
+ if irc.pack["cmd"] == "PING":
+ irc.Pong(irc.pack["text"])
# Send user mode message after command 001
- elif pack["cmd"] == "001":
- irc.Mode(config["nick"], config["mode"])
+ elif irc.pack["cmd"] == "001":
+ irc.Mode(irc.config["nick"], irc.config["mode"])
- elif pack["cmd"] == "NOTICE":
- if pack["ident"] == "NickServ":
+ 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, pack["text"]):
- irc.Identify(config["password"])
- irc.Join("#Flea")
+ if re.search(pattern, irc.pack["text"]):
+ irc.Identify(irc.config["password"])
+ irc.Join(irc.config["channel"])
main()
diff --git a/plugins/Control/__init__.py b/plugins/Control/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/plugins/Control/main.py b/plugins/Control/main.py
new file mode 100644
index 0000000..72cbdad
--- /dev/null
+++ b/plugins/Control/main.py
@@ -0,0 +1,206 @@
+import re
+
+# Init
+controlchan = ''
+chans = {}
+access = []
+queue = []
+
+
+def chkcontrol(irc):
+ global access
+ global queue
+
+ nick = irc.pack["nick"]
+
+ for person in access:
+ if nick == person:
+ return True
+
+ if queue.count(nick) == 0:
+ queue.append(nick)
+ irc.Whois(nick)
+
+def noaccess(irc):
+ msg = "You don't have access to that."
+ irc.Notice(msg, irc.pack["nick"])
+
+def main(irc):
+ global controlchan
+ global access
+ global chans
+ global queue
+
+ # Set control channel
+ controlchan = irc.config["channel"]
+
+ # 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"]:
+
+ # Split message by spaces, for functions with
+ # required parameters. e.g. " "
+ if irc.pack["text"].find(' ') != -1:
+ command = irc.pack["text"].lower().split(' ')
+
+ # Command Flea to join a channel
+ if command[0] == "join":
+ if chkcontrol(irc):
+ irc.Join(command[1])
+ else:
+ noaccess(irc)
+
+ # Command Flea to part
+ elif command[0] == "part":
+ if chkcontrol(irc):
+ irc.Part(command[1],
+ "Fleabot https://github.com/Kris619/Flea")
+ else:
+ noaccess(irc)
+
+ # Single word commands
+ else:
+ if irc.pack["text"] == "acc":
+ 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()
+ else:
+ noaccess(irc)
+
+ # Check if commanding Nick is identified
+ elif irc.pack["cmd"] == "307":
+ if irc.pack["text"] == "is identified for this nick":
+
+ # Check if Nick is in the queue for access list
+ if queue.count(irc.pack["params"][1]) == 1:
+
+ # Remove Nick from queue
+ queue.remove(irc.pack["params"][1])
+
+ # Check if user is set to control in settings
+ # e.g. control = Kris
+ if irc.pack["params"][1] == irc.config["control"]:
+
+
+ # Is control user inside the control channel?
+ if chans[controlchan].count(irc.pack["params"][1]) == 1:
+
+ # Grant access
+ access.append(irc.pack["params"][1])
+
+ print irc.pack["params"][1]+" added to Access"
+
+ irc.Notice(
+ "You have been given access to Control.",
+ irc.pack["params"][1])
+ else:
+ irc.Notice(
+ "You are not in the Control channel: "+controlchan,
+ irc.pack["params"][1])
+
+ # Keep track of users in every channel
+ # "353" lists users to a channel
+ elif irc.pack["cmd"] == "353":
+
+ # If channel is in dictionary of channels
+ if chans.keys().count(irc.pack["params"][2]) == 1:
+
+ # Split list of channel users by space
+ # "+Kris @Flea" > ["+Kris", "@Flea"]
+ if irc.pack["text"].find(' ') != -1:
+ chan_nicks = irc.pack["text"].split(' ')
+
+ for aNick in chan_nicks:
+ if aNick != '':
+
+ # Remove prefix; e.g. "+Kris" > "Kris"
+ if re.search("^[~&@%+]", aNick):
+ aNick = aNick[1:]
+
+ # Add nick to it's channel
+ chans[irc.pack["params"][2]].append(aNick)
+
+ # Track users joining channels
+ elif irc.pack["cmd"] == "JOIN":
+
+ # Check to see if it is the bot that joined
+ 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"]] = []
+
+ # Another user joined
+ else:
+ # Add user to channel; chans["#Channel"].append("Kris")
+ chans[irc.pack["text"]].append(irc.pack["nick"])
+
+ # Track users parting from the channel
+ elif irc.pack["cmd"] == "PART":
+ # Remove nick from channel they parted from
+ chans[irc.pack["params"][0]].remove(irc.pack["nick"])
+
+ # If someone parted the control channel
+ # check if it was someone on the access list
+ if irc.pack["params"][0] == controlchan:
+ for usr in access:
+ if usr == irc.pack["nick"]:
+ # Someone on the access list left.
+ access.remove(irc.pack["nick"])
+ print irc.pack["nick"]+" removed from Access"
+
+ # Track users parting from the channel
+ elif irc.pack["cmd"] == "QUIT":
+
+ # Remove user from channels
+ for channel in chans.keys():
+ if chans[channel].count(irc.pack["nick"]) == 1:
+ chans[channel].remove(irc.pack["nick"])
+
+ # Remove access if user quitting had it
+ for usr in access:
+ if usr == irc.pack["nick"]:
+ access.remove(irc.pack["nick"])
+ print irc.pack["nick"]+" removed from Access"
+
+ # Track users being kicked from the channel
+ elif irc.pack["cmd"] == "KICK":
+
+ # Remove nick from channel they were kicked from
+ chans[irc.pack["params"][0]].remove(irc.pack["params"][1])
+
+ # If someone was kicked from the control channel
+ # check if it was someone on the access list
+ if irc.pack["params"][0] == controlchan:
+ if irc.pack["params"][1] == irc.config["nick"]:
+ print "Access list is erased, control channel is gone"
+ access = []
+ else:
+ for usr in access:
+ if usr == irc.pack["params"][1]:
+ # Someone on the access list was kicked.
+ access.remove(irc.pack["params"][1])
+ print irc.pack["params"][1]+" removed from Access"
+
+ # Track users changing their nick
+ elif irc.pack["cmd"] == "NICK":
+
+ for channel in chans.keys():
+ if channel.count(irc.pack["nick"]) == 1:
+ channel.remove(irc.pack["nick"])
+ channel.append(irc.pack["text"])
+
+ # Remove access to users changing their nick
+ for usr in access:
+ if access.count(irc.pack["nick"]) == 1:
+ access.remove(irc.pack["nick"])
+ print irc.pack["nick"]+" removed from Access"
diff --git a/settings.conf b/settings.conf
index 59a5f7b..44babd0 100644
--- a/settings.conf
+++ b/settings.conf
@@ -1,5 +1,5 @@
debug = true
-plugins = false
+plugins = true
host = irc.example.net
port = 7001
@@ -11,3 +11,5 @@ mode = +B
unused = *
realname = your_name
+control = your_nick
+channel = #MyChannel
\ No newline at end of file