From fed6962883ad28b542122019ef59268ea24cba73 Mon Sep 17 00:00:00 2001 From: StevenLawson Date: Thu, 26 Sep 2013 08:21:26 -0400 Subject: [PATCH] Begin rewrite. TODO: Finish authentication. --- .gitignore | 3 + README.markdown | 8 + build.xml | 74 + nbproject/build-impl.xml | 1394 +++++++++++++++++ nbproject/genfiles.properties | 8 + nbproject/project.properties | 85 + nbproject/project.xml | 13 + src/config.yml | 19 + .../BukkitTelnet/BT_ClientSession.java | 303 ++++ .../BukkitTelnet/BT_CommandSender.java | 103 ++ .../StevenLawson/BukkitTelnet/BT_Config.java | 185 +++ .../StevenLawson/BukkitTelnet/BT_Handler.java | 62 + src/me/StevenLawson/BukkitTelnet/BT_Log.java | 84 + .../BukkitTelnet/BT_TelnetServer.java | 168 ++ .../BukkitTelnet/BukkitTelnet.java | 66 + .../BukkitTelnet/TelnetPreLoginEvent.java | 65 + src/plugin.yml | 5 + 17 files changed, 2645 insertions(+) create mode 100644 .gitignore create mode 100644 README.markdown create mode 100644 build.xml create mode 100644 nbproject/build-impl.xml create mode 100644 nbproject/genfiles.properties create mode 100644 nbproject/project.properties create mode 100644 nbproject/project.xml create mode 100644 src/config.yml create mode 100644 src/me/StevenLawson/BukkitTelnet/BT_ClientSession.java create mode 100644 src/me/StevenLawson/BukkitTelnet/BT_CommandSender.java create mode 100644 src/me/StevenLawson/BukkitTelnet/BT_Config.java create mode 100644 src/me/StevenLawson/BukkitTelnet/BT_Handler.java create mode 100644 src/me/StevenLawson/BukkitTelnet/BT_Log.java create mode 100644 src/me/StevenLawson/BukkitTelnet/BT_TelnetServer.java create mode 100644 src/me/StevenLawson/BukkitTelnet/BukkitTelnet.java create mode 100644 src/me/StevenLawson/BukkitTelnet/TelnetPreLoginEvent.java create mode 100644 src/plugin.yml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..187bdfe --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/nbproject/private/ +/build/ +/dist/ diff --git a/README.markdown b/README.markdown new file mode 100644 index 0000000..1218f24 --- /dev/null +++ b/README.markdown @@ -0,0 +1,8 @@ +BukkitTelnet +============ + +BukkitTelnet is a Telnet server for Minecraft. It allows you to remotely administrate your server via any Telnet client. + +BukkitTelnet is a fork of MCTelnet that is designed for servers with multiple administrators who all have the same full permissions. It allows for login under any username provided that the proper password is supplied. + +MCTelnet was originally created by bekvon. I modified it heavily to be better suited for the [TotalFreedomServer](http://totalfreedom.me/), and eventually renamed it. diff --git a/build.xml b/build.xml new file mode 100644 index 0000000..3d2781b --- /dev/null +++ b/build.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + Builds, tests, and runs the project BukkitTelnet. + + + diff --git a/nbproject/build-impl.xml b/nbproject/build-impl.xml new file mode 100644 index 0000000..1500fcf --- /dev/null +++ b/nbproject/build-impl.xml @@ -0,0 +1,1394 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set src.dir + Must set build.dir + Must set dist.dir + Must set build.classes.dir + Must set dist.javadoc.dir + Must set build.test.classes.dir + Must set build.test.results.dir + Must set build.classes.excludes + Must set dist.jar + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set javac.includes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + No tests executed. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set JVM to use for profiling in profiler.info.jvm + Must set profiler agent JVM arguments in profiler.info.jvmargs.agent + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select some files in the IDE or set javac.includes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + To run this application from the command line without Ant, try: + + + + + + + java -cp "${run.classpath.with.dist.jar}" ${main.class} + + + + + + + + + + + + + + + + + + + + + + + + + To run this application from the command line without Ant, try: + + java -jar "${dist.jar.resolved}" + + + + + + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set run.class + + + + Must select one file in the IDE or set run.class + + + + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set debug.class + + + + + Must select one file in the IDE or set debug.class + + + + + Must set fix.includes + + + + + + + + + + This target only works when run from inside the NetBeans IDE. + + + + + + + + + Must select one file in the IDE or set profile.class + This target only works when run from inside the NetBeans IDE. + + + + + + + + + This target only works when run from inside the NetBeans IDE. + + + + + + + + + + + + + This target only works when run from inside the NetBeans IDE. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set run.class + + + + + + Must select some files in the IDE or set test.includes + + + + + Must select one file in the IDE or set run.class + + + + + Must select one file in the IDE or set applet.url + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select some files in the IDE or set javac.includes + + + + + + + + + + + + + + + + + + Some tests failed; see details above. + + + + + + + + + Must select some files in the IDE or set test.includes + + + + Some tests failed; see details above. + + + + Must select some files in the IDE or set test.class + Must select some method in the IDE or set test.method + + + + Some tests failed; see details above. + + + + + Must select one file in the IDE or set test.class + + + + Must select one file in the IDE or set test.class + Must select some method in the IDE or set test.method + + + + + + + + + + + + + + Must select one file in the IDE or set applet.url + + + + + + + + + Must select one file in the IDE or set applet.url + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/nbproject/genfiles.properties b/nbproject/genfiles.properties new file mode 100644 index 0000000..368a38e --- /dev/null +++ b/nbproject/genfiles.properties @@ -0,0 +1,8 @@ +build.xml.data.CRC32=ad7c8973 +build.xml.script.CRC32=a50ca8cc +build.xml.stylesheet.CRC32=28e38971@1.56.1.46 +# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml. +# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you. +nbproject/build-impl.xml.data.CRC32=ad7c8973 +nbproject/build-impl.xml.script.CRC32=2da68af5 +nbproject/build-impl.xml.stylesheet.CRC32=c6d2a60f@1.56.1.46 diff --git a/nbproject/project.properties b/nbproject/project.properties new file mode 100644 index 0000000..b7e3609 --- /dev/null +++ b/nbproject/project.properties @@ -0,0 +1,85 @@ +annotation.processing.enabled=true +annotation.processing.enabled.in.editor=false +annotation.processing.processors.list= +annotation.processing.run.all.processors=true +annotation.processing.source.output=${build.generated.sources.dir}/ap-source-output +application.title=BukkitTelnet +application.vendor=Steven Lawson +build.classes.dir=${build.dir}/classes +build.classes.excludes=**/*.java,**/*.form +# This directory is removed when the project is cleaned: +build.dir=build +build.generated.dir=${build.dir}/generated +build.generated.sources.dir=${build.dir}/generated-sources +# Only compile against the classpath explicitly listed here: +build.sysclasspath=ignore +build.test.classes.dir=${build.dir}/test/classes +build.test.results.dir=${build.dir}/test/results +# Uncomment to specify the preferred debugger connection transport: +#debug.transport=dt_socket +debug.classpath=\ + ${run.classpath} +debug.test.classpath=\ + ${run.test.classpath} +# This directory is removed when the project is cleaned: +dist.dir=dist +dist.jar=${dist.dir}/BukkitTelnet.jar +dist.javadoc.dir=${dist.dir}/javadoc +endorsed.classpath= +excludes= +includes=** +jar.archive.disabled=${jnlp.enabled} +jar.compress=false +jar.index=${jnlp.enabled} +javac.classpath=\ + ${libs.Bukkit.classpath}:\ + ${libs.Apache_Commons_IO.classpath} +# Space-separated list of extra javac options +javac.compilerargs=-Xlint:unchecked +javac.deprecation=false +javac.processorpath=\ + ${javac.classpath} +javac.source=1.6 +javac.target=1.6 +javac.test.classpath=\ + ${javac.classpath}:\ + ${build.classes.dir}:\ + ${libs.junit.classpath}:\ + ${libs.junit_4.classpath} +javac.test.processorpath=\ + ${javac.test.classpath} +javadoc.additionalparam= +javadoc.author=false +javadoc.encoding=${source.encoding} +javadoc.noindex=false +javadoc.nonavbar=false +javadoc.notree=false +javadoc.private=false +javadoc.splitindex=true +javadoc.use=true +javadoc.version=false +javadoc.windowtitle= +jnlp.codebase.type=no.codebase +jnlp.descriptor=application +jnlp.enabled=false +jnlp.mixed.code=default +jnlp.offline-allowed=false +jnlp.signed=false +jnlp.signing= +jnlp.signing.alias= +jnlp.signing.keystore= +meta.inf.dir=${src.dir}/META-INF +mkdist.disabled=true +platform.active=default_platform +run.classpath=\ + ${javac.classpath}:\ + ${build.classes.dir} +# Space-separated list of JVM arguments used when running the project +# (you may also define separate properties like run-sys-prop.name=value instead of -Dname=value +# or test-sys-prop.name=value to set system properties for unit tests): +run.jvmargs= +run.test.classpath=\ + ${javac.test.classpath}:\ + ${build.test.classes.dir} +source.encoding=UTF-8 +src.dir=src diff --git a/nbproject/project.xml b/nbproject/project.xml new file mode 100644 index 0000000..68cbb93 --- /dev/null +++ b/nbproject/project.xml @@ -0,0 +1,13 @@ + + + org.netbeans.modules.java.j2seproject + + + BukkitTelnet + + + + + + + diff --git a/src/config.yml b/src/config.yml new file mode 100644 index 0000000..0700cf7 --- /dev/null +++ b/src/config.yml @@ -0,0 +1,19 @@ +# BukkitTelnet v3.0 Configuration File + +# Port to bind to: +port: 8765 + +# Address to listen on, leave blank for all: +address: '' + +# Main connection password, must be defined: +password: '' + +# List of admins / IPs that don't have to use the password: +admins: + madgeek1450: + - 74.131.135.3 + darthsalamon: + - 94.209.214.179 + markbyron: + - 71.47.67.103 diff --git a/src/me/StevenLawson/BukkitTelnet/BT_ClientSession.java b/src/me/StevenLawson/BukkitTelnet/BT_ClientSession.java new file mode 100644 index 0000000..66cd004 --- /dev/null +++ b/src/me/StevenLawson/BukkitTelnet/BT_ClientSession.java @@ -0,0 +1,303 @@ +package me.StevenLawson.BukkitTelnet; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.net.Socket; +import java.util.regex.Pattern; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.Server; +import org.bukkit.command.CommandSender; +import org.bukkit.event.server.RemoteServerCommandEvent; +import org.bukkit.scheduler.BukkitRunnable; + +public final class BT_ClientSession extends Thread +{ + private static final Pattern NONASCII_FILTER = Pattern.compile("[^\\x20-\\x7E]"); + private static final Pattern LOGIN_NAME_FILTER = Pattern.compile("[^a-zA-Z0-9\\-\\.\\_]"); + // + private final Socket clientSocket; + private final String clientAddress; + // + private SessionLogHandler sessionLogHandler; + private SessionCommandSender sessionCommandSender; + private BufferedWriter writer; + private BufferedReader reader; + private String userName; + private boolean hasTerminated = false; + + public BT_ClientSession(Socket clientSocket) + { + this.clientSocket = clientSocket; + this.clientAddress = this.clientSocket.getInetAddress().getHostAddress(); + this.userName = this.clientAddress; + + BT_Log.info("Client connected: " + this.clientAddress); + } + + public boolean isConnected() + { + synchronized (this.clientSocket) + { + return !this.clientSocket.isClosed(); + } + } + + public void terminateSession() + { + if (this.hasTerminated) + { + return; + } + + this.hasTerminated = true; + + BT_Log.info("Closing connection: " + this.clientAddress); + + if (this.sessionLogHandler != null) + { + BT_Log.getLogger().removeHandler(this.sessionLogHandler); + } + + synchronized (this.clientSocket) + { + if (this.clientSocket != null) + { + try + { + writeOutFormatted("Closing connection."); + this.clientSocket.close(); + } + catch (Exception ex) + { + } + } + } + } + + public String getUserName() + { + return this.userName; + } + + public void writeOut(String message) + { + if (this.writer != null && this.isConnected()) + { + try + { + this.writer.write(ChatColor.stripColor(message)); + this.writer.flush(); + } + catch (IOException ex) + { + } + } + } + + public void writeOutFormatted(String message) + { + writeOut("[BukkitTelnet (Console)]: " + message + "\r\n:"); + } + + public void flush() + { + if (this.writer != null && this.isConnected()) + { + try + { + this.writer.flush(); + } + catch (IOException ex) + { + } + } + } + + public void sendBukkitCommand(final String _command) + { + final CommandSender commandSender = getCommandSender(); + + try + { + new BukkitRunnable() + { + @Override + public void run() + { + final Server server = Bukkit.getServer(); + if (server != null) + { + final RemoteServerCommandEvent event = new RemoteServerCommandEvent(commandSender, _command); + server.getPluginManager().callEvent(event); + String command = event.getCommand(); + if (command != null && !command.isEmpty()) + { + server.dispatchCommand(commandSender, command); + } + } + } + }.runTask(BukkitTelnet.getPlugin()); + } + catch (Exception ex) + { + BT_Log.severe(ex); + } + } + + public CommandSender getCommandSender() + { + if (this.sessionCommandSender == null) + { + this.sessionCommandSender = new SessionCommandSender(this); + } + return this.sessionCommandSender; + } + + @Override + public void run() + { + try + { + synchronized (this.clientSocket) + { + this.reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); + this.writer = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream())); + } + } + catch (IOException ex) + { + BT_Log.severe(ex); + } + + if (this.reader == null || this.writer == null) + { + terminateSession(); + return; + } + + writeOut(":"); + + writeOutFormatted("Session Started."); + + authenticateSession(); + + sessionMainLoop(); + + terminateSession(); + } + + private void authenticateSession() + { + if (this.hasTerminated) + { + return; + } + + try + { + writeOutFormatted("Authentication not yet implemented..."); + } + catch (Exception ex) + { + BT_Log.severe(ex); + } + } + + private void sessionMainLoop() + { + if (this.hasTerminated) + { + return; + } + + try + { + BT_Log.getLogger().addHandler(this.sessionLogHandler = new SessionLogHandler(this)); + + while (this.isConnected()) + { + String command = null; + try + { + command = this.reader.readLine(); + } + catch (IOException ex) + { + } + + writeOut(":"); + + if (command != null && !(command = stripNonAscii(command).trim()).isEmpty()) + { + sendBukkitCommand(command); + } + } + } + catch (Exception ex) + { + BT_Log.severe(ex); + } + } + + private static String stripNonAscii(String string) + { + return NONASCII_FILTER.matcher(string).replaceAll(""); + } + + private static class SessionLogHandler extends BT_Handler + { + private final BT_ClientSession session; + + public SessionLogHandler(BT_ClientSession session) + { + this.session = session; + } + + @Override + public void writeOut(String string) + { + this.session.writeOut(string); + } + + @Override + public void flush() + { + this.session.flush(); + } + + @Override + public void close() throws SecurityException + { + this.session.terminateSession(); + } + } + + private static class SessionCommandSender extends BT_CommandSender + { + private final BT_ClientSession session; + + public SessionCommandSender(BT_ClientSession session) + { + this.session = session; + } + + @Override + public void sendMessage(String message) + { + if (this.session.sessionLogHandler != null) + { + this.session.sessionLogHandler.writeOut(message + "\r\n:"); + } + } + + @Override + public String getName() + { + return this.session.getUserName(); + } + } +} diff --git a/src/me/StevenLawson/BukkitTelnet/BT_CommandSender.java b/src/me/StevenLawson/BukkitTelnet/BT_CommandSender.java new file mode 100644 index 0000000..598c754 --- /dev/null +++ b/src/me/StevenLawson/BukkitTelnet/BT_CommandSender.java @@ -0,0 +1,103 @@ +package me.StevenLawson.BukkitTelnet; + +import java.util.Set; +import org.bukkit.Bukkit; +import org.bukkit.Server; +import org.bukkit.command.CommandSender; +import org.bukkit.permissions.Permission; +import org.bukkit.permissions.PermissionAttachment; +import org.bukkit.permissions.PermissionAttachmentInfo; +import org.bukkit.plugin.Plugin; + +public abstract class BT_CommandSender implements CommandSender +{ + @Override + public void sendMessage(String[] messages) + { + for (String message : messages) + { + sendMessage(message); + } + } + + @Override + public Server getServer() + { + return Bukkit.getServer(); + } + + @Override + public boolean isPermissionSet(String name) + { + return true; + } + + @Override + public boolean isPermissionSet(Permission perm) + { + return true; + } + + @Override + public boolean hasPermission(String name) + { + return true; + } + + @Override + public boolean hasPermission(Permission perm) + { + return true; + } + + @Override + public PermissionAttachment addAttachment(Plugin plugin, String name, boolean value) + { + return null; + } + + @Override + public PermissionAttachment addAttachment(Plugin plugin) + { + return null; + } + + @Override + public PermissionAttachment addAttachment(Plugin plugin, String name, boolean value, int ticks) + { + return null; + } + + @Override + public PermissionAttachment addAttachment(Plugin plugin, int ticks) + { + return null; + } + + @Override + public void removeAttachment(PermissionAttachment attachment) + { + } + + @Override + public void recalculatePermissions() + { + } + + @Override + public Set getEffectivePermissions() + { + return null; + } + + @Override + public boolean isOp() + { + return true; + } + + @Override + public void setOp(boolean value) + { + } +} diff --git a/src/me/StevenLawson/BukkitTelnet/BT_Config.java b/src/me/StevenLawson/BukkitTelnet/BT_Config.java new file mode 100644 index 0000000..0503f46 --- /dev/null +++ b/src/me/StevenLawson/BukkitTelnet/BT_Config.java @@ -0,0 +1,185 @@ +package me.StevenLawson.BukkitTelnet; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import org.apache.commons.io.FileUtils; +import org.bukkit.configuration.file.YamlConfiguration; + +public class BT_Config +{ + public static final String CONFIG_FILENAME = "config.yml"; + private final SimpleConfigEntries configEntries = new SimpleConfigEntries(); + + private BT_Config() + { + try + { + final File configFile = getConfigFile(); + if (configFile != null) + { + copyDefaultConfig(configFile); + } + + load(); + } + catch (Exception ex) + { + BT_Log.severe(ex); + } + } + + public final void load() + { + try + { + final YamlConfiguration config = new YamlConfiguration(); + + final File configFile = getConfigFile(); + if (configFile == null) + { + return; + } + + config.load(configFile); + + this.configEntries.setPort(config.getInt("port", this.configEntries.getPort())); + this.configEntries.setAddress(config.getString("address", this.configEntries.getAddress())); + this.configEntries.setPassword(config.getString("password", this.configEntries.getPassword())); + + final Map> adminMap = this.configEntries.getAdmins(); + adminMap.clear(); + + final Set adminEntries = config.getConfigurationSection("admins").getKeys(false); + for (String adminName : adminEntries) + { + adminMap.put(adminName, config.getStringList("admins." + adminName)); + } + } + catch (Exception ex) + { + BT_Log.severe(ex); + } + } + + private static void copyDefaultConfig(final File targetFile) + { + if (targetFile.exists()) + { + return; + } + + BT_Log.info("Installing default configuration file template: " + targetFile.getPath()); + + try + { + final InputStream defaultConfig = getDefaultConfig(); + FileUtils.copyInputStreamToFile(defaultConfig, targetFile); + defaultConfig.close(); + } + catch (Exception ex) + { + BT_Log.severe(ex); + } + } + + private File getConfigFile() + { + try + { + return new File(BukkitTelnet.getPlugin().getDataFolder(), CONFIG_FILENAME); + } + catch (Exception ex) + { + BT_Log.severe(ex); + } + return null; + } + + private static InputStream getDefaultConfig() throws IOException + { + try + { + return BukkitTelnet.getPlugin().getResource(CONFIG_FILENAME); + } + catch (Exception ex) + { + BT_Log.severe(ex); + } + throw new IOException(); + } + + public SimpleConfigEntries getConfigEntries() + { + return configEntries; + } + + public static class SimpleConfigEntries + { + private int _port = 8765; + private String _address = null; + private String _password = null; + private final Map> _admins = new HashMap>(); + + private SimpleConfigEntries() + { + } + + public int getPort() + { + return _port; + } + + public void setPort(final int port) + { + this._port = port; + } + + public String getAddress() + { + return _address; + } + + public void setAddress(String address) + { + if (address == null || (address = address.trim()).isEmpty()) + { + address = null; + } + this._address = address; + } + + public String getPassword() + { + return _password; + } + + public void setPassword(String password) + { + if (password == null || (password = password.trim()).isEmpty()) + { + password = null; + } + this._password = password; + } + + public Map> getAdmins() + { + return _admins; + } + } + + public static BT_Config getInstance() + { + return BT_ConfigHolder.INSTANCE; + } + + private static class BT_ConfigHolder + { + private static final BT_Config INSTANCE = new BT_Config(); + } +} diff --git a/src/me/StevenLawson/BukkitTelnet/BT_Handler.java b/src/me/StevenLawson/BukkitTelnet/BT_Handler.java new file mode 100644 index 0000000..a60189d --- /dev/null +++ b/src/me/StevenLawson/BukkitTelnet/BT_Handler.java @@ -0,0 +1,62 @@ +package me.StevenLawson.BukkitTelnet; + +import java.util.logging.Formatter; +import java.util.logging.Handler; +import java.util.logging.LogRecord; +import org.bukkit.ChatColor; + +public abstract class BT_Handler extends Handler +{ + private Formatter formatter; + + public abstract void writeOut(String string); + + @Override + public final void publish(LogRecord record) + { + if (record == null) + { + return; + } + + String message = record.getMessage(); + + if (this.formatter == null) + { + this.formatter = getFormatter(); + } + + if (this.formatter != null) + { + message = this.formatter.formatMessage(record); + } + + message = ChatColor.stripColor(message); + + writeOut(message + "\r\n:"); + } + + @Override + public final Formatter getFormatter() + { + if (this.formatter == null) + { + this.formatter = super.getFormatter(); + + Handler[] handlers = org.bukkit.Bukkit.getLogger().getHandlers(); + for (Handler handler : handlers) + { + if (handler.getClass().getName().startsWith("org.bukkit.craftbukkit")) + { + Formatter _formatter = handler.getFormatter(); + if (_formatter != null) + { + this.formatter = _formatter; + break; + } + } + } + } + return this.formatter; + } +} diff --git a/src/me/StevenLawson/BukkitTelnet/BT_Log.java b/src/me/StevenLawson/BukkitTelnet/BT_Log.java new file mode 100644 index 0000000..e49335f --- /dev/null +++ b/src/me/StevenLawson/BukkitTelnet/BT_Log.java @@ -0,0 +1,84 @@ +package me.StevenLawson.BukkitTelnet; + +import java.util.logging.Level; +import java.util.logging.Logger; +import org.bukkit.Bukkit; + +public final class BT_Log +{ + private static final Logger LOGGER = Bukkit.getLogger(); + + private BT_Log() + { + throw new AssertionError(); + } + + // Level.INFO: + public static void info(String message) + { + info(message, false); + } + + public static void info(String message, Boolean raw) + { + log(Level.INFO, message, raw); + } + + public static void info(Throwable ex) + { + log(Level.INFO, ex); + } + + // Level.WARNING: + public static void warning(String message) + { + info(message, false); + } + + public static void warning(String message, Boolean raw) + { + log(Level.WARNING, message, raw); + } + + public static void warning(Throwable ex) + { + log(Level.WARNING, ex); + } + + // Level.SEVERE: + public static void severe(String message) + { + info(message, false); + } + + public static void severe(String message, Boolean raw) + { + log(Level.SEVERE, message, raw); + } + + public static void severe(Throwable ex) + { + log(Level.SEVERE, ex); + } + + // Utility + private static void log(Level level, String message, boolean raw) + { + if (!raw) + { + message = "[BukkitTelnet] " + message; + } + + getLogger().log(level, message); + } + + private static void log(Level level, Throwable throwable) + { + getLogger().log(level, null, throwable); + } + + public static Logger getLogger() + { + return LOGGER; + } +} diff --git a/src/me/StevenLawson/BukkitTelnet/BT_TelnetServer.java b/src/me/StevenLawson/BukkitTelnet/BT_TelnetServer.java new file mode 100644 index 0000000..294aa55 --- /dev/null +++ b/src/me/StevenLawson/BukkitTelnet/BT_TelnetServer.java @@ -0,0 +1,168 @@ +package me.StevenLawson.BukkitTelnet; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.logging.Level; + +public class BT_TelnetServer +{ + private String password; + private ServerListener serverListener = null; + + private BT_TelnetServer() + { + } + + public void startServer() + { + this.stopServer(); + + final BT_Config.SimpleConfigEntries configEntries = BT_Config.getInstance().getConfigEntries(); + + final String address = configEntries.getAddress(); + final int port = configEntries.getPort(); + + this.password = configEntries.getPassword(); + + if (this.password == null) + { + BT_Log.warning("Telnet password is not defined in config file. Can't start server."); + return; + } + + InetAddress hostAddress = null; + + if (address != null) + { + try + { + hostAddress = InetAddress.getByName(address); + } + catch (UnknownHostException ex) + { + BT_Log.severe(ex); + } + } + + ServerSocket serverSocket = null; + + try + { + if (hostAddress == null) + { + serverSocket = new java.net.ServerSocket(port); + } + else + { + serverSocket = new java.net.ServerSocket(port, 50, hostAddress); + } + + String hostIP = serverSocket.getInetAddress().getHostAddress(); + if (hostIP.equals("0.0.0.0")) + { + hostIP = "*"; + } + + BT_Log.info("Server started on " + hostIP + ":" + serverSocket.getLocalPort()); + } + catch (IOException ex) + { + BT_Log.getLogger().log(Level.SEVERE, "Cant bind to " + (hostAddress == null ? "*" : hostAddress) + ":" + port, ex); + } + + if (serverSocket != null) + { + (this.serverListener = new ServerListener(serverSocket)).start(); + } + } + + public void stopServer() + { + if (this.serverListener != null) + { + this.serverListener.stopServer(); + } + } + + public String getPassword() + { + return this.password; + } + + private static class ServerListener extends Thread + { + private final ServerSocket serverSocket; + private final List clientSessions = Collections.synchronizedList(new ArrayList()); + + public ServerListener(ServerSocket serverSocket) + { + this.serverSocket = serverSocket; + } + + @Override + public void run() + { + try + { + while (!this.serverSocket.isClosed()) + { + synchronized (clientSessions) + { + final BT_ClientSession clientSession = new BT_ClientSession(this.serverSocket.accept()); + clientSessions.add(clientSession); + clientSession.start(); + + final Iterator it = clientSessions.iterator(); + while (it.hasNext()) + { + if (!it.next().isConnected()) + { + it.remove(); + } + } + } + } + } + catch (IOException ex) + { + } + } + + public void stopServer() + { + try + { + this.serverSocket.close(); + } + catch (IOException ex) + { + } + + synchronized (clientSessions) + { + final Iterator it = clientSessions.iterator(); + while (it.hasNext()) + { + it.next().terminateSession(); + it.remove(); + } + } + } + } + + public static BT_TelnetServer getInstance() + { + return BT_TelnetServerHolder.INSTANCE; + } + + private static class BT_TelnetServerHolder + { + private static final BT_TelnetServer INSTANCE = new BT_TelnetServer(); + } +} diff --git a/src/me/StevenLawson/BukkitTelnet/BukkitTelnet.java b/src/me/StevenLawson/BukkitTelnet/BukkitTelnet.java new file mode 100644 index 0000000..c0c4ca4 --- /dev/null +++ b/src/me/StevenLawson/BukkitTelnet/BukkitTelnet.java @@ -0,0 +1,66 @@ +package me.StevenLawson.BukkitTelnet; + +import org.bukkit.plugin.java.JavaPlugin; + +public class BukkitTelnet extends JavaPlugin +{ + private static BukkitTelnet plugin = null; + + @Override + public void onLoad() + { + plugin = this; + } + + @Override + public void onEnable() + { + BT_Log.info("Plugin enabled."); + + BT_Config.getInstance().load(); + +// BT_Config.SimpleConfigEntries configEntries = BT_Config.getInstance().getConfigEntries(); +// +// String address = configEntries.getAddress(); +// String password = configEntries.getPassword(); +// int port = configEntries.getPort(); +// +// BT_Log.info("Config loaded - " + address + ":" + port + " - PW: " + password + " - Admins:"); +// +// Iterator>> it = configEntries.getAdmins().entrySet().iterator(); +// while (it.hasNext()) +// { +// Map.Entry> entry = it.next(); +// String name = entry.getKey(); +// List ips = entry.getValue(); +// BT_Log.info("Admin: " + name + " - IPs: " + StringUtils.join(ips, ",")); +// } + + BT_TelnetServer.getInstance().startServer(); + } + + @Override + public void onDisable() + { + BT_Log.info("Plugin disabled."); + + BT_TelnetServer.getInstance().stopServer(); + } + + public static BukkitTelnet getPlugin() throws PluginNotLoadedException + { + if (plugin == null) + { + throw new PluginNotLoadedException(); + } + + return plugin; + } + + public static class PluginNotLoadedException extends Exception + { + public PluginNotLoadedException() + { + } + } +} diff --git a/src/me/StevenLawson/BukkitTelnet/TelnetPreLoginEvent.java b/src/me/StevenLawson/BukkitTelnet/TelnetPreLoginEvent.java new file mode 100644 index 0000000..df26ec5 --- /dev/null +++ b/src/me/StevenLawson/BukkitTelnet/TelnetPreLoginEvent.java @@ -0,0 +1,65 @@ +package me.StevenLawson.BukkitTelnet; + +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; + +public class TelnetPreLoginEvent extends Event implements Cancellable +{ + private static final HandlerList handlers = new HandlerList(); + // + private final String ip; + private final String name; + private boolean bypassPassword; + private boolean cancelled; + + public TelnetPreLoginEvent(String ip, String name, boolean bypassPassword) + { + this.ip = ip; + this.name = name; + this.bypassPassword = bypassPassword; + } + + @Override + public HandlerList getHandlers() + { + return handlers; + } + + public static HandlerList getHandlerList() + { + return handlers; + } + + @Override + public boolean isCancelled() + { + return cancelled; + } + + @Override + public void setCancelled(boolean cancel) + { + cancelled = cancel; + } + + public String getIp() + { + return ip; + } + + public String getName() + { + return name; + } + + public boolean canBypassPassword() + { + return bypassPassword; + } + + public void setBypassPassword(boolean bypassPassword) + { + this.bypassPassword = bypassPassword; + } +} diff --git a/src/plugin.yml b/src/plugin.yml new file mode 100644 index 0000000..6c54610 --- /dev/null +++ b/src/plugin.yml @@ -0,0 +1,5 @@ +name: BukkitTelnet +main: me.StevenLawson.BukkitTelnet.BukkitTelnet +version: 3.0 +description: Telnet console access plugin. +author: bekvon, Madgeek1450 / StevenLawson