summaryrefslogtreecommitdiffstats
path: root/EssentialsUpdate/src/com/earth2me
diff options
context:
space:
mode:
Diffstat (limited to 'EssentialsUpdate/src/com/earth2me')
-rw-r--r--EssentialsUpdate/src/com/earth2me/essentials/update/EssentialsHelp.java479
-rw-r--r--EssentialsUpdate/src/com/earth2me/essentials/update/EssentialsUpdate.java66
-rw-r--r--EssentialsUpdate/src/com/earth2me/essentials/update/GetFile.java112
-rw-r--r--EssentialsUpdate/src/com/earth2me/essentials/update/IrcBot.java188
-rw-r--r--EssentialsUpdate/src/com/earth2me/essentials/update/ModuleInfo.java35
-rw-r--r--EssentialsUpdate/src/com/earth2me/essentials/update/PastieUpload.java40
-rw-r--r--EssentialsUpdate/src/com/earth2me/essentials/update/PostToUrl.java66
-rw-r--r--EssentialsUpdate/src/com/earth2me/essentials/update/UpdateCheck.java203
-rw-r--r--EssentialsUpdate/src/com/earth2me/essentials/update/UpdateFile.java204
-rw-r--r--EssentialsUpdate/src/com/earth2me/essentials/update/UpdateProcess.java128
-rw-r--r--EssentialsUpdate/src/com/earth2me/essentials/update/UpdatesDownloader.java19
-rw-r--r--EssentialsUpdate/src/com/earth2me/essentials/update/Version.java173
-rw-r--r--EssentialsUpdate/src/com/earth2me/essentials/update/VersionInfo.java48
-rw-r--r--EssentialsUpdate/src/com/earth2me/essentials/update/states/Modules.java7
14 files changed, 1768 insertions, 0 deletions
diff --git a/EssentialsUpdate/src/com/earth2me/essentials/update/EssentialsHelp.java b/EssentialsUpdate/src/com/earth2me/essentials/update/EssentialsHelp.java
new file mode 100644
index 000000000..3caa22cc3
--- /dev/null
+++ b/EssentialsUpdate/src/com/earth2me/essentials/update/EssentialsHelp.java
@@ -0,0 +1,479 @@
+package com.earth2me.essentials.update;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.nio.charset.Charset;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import org.bukkit.Bukkit;
+import org.bukkit.Server;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+import org.bukkit.event.Event.Priority;
+import org.bukkit.event.Event.Type;
+import org.bukkit.event.player.PlayerChatEvent;
+import org.bukkit.event.player.PlayerListener;
+import org.bukkit.event.player.PlayerQuitEvent;
+import org.bukkit.plugin.Plugin;
+import org.bukkit.plugin.PluginManager;
+import org.jibble.pircbot.User;
+
+
+public class EssentialsHelp extends PlayerListener
+{
+ private transient Player chatUser;
+ private final transient Server server;
+ private final transient Plugin plugin;
+ private final static Charset UTF8 = Charset.forName("utf-8");
+ private transient IrcBot ircBot;
+
+ public EssentialsHelp(final Plugin plugin)
+ {
+ super();
+ this.plugin = plugin;
+ this.server = plugin.getServer();
+ }
+
+ public void registerEvents()
+ {
+ final PluginManager pluginManager = server.getPluginManager();
+ pluginManager.registerEvent(Type.PLAYER_QUIT, this, Priority.Low, plugin);
+ pluginManager.registerEvent(Type.PLAYER_CHAT, this, Priority.Low, plugin);
+ }
+
+ public void onCommand(CommandSender sender)
+ {
+ if (sender instanceof Player && sender.hasPermission("essentials.helpchat"))
+ {
+ if (chatUser == null)
+ {
+ chatUser = (Player)sender;
+ ircBot = null;
+ sender.sendMessage("You will be connected to the Essentials Help Chat.");
+ sender.sendMessage("All your chat messages will be forwarded to the channel. You can't chat with other players on your server while in help chat, but you can use commands.");
+ sender.sendMessage("Please be patient, if noone is available, check back later.");
+ sender.sendMessage("Type !help to get a list of all commands.");
+ sender.sendMessage("Type !quit to leave the channel.");
+ sender.sendMessage("Do you want to join the channel now? (yes/no)");
+ }
+ if (!chatUser.equals(sender))
+ {
+ sender.sendMessage("The player " + chatUser.getDisplayName() + " is already using the essentialshelp.");
+ }
+ }
+ else
+ {
+ sender.sendMessage("Please run the command as op from in game.");
+ }
+ }
+
+ public void onDisable()
+ {
+ if ( ircBot != null)
+ {
+ ircBot.quit();
+ ircBot = null;
+ }
+ }
+
+ private boolean sendChatMessage(final Player player, final String message)
+ {
+ final String messageCleaned = message.trim();
+ if (messageCleaned.isEmpty())
+ {
+ return false;
+ }
+ if (ircBot == null)
+ {
+ if (messageCleaned.equalsIgnoreCase("yes"))
+ {
+ player.sendMessage("Connecting...");
+ connectToIRC(player);
+ return true;
+ }
+ if (messageCleaned.equalsIgnoreCase("no") || message.equalsIgnoreCase("!quit"))
+ {
+ chatUser = null;
+ return true;
+ }
+ return false;
+ }
+ else
+ {
+ if (ircBot.isKicked()) {
+ chatUser = null;
+ ircBot.quit();
+ ircBot = null;
+ return false;
+ }
+ final String lowMessage = messageCleaned.toLowerCase();
+ if (lowMessage.startsWith("!quit"))
+ {
+ chatUser = null;
+ if (ircBot != null) {
+ ircBot.quit();
+ ircBot = null;
+ }
+ player.sendMessage("Connection closed.");
+ return true;
+ }
+ if (!ircBot.isConnected() || ircBot.getChannels().length == 0)
+ {
+ return false;
+ }
+ if (lowMessage.startsWith("!list"))
+ {
+ final User[] members = ircBot.getUsers();
+ final StringBuilder sb = new StringBuilder();
+ for (User user : members)
+ {
+ if (sb.length() > 0)
+ {
+ sb.append("§f, ");
+ }
+ if (user.isOp() || user.hasVoice())
+ {
+ sb.append("§6");
+ }
+ else
+ {
+ sb.append("§7");
+ }
+ sb.append(user.getPrefix()).append(user.getNick());
+ }
+ player.sendMessage(sb.toString());
+ return true;
+ }
+ if (lowMessage.startsWith("!help"))
+ {
+ player.sendMessage("Commands: (Note: Files send to the chat will be public viewable.)");
+ player.sendMessage("!errors - Send the last server errors to the chat.");
+ player.sendMessage("!startup - Send the last startup messages to the chat.");
+ player.sendMessage("!config - Sends your Essentials config to the chat.");
+ player.sendMessage("!list - List all players in chat.");
+ player.sendMessage("!quit - Leave chat.");
+ return true;
+ }
+ if (lowMessage.startsWith("!errors"))
+ {
+ sendErrors();
+ return true;
+ }
+ if (lowMessage.startsWith("!startup"))
+ {
+ sendStartup();
+ return true;
+ }
+ if (lowMessage.startsWith("!config"))
+ {
+ sendConfig();
+ return true;
+ }
+ ircBot.sendMessage(messageCleaned);
+ chatUser.sendMessage("§6" + ircBot.getNick() + ": §7" + messageCleaned);
+ return true;
+ }
+ }
+
+ private String buildIrcName()
+ {
+ final StringBuilder nameBuilder = new StringBuilder();
+ nameBuilder.append(chatUser.getName());
+
+ final Matcher versionMatch = Pattern.compile("git-Bukkit-([0-9]+).([0-9]+).([0-9]+)-[0-9]+-[0-9a-z]+-b([0-9]+)jnks.*").matcher(server.getVersion());
+ if (versionMatch.matches())
+ {
+ nameBuilder.append(" CB");
+ nameBuilder.append(versionMatch.group(4));
+ }
+
+ final Plugin essentials = server.getPluginManager().getPlugin("Essentials");
+ if (essentials != null)
+ {
+ nameBuilder.append(" ESS");
+ nameBuilder.append(essentials.getDescription().getVersion());
+ }
+
+ final Plugin groupManager = server.getPluginManager().getPlugin("GroupManager");
+ if (groupManager != null)
+ {
+ nameBuilder.append(" GM");
+ if (!groupManager.isEnabled())
+ {
+ nameBuilder.append('!');
+ }
+ }
+
+ final Plugin pex = server.getPluginManager().getPlugin("PermissionsEx");
+ if (pex != null)
+ {
+ nameBuilder.append(" PEX");
+ if (!pex.isEnabled())
+ {
+ nameBuilder.append('!');
+ }
+ nameBuilder.append(pex.getDescription().getVersion());
+ }
+
+ final Plugin pb = server.getPluginManager().getPlugin("PermissionsBukkit");
+ if (pb != null)
+ {
+ nameBuilder.append(" PB");
+ if (!pb.isEnabled())
+ {
+ nameBuilder.append('!');
+ }
+ nameBuilder.append(pb.getDescription().getVersion());
+ }
+
+ final Plugin bp = server.getPluginManager().getPlugin("bPermissions");
+ if (bp != null)
+ {
+ nameBuilder.append(" BP");
+ if (!bp.isEnabled())
+ {
+ nameBuilder.append('!');
+ }
+ nameBuilder.append(bp.getDescription().getVersion());
+ }
+
+ final Plugin perm = server.getPluginManager().getPlugin("Permissions");
+ if (perm != null)
+ {
+ nameBuilder.append(" P");
+ if (!perm.isEnabled())
+ {
+ nameBuilder.append('!');
+ }
+ nameBuilder.append(perm.getDescription().getVersion());
+ }
+
+ return nameBuilder.toString();
+ }
+
+ private void connectToIRC(final Player player)
+ {
+ ircBot = new IrcBot(player, "Ess_" + player.getName(), buildIrcName());
+ }
+
+ private void sendErrors()
+ {
+ BufferedReader page = null;
+ try
+ {
+ File bukkitFolder = plugin.getDataFolder().getAbsoluteFile().getParentFile().getParentFile();
+ if (bukkitFolder == null || !bukkitFolder.exists())
+ {
+ chatUser.sendMessage("Bukkit folder not found.");
+ return;
+ }
+ File logFile = new File(bukkitFolder, "server.log");
+ if (!logFile.exists())
+ {
+ chatUser.sendMessage("Server log not found.");
+ return;
+ }
+ FileInputStream fis = new FileInputStream(logFile);
+ if (logFile.length() > 1000000)
+ {
+ fis.skip(logFile.length() - 1000000);
+ }
+ page = new BufferedReader(new InputStreamReader(fis));
+ final StringBuilder input = new StringBuilder();
+ String line;
+ Pattern pattern = Pattern.compile("^[0-9 :-]+\\[INFO\\].*");
+ while ((line = page.readLine()) != null)
+ {
+ if (!pattern.matcher(line).matches())
+ {
+ input.append(line).append("\n");
+ }
+ }
+ if (input.length() > 10000)
+ {
+ input.delete(0, input.length() - 10000);
+ }
+ final PastieUpload pastie = new PastieUpload();
+ final String url = pastie.send(input.toString());
+ String message = "Errors: " + url;
+ chatUser.sendMessage("§6" + ircBot.getNick() + ": §7" + message);
+ ircBot.sendMessage(message);
+ }
+ catch (IOException ex)
+ {
+ Bukkit.getLogger().log(Level.SEVERE, null, ex);
+ chatUser.sendMessage(ex.getMessage());
+ }
+ finally
+ {
+ try
+ {
+ if (page != null)
+ {
+ page.close();
+ }
+ }
+ catch (IOException ex)
+ {
+ Logger.getLogger(EssentialsHelp.class.getName()).log(Level.SEVERE, null, ex);
+ }
+ }
+ }
+
+ private void sendStartup()
+ {
+ BufferedReader page = null;
+ try
+ {
+ File bukkitFolder = plugin.getDataFolder().getAbsoluteFile().getParentFile().getParentFile();
+ if (bukkitFolder == null || !bukkitFolder.exists())
+ {
+ chatUser.sendMessage("Bukkit folder not found.");
+ return;
+ }
+ File logFile = new File(bukkitFolder, "server.log");
+ if (!logFile.exists())
+ {
+ chatUser.sendMessage("Server log not found.");
+ return;
+ }
+ FileInputStream fis = new FileInputStream(logFile);
+ if (logFile.length() > 1000000)
+ {
+ fis.skip(logFile.length() - 1000000);
+ }
+ page = new BufferedReader(new InputStreamReader(fis));
+ final StringBuilder input = new StringBuilder();
+ String line;
+ Pattern patternStart = Pattern.compile("^[0-9 :-]+\\[INFO\\] Starting minecraft server version.*");
+ Pattern patternEnd = Pattern.compile("^[0-9 :-]+\\[INFO\\] Done \\([0-9.,]+s\\)! For help, type \"help\".*");
+ boolean log = false;
+ while ((line = page.readLine()) != null)
+ {
+ if (patternStart.matcher(line).matches())
+ {
+ if (input.length() > 0)
+ {
+ input.delete(0, input.length());
+ }
+ log = true;
+ }
+ if (log)
+ {
+ input.append(line).append("\n");
+ }
+ if (patternEnd.matcher(line).matches())
+ {
+ log = false;
+ }
+ }
+ if (input.length() > 10000)
+ {
+ input.delete(0, input.length() - 10000);
+ }
+ final PastieUpload pastie = new PastieUpload();
+ final String url = pastie.send(input.toString());
+ String message = "Startup: " + url;
+ chatUser.sendMessage("§6" + ircBot.getNick() + ": §7" + message);
+ ircBot.sendMessage(message);
+ }
+ catch (IOException ex)
+ {
+ Bukkit.getLogger().log(Level.SEVERE, null, ex);
+ chatUser.sendMessage(ex.getMessage());
+ }
+ finally
+ {
+ try
+ {
+ if (page != null)
+ {
+ page.close();
+ }
+ }
+ catch (IOException ex)
+ {
+ Logger.getLogger(EssentialsHelp.class.getName()).log(Level.SEVERE, null, ex);
+ }
+ }
+ }
+
+ private void sendConfig()
+ {
+ BufferedReader page = null;
+ try
+ {
+ File configFolder = new File(plugin.getDataFolder().getParentFile(), "Essentials");
+ if (!configFolder.exists())
+ {
+ chatUser.sendMessage("Essentials plugin folder not found.");
+ return;
+ }
+ File configFile = new File(configFolder, "config.yml");
+ if (!configFile.exists())
+ {
+ chatUser.sendMessage("Essentials config file not found.");
+ return;
+ }
+ page = new BufferedReader(new InputStreamReader(new FileInputStream(configFile), UTF8));
+ final StringBuilder input = new StringBuilder();
+ String line;
+ while ((line = page.readLine()) != null)
+ {
+ input.append(line).append("\n");
+ }
+ final PastieUpload pastie = new PastieUpload();
+ final String url = pastie.send(input.toString());
+ String message = "Essentials config.yml: " + url;
+ chatUser.sendMessage("§6" + ircBot.getNick() + ": §7" + message);
+ ircBot.sendMessage(message);
+
+ }
+ catch (IOException ex)
+ {
+ Bukkit.getLogger().log(Level.SEVERE, null, ex);
+ chatUser.sendMessage(ex.getMessage());
+ }
+ finally
+ {
+ try
+ {
+ if (page != null)
+ {
+ page.close();
+ }
+ }
+ catch (IOException ex)
+ {
+ Logger.getLogger(EssentialsHelp.class.getName()).log(Level.SEVERE, null, ex);
+ }
+ }
+ }
+
+ @Override
+ public void onPlayerChat(PlayerChatEvent event)
+ {
+ if (event.getPlayer() == chatUser)
+ {
+ boolean success = sendChatMessage(event.getPlayer(), event.getMessage());
+ event.setCancelled(success);
+ return;
+ }
+ }
+
+ @Override
+ public void onPlayerQuit(PlayerQuitEvent event)
+ {
+ chatUser = null;
+ if (ircBot != null) {
+ ircBot.quit();
+ ircBot = null;
+ }
+ return;
+ }
+}
diff --git a/EssentialsUpdate/src/com/earth2me/essentials/update/EssentialsUpdate.java b/EssentialsUpdate/src/com/earth2me/essentials/update/EssentialsUpdate.java
new file mode 100644
index 000000000..d4ee6c0fc
--- /dev/null
+++ b/EssentialsUpdate/src/com/earth2me/essentials/update/EssentialsUpdate.java
@@ -0,0 +1,66 @@
+package com.earth2me.essentials.update;
+
+import com.earth2me.essentials.update.UpdateCheck.CheckResult;
+import org.bukkit.Bukkit;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandSender;
+import org.bukkit.plugin.java.JavaPlugin;
+
+
+public class EssentialsUpdate extends JavaPlugin
+{
+ private transient EssentialsHelp essentialsHelp;
+ private transient UpdateProcess updateProcess;
+
+ @Override
+ public void onEnable()
+ {
+ if (!getDataFolder().exists() && !getDataFolder().mkdirs() ) {
+ Bukkit.getLogger().severe("Could not create data folder:"+getDataFolder().getPath());
+ }
+ essentialsHelp = new EssentialsHelp(this);
+ essentialsHelp.registerEvents();
+
+ final UpdateCheck updateCheck = new UpdateCheck(this);
+ updateProcess = new UpdateProcess(this, updateCheck);
+ updateProcess.registerEvents();
+
+ Bukkit.getLogger().info("EssentialsUpdate " + getDescription().getVersion() + " loaded.");
+
+ if (updateCheck.isEssentialsInstalled())
+ {
+ updateCheck.checkForUpdates();
+ final Version myVersion = new Version(getDescription().getVersion());
+ if (updateCheck.getResult() == CheckResult.NEW_ESS && myVersion.equals(updateCheck.getNewVersion()))
+ {
+ Bukkit.getLogger().info("Versions of EssentialsUpdate and Essentials do not match. Starting automatic update.");
+ updateProcess.doAutomaticUpdate();
+ }
+ updateCheck.scheduleUpdateTask();
+ }
+ else
+ {
+ Bukkit.getLogger().info("Essentials is ready for installation. Join the game and follow the instructions.");
+ }
+ }
+
+ @Override
+ public void onDisable()
+ {
+ essentialsHelp.onDisable();
+ }
+
+ @Override
+ public boolean onCommand(final CommandSender sender, final Command command, final String label, final String[] args)
+ {
+ if (command.getName().equalsIgnoreCase("essentialsupdate"))
+ {
+ updateProcess.onCommand(sender);
+ }
+ if (command.getName().equalsIgnoreCase("essentialshelp"))
+ {
+ essentialsHelp.onCommand(sender);
+ }
+ return true;
+ }
+}
diff --git a/EssentialsUpdate/src/com/earth2me/essentials/update/GetFile.java b/EssentialsUpdate/src/com/earth2me/essentials/update/GetFile.java
new file mode 100644
index 000000000..888950f34
--- /dev/null
+++ b/EssentialsUpdate/src/com/earth2me/essentials/update/GetFile.java
@@ -0,0 +1,112 @@
+package com.earth2me.essentials.update;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.logging.Logger;
+
+
+public class GetFile
+{
+ private transient URLConnection connection;
+ private transient MessageDigest digest;
+
+ public GetFile(final String urlString) throws MalformedURLException, IOException
+ {
+ final URL url = new URL(urlString);
+ this.connection = url.openConnection();
+ this.connection.setConnectTimeout(1000);
+ this.connection.setReadTimeout(5000);
+ this.connection.setUseCaches(false);
+ this.connection.connect();
+ final int respCode = ((HttpURLConnection)this.connection).getResponseCode();
+ if (respCode >= 300 && respCode < 400 && this.connection.getHeaderField("Location") != null)
+ {
+ connection.getInputStream().close();
+ final URL redirect = new URL(this.connection.getHeaderField("Location"));
+ this.connection = redirect.openConnection();
+ this.connection.setConnectTimeout(1000);
+ this.connection.setReadTimeout(5000);
+ this.connection.setUseCaches(false);
+ this.connection.connect();
+ }
+ }
+
+ public void saveTo(final File file) throws IOException
+ {
+ try
+ {
+ saveTo(file, null);
+ }
+ catch (NoSuchAlgorithmException ex)
+ {
+ // Ignore because the code is never called
+ }
+ }
+
+ public void saveTo(final File file, final String key) throws IOException, NoSuchAlgorithmException
+ {
+ if (key != null)
+ {
+ digest = MessageDigest.getInstance("SHA256");
+ }
+ final byte[] buffer = new byte[1024 * 8];
+ boolean brokenFile = false;
+ final BufferedInputStream input = new BufferedInputStream(connection.getInputStream());
+ try
+ {
+ final BufferedOutputStream output = new BufferedOutputStream(new FileOutputStream(file));
+ try
+ {
+ int length;
+ do
+ {
+ length = input.read(buffer);
+ if (length >= 0)
+ {
+ if (key != null)
+ {
+ digest.update(buffer, 0, length);
+ }
+ output.write(buffer, 0, length);
+ }
+ }
+ while (length >= 0);
+ if (key != null)
+ {
+ final byte[] checksum = digest.digest();
+ final String checksumString = new BigInteger(checksum).toString(36);
+ if (!checksumString.equals(key))
+ {
+ brokenFile = true;
+ }
+ }
+ }
+ finally
+ {
+ output.close();
+ }
+ if (brokenFile && !file.delete())
+ {
+ Logger.getLogger("Minecraft").severe("Could not delete file " + file.getPath());
+ }
+ }
+ finally
+ {
+ input.close();
+ }
+ if (brokenFile)
+ {
+ throw new IOException("Checksum check failed.");
+ }
+ }
+}
diff --git a/EssentialsUpdate/src/com/earth2me/essentials/update/IrcBot.java b/EssentialsUpdate/src/com/earth2me/essentials/update/IrcBot.java
new file mode 100644
index 000000000..a314df15d
--- /dev/null
+++ b/EssentialsUpdate/src/com/earth2me/essentials/update/IrcBot.java
@@ -0,0 +1,188 @@
+package com.earth2me.essentials.update;
+
+import java.io.IOException;
+import java.util.logging.Level;
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
+import org.jibble.pircbot.Colors;
+import org.jibble.pircbot.IrcException;
+import org.jibble.pircbot.PircBot;
+import org.jibble.pircbot.User;
+
+
+public class IrcBot extends PircBot
+{
+ private static final String CHANNEL = "#essentials";
+ private static final int PORT = 6667;
+ private static final String SERVER = "irc.esper.net";
+ private transient boolean reconnect = true;
+ private final transient Player player;
+ private transient boolean kicked = false;
+
+ public IrcBot(final Player player, final String nickName, final String versionString)
+ {
+ super();
+ this.player = player;
+ setName(nickName);
+ setLogin("esshelp");
+ setVersion(versionString);
+ connect();
+ joinChannel(CHANNEL);
+ }
+
+ private void connect()
+ {
+ try
+ {
+ connect(SERVER, PORT);
+ return;
+ }
+ catch (IOException ex)
+ {
+ Bukkit.getLogger().log(Level.SEVERE, ex.getMessage(), ex);
+ }
+ catch (IrcException ex)
+ {
+ Bukkit.getLogger().log(Level.SEVERE, ex.getMessage(), ex);
+ }
+ }
+
+ public void quit()
+ {
+ reconnect = false;
+ disconnect();
+ }
+
+ @Override
+ protected void onConnect()
+ {
+ reconnect = true;
+ }
+
+ @Override
+ protected void onDisconnect()
+ {
+ if (reconnect)
+ {
+ int tries = 10;
+ while (!isConnected())
+ {
+ try
+ {
+ tries--;
+ reconnect();
+ }
+ catch (Exception e)
+ {
+ Bukkit.getLogger().log(Level.WARNING, e.getMessage(), e);
+ try
+ {
+ Thread.sleep(10000);
+ }
+ catch (InterruptedException ex)
+ {
+ Bukkit.getLogger().log(Level.WARNING, e.getMessage(), e);
+ }
+ }
+ if (tries <= 0)
+ {
+ player.sendMessage("Connection lost to server.");
+ kicked = true;
+ break;
+ }
+ }
+ }
+ }
+
+ @Override
+ protected void onKick(String channel, String kickerNick, String kickerLogin, String kickerHostname, String recipientNick, String reason)
+ {
+ if (recipientNick.equals(getNick()))
+ {
+ player.sendMessage("You have been kicked from the channel: " + reason);
+ quit();
+ kicked = true;
+ }
+ }
+
+ public boolean isKicked()
+ {
+ return kicked;
+ }
+
+ @Override
+ protected void onMessage(String channel, String sender, String login, String hostname, String message)
+ {
+ player.sendMessage(formatChatMessage(sender, message, false));
+ }
+
+ @Override
+ protected void onAction(String sender, String login, String hostname, String target, String action)
+ {
+ player.sendMessage(formatChatMessage(sender, action, true));
+ }
+
+ @Override
+ protected void onNotice(String sourceNick, String sourceLogin, String sourceHostname, String target, String notice)
+ {
+ player.sendMessage(formatChatMessage(sourceNick, notice, false));
+ }
+
+ @Override
+ protected void onTopic(String channel, String topic, String setBy, long date, boolean changed)
+ {
+ player.sendMessage(formatChatMessage(channel, topic, false));
+ }
+
+ public String formatChatMessage(final String nick, final String message, final boolean action)
+ {
+ final StringBuilder builder = new StringBuilder();
+ builder.append("§6");
+ if (action)
+ {
+ builder.append('*');
+ }
+ builder.append(nick);
+ if (!action)
+ {
+ builder.append(':');
+ }
+ builder.append(" §7");
+ builder.append(replaceColors(message));
+ return builder.toString();
+ }
+
+ private String replaceColors(final String message)
+ {
+ String m = Colors.removeFormatting(message);
+ m = m.replaceAll("\u000310(,(0?[0-9]|1[0-5]))?", "§b");
+ m = m.replaceAll("\u000311(,(0?[0-9]|1[0-5]))?", "§f");
+ m = m.replaceAll("\u000312(,(0?[0-9]|1[0-5]))?", "§9");
+ m = m.replaceAll("\u000313(,(0?[0-9]|1[0-5]))?", "§d");
+ m = m.replaceAll("\u000314(,(0?[0-9]|1[0-5]))?", "§8");
+ m = m.replaceAll("\u000315(,(0?[0-9]|1[0-5]))?", "§7");
+ m = m.replaceAll("\u00030?1(,(0?[0-9]|1[0-5]))?", "§0");
+ m = m.replaceAll("\u00030?2(,(0?[0-9]|1[0-5]))?", "§1");
+ m = m.replaceAll("\u00030?3(,(0?[0-9]|1[0-5]))?", "§2");
+ m = m.replaceAll("\u00030?4(,(0?[0-9]|1[0-5]))?", "§c");
+ m = m.replaceAll("\u00030?5(,(0?[0-9]|1[0-5]))?", "§4");
+ m = m.replaceAll("\u00030?6(,(0?[0-9]|1[0-5]))?", "§5");
+ m = m.replaceAll("\u00030?7(,(0?[0-9]|1[0-5]))?", "§6");
+ m = m.replaceAll("\u00030?8(,(0?[0-9]|1[0-5]))?", "§e");
+ m = m.replaceAll("\u00030?9(,(0?[0-9]|1[0-5]))?", "§a");
+ m = m.replaceAll("\u00030?0(,(0?[0-9]|1[0-5]))?", "§f");
+ m = m.replace("\u000f", "§7");
+ m = Colors.removeColors(m);
+ return m;
+ }
+
+ public void sendMessage(final String message)
+ {
+ sendMessage(CHANNEL, message);
+ }
+
+ public User[] getUsers()
+ {
+ return getUsers(CHANNEL);
+ }
+}
diff --git a/EssentialsUpdate/src/com/earth2me/essentials/update/ModuleInfo.java b/EssentialsUpdate/src/com/earth2me/essentials/update/ModuleInfo.java
new file mode 100644
index 000000000..722fca3e1
--- /dev/null
+++ b/EssentialsUpdate/src/com/earth2me/essentials/update/ModuleInfo.java
@@ -0,0 +1,35 @@
+package com.earth2me.essentials.update;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import org.bukkit.configuration.Configuration;
+
+
+public class ModuleInfo
+{
+ private final transient String url;
+ private final transient String version;
+ private final transient String hash;
+
+ public ModuleInfo(final Configuration updateConfig, final String path)
+ {
+ url = updateConfig.getString(path + ".url", null);
+ version = updateConfig.getString(path + ".version", null);
+ hash = updateConfig.getString(path + ".hash", null);
+ }
+
+ public URL getUrl() throws MalformedURLException
+ {
+ return new URL(url);
+ }
+
+ public String getVersion()
+ {
+ return version;
+ }
+
+ public String getHash()
+ {
+ return hash;
+ }
+}
diff --git a/EssentialsUpdate/src/com/earth2me/essentials/update/PastieUpload.java b/EssentialsUpdate/src/com/earth2me/essentials/update/PastieUpload.java
new file mode 100644
index 000000000..6cad44e4d
--- /dev/null
+++ b/EssentialsUpdate/src/com/earth2me/essentials/update/PastieUpload.java
@@ -0,0 +1,40 @@
+package com.earth2me.essentials.update;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+
+public class PastieUpload
+{
+ private final transient PostToUrl connection;
+
+ public PastieUpload() throws MalformedURLException
+ {
+ connection = new PostToUrl(new URL("http://pastie.org/pastes"));
+ }
+
+ public String send(final String data) throws IOException
+ {
+ final Map<String, Object> map = new HashMap<String, Object>();
+ map.put("paste[parser_id]", "19");
+ map.put("paste[authorization]", "burger");
+ map.put("paste[body]", data);
+ map.put("paste[restricted]", "1");
+ final String html = connection.send(map);
+ final Matcher matcher = Pattern.compile("(?s).*\\?key=([a-z0-9]+).*").matcher(html);
+ if (matcher.matches())
+ {
+ final String key = matcher.group(1);
+ return "http://pastie.org/private/" + key;
+ }
+ else
+ {
+ throw new IOException("Failed to upload to pastie.org");
+ }
+ }
+} \ No newline at end of file
diff --git a/EssentialsUpdate/src/com/earth2me/essentials/update/PostToUrl.java b/EssentialsUpdate/src/com/earth2me/essentials/update/PostToUrl.java
new file mode 100644
index 000000000..c8978961b
--- /dev/null
+++ b/EssentialsUpdate/src/com/earth2me/essentials/update/PostToUrl.java
@@ -0,0 +1,66 @@
+package com.earth2me.essentials.update;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.math.BigInteger;
+import java.net.URL;
+import java.net.URLConnection;
+import java.nio.charset.Charset;
+import java.util.Map;
+import java.util.Random;
+
+
+public class PostToUrl
+{
+ private final transient URL url;
+ private final transient String boundary;
+ private final transient Random random = new Random();
+ private final static String CRLF = "\r\n";
+ private final static Charset UTF8 = Charset.forName("utf-8");
+
+ public PostToUrl(final URL url)
+ {
+ this.url = url;
+ final byte[] bytes = new byte[32];
+ random.nextBytes(bytes);
+ this.boundary = "----------" + new BigInteger(bytes).toString(Character.MAX_RADIX) + "_$";
+ }
+
+ public String send(final Map<String, Object> data) throws IOException
+ {
+ final URLConnection connection = url.openConnection();
+ connection.setRequestProperty("content-type", "multipart/form-data; boundary=" + boundary);
+ final StringBuilder dataBuilder = new StringBuilder();
+ for (Map.Entry<String, Object> entry : data.entrySet())
+ {
+ if (entry.getValue() instanceof String)
+ {
+ dataBuilder.append("--").append(boundary).append(CRLF);
+ dataBuilder.append("Content-Disposition: form-data; name=\"").append(entry.getKey()).append('"').append(CRLF);
+ dataBuilder.append(CRLF);
+ dataBuilder.append(entry.getValue()).append(CRLF);
+ }
+ // TODO: Add support for file upload
+ }
+ dataBuilder.append("--").append(boundary).append("--").append(CRLF);
+ dataBuilder.append(CRLF);
+ connection.setDoOutput(true);
+ final byte[] message = dataBuilder.toString().getBytes(UTF8);
+ connection.setRequestProperty("content-length", Integer.toString(message.length));
+ connection.connect();
+ final OutputStream stream = connection.getOutputStream();
+ stream.write(message);
+ stream.close();
+ final BufferedReader page = new BufferedReader(new InputStreamReader(connection.getInputStream(), UTF8));
+ final StringBuilder input = new StringBuilder();
+ String line;
+ while ((line = page.readLine()) != null)
+ {
+ input.append(line).append("\n");
+ }
+ page.close();
+ return input.toString();
+ }
+}
diff --git a/EssentialsUpdate/src/com/earth2me/essentials/update/UpdateCheck.java b/EssentialsUpdate/src/com/earth2me/essentials/update/UpdateCheck.java
new file mode 100644
index 000000000..dcda252a0
--- /dev/null
+++ b/EssentialsUpdate/src/com/earth2me/essentials/update/UpdateCheck.java
@@ -0,0 +1,203 @@
+package com.earth2me.essentials.update;
+
+import java.io.File;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import org.bukkit.Bukkit;
+import org.bukkit.plugin.Plugin;
+import org.bukkit.plugin.PluginManager;
+
+
+public class UpdateCheck
+{
+ private transient CheckResult result = CheckResult.UNKNOWN;
+ private transient Version currentVersion;
+ private transient Version newVersion = null;
+ private transient int bukkitResult = 0;
+ private transient UpdateFile updateFile;
+ private final static int CHECK_INTERVAL = 20 * 60 * 60 * 6;
+ private final transient Plugin plugin;
+ private transient boolean essentialsInstalled;
+
+ public UpdateCheck(Plugin plugin)
+ {
+ this.plugin = plugin;
+ updateFile = new UpdateFile(plugin);
+ checkForEssentials();
+ }
+
+ private void checkForEssentials()
+ {
+ PluginManager pm = plugin.getServer().getPluginManager();
+ Plugin essentials = pm.getPlugin("Essentials");
+ if (essentials == null)
+ {
+ essentialsInstalled = false;
+ if (new File(plugin.getDataFolder().getParentFile(), "Essentials.jar").exists())
+ {
+ Bukkit.getLogger().severe("Essentials.jar found, but not recognized by Bukkit. Broken download?");
+ }
+ }
+ else
+ {
+ essentialsInstalled = true;
+ currentVersion = new Version(essentials.getDescription().getVersion());
+ }
+ }
+
+ public void scheduleUpdateTask()
+ {
+ plugin.getServer().getScheduler().scheduleAsyncRepeatingTask(plugin, new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ updateFile = new UpdateFile(plugin);
+ checkForUpdates();
+ }
+ }, CHECK_INTERVAL, CHECK_INTERVAL);
+ }
+
+ public boolean isEssentialsInstalled()
+ {
+ return essentialsInstalled;
+ }
+
+ public CheckResult getResult()
+ {
+ return result;
+ }
+
+ int getNewBukkitVersion()
+ {
+ return bukkitResult;
+ }
+
+ VersionInfo getNewVersionInfo()
+ {
+ return updateFile.getVersions().get(newVersion);
+ }
+
+ public enum CheckResult
+ {
+ NEW_ESS, NEW_ESS_BUKKIT, NEW_BUKKIT, OK, UNKNOWN
+ }
+
+ public void checkForUpdates()
+ {
+ if (currentVersion == null)
+ {
+ return;
+ }
+ final Map<Version, VersionInfo> versions = updateFile.getVersions();
+ final int bukkitVersion = getBukkitVersion();
+ Version higher = null;
+ Version found = null;
+ Version lower = null;
+ int bukkitHigher = 0;
+ int bukkitLower = 0;
+ for (Entry<Version, VersionInfo> entry : versions.entrySet())
+ {
+ final int minBukkit = entry.getValue().getMinBukkit();
+ final int maxBukkit = entry.getValue().getMaxBukkit();
+ if (minBukkit == 0 || maxBukkit == 0)
+ {
+ continue;
+ }
+ if (bukkitVersion <= maxBukkit)
+ {
+ if (bukkitVersion < minBukkit)
+ {
+ if (higher == null || higher.compareTo(entry.getKey()) < 0)
+ {
+
+ higher = entry.getKey();
+ bukkitHigher = minBukkit;
+ }
+ }
+ else
+ {
+ if (found == null || found.compareTo(entry.getKey()) < 0)
+ {
+ found = entry.getKey();
+ }
+ }
+ }
+ else
+ {
+ if (lower == null || lower.compareTo(entry.getKey()) < 0)
+ {
+ lower = entry.getKey();
+ bukkitLower = minBukkit;
+ }
+ }
+ }
+ if (found != null)
+ {
+ if (found.compareTo(currentVersion) > 0)
+ {
+ result = CheckResult.NEW_ESS;
+ newVersion = found;
+ }
+ else
+ {
+ result = CheckResult.OK;
+ }
+ }
+ else if (higher != null)
+ {
+ if (higher.compareTo(currentVersion) > 0)
+ {
+ newVersion = higher;
+ result = CheckResult.NEW_ESS_BUKKIT;
+ bukkitResult = bukkitHigher;
+ }
+ else if (higher.compareTo(currentVersion) < 0)
+ {
+ result = CheckResult.UNKNOWN;
+ }
+ else
+ {
+ result = CheckResult.NEW_BUKKIT;
+ bukkitResult = bukkitHigher;
+ }
+ }
+ else if (lower != null)
+ {
+ if (lower.compareTo(currentVersion) > 0)
+ {
+ result = CheckResult.NEW_ESS_BUKKIT;
+ newVersion = lower;
+ bukkitResult = bukkitLower;
+ }
+ else if (lower.compareTo(currentVersion) < 0)
+ {
+ result = CheckResult.UNKNOWN;
+ }
+ else
+ {
+ result = CheckResult.NEW_BUKKIT;
+ bukkitResult = bukkitLower;
+ }
+ }
+
+ }
+
+ private int getBukkitVersion()
+ {
+ final Matcher versionMatch = Pattern.compile("git-Bukkit-([0-9]+).([0-9]+).([0-9]+)-[0-9]+-[0-9a-z]+-b([0-9]+)jnks.*").matcher(plugin.getServer().getVersion());
+ if (versionMatch.matches())
+ {
+ return Integer.parseInt(versionMatch.group(4));
+ }
+ throw new NumberFormatException("Bukkit Version changed!");
+ }
+
+ public Version getNewVersion()
+ {
+ return newVersion;
+ }
+}
diff --git a/EssentialsUpdate/src/com/earth2me/essentials/update/UpdateFile.java b/EssentialsUpdate/src/com/earth2me/essentials/update/UpdateFile.java
new file mode 100644
index 000000000..8f34bffc4
--- /dev/null
+++ b/EssentialsUpdate/src/com/earth2me/essentials/update/UpdateFile.java
@@ -0,0 +1,204 @@
+package com.earth2me.essentials.update;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.KeyFactory;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.Collections;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.bukkit.plugin.Plugin;
+import org.bukkit.configuration.file.YamlConfiguration;
+
+
+public class UpdateFile
+{
+ private final static Logger LOGGER = Logger.getLogger("Minecraft");
+ private final static String UPDATE_URL = "http://goo.gl/67jev";
+ private final static BigInteger PUBLIC_KEY = new BigInteger("5ha6a2d4qdy17ttkg8evh74sl5a87djojwenu12k1lvy8ui6003e6l06rntczpoh99mhc3txj8mqlxw111oyy9yl7s7qpyluyzix3j1odxrxx4u52gxvyu6qiteapczkzvi7rxgeqsozz7b19rdx73a7quo9ybwpz1cr82r7x5k0pg2a73pjjsv2j1awr13azo7klrcxp9y5xxwf5qv1s3tw4zqftli18u0ek5qkbzfbgk1v5n2f11pkwwk6p0mibrn26wnjbv11vyiqgu95o7busmt6vf5q7grpcenl637w83mbin56s3asj1131b2mscj9xep3cbj7la9tgsxl5bj87vzy8sk2d34kzwqdqgh9nry43nqqus12l1stmiv184r8r3jcy8w43e8h1u1mzklldb5eytkuhayqik8l3ns04hwt8sgacvw534be8sx26qrn5s1", 36);
+ private final transient File file;
+ private transient YamlConfiguration updateConfig;
+ private final transient Plugin plugin;
+ private final transient TreeMap<Version, VersionInfo> versions = new TreeMap<Version, VersionInfo>();
+
+ public UpdateFile(final Plugin plugin)
+ {
+ this.plugin = plugin;
+ final long lastUpdate = Long.parseLong(plugin.getConfig().getString("lastupdate", "0"));
+ file = new File(plugin.getDataFolder(), "update.yml");
+ if (lastUpdate < System.currentTimeMillis() - 1000 * 60 * 60 * 6 || !file.exists())
+ {
+ if (file.exists() && !file.delete())
+ {
+ LOGGER.log(Level.SEVERE, "Could not delete file update.yml!");
+ return;
+ }
+ if (!downloadFile() || !checkFile())
+ {
+ LOGGER.log(Level.SEVERE, "Could not download and verify file update.yml!");
+ return;
+ }
+ }
+ try
+ {
+ readVersions();
+ }
+ catch (Exception ex)
+ {
+ LOGGER.log(Level.SEVERE, "Could not load update.yml!");
+ return;
+ }
+ }
+
+ private boolean downloadFile()
+ {
+ GetFile getFile;
+ try
+ {
+ getFile = new GetFile(UPDATE_URL);
+ getFile.saveTo(file);
+ plugin.getConfig().set("lastupdate", System.currentTimeMillis());
+ plugin.getConfig().save(new File(plugin.getDataFolder(),"config.yml"));
+ return true;
+ }
+ catch (IOException ex)
+ {
+ LOGGER.log(Level.SEVERE, "Error while downloading update.yml", ex);
+ return false;
+ }
+ }
+
+ private boolean checkFile()
+ {
+ BufferedInputStream bis = null;
+ try
+ {
+ bis = new BufferedInputStream(new FileInputStream(file));
+ if (bis.read() != '#')
+ {
+ throw new IOException("File has to start with #");
+ }
+ final StringBuilder length = new StringBuilder();
+ final StringBuilder signature = new StringBuilder();
+ boolean isSignature = false;
+ do
+ {
+ final int cur = bis.read();
+ if (cur == -1)
+ {
+ break;
+ }
+ if (cur == ':')
+ {
+ isSignature = true;
+ }
+ else if (cur == '\n')
+ {
+ break;
+ }
+ else if ((cur >= '0' && cur <= '9')
+ || (cur >= 'a' && cur <= 'z'))
+ {
+ if (isSignature)
+ {
+ signature.append((char)cur);
+ }
+ else
+ {
+ length.append((char)cur);
+ }
+ }
+ else
+ {
+ throw new IOException("Illegal character in signature!");
+ }
+ }
+ while (true);
+ if (length.length() == 0 || signature.length() == 0)
+ {
+ throw new IOException("Broken signature!");
+ }
+ final int sigLength = new BigInteger(length.toString(), 36).intValue();
+ if (sigLength < 0 || sigLength > 2048)
+ {
+ throw new IOException("Invalid signature length!");
+ }
+ final byte[] sigBytes = new BigInteger(signature.toString(), 36).toByteArray();
+ if (sigLength < sigBytes.length)
+ {
+ throw new IOException("Length is less then available bytes.");
+ }
+ byte[] realBytes;
+ if (sigLength == sigBytes.length)
+ {
+ realBytes = sigBytes;
+ }
+ else
+ {
+ realBytes = new byte[sigLength];
+ System.arraycopy(sigBytes, 0, realBytes, sigLength - sigBytes.length, sigBytes.length);
+ }
+ final X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(PUBLIC_KEY.toByteArray());
+ final KeyFactory keyFactory = KeyFactory.getInstance("RSA");
+ final PublicKey pubKey = keyFactory.generatePublic(pubKeySpec);
+ final Signature rsa = Signature.getInstance("SHA256withRSA");
+ rsa.initVerify(pubKey);
+ final byte[] buffer = new byte[2048];
+ int readLength;
+ do
+ {
+ readLength = bis.read(buffer);
+ if (readLength >= 0)
+ {
+ rsa.update(buffer, 0, readLength);
+ }
+ }
+ while (readLength >= 0);
+ return rsa.verify(realBytes);
+ }
+ catch (Exception ex)
+ {
+ LOGGER.log(Level.SEVERE, ex.getMessage(), ex);
+ }
+ finally
+ {
+ try
+ {
+ if (bis != null)
+ {
+ bis.close();
+ }
+ }
+ catch (IOException ex)
+ {
+ LOGGER.log(Level.SEVERE, ex.getMessage(), ex);
+ }
+ }
+ return false;
+ }
+
+ private void readVersions() throws Exception
+ {
+ updateConfig = new YamlConfiguration();
+ updateConfig.load(file);
+ versions.clear();
+ for (String versionString : updateConfig.getKeys(false))
+ {
+ final Version version = new Version(versionString);
+ final VersionInfo info = new VersionInfo(updateConfig, versionString);
+ versions.put(version, info);
+ }
+ }
+
+ public Map<Version, VersionInfo> getVersions()
+ {
+ return Collections.unmodifiableMap(versions.descendingMap());
+ }
+}
diff --git a/EssentialsUpdate/src/com/earth2me/essentials/update/UpdateProcess.java b/EssentialsUpdate/src/com/earth2me/essentials/update/UpdateProcess.java
new file mode 100644
index 000000000..95898bcb6
--- /dev/null
+++ b/EssentialsUpdate/src/com/earth2me/essentials/update/UpdateProcess.java
@@ -0,0 +1,128 @@
+package com.earth2me.essentials.update;
+
+import java.util.List;
+import org.bukkit.Bukkit;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+import org.bukkit.event.Event.Priority;
+import org.bukkit.event.Event.Type;
+import org.bukkit.event.player.PlayerChatEvent;
+import org.bukkit.event.player.PlayerJoinEvent;
+import org.bukkit.event.player.PlayerListener;
+import org.bukkit.plugin.Plugin;
+import org.bukkit.plugin.PluginManager;
+
+
+public class UpdateProcess extends PlayerListener
+{
+ private transient Player currentPlayer;
+ private final transient Plugin plugin;
+ private final transient UpdateCheck updateCheck;
+
+ public UpdateProcess(final Plugin plugin, final UpdateCheck updateCheck)
+ {
+ this.plugin = plugin;
+ this.updateCheck = updateCheck;
+ }
+
+ public void registerEvents()
+ {
+ final PluginManager pluginManager = plugin.getServer().getPluginManager();
+ pluginManager.registerEvent(Type.PLAYER_QUIT, this, Priority.Low, plugin);
+ pluginManager.registerEvent(Type.PLAYER_CHAT, this, Priority.Lowest, plugin);
+ }
+
+ @Override
+ public void onPlayerChat(final PlayerChatEvent event)
+ {
+ if (event.getPlayer() == currentPlayer)
+ {
+ reactOnMessage(event.getMessage());
+ event.setCancelled(true);
+ return;
+ }
+ }
+
+ @Override
+ public void onPlayerJoin(final PlayerJoinEvent event)
+ {
+ final Player player = event.getPlayer();
+ if (player.hasPermission("essentials.update") && !updateCheck.isEssentialsInstalled())
+ {
+ player.sendMessage("Hello " + player.getDisplayName());
+ player.sendMessage("Please type /essentialsupdate into the chat to start the installation of Essentials.");
+ }
+ if (player.hasPermission("essentials.update"))
+ {
+ final UpdateCheck.CheckResult result = updateCheck.getResult();
+ switch (result)
+ {
+ case NEW_ESS:
+ player.sendMessage("The new version " + updateCheck.getNewVersion().toString() + " for Essentials is available. Please type /essentialsupdate to update.");
+ break;
+ case NEW_BUKKIT:
+ player.sendMessage("Your bukkit version is not the recommended build for Essentials, please update to version " + updateCheck.getNewBukkitVersion() + ".");
+ break;
+ case NEW_ESS_BUKKIT:
+ player.sendMessage("There is a new version " + updateCheck.getNewVersion().toString() + " of Essentials for Bukkit " + updateCheck.getNewBukkitVersion());
+ break;
+ default:
+ }
+ }
+ }
+
+ void doAutomaticUpdate()
+ {
+ final UpdatesDownloader downloader = new UpdatesDownloader();
+ final VersionInfo info = updateCheck.getNewVersionInfo();
+ final List<String> changelog = info.getChangelog();
+ Bukkit.getLogger().info("Essentials changelog " + updateCheck.getNewVersion().toString());
+ for (String line : changelog)
+ {
+ Bukkit.getLogger().info(" - "+line);
+ }
+ downloader.start(plugin.getServer().getUpdateFolderFile(), info);
+ }
+
+ void doManualUpdate()
+ {
+
+ }
+
+ void onCommand(CommandSender sender)
+ {
+ if (sender instanceof Player && sender.hasPermission("essentials.install"))
+ {
+ if (currentPlayer == null)
+ {
+ currentPlayer = (Player)sender;
+ if (updateCheck.isEssentialsInstalled())
+ {
+ doManualUpdate();
+ }
+ else
+ {
+ sender.sendMessage("Thank you for choosing Essentials.");
+ sender.sendMessage("The following installation wizard will guide you through the installation of Essentials.");
+ sender.sendMessage("Your answers will be saved for a later update.");
+ sender.sendMessage("Please answer the messages with yes or no, if not otherwise stated.");
+ sender.sendMessage("Write bye/exit/quit if you want to exit the wizard at anytime.");
+
+ }
+ }
+ if (!currentPlayer.equals(sender))
+ {
+ sender.sendMessage("The player " + currentPlayer.getDisplayName() + " is already using the wizard.");
+ }
+ }
+ else
+ {
+ sender.sendMessage("Please run the command as op from in game.");
+ }
+ }
+
+ private void reactOnMessage(String message)
+ {
+ throw new UnsupportedOperationException("Not yet implemented");
+ }
+}
diff --git a/EssentialsUpdate/src/com/earth2me/essentials/update/UpdatesDownloader.java b/EssentialsUpdate/src/com/earth2me/essentials/update/UpdatesDownloader.java
new file mode 100644
index 000000000..28ffdfe3c
--- /dev/null
+++ b/EssentialsUpdate/src/com/earth2me/essentials/update/UpdatesDownloader.java
@@ -0,0 +1,19 @@
+package com.earth2me.essentials.update;
+
+import java.io.File;
+
+
+public class UpdatesDownloader
+{
+
+ UpdatesDownloader()
+ {
+
+ }
+
+ void start(File updateFolderFile, VersionInfo newVersion)
+ {
+
+ }
+
+}
diff --git a/EssentialsUpdate/src/com/earth2me/essentials/update/Version.java b/EssentialsUpdate/src/com/earth2me/essentials/update/Version.java
new file mode 100644
index 000000000..8e6cbc97f
--- /dev/null
+++ b/EssentialsUpdate/src/com/earth2me/essentials/update/Version.java
@@ -0,0 +1,173 @@
+package com.earth2me.essentials.update;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+
+public class Version implements Comparable<Version>
+{
+ public enum Type
+ {
+ STABLE, PREVIEW, DEVELOPER
+ }
+
+ public int getMajor()
+ {
+ return major;
+ }
+
+ public int getMinor()
+ {
+ return minor;
+ }
+
+ public int getBuild()
+ {
+ return build;
+ }
+
+ public Type getType()
+ {
+ return type;
+ }
+ private final transient int major;
+ private final transient int minor;
+ private final transient int build;
+ private final transient Type type;
+
+ public Version(final String versionString)
+ {
+ final Matcher matcher = Pattern.compile("(Pre|Dev)?([0-9]+)[_\\.]([0-9]+)[_\\.]([0-9]+).*").matcher(versionString);
+ if (!matcher.matches() || matcher.groupCount() < 4)
+ {
+ type = Type.DEVELOPER;
+ major = 99;
+ minor = build = 0;
+ return;
+ }
+ if (versionString.startsWith("Pre"))
+ {
+ type = Type.PREVIEW;
+ }
+ else if (versionString.startsWith("Dev"))
+ {
+ type = Type.DEVELOPER;
+ }
+ else
+ {
+ type = Type.STABLE;
+ }
+ major = Integer.parseInt(matcher.group(2));
+ minor = Integer.parseInt(matcher.group(3));
+ build = Integer.parseInt(matcher.group(4));
+ }
+
+ @Override
+ public int compareTo(final Version other)
+ {
+ int ret = 0;
+ if (other.getType() == Type.DEVELOPER && getType() != Type.DEVELOPER)
+ {
+ ret = -1;
+ }
+ else if (getType() == Type.DEVELOPER && other.getType() != Type.DEVELOPER)
+ {
+ ret = 1;
+ }
+ else if (other.getMajor() > getMajor())
+ {
+ ret = -1;
+ }
+ else if (getMajor() > other.getMajor())
+ {
+ ret = 1;
+ }
+ else if (other.getMinor() > getMinor())
+ {
+ ret = -1;
+ }
+ else if (getMinor() > other.getMinor())
+ {
+ ret = 1;
+ }
+ else if (other.getBuild() > getBuild())
+ {
+ ret = -1;
+ }
+ else if (getBuild() > other.getBuild())
+ {
+ ret = 1;
+ }
+ else if (other.getType() == Type.STABLE && getType() == Type.PREVIEW)
+ {
+ ret = -1;
+ }
+ else if (getType() == Type.STABLE && other.getType() == Type.PREVIEW)
+ {
+ ret = 1;
+ }
+ return ret;
+ }
+
+ @Override
+ public boolean equals(final Object obj)
+ {
+ if (obj == null)
+ {
+ return false;
+ }
+ if (getClass() != obj.getClass())
+ {
+ return false;
+ }
+ final Version other = (Version)obj;
+ if (this.major != other.major)
+ {
+ return false;
+ }
+ if (this.minor != other.minor)
+ {
+ return false;
+ }
+ if (this.build != other.build)
+ {
+ return false;
+ }
+ if (this.type != other.type)
+ {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public int hashCode()
+ {
+ int hash = 5;
+ hash = 71 * hash + this.major;
+ hash = 71 * hash + this.minor;
+ hash = 71 * hash + this.build;
+ hash = 71 * hash + (this.type != null ? this.type.hashCode() : 0);
+ return hash;
+ }
+
+ @Override
+ public String toString()
+ {
+ final StringBuilder builder = new StringBuilder();
+ if (type == Type.DEVELOPER)
+ {
+ builder.append("Dev");
+ }
+ if (type == Type.PREVIEW)
+ {
+ builder.append("Pre");
+ }
+ builder.append(major);
+ builder.append('.');
+ builder.append(minor);
+ builder.append('.');
+ builder.append(build);
+ return builder.toString();
+ }
+}
diff --git a/EssentialsUpdate/src/com/earth2me/essentials/update/VersionInfo.java b/EssentialsUpdate/src/com/earth2me/essentials/update/VersionInfo.java
new file mode 100644
index 000000000..9cd1e5edb
--- /dev/null
+++ b/EssentialsUpdate/src/com/earth2me/essentials/update/VersionInfo.java
@@ -0,0 +1,48 @@
+package com.earth2me.essentials.update;
+
+import java.util.ArrayList;
+import org.bukkit.configuration.Configuration;
+import java.util.Collections;
+import java.util.List;
+
+
+public class VersionInfo
+{
+ private final transient List<String> changelog;
+ private final transient int minBukkit;
+ private final transient int maxBukkit;
+ private final transient List<ModuleInfo> modules;
+
+ public VersionInfo(final Configuration updateConfig, final String path)
+ {
+ changelog = updateConfig.getList(path + ".changelog", Collections.<String>emptyList());
+ minBukkit = updateConfig.getInt(path + ".min-bukkit", 0);
+ maxBukkit = updateConfig.getInt(path + ".max-bukkit", 0);
+ modules = new ArrayList<ModuleInfo>();
+ final String modulesPath = path + ".modules";
+ for (String module : updateConfig.getKeys(false))
+ {
+ modules.add(new ModuleInfo(updateConfig, modulesPath + module));
+ }
+ }
+
+ public List<String> getChangelog()
+ {
+ return Collections.unmodifiableList(changelog);
+ }
+
+ public int getMinBukkit()
+ {
+ return minBukkit;
+ }
+
+ public int getMaxBukkit()
+ {
+ return maxBukkit;
+ }
+
+ public List<ModuleInfo> getModules()
+ {
+ return Collections.unmodifiableList(modules);
+ }
+}
diff --git a/EssentialsUpdate/src/com/earth2me/essentials/update/states/Modules.java b/EssentialsUpdate/src/com/earth2me/essentials/update/states/Modules.java
new file mode 100644
index 000000000..56d2445c9
--- /dev/null
+++ b/EssentialsUpdate/src/com/earth2me/essentials/update/states/Modules.java
@@ -0,0 +1,7 @@
+package com.earth2me.essentials.update.states;
+
+
+public class Modules
+{
+
+}