Răsfoiți Sursa

track channelkeys, botoperators, refactoring, aggressiveness modes

tBKwtWS 7 ani în urmă
părinte
comite
ca88f1d7ac

+ 6 - 0
.eric6project/pyRot.e4q

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE UserProject SYSTEM "UserProject-4.0.dtd">
+<!-- eric6 user project file for project pyRot -->
+<!-- Saved: 2018-01-27, 00:37:00 -->
+<!-- Copyright (C) 2018 tBKwtWS,  -->
+<UserProject version="4.0"/>

+ 7 - 0
.eric6project/pyRot.e6t

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE Tasks SYSTEM "Tasks-6.0.dtd">
+<!-- eric6 tasks file for project pyRot -->
+<!-- Saved: 2018-01-27, 00:37:00 -->
+<Tasks version="6.0">
+  <ProjectScanFilter></ProjectScanFilter>
+</Tasks>

+ 104 - 0
.gitignore

@@ -0,0 +1,104 @@
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+#  Usually these files are written by a python script from a template
+#  before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+.hypothesis/
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+.static_storage/
+.media/
+local_settings.py
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# pyenv
+.python-version
+
+# celery beat schedule file
+celerybeat-schedule
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/

BIN
__pycache__/commands.cpython-35.pyc


BIN
__pycache__/ircservices.cpython-35.pyc


BIN
commands/__pycache__/admin.cpython-36.pyc


BIN
commands/__pycache__/common.cpython-36.pyc


BIN
commands/__pycache__/games.cpython-36.pyc


BIN
commands/__pycache__/public.cpython-35.pyc


BIN
commands/__pycache__/public.cpython-36.pyc


BIN
commands/__pycache__/statistics.cpython-36.pyc


+ 4 - 5
commands/admin.py

@@ -1,4 +1,4 @@
-from common import userstatus
+from common import userstatus, do_everything_to
 from commands.common import CommandHelpers as CH
 from commands.common import AdminHelpers as AH
 bold = "\x02"
@@ -45,7 +45,7 @@ def do_command(self, connection, event):
             connection.privmsg(replyto, message[:-2] + ".")
     
     elif command.split()[0] == "die":
-        if not userstatus.atleast_admin(self, event.source.nick,  self.homechannel):
+        if not userstatus.atleast_admin(self, event.source.nick, self.homechannel): #Insufficient rights.
             connection.privmsg(replyto, "Denied, you need to have admin (super operator) status or higher in " + red + self.homechannel  + reset + ".")
             return
         if cmdtype == "help":    # Display help text.
@@ -107,10 +107,9 @@ def do_command(self, connection, event):
             try:
                 key = command.split(maxsplit=2)[2]
             except IndexError:
-                connection.join(channel)
+                do_everything_to.join(self, connection, channel)
                 return
-            print(channel + " | " + key)
-            connection.join(channel, key=key)
+            do_everything_to.join(self, connection, channel, key)
     
     elif command.split()[0] == "part":
         if cmdtype == "help":    #Display help text.

+ 4 - 2
commands/games.py

@@ -13,8 +13,10 @@ grey = "\x0314"
 
 def do_command(self, connection, event):
     cmdtype, trigger, command, replyto = CH.disect_command(self, event)
-    if not command: # Do nothing if there is no command.
-        return
+    if not command:
+        return  # Do nothing if there is no command.
+    if not self.db.one("SELECT games FROM channels WHERE name='" + event.target + "' AND network='" + self.network + "'"):
+        return  # Do noting if the games channel function is off.
     
     if command == "cmd" or command == "commands":
         if cmdtype == "cmd":

+ 7 - 1
commands/public.py

@@ -23,7 +23,13 @@ def do_command(self, connection, event):
             connection.privmsg(replyto, "Strictly for testing purposes only!")
         elif cmdtype == "cmd":
             
-            connection.privmsg(replyto, event)
+            connection.privmsg(replyto, str(self.channels[self.homechannel].owners()))
+            if event.target == connection.get_nickname():   # PM
+                connection.privmsg(replyto, event)
+            else:   # Channel message.
+                connection.privmsg(replyto, str(self.channels[event.target]))
+                print(connection.userhost(event.source.nick))   # Empty reply on GamerGalaxy, check what happens on GTAnet.
+                print(connection.who(event.source.nick))
             
     elif command == "cmd" or command == "commands":
         if cmdtype == "help":    #Display help text.

+ 2 - 0
commands/statistics.py

@@ -14,6 +14,8 @@ def do_command(self, connection, event):
     cmdtype, trigger, command, replyto = CH.disect_command(self, event)
     if not command: # Do nothing if there is no command.
         return
+    if not self.db.one("SELECT games FROM channels WHERE name='" + event.target + "' AND network='" + self.network + "'"):
+        return  # Do noting if the games channel function is off.
 
     if command == "cmd" or command == "commands":
         if cmdtype == "help":    #Display help text.

BIN
common/__pycache__/log.cpython-36.pyc


BIN
common/__pycache__/networkservices.cpython-35.pyc


BIN
common/__pycache__/networkservices.cpython-36.pyc


BIN
common/__pycache__/userstatus.cpython-36.pyc


+ 21 - 0
common/do_everything_to.py

@@ -0,0 +1,21 @@
+from common.networkservices import ChanServ
+
+def join(self, connection, channel, key=False):
+    connection.privmsg("ChanServ", "UNBAN")
+    ChanServ.unban(connection, channel, connection.get_nickname())
+    ChanServ.akick_del(connection, channel, connection.get_nickname())
+    ChanServ.invite(connection, channel)
+    ChanServ.getkey(connection, channel)
+    knownkey = self.db.one("SELECT key FROM channels WHERE name='" + channel + "' AND network='" + self.network + "'")
+    if key:
+        connection.join(channel, key)
+        if not key == knownkey:
+            self.channelkeys[channel] = key
+    elif knownkey:
+        connection.join(channel, key)
+    else:
+        connection.join(channel)
+
+def unban(connection, channel, user, mask):
+    ChanServ.unban(connection, channel, user)
+    connection.mode(connection, "-b " + mask)

+ 6 - 0
common/networkservices.py

@@ -6,6 +6,12 @@ class NickServ():
         connection.nick(connection.nickname)    # Set original nickname. Should have happened during the nickServ recover, this fails when still connecting. So this creates a loop to successfully recover via NickServ.
 
 class ChanServ():
+    def invite(connection, channel):
+        connection.privmsg("ChanServ", "INVITE " + channel)
+    
+    def getkey(connection, channel):
+        connection.privmsg("ChanServ", "GETKEY " + channel)
+    
     def ban(connection, channel, user, reason):
         connection.privmsg("ChanServ", "BAN " + channel + " " + user + " " + reason)
     

BIN
events/__pycache__/on_join.cpython-36.pyc


BIN
events/__pycache__/on_kick.cpython-36.pyc


BIN
events/__pycache__/on_pubmsg.cpython-36.pyc


+ 11 - 0
events/common.py

@@ -0,0 +1,11 @@
+from common import userstatus
+class Protectees:
+    def update(self, nick, user, host):
+        if nick in self.protectees: # On record.
+            if userstatus.atleast_halfop(self, user, self.homechannel) or nick == self.connection.get_nickname():   # Update. Is atleast halfop or bot itself.
+                self.protectees[nick].update({'ident': nick + "!" + user + "@" + host})
+            else:   # Delete.
+                del self.protectees[nick]
+        else:   # Append.
+            if userstatus.atleast_halfop(self, user, self.homechannel) or nick == self.connection.get_nickname():   # Update. Is atleast halfop or bot itself.
+                self.protectees[nick] = {'ident': nick + "!" + user + "@" + host}

+ 8 - 1
events/on_join.py

@@ -19,7 +19,14 @@ def process_event(self, connection, event):
     self.db.run("UPDATE joins SET joins = joins + 1 WHERE channel='" + event.target + "' AND channel_network='" + self.network + "' AND \"user\"='" + event.source.nick + "' AND user_network='" + self.network + "'")
     
     if event.source.nick == connection.get_nickname():  # The bot joined a channel.
-        return
+        connection.who(self.homechannel)    # Get whoreplies for users of homechannel.
+        if self.channels[event.target].has_key():
+            if event.target in self.channelkeys:    # New key used to join channel.
+                self.db.run("UPDATE channels SET key='" + self.channelkeys[event.target] + "' WHERE name='" + event.target + "' AND network='" + self.network + "'")    # Save new key to DB.
+                del self.channelkeys[event.target]  # Delete entry.
+        if event.target == self.homechannel:    # Home channel.
+            connection.who(connection.get_nickname())   # get whoreply to add bot to protectees.
+        return  # Do not greet myself.
     
     # Stop if greeting is not wanted.
     joingreeting = self.db.one("SELECT join_greeting FROM channels WHERE name='" + event.target + "' AND network='" + self.network + "'")

+ 30 - 22
events/on_kick.py

@@ -1,5 +1,6 @@
 from common.networkservices import ChanServ
-from common import userstatus
+from common import userstatus, do_everything_to
+
 bold = "\x02"
 italic = "\x1D"
 underline = "\x1F"
@@ -11,7 +12,6 @@ red = "\x0304"
 grey = "\x0314"
 
 def process_event(self, connection, event):
-    print(event)
     kicker = event.source.nick
     channel = event.target
     kicked = event.arguments[0]
@@ -33,30 +33,38 @@ def process_event(self, connection, event):
     self.db.run("UPDATE kicks SET given = given + 1 WHERE channel='" + channel + "'AND channel_network='" + self.network + "' AND \"user\"='" + kicker + "' AND user_network='" + self.network + "'")
     self.db.run("UPDATE kicks SET received = received + 1 WHERE channel='" + channel + "'AND channel_network='" + self.network + "' AND \"user\"='" + kicked + "' AND user_network='" + self.network + "'")
     
-    if not userstatus.atleast_halfop(self, kicked, self.homechannel) and not kicked == connection.get_nickname():   # Insufficient rights.
+    # Update protectees if needed.
+    if channel == self.homechannel: # Kicked from home channel
+        if event.source.nick in self.protectees:    # Protectee kicked.
+            del self.protectees[event.source.nick]  # Remove old nick from list.
+    
+    # Do nothing more when user is not protected.
+    if not userstatus.atleast_halfop(self, kicked, self.homechannel) and not kicked == connection.get_nickname():
         return
     
-    # Report to home channel.
-    if not channel == self.homechannel: # Not from it's homechannel.
-        if reason:
-            connection.action(self.homechannel, "has been kicked from " + red + channel + reset + " by " + red + kicker + reset + ": " + green + reason)
-        else:
-            connection.action(self.homechannel, "has been kicked from " + red + channel + reset + " by " + red + kicker + reset + ".")
+    # Report.
+    if not channel == self.homechannel: # Not kicked from homechannel.
+        if not userstatus.atleast_halfop(self, kicked, self.homechannel):
+            if reason:
+                connection.privmsg(self.homechannel, red + kicked + reset + " has been kicked from " + red + channel + reset + " by " + red + kicker + reset + ": " + green + reason)
+            else:
+                connection.privmsg(self.homechannel, red + kicked + reset + " has been kicked from " + red + channel + reset + " by " + red + kicker + reset + ".")
     
     # React.
+    
     behaviour = self.db.one("SELECT aggressiveness FROM channels WHERE name='" + channel + "' AND network='" + self.network + "'")
     if behaviour == "passive":    # Passive behaviour.
         if kicked == connection.get_nickname() and channel == self.homechannel: # Bot was kicked from it's home channel.
             ChanServ.unban(connection, channel, kicked)
             ChanServ.akick_del(connection, channel, kicked)
             connection.privmsg("ChanServ", "UNBAN " + channel)
-            connection.join(self.homechannel)
+            do_everything_to.join(self, connection, self.homechannel)
     elif behaviour == "defense_only":   # Defensive behaviour.
         ChanServ.unban(connection, channel, kicked)
         ChanServ.akick_del(connection, channel, kicked)
-        if kicked == connection.get_nickname() and channel == self.homechannel: # Bot was kicked from it's home channel.
+        if kicked == connection.get_nickname(): # Bot was kicked.
             connection.privmsg("ChanServ", "UNBAN " + channel)
-            connection.join(self.homechannel)
+            do_everything_to.join(self, connection, channel)
     elif behaviour == "equal_retalliation":   # Equal retalitory behaviour.
         ChanServ.unban(connection, channel, kicked)
         ChanServ.akick_del(connection, channel, kicked)
@@ -64,35 +72,35 @@ def process_event(self, connection, event):
         # Rejoin if bot was kicked from it's home channel.
         if kicked == connection.get_nickname() and channel == self.homechannel:
             connection.privmsg("ChanServ", "UNBAN " + channel)
-            connection.join(self.homechannel)
+            do_everything_to.join(self, connection, self.homechannel)
         
-        # Stop if the offender is a bot operator and the offended is not the bot owner or if the 2 parties are both bot owner.
-        if userstatus.atleast_halfop(self, kicker, self.homechannel) and not self.channels[self.homechannel].isowner(kicked) or self.channels[self.homechannel].isowner(kicked) == self.channels[self.homechannel].isowner(kicker):
+        # Stop if the offender is a bot operator and the offended is not the bot owner or if the 2 parties are both bot owner or if the offender is the bot.
+        if userstatus.atleast_halfop(self, kicker, self.homechannel) and not self.channels[self.homechannel].isowner(kicked) or self.channels[self.homechannel].isowner(kicked) == self.channels[self.homechannel].isowner(kicker) or event.source.nick == connection.get_nickname():
             return
         
         # Kick.
         ChanServ.kick(connection, channel, kicker, "Aggression channel function = equal_retalliation: " + kicked + " is an operator of " + connection.get_nickname() + ".")
         connection.kick(channel, kicker, "Aggression channel function = equal_retalliation: " + kicked + " is an operator of " + connection.get_nickname() + ".")
-    elif behaviour == "battlebot":   # Battlebot behaviour.
+    
+    # Battlebot behaviour.
+    elif behaviour == "battlebot":
         ChanServ.unban(connection, channel, kicked)
         ChanServ.akick_del(connection, channel, kicked)
         
         # Rejoin if bot was kicked from it's home channel.
         if kicked == connection.get_nickname() and channel == self.homechannel:
             connection.privmsg("ChanServ", "UNBAN " + channel)
-            connection.join(self.homechannel)
+            do_everything_to.join(self, connection, self.homechannel)
         
-        # Stop if the offender is a bot operator and the offended is not the bot owner or if the 2 parties are both bot owner.
-        if userstatus.atleast_halfop(self, kicker, self.homechannel) and not self.channels[self.homechannel].isowner(kicked) or self.channels[self.homechannel].isowner(kicked) == self.channels[self.homechannel].isowner(kicker):
+        # Stop if the offender is a bot operator and the offended is not the bot owner or if the 2 parties are both bot owner or if the offender is the bot.
+        if userstatus.atleast_halfop(self, kicker, self.homechannel) and not self.channels[self.homechannel].is_owner(kicked) or self.channels[self.homechannel].is_owner(kicked) == self.channels[self.homechannel].is_owner(kicker) or event.source.nick == connection.get_nickname():
             return
         
         # Ban.
         ChanServ.tempban(connection, channel, kicker, "Aggression channel function = equal_retalliation: " + kicked + " is an operator of " + connection.get_nickname() + ".")
-        print(event.source)
-        print(event.target)
         connection.mode(channel, "+b " + event.source)
         
-        #connection.mode(channel, "+e " + event.source)  # Protect operator.
+        connection.mode(channel, "+e " + event.source)  # Excempt operator.
         ChanServ.akick_add(connection, channel, kicker) # Add kicker to ChanServs autokick.
         
         # Kick.

+ 111 - 0
events/on_mode.py

@@ -0,0 +1,111 @@
+import fnmatch
+from irc.modes import parse_channel_modes
+from common.networkservices import ChanServ
+bold = "\x02"
+italic = "\x1D"
+underline = "\x1F"
+reverse = "\x16" 	# swap background and foreground colors ("reverse video")
+reset = "\x0F"
+blue = "\x0302"
+green = "\x0303"
+red = "\x0304"
+grey = "\x0314"
+
+def process_event(self, connection, event):
+    print(event)
+    
+    if event.target == self.homechannel:    # Home channel
+        if any(mode in event.arguments[0][-1:] for mode in ("q", "a", "o", "h")):  # Atleast halfop.
+            connection.who(event.arguments[1])  # Get whorepy to update protectees.
+    modes = parse_channel_modes(" ".join(event.arguments))
+    for mode in modes:
+        
+        # Report.
+        if not event.target == self.homechannel:    # Not in home channel.
+            for protectee in self.protectees:
+                if mode[1] == "b" and fnmatch.fnmatch(self.protectees[protectee]['ident'], mode[2]) and mode[0] == "+":   # Protectee banned.
+                    connection.privmsg(self.homechannel, red + protectee + reset + " banned from " + red + event.target + reset + " by " + red + event.source.nick + reset + ": " + green + mode[2])
+                if mode[1] == "e" and fnmatch.fnmatch(self.protectees[protectee]['ident'], mode[2]) and mode[0] == "-":   # Protectee's exception removed.
+                    connection.privmsg(self.homechannel, red + protectee + reset + " has had their exception removed from " + red + event.target + reset + " by " + red + event.source.nick + reset + ": " + green + mode[2])
+    
+        # Track channel keys.
+        if mode[1] == "k":  # Channel key changed.
+            if mode[0] == "+":  # Key set.
+                self.db.run("UPDATE channels SET key='" + mode[2] + "' WHERE name='" + event.target + "' AND network='" + self.network + "'")
+            else:   # Key removed.
+                self.db.run("UPDATE channels SET key=NULL WHERE name='" + event.target + "' AND network='" + self.network + "'")
+    
+    # Do not revert the actions of retalliate upon one self.
+    if event.source.nick == connection.get_nickname():
+        return
+    
+    # React.
+    behaviour = self.db.one("SELECT aggressiveness FROM channels WHERE name='" + event.target + "' AND network='" + self.network + "'")
+    for mode in modes:
+        if behaviour == "passive":    # Passive behaviour.
+            if event.target == self.homechannel:    # Home channel
+                if mode[1] == "b" and fnmatch.fnmatch(self.protectees[connection.get_nickname()]['ident'], mode[2]) and mode[0] == "+": # Bot banned.
+                    ChanServ.unban(connection, event.target, connection.get_nickname())
+                    connection.privmsg("ChanServ", "UNBAN")
+                    connection.mode(event.target, "-b " + mode[2])
+        elif behaviour == "defense_only":   # Defensive only behaviour.
+            if mode[1] == "b" and mode[0] == "+":  # Ban.
+                for protectee in self.protectees:
+                    if fnmatch.fnmatch(self.protectees[protectee]['ident'], mode[2]):  # Protectee.
+                        ChanServ.unban(connection, event.target, protectee)
+                        connection.mode(event.target, "-b " + modes[1])
+            elif mode[1] == "e" and mode[0] == "-":  # Removed exception.
+                for protectee in self.protectees:
+                    if fnmatch.fnmatch(self.protectees[protectee]['ident'], mode[2]):  # Protectee.
+                        connection.mode(event.target, "+e " + mode[2])
+        elif behaviour == "equal_retalliation":   # Equal retaliatory behaviour.
+            if modes[1] == "b" and mode[0] == "+":  # Ban.
+                for protectee in self.protectees:
+                    if fnmatch.fnmatch(self.protectees[protectee]['ident'], mode[2]):  # Protectee.
+                        ChanServ.unban(connection, event.target, protectee)
+                        connection.mode(event.target, "-b " + mode[2])
+                        if protectee == connection.get_nickname():  # Bot banned.
+                            ChanServ.ban(connection, event.target, event.source.nick, "Aggression channel function = equal_retalliation.")
+                        else:
+                            ChanServ.ban(connection, event.target, event.source.nick, "Aggression channel function = equal_retalliation: " + protectee + " is an operator of " + connection.get_nickname() + ".")
+                        connection.mode(event.target, "+b " + event.source)
+            elif mode[1] == "e" and mode[0] == "-":  # Removed exception.
+                for protectee in self.protectees:
+                    if fnmatch.fnmatch(self.protectees[protectee]['ident'], mode[2]):  # Protectee.
+                        connection.mode(event.target, "+e " + mode[2])
+        elif behaviour == "battlebot":  # Battlebot behaviour.
+            if mode[1] == "b" and mode[0] == "+":  # Ban.
+                for protectee in self.protectees:
+                    if fnmatch.fnmatch(self.protectees[protectee]['ident'], mode[2]):  # Protectee.
+                        ChanServ.unban(connection, event.target, protectee)
+                        connection.mode(event.target, "-b " + mode[2])
+                        if protectee == connection.get_nickname():  # Bot banned.
+                            ChanServ.ban(connection, event.target, event.source.nick, "Aggression channel function = battlebot.")
+                        else:
+                            ChanServ.ban(connection, event.target, event.source.nick, "Aggression channel function = battlebot: " + protectee + " is an operator of " + connection.get_nickname() + ".")
+                        connection.mode(event.target, "+b " + event.source)
+                        connection.mode(event.target, "+e " + mode[2])
+                        ChanServ.akick_add(connection, event.target, event.source.nick)
+                        if protectee == connection.get_nickname():  # Bot banned.
+                            ChanServ.kick(connection, event.target, event.source.nick, "Aggression channel function = battlebot.")
+                            connection.kick(event.target, event.source.nick, "Aggression channel function = battlebot.")
+                        else:
+                            ChanServ.kick(connection, event.target, event.source.nick, "Aggression channel function = battlebot: " + protectee + " is an operator of " + connection.get_nickname() + ".")
+                            connection.kick(event.target, event.source.nick, "Aggression channel function = battlebot: " + protectee + " is an operator of " + connection.get_nickname() + ".")
+            elif mode[1] == "e" and mode[0] == "-":  # Removed exception.
+                for protectee in self.protectees:
+                    if fnmatch.fnmatch(self.protectees[protectee]['ident'], mode[2]):  # Protectee.
+                        if protectee == connection.get_nickname():  # Bot.
+                            ChanServ.ban(connection, event.target, event.source.nick, "Aggression channel function = battlebot.")
+                        else:
+                            ChanServ.ban(connection, event.target, event.source.nick, "Aggression channel function = battlebot: " + protectee + " is an operator of " + connection.get_nickname() + ".")
+                        print(event.target, "+b " + event.source)
+                        connection.mode(event.target, "+b " + event.source)
+                        connection.mode(event.target, "+e " + modes[mode]['value'])
+                        ChanServ.akick_add(connection, event.target, event.source.nick)
+                        if protectee == connection.get_nickname():  # Bot.
+                            ChanServ.kick(connection, event.target, event.source.nick, "Aggression channel function = battlebot..")
+                            connection.kick(event.target, event.source.nick, "Aggression channel function = battlebot.")
+                        else:
+                            ChanServ.kick(connection, event.target, event.source.nick, "Aggression channel function = battlebot: " + protectee + " is an operator of " + connection.get_nickname() + ".")
+                            connection.kick(event.target, event.source.nick, "Aggression channel function = battlebot: " + protectee + " is an operator of " + connection.get_nickname() + ".")

+ 13 - 0
events/on_nick.py

@@ -0,0 +1,13 @@
+from common import log
+from common.networkservices import NickServ
+
+def process_event(self, connection, event):
+    
+    # Keep preferred nick.
+    if event.source.nick == connection.nickname:    # Preffered nick being changed.
+            log.info("Assuming original nick.")
+            NickServ.recover_nick(connection, self.password)
+            
+    if event.source.nick in self.protectees:    # Protectee chaning nick.
+        del self.protectees[event.source.nick]  # Remove old nick from list.
+        connection.who(event.target)    # Get whorepy to add new nick to protectees.

+ 3 - 9
events/on_pubmsg.py

@@ -1,17 +1,11 @@
 import random
 
 def process_event(self, connection, event):
-    
     if connection.get_nickname().lower() in event.arguments[0].lower() and event.source.nick is not connection.get_nickname(): # Bot's name was mentioned
-        
-        # Stop if it's a command.
         if event.arguments[0].startswith(self.cmdchar):
-            return
-    
-        # Stop if channelfunction chat if off.
-        chat = self.db.one("SELECT chat FROM channels WHERE name='" + event.target + "' AND network='" + self.network + "'")
-        if not chat:
-            return
+            return  # Stop if it's a command.
+        if not self.db.one("SELECT chat FROM channels WHERE name='" + event.target + "' AND network='" + self.network + "'"):
+            return  # Stop if channelfunction chat if off.
         
         messages = [
             "Hello " + event.source.nick + ".", 

+ 12 - 0
events/on_welcome.py

@@ -0,0 +1,12 @@
+from common import log, do_everything_to
+
+def process_event(self, connection, event):
+    log.info(event)    # Handy for debugging. Keep this.
+    if self.password:   # Id with NickServ
+        connection.privmsg("NickServ", "identify " + connection.nickname + " " + self.password) # Identify with NickServ.
+    channels = self.db.all("SELECT name FROM channels WHERE network='" + self.network + "' AND autojoin=True")
+    connection.join(self.homechannel)
+    for channel in channels:    # Join channels with autojoin function.
+        connection.join(channel)
+    do_everything_to.join(self, connection, self.homechannel)
+    connection.who(connection.get_nickname())   # Get whoreply to add bot to protectees.

+ 4 - 0
events/on_whoreply.py

@@ -0,0 +1,4 @@
+from events.common import Protectees
+
+def process_event(self, connection, event):
+    Protectees.update(self,  event.arguments[4], event.arguments[1], event.arguments[2])

+ 10 - 3
pyRot.e4p

@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE Project SYSTEM "Project-5.1.dtd">
 <!-- eric project file for project pyRot -->
-<!-- Saved: 2018-01-25, 22:51:57 -->
+<!-- Saved: 2018-01-27, 00:37:00 -->
 <!-- Copyright (C) 2018 tBKwtWS,  -->
 <Project version="5.1">
   <Language>en_US</Language>
@@ -14,18 +14,23 @@
   <Email></Email>
   <Eol index="0"/>
   <Sources>
-    <Source>__init__.py</Source>
     <Source>commands/admin.py</Source>
     <Source>commands/common.py</Source>
     <Source>commands/games.py</Source>
     <Source>commands/public.py</Source>
     <Source>commands/statistics.py</Source>
+    <Source>common/do_everything_to.py</Source>
     <Source>common/log.py</Source>
     <Source>common/networkservices.py</Source>
     <Source>common/userstatus.py</Source>
+    <Source>events/common.py</Source>
     <Source>events/on_join.py</Source>
     <Source>events/on_kick.py</Source>
+    <Source>events/on_mode.py</Source>
+    <Source>events/on_nick.py</Source>
     <Source>events/on_pubmsg.py</Source>
+    <Source>events/on_welcome.py</Source>
+    <Source>events/on_whoreply.py</Source>
     <Source>original_testbot.py</Source>
     <Source>rotbot.py</Source>
     <Source>test.py</Source>
@@ -34,7 +39,9 @@
   <Translations/>
   <Resources/>
   <Interfaces/>
-  <Others/>
+  <Others>
+    <Other>pyRot.e4p</Other>
+  </Others>
   <MainScript>rotbot.py</MainScript>
   <Vcs>
     <VcsType>None</VcsType>

+ 34 - 31
rotbot.py

@@ -5,13 +5,14 @@ import irc.bot#, irc.strings
 from irc.client import ip_numstr_to_quad#, ip_quad_to_numstr
 from postgres import Postgres
 import commands.public, commands.admin, commands.games, commands.statistics
-import events.on_join, events.on_kick, events.on_pubmsg
-from common.networkservices import NickServ
+import events.on_welcome, events.on_join, events.on_kick, events.on_mode, events.on_pubmsg, events.on_whoreply, events.on_nick
 from common import log
+from common.networkservices import NickServ
+
 bold = "\x02"
 italic = "\x1D"
 underline = "\x1F"
-reverse = "\x16" 	# swap background and foreground colors ("reverse video")
+reverse = "\x16"    # swap background and foreground colors ("reverse video")
 reset = "\x0F"
 blue = "\x0302"
 green = "\x0303"
@@ -26,6 +27,8 @@ class PyRot(irc.bot.SingleServerIRCBot):
         self.password = password
         self.cmdchar = cmdchar
         self.helpchar = helpchar
+        self.protectees = {}
+        self.channelkeys = {}
         
         if usessl:
             factory = irc.connection.Factory(wrapper=ssl.wrap_socket)
@@ -45,40 +48,35 @@ class PyRot(irc.bot.SingleServerIRCBot):
         NickServ.recover_nick(connection, self.password)
     
     def on_welcome(self, connection, event):
-        log.info(event)    # Handy for debugging. Keep this.
-        if self.password:   # Id with NickServ
-            connection.privmsg("NickServ", "identify " + connection.nickname + " " + self.password) # Identify with NickServ.
-        channels = self.db.all("SELECT name FROM channels WHERE network='" + self.network + "' AND autojoin=True")
-        connection.join(self.homechannel)
-        for channel in channels:    # Join channels with autojoin function.
-            connection.join(channel)
-        connection.join(self.homechannel)
+        events.on_welcome.process_event(self, connection, event)
         
     def on_error(self, connection, event):
         log.notice(event)
         connection.privmsg(self.homechannel, "ERROR: " + event)
     
-    def on_nick(self,  connection,  event):
-        if event.source.nick == connection.nickname:    # If the nick boing changes is the bots prefered nickname.
-            log.info("Assuming original nick.")
-            NickServ.recover_nick(connection, self.password)
+    def on_nick(self, connection, event):
+        events.on_nick.process_event(self, connection, event)
     
     def on_join(self, connection, event):
-        log.info(event)
         events.on_join.process_event(self, connection, event)
     
     def on_kick(self, connection, event):
-        log.info(event)
         events.on_kick.process_event(self, connection, event)
     
     def on_mode(self, connection, event):
-        log.info(event)
+        events.on_mode.process_event(self, connection, event)
     
     def on_part(self, connection, event):
-        log.info(event)
+        
+        # Update protectees
+        if event.target == self.homechannel and event.source.nick in self.protectees:    # Protectee parted home channel.
+            del self.protectees[event.source.nick] # Delete from protectees.
     
     def on_quit(self, connection, event):
-        log.info(event)
+        
+        # Update protectees
+        if event.source.nick in self.protectees:    # Protectee parted home channel.
+            del self.protectees[event.source.nick] # Delete from protectees.
     
     def on_invite(self, connection, event):
         log.info(event)
@@ -90,17 +88,9 @@ class PyRot(irc.bot.SingleServerIRCBot):
         commands.public.do_command(self, connection, event)
         commands.admin.do_command(self, connection, event)
         commands.statistics.do_command(self, connection, event)
-        try:
-            games = self.db.one("SELECT games FROM channels WHERE name='" + event.target + "' AND network='" + self.network + "'")
-        except:
-            pass
-        if games:
-            commands.games.do_command(self, connection, event)
+        commands.games.do_command(self, connection, event)
         events.on_pubmsg.process_event(self, connection, event)
     
-    def on_pubnotice(self, connection, event):
-        log.info(event)
-    
     def on_privmsg(self, connection, event):
         log.info(event)
         commands.public.do_command(self, connection, event)
@@ -108,18 +98,31 @@ class PyRot(irc.bot.SingleServerIRCBot):
         commands.statistics.do_command(self, connection, event)
         commands.games.do_command(self, connection, event)
     
+    def on_pubnotice(self, connection, event):
+        log.info(event)
+    
     def on_privnotice(self,  connection,  event):
         log.info(event)
         commands.public.do_command(self, connection, event)
         commands.admin.do_command(self, connection, event)
         commands.statistics.do_command(self, connection, event)
         commands.games.do_command(self, connection, event)
-        if event.source.nick == NickServ and event.arguments[0].startswith("This nickname is registered"):
-            connection.privmsg("NickServ", "identify " + connection.nickname + " " + connection.password) # Identify with NickServ.
+        if event.source.nick == "NickServ" and event.arguments[0].startswith("This nickname is registered"):
+            connection.privmsg("NickServ", "identify " + connection.nickname + " " + self.password) # Identify with NickServ.
+        if event.source.nick == "ChanServ" and event.arguments[0].startswith("Key for channel ") and len(event.arguments[0]) > 5:   # Received channel key.
+            connection.join(event.arguments[0].split(' ')[3], event.arguments[0].split(' ')[5][:-1])
     
     def on_action(self, connection, event):
         log.info(event)
     
+    
+    def on_userhost(self, connection, event):
+        print(event)
+    
+    def on_whoreply(self, connection, event):
+        events.on_whoreply.process_event(self, connection, event)
+    
+    
     # DCC stuff from originalexample file.
     def on_dccmsg(self, c, e):
         log.info(e)