<module>acid</module>
<module>pyva</module>
+ <module>trapbot</module>
</modules>
<build>
--- /dev/null
+<?xml version="1.0"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>net.rizon</groupId>
+ <artifactId>acid</artifactId>
+ <version>4.0-SNAPSHOT</version>
+ </parent>
+
+ <groupId>net.rizon</groupId>
+ <artifactId>acid-trapbot</artifactId>
+ <version>4.0-SNAPSHOT</version>
+
+ <dependencies>
+ <dependency>
+ <groupId>net.rizon</groupId>
+ <artifactId>acid-acid</artifactId>
+ <version>4.0-SNAPSHOT</version>
+ </dependency>
+ </dependencies>
+</project>
--- /dev/null
+package net.rizon.acid.plugins.trapbot;
+
+import net.rizon.acid.core.Timer;
+
+import java.util.Date;
+import java.util.Iterator;
+import java.util.Map;
+
+class ExpireTimer extends Timer
+{
+ ExpireTimer()
+ {
+ // one day
+ super(60 * 60 * 24, true);
+ }
+
+ @Override
+ public void run(Date now)
+ {
+ for (Iterator<Map.Entry<String, TrappedUser>> it = trapbot.users.entrySet().iterator(); it.hasNext();)
+ {
+ Map.Entry<String, TrappedUser> e = it.next();
+ TrappedUser t = e.getValue();
+
+ /* how many days have passed */
+ int days = (int)((now.getTime() - t.lastTrap.getTime()) / (1000 * 60 * 60 * 24));
+
+ if (days >= trapbot.conf.expire)
+ it.remove();
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+package net.rizon.acid.plugins.trapbot;
+
+import net.rizon.acid.core.Message;
+import net.rizon.acid.core.Protocol;
+import net.rizon.acid.core.Timer;
+
+import java.util.Date;
+import java.util.Random;
+
+class ReleaseTimer extends Timer
+{
+ ReleaseTimer()
+ {
+ // XXX magic?
+ super(new Random().nextInt(2700) + 2700, false);
+ }
+
+ @Override
+ public void run(final Date now)
+ {
+ Protocol.privmsg(trapbot.trapbot.getUID(), trapbot.getTrapChanName(), Message.BOLD + "YOU HAVE 1 MINUTE TO PART THE CHANNEL, GET OUT WHILE YOU CAN!" + Message.BOLD);
+
+ trapbot.enforce = false;
+ trapbot.releaseTimer = null;
+
+ trapbot.retrapTimer = new RetrapTimer(60, false);
+ trapbot.retrapTimer.start();
+ }
+}
--- /dev/null
+package net.rizon.acid.plugins.trapbot;
+
+import net.rizon.acid.core.Message;
+import net.rizon.acid.core.Protocol;
+import net.rizon.acid.core.Timer;
+
+import java.util.Date;
+
+class RetrapTimer extends Timer
+{
+ RetrapTimer(long time_from_now, boolean repeating)
+ {
+ super(time_from_now, repeating);
+ }
+
+ /*
+ * release users
+ */
+ @Override
+ public void run(final Date now)
+ {
+ /* start enforcing again and announce it */
+ trapbot.enforce = true;
+ trapbot.retrapTimer = null;
+
+ Protocol.privmsg(trapbot.trapbot.getUID(), trapbot.getTrapChanName(), Message.BOLD + "HAHA TRAPPED AGAIN!" + Message.BOLD);
+
+ trapbot.releaseTimer = new ReleaseTimer();
+ trapbot.releaseTimer.start();
+ }
+}
--- /dev/null
+package net.rizon.acid.plugins.trapbot;
+
+import net.rizon.acid.core.Event;
+import net.rizon.acid.core.Protocol;
+import net.rizon.acid.core.User;
+
+class TrapEvent extends Event
+{
+ @Override
+ public void onUserConnect(User u)
+ {
+ TrappedUser t = trapbot.getTrappedUser(u);
+ /* force the user back in */
+ if (t != null)
+ {
+ t.update();
+ Protocol.svsjoin(u, trapbot.getTrapChanName());
+ }
+ }
+
+ @Override
+ public void onJoin(final String channel, final User[] users)
+ {
+ if (!channel.equalsIgnoreCase(trapbot.getTrapChanName()))
+ return;
+
+ for (User u : users)
+ {
+ trapbot.updateTrap(u);
+ }
+ }
+
+ @Override
+ public void onPart(final String parter, final String channel)
+ {
+ User u = User.findUser(parter);
+
+ if (u == null)
+ return;
+
+ if (!channel.equalsIgnoreCase(trapbot.getTrapChanName()))
+ return;
+
+ if (u.hasMode("o"))
+ return;
+
+ TrappedUser tu = trapbot.getTrappedUser(u);
+ if (tu == null)
+ tu = trapbot.makeTrappedUser(u);
+
+ /*
+ * if enforce is disabled, we let the parting users go
+ */
+ if (trapbot.enforce)
+ {
+ tu.update();
+ Protocol.svsjoin(u, trapbot.getTrapChanName());
+ }
+ else
+ trapbot.freeUser(u);
+ }
+
+ public void onKick(String kicker, User victim, String channel, String reason)
+ {
+ if (!channel.equalsIgnoreCase(trapbot.getTrapChanName()))
+ return;
+
+ trapbot.freeUser(victim);
+ }
+}
\ No newline at end of file
--- /dev/null
+package net.rizon.acid.plugins.trapbot;
+
+import java.util.Date;
+
+class TrappedUser
+{
+ public String ip;
+ public Date lastTrap;
+
+ TrappedUser(String ip)
+ {
+ this.ip = ip;
+ }
+
+ public void update()
+ {
+ lastTrap = new Date();
+ }
+}
\ No newline at end of file
--- /dev/null
+package net.rizon.acid.plugins.trapbot.commands;
+
+import net.rizon.acid.core.AcidUser;
+import net.rizon.acid.core.Acidictive;
+import net.rizon.acid.core.Channel;
+import net.rizon.acid.core.Command;
+import net.rizon.acid.core.Protocol;
+import net.rizon.acid.core.User;
+import net.rizon.acid.plugins.trapbot.trapbot;
+
+public class Untrap extends Command
+{
+ public Untrap()
+ {
+ super(1, 1);
+ }
+
+ @Override
+ public void Run(User x, AcidUser to, Channel c, final String[] args)
+ {
+ User u = User.findUser(args[0]);
+
+ if (u == null || u.getServer() == Acidictive.me || u.getServer().isUlined())
+ {
+ Acidictive.reply(u, to, c, "Cannot find user \2" + args[0] + "\2.");
+ return;
+ }
+
+ Channel trapchan = Channel.findChannel(trapbot.getTrapChanName());
+ if (trapchan == null)
+ {
+ Acidictive.reply(u, to, c, "Cannot find trapchan");
+ return;
+ }
+
+ if (!u.isOnChan(trapchan.getName()))
+ {
+ Acidictive.reply(u, to, c, "User " + u.getNick() + " is on on " + trapbot.getTrapChanName());
+ return;
+ }
+
+ if (u.hasMode("o"))
+ {
+ Acidictive.reply(u, to, c, "Access denied.");
+ return;
+ }
+
+ trapbot.freeUser(u);
+
+ String reason = "You're free now!";
+
+ Protocol.kick(trapbot.trapbot, u, trapchan.getName(), reason);
+ Acidictive.onKick(trapbot.trapbot.getNick(), u, trapchan.getName(), reason);
+
+ Acidictive.reply(u, to, c, "User \2" + u.getNick() + "\2 was freed and kicked.");
+ }
+
+ @Override
+ public boolean onHelpCommand(User u, AcidUser to, Channel c)
+ {
+ Acidictive.reply(u, to, c, "Syntax: \2untrap [user]\2");
+ Acidictive.reply(u, to, c, " ");
+ Acidictive.reply(u, to, c, "Frees and kicks a given user from the trap channel.");
+
+ return true;
+ }
+}
--- /dev/null
+package net.rizon.acid.plugins.trapbot.conf;
+
+import net.rizon.acid.conf.Client;
+import net.rizon.acid.conf.ConfigException;
+import net.rizon.acid.conf.Configuration;
+
+import java.util.List;
+
+public class Config extends Configuration
+{
+ public List<Client> clients;
+
+ public String trapbot, trapchan;
+ public int expire;
+
+ @Override
+ public void validate() throws ConfigException
+ {
+ }
+}
--- /dev/null
+package net.rizon.acid.plugins.trapbot;
+
+import net.rizon.acid.core.AcidUser;
+import net.rizon.acid.core.Acidictive;
+import net.rizon.acid.core.Event;
+import net.rizon.acid.core.Logger;
+import net.rizon.acid.core.Plugin;
+import net.rizon.acid.core.Timer;
+import net.rizon.acid.core.User;
+import net.rizon.acid.plugins.trapbot.conf.Config;
+
+import java.util.HashMap;
+
+public class trapbot extends Plugin
+{
+ protected static final Logger log = Logger.getLogger(trapbot.class.getName());
+
+ private Event ev;
+ public static AcidUser trapbot;
+ public static Config conf;
+ private Timer expireTimer;
+ public static Timer retrapTimer;
+ public static Timer releaseTimer;
+ // ip -> user
+ public static HashMap<String, TrappedUser> users = new HashMap<String, TrappedUser>();
+ public static boolean enforce = true;
+
+ public static String getTrapChanName()
+ {
+ return Acidictive.conf.getChannelNamed(conf.trapchan);
+ }
+
+ public static TrappedUser makeTrappedUser(User u)
+ {
+ TrappedUser tu = new TrappedUser(u.getIP());
+ users.put(u.getIP(), tu);
+ return tu;
+ }
+
+ public static TrappedUser getTrappedUser(User u)
+ {
+ if (u.getIP() == null || u.getIP().equals("0"))
+ return null;
+
+ return users.get(u.getIP());
+ }
+
+ public static void freeUser(User u)
+ {
+ users.remove(u.getIP());
+ }
+
+ public static void updateTrap(User u)
+ {
+ if (u.getServer() == Acidictive.me || u.getServer().isUlined())
+ return;
+
+ /* ignore spoofed users */
+ if (u.getIP() == null || u.getIP().equals("0") || u.getIP().equals("255.255.255.255"))
+ return;
+
+ TrappedUser t = getTrappedUser(u);
+
+ if (t == null)
+ t = makeTrappedUser(u);
+
+ t.update();
+ }
+
+ @Override
+ public void start() throws Exception
+ {
+ ev = new TrapEvent();
+
+ reload();
+
+ expireTimer = new ExpireTimer();
+ expireTimer.start();
+
+ releaseTimer = new ReleaseTimer();
+ releaseTimer.start();
+ }
+
+ @Override
+ public void reload() throws Exception
+ {
+ conf = (Config) net.rizon.acid.conf.Config.load("trapbot.yml", Config.class);
+ Acidictive.loadClients(this, conf.clients);
+
+ User u = User.findUser(conf.trapbot);
+ if (u == null || !(u instanceof AcidUser))
+ throw new Exception("Unable to find trapbot " + conf.trapbot);
+
+ trapbot = (AcidUser) u;
+ }
+
+ @Override
+ public void stop()
+ {
+ ev.remove();
+
+ if (expireTimer != null)
+ expireTimer.stop();
+
+ if (releaseTimer != null)
+ releaseTimer.stop();
+
+ if (retrapTimer != null)
+ retrapTimer.stop();
+ }
+}
--- /dev/null
+clients:
+ -
+ nick: TrapBot
+ user: trapped
+ host: services.rizon.net
+ vhost: services.rizon.net
+ name: Gotcha!
+ modes: i
+ channels: [ trapchan ]
+ commands:
+ -
+ name: help
+ privilege: none
+ clazz: net.rizon.acid.commands.Help
+ -
+ name: untrap
+ privilege: none
+ clazz: net.rizon.acid.plugins.trapbot.commands.Untrap
+
+# Nickname of the trapbot client
+trapbot: TrapBot
+# Our name for the channel that is the trap channel
+trapchan: trapchan
+# Number of days before IPs added to the trap list are forgotten
+expire: 2