diff --git a/Essentials/src/main/resources/messages.properties b/Essentials/src/main/resources/messages.properties index b609b70fc..b741afc47 100644 --- a/Essentials/src/main/resources/messages.properties +++ b/Essentials/src/main/resources/messages.properties @@ -314,6 +314,7 @@ enderchestCommandUsage2=/ enderchestCommandUsage2Description=Opens the ender chest of the target player errorCallingCommand=Error calling the command /{0} errorWithMessage=\u00a7cError\:\u00a74 {0} +essChatNoSecureMsg=EssentialsX Chat version {0} does not support secure chat on this server software. Update EssentialsX, and if this issue persists, inform the developers. essentialsCommandDescription=Reloads essentials. essentialsCommandUsage=/ essentialsCommandUsage1=/ reload diff --git a/EssentialsChat/src/main/java/com/earth2me/essentials/chat/ChatStore.java b/EssentialsChat/src/main/java/com/earth2me/essentials/chat/ChatStore.java deleted file mode 100644 index 915aebf0e..000000000 --- a/EssentialsChat/src/main/java/com/earth2me/essentials/chat/ChatStore.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.earth2me.essentials.chat; - -import com.earth2me.essentials.Trade; -import com.earth2me.essentials.User; -import net.ess3.api.IEssentials; - -class ChatStore { - private final User user; - private final String type; - private final Trade charge; - private long radius; - - ChatStore(final IEssentials ess, final User user, final String type) { - this.user = user; - this.type = type; - this.charge = new Trade(getLongType(), ess); - } - - User getUser() { - return user; - } - - Trade getCharge() { - return charge; - } - - String getType() { - return type; - } - - final String getLongType() { - return type.length() == 0 ? "chat" : "chat-" + type; - } - - long getRadius() { - return radius; - } - - void setRadius(final long radius) { - this.radius = radius; - } -} diff --git a/EssentialsChat/src/main/java/com/earth2me/essentials/chat/EssentialsChat.java b/EssentialsChat/src/main/java/com/earth2me/essentials/chat/EssentialsChat.java index e9c2c6d0d..969714aa6 100644 --- a/EssentialsChat/src/main/java/com/earth2me/essentials/chat/EssentialsChat.java +++ b/EssentialsChat/src/main/java/com/earth2me/essentials/chat/EssentialsChat.java @@ -1,17 +1,16 @@ package com.earth2me.essentials.chat; +import com.earth2me.essentials.Essentials; import com.earth2me.essentials.EssentialsLogger; +import com.earth2me.essentials.chat.processing.LegacyChatHandler; +import com.earth2me.essentials.chat.processing.SignedChatHandler; import com.earth2me.essentials.metrics.MetricsWrapper; import net.ess3.api.IEssentials; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; -import org.bukkit.event.player.AsyncPlayerChatEvent; import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.java.JavaPlugin; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; import java.util.logging.Level; import static com.earth2me.essentials.I18n.tl; @@ -33,14 +32,13 @@ public class EssentialsChat extends JavaPlugin { return; } - final Map chatStore = Collections.synchronizedMap(new HashMap<>()); - - final EssentialsChatPlayerListenerLowest playerListenerLowest = new EssentialsChatPlayerListenerLowest(getServer(), ess, this, chatStore); - final EssentialsChatPlayerListenerNormal playerListenerNormal = new EssentialsChatPlayerListenerNormal(getServer(), ess, this, chatStore); - final EssentialsChatPlayerListenerHighest playerListenerHighest = new EssentialsChatPlayerListenerHighest(getServer(), ess, this, chatStore); - pluginManager.registerEvents(playerListenerLowest, this); - pluginManager.registerEvents(playerListenerNormal, this); - pluginManager.registerEvents(playerListenerHighest, this); + final SignedChatHandler signedHandler = new SignedChatHandler((Essentials) ess, this); + if (signedHandler.tryRegisterListeners()) { + getLogger().info("Secure signed chat and previews are enabled."); + } else { + final LegacyChatHandler legacyHandler = new LegacyChatHandler((Essentials) ess, this); + legacyHandler.registerListeners(); + } if (metrics == null) { metrics = new MetricsWrapper(this, 3814, false); diff --git a/EssentialsChat/src/main/java/com/earth2me/essentials/chat/EssentialsChatPlayer.java b/EssentialsChat/src/main/java/com/earth2me/essentials/chat/EssentialsChatPlayer.java deleted file mode 100644 index c3d991ac2..000000000 --- a/EssentialsChat/src/main/java/com/earth2me/essentials/chat/EssentialsChatPlayer.java +++ /dev/null @@ -1,79 +0,0 @@ -package com.earth2me.essentials.chat; - -import com.earth2me.essentials.ChargeException; -import com.earth2me.essentials.Trade; -import com.earth2me.essentials.User; -import net.ess3.api.IEssentials; -import org.bukkit.Server; -import org.bukkit.event.Listener; -import org.bukkit.event.player.AsyncPlayerChatEvent; - -import java.util.Map; - -public abstract class EssentialsChatPlayer implements Listener { - final transient IEssentials ess; - final transient EssentialsChat essChat; - final transient Server server; - private final transient Map chatStorage; - - EssentialsChatPlayer(final Server server, final IEssentials ess, final EssentialsChat essChat, final Map chatStorage) { - this.ess = ess; - this.essChat = essChat; - this.server = server; - this.chatStorage = chatStorage; - } - - public abstract void onPlayerChat(final AsyncPlayerChatEvent event); - - boolean isAborted(final AsyncPlayerChatEvent event) { - return event.isCancelled(); - } - - String getChatType(final User user, final String message) { - if (message.length() == 0) { - //Ignore empty chat events generated by plugins - return ""; - } - - final char prefix = message.charAt(0); - if (prefix == ess.getSettings().getChatShout()) { - if (user.isToggleShout()) { - return ""; - } - return message.length() > 1 ? "shout" : ""; - } else if (ess.getSettings().isChatQuestionEnabled() && prefix == ess.getSettings().getChatQuestion()) { - return message.length() > 1 ? "question" : ""; - } else if (user.isToggleShout()) { - return message.length() > 1 ? "shout" : ""; - } else { - return ""; - } - } - - ChatStore getChatStore(final AsyncPlayerChatEvent event) { - return chatStorage.get(event); - } - - void setChatStore(final AsyncPlayerChatEvent event, final ChatStore chatStore) { - chatStorage.put(event, chatStore); - } - - ChatStore delChatStore(final AsyncPlayerChatEvent event) { - return chatStorage.remove(event); - } - - private void charge(final User user, final Trade charge) throws ChargeException { - charge.charge(user); - } - - boolean charge(final AsyncPlayerChatEvent event, final ChatStore chatStore) { - try { - charge(chatStore.getUser(), chatStore.getCharge()); - } catch (final ChargeException e) { - ess.showError(chatStore.getUser().getSource(), e, "\\ chat " + chatStore.getLongType()); - event.setCancelled(true); - return false; - } - return true; - } -} diff --git a/EssentialsChat/src/main/java/com/earth2me/essentials/chat/EssentialsChatPlayerListenerHighest.java b/EssentialsChat/src/main/java/com/earth2me/essentials/chat/EssentialsChatPlayerListenerHighest.java deleted file mode 100644 index 863c2ed65..000000000 --- a/EssentialsChat/src/main/java/com/earth2me/essentials/chat/EssentialsChatPlayerListenerHighest.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.earth2me.essentials.chat; - -import net.ess3.api.IEssentials; -import org.bukkit.Server; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.player.AsyncPlayerChatEvent; - -import java.util.Map; - -public class EssentialsChatPlayerListenerHighest extends EssentialsChatPlayer { - EssentialsChatPlayerListenerHighest(final Server server, final IEssentials ess, final EssentialsChat essChat, final Map chatStorage) { - super(server, ess, essChat, chatStorage); - } - - @EventHandler(priority = EventPriority.HIGHEST) - @Override - public void onPlayerChat(final AsyncPlayerChatEvent event) { - final ChatStore chatStore = delChatStore(event); - if (isAborted(event) || chatStore == null) { - return; - } - - // This file should handle charging the user for the action before returning control back - charge(event, chatStore); - } -} diff --git a/EssentialsChat/src/main/java/com/earth2me/essentials/chat/EssentialsChatPlayerListenerLowest.java b/EssentialsChat/src/main/java/com/earth2me/essentials/chat/EssentialsChatPlayerListenerLowest.java deleted file mode 100644 index 8e113e8f6..000000000 --- a/EssentialsChat/src/main/java/com/earth2me/essentials/chat/EssentialsChatPlayerListenerLowest.java +++ /dev/null @@ -1,72 +0,0 @@ -package com.earth2me.essentials.chat; - -import com.earth2me.essentials.User; -import com.earth2me.essentials.utils.FormatUtil; -import net.ess3.api.IEssentials; -import org.bukkit.ChatColor; -import org.bukkit.Server; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.player.AsyncPlayerChatEvent; -import org.bukkit.scoreboard.Team; - -import java.util.Locale; -import java.util.Map; - -public class EssentialsChatPlayerListenerLowest extends EssentialsChatPlayer { - EssentialsChatPlayerListenerLowest(final Server server, final IEssentials ess, final EssentialsChat essChat, final Map chatStorage) { - super(server, ess, essChat, chatStorage); - } - - @EventHandler(priority = EventPriority.LOWEST) - @Override - public void onPlayerChat(final AsyncPlayerChatEvent event) { - if (isAborted(event)) { - return; - } - - final User user = ess.getUser(event.getPlayer()); - - if (user == null) { - event.setCancelled(true); - return; - } - - final ChatStore chatStore = new ChatStore(ess, user, getChatType(user, event.getMessage())); - setChatStore(event, chatStore); - - // This listener should apply the general chat formatting only...then return control back the event handler - event.setMessage(FormatUtil.formatMessage(user, "essentials.chat", event.getMessage())); - - if (ChatColor.stripColor(event.getMessage()).length() == 0) { - event.setCancelled(true); - return; - } - - final String group = user.getGroup(); - final String world = user.getWorld().getName(); - final String username = user.getName(); - final String nickname = user.getFormattedNickname(); - - final Player player = user.getBase(); - final String prefix = FormatUtil.replaceFormat(ess.getPermissionsHandler().getPrefix(player)); - final String suffix = FormatUtil.replaceFormat(ess.getPermissionsHandler().getSuffix(player)); - final Team team = player.getScoreboard().getPlayerTeam(player); - - String format = ess.getSettings().getChatFormat(group); - format = format.replace("{0}", group); - format = format.replace("{1}", ess.getSettings().getWorldAlias(world)); - format = format.replace("{2}", world.substring(0, 1).toUpperCase(Locale.ENGLISH)); - format = format.replace("{3}", team == null ? "" : team.getPrefix()); - format = format.replace("{4}", team == null ? "" : team.getSuffix()); - format = format.replace("{5}", team == null ? "" : team.getDisplayName()); - format = format.replace("{6}", prefix); - format = format.replace("{7}", suffix); - format = format.replace("{8}", username); - format = format.replace("{9}", nickname == null ? username : nickname); - synchronized (format) { - event.setFormat(format); - } - } -} diff --git a/EssentialsChat/src/main/java/com/earth2me/essentials/chat/EssentialsChatPlayerListenerNormal.java b/EssentialsChat/src/main/java/com/earth2me/essentials/chat/EssentialsChatPlayerListenerNormal.java deleted file mode 100644 index 7726dbaca..000000000 --- a/EssentialsChat/src/main/java/com/earth2me/essentials/chat/EssentialsChatPlayerListenerNormal.java +++ /dev/null @@ -1,136 +0,0 @@ -package com.earth2me.essentials.chat; - -import com.earth2me.essentials.User; -import net.ess3.api.IEssentials; -import net.ess3.api.events.LocalChatSpyEvent; -import org.bukkit.Location; -import org.bukkit.Server; -import org.bukkit.World; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.player.AsyncPlayerChatEvent; - -import java.util.HashSet; -import java.util.Iterator; -import java.util.Locale; -import java.util.Map; -import java.util.Set; -import java.util.logging.Level; - -import static com.earth2me.essentials.I18n.tl; - -public class EssentialsChatPlayerListenerNormal extends EssentialsChatPlayer { - EssentialsChatPlayerListenerNormal(final Server server, final IEssentials ess, final EssentialsChat essChat, final Map chatStorage) { - super(server, ess, essChat, chatStorage); - } - - @EventHandler(priority = EventPriority.NORMAL) - @Override - public void onPlayerChat(final AsyncPlayerChatEvent event) { - if (isAborted(event)) { - return; - } - - // This file should handle detection of the local chat features; if local chat is enabled, we need to handle it here - long radius = ess.getSettings().getChatRadius(); - if (radius < 1) { - return; - } - radius *= radius; - - final ChatStore chatStore = getChatStore(event); - final User user = chatStore.getUser(); - chatStore.setRadius(radius); - - if (event.getMessage().length() > 1) { - if (chatStore.getType().isEmpty()) { - if (!user.isAuthorized("essentials.chat.local")) { - user.sendMessage(tl("notAllowedToLocal")); - event.setCancelled(true); - return; - } - - if (user.isToggleShout() && event.getMessage().length() > 1 && event.getMessage().charAt(0) == ess.getSettings().getChatShout()) { - event.setMessage(event.getMessage().substring(1)); - } - - event.getRecipients().removeIf(player -> !ess.getUser(player).isAuthorized("essentials.chat.receive.local")); - } else { - final String permission = "essentials.chat." + chatStore.getType(); - - if (user.isAuthorized(permission)) { - if (event.getMessage().charAt(0) == ess.getSettings().getChatShout() || (event.getMessage().charAt(0) == ess.getSettings().getChatQuestion() && ess.getSettings().isChatQuestionEnabled())) { - event.setMessage(event.getMessage().substring(1)); - } - event.setFormat(tl(chatStore.getType() + "Format", event.getFormat())); - event.getRecipients().removeIf(player -> !ess.getUser(player).isAuthorized("essentials.chat.receive." + chatStore.getType())); - return; - } - - user.sendMessage(tl("notAllowedTo" + chatStore.getType().substring(0, 1).toUpperCase(Locale.ENGLISH) + chatStore.getType().substring(1))); - event.setCancelled(true); - return; - } - } - - final Location loc = user.getLocation(); - final World world = loc.getWorld(); - - if (!charge(event, chatStore)) { - return; - } - - final Set outList = event.getRecipients(); - final Set spyList = new HashSet<>(); - - try { - outList.add(event.getPlayer()); - } catch (final UnsupportedOperationException ex) { - if (ess.getSettings().isDebug()) { - essChat.getLogger().log(Level.INFO, "Plugin triggered custom chat event, local chat handling aborted.", ex); - } - return; - } - - final String format = event.getFormat(); - event.setFormat(tl("chatTypeLocal").concat(event.getFormat())); - - final Iterator it = outList.iterator(); - while (it.hasNext()) { - final Player onlinePlayer = it.next(); - final User onlineUser = ess.getUser(onlinePlayer); - if (!onlineUser.equals(user)) { - boolean abort = false; - final Location playerLoc = onlineUser.getLocation(); - if (playerLoc.getWorld() != world) { - abort = true; - } else { - final double delta = playerLoc.distanceSquared(loc); - if (delta > chatStore.getRadius()) { - abort = true; - } - } - if (abort) { - if (onlineUser.isAuthorized("essentials.chat.spy")) { - spyList.add(onlinePlayer); - } - it.remove(); - } - } - } - - if (outList.size() < 2) { - user.sendMessage(tl("localNoOne")); - } - - final LocalChatSpyEvent spyEvent = new LocalChatSpyEvent(event.isAsynchronous(), event.getPlayer(), format, event.getMessage(), spyList); - server.getPluginManager().callEvent(spyEvent); - - if (!spyEvent.isCancelled()) { - for (final Player onlinePlayer : spyEvent.getRecipients()) { - onlinePlayer.sendMessage(String.format(spyEvent.getFormat(), user.getDisplayName(), spyEvent.getMessage())); - } - } - } -} diff --git a/EssentialsChat/src/main/java/com/earth2me/essentials/chat/processing/AbstractChatHandler.java b/EssentialsChat/src/main/java/com/earth2me/essentials/chat/processing/AbstractChatHandler.java index 4aee07787..b0dd5e73a 100644 --- a/EssentialsChat/src/main/java/com/earth2me/essentials/chat/processing/AbstractChatHandler.java +++ b/EssentialsChat/src/main/java/com/earth2me/essentials/chat/processing/AbstractChatHandler.java @@ -29,7 +29,7 @@ public abstract class AbstractChatHandler { protected final Essentials ess; protected final EssentialsChat essChat; protected final Server server; - private final ChatProcessingCache cache; + protected final ChatProcessingCache cache; protected AbstractChatHandler(Essentials ess, EssentialsChat essChat) { this.ess = ess; @@ -87,7 +87,8 @@ public abstract class AbstractChatHandler { event.setFormat(format); } - chat.setModifiedMessage(String.format(format, player.getDisplayName(), event.getMessage())); + chat.setFormatResult(format); + chat.setMessageResult(event.getMessage()); } // Local chat recipients logic, handled at NORMAL level @@ -103,9 +104,8 @@ public abstract class AbstractChatHandler { } radius *= radius; - final ChatProcessingCache.IntermediateChat chatStore = cache.getIntermediateChat(event.getPlayer()); + final ChatProcessingCache.Chat chatStore = cache.getIntermediateOrElseProcessedChat(event.getPlayer()); final User user = chatStore.getUser(); - chatStore.setRadius(radius); if (event.getMessage().length() > 1) { if (chatStore.getType().isEmpty()) { @@ -124,6 +124,7 @@ public abstract class AbstractChatHandler { final String permission = "essentials.chat." + chatStore.getType(); if (user.isAuthorized(permission)) { + // TODO: move this formatting over to handleChatFormat to avoid breaking signing if (event.getMessage().charAt(0) == ess.getSettings().getChatShout() || (event.getMessage().charAt(0) == ess.getSettings().getChatQuestion() && ess.getSettings().isChatQuestionEnabled())) { event.setMessage(event.getMessage().substring(1)); } @@ -141,11 +142,6 @@ public abstract class AbstractChatHandler { final Location loc = user.getLocation(); final World world = loc.getWorld(); - // TODO: why here, why again in highest? who did this? why? pay for your crimes - if (!charge(event, chatStore)) { - return; - } - final Set outList = event.getRecipients(); final Set spyList = new HashSet<>(); @@ -172,7 +168,7 @@ public abstract class AbstractChatHandler { abort = true; } else { final double delta = playerLoc.distanceSquared(loc); - if (delta > chatStore.getRadius()) { + if (delta > radius) { abort = true; } } @@ -199,13 +195,17 @@ public abstract class AbstractChatHandler { } } - // Finalising the intermediate stages of chat processing, handled at HIGHEST level - protected void handleChatComplete(AsyncPlayerChatEvent event) { + // Finalising the intermediate stages of chat processing, handled at HIGHEST level during previews + protected void handleChatPostFormat(AsyncPlayerChatEvent event) { final ChatProcessingCache.IntermediateChat intermediateChat = cache.clearIntermediateChat(event.getPlayer()); if (isAborted(event) || intermediateChat == null) { return; } + // in case of modifications by other plugins during the preview + intermediateChat.setFormatResult(event.getFormat()); + intermediateChat.setMessageResult(event.getMessage()); + final ChatProcessingCache.ProcessedChat processed = new ChatProcessingCache.ProcessedChat(ess, intermediateChat); cache.setProcessedChat(event.getPlayer(), processed); } @@ -217,6 +217,8 @@ public abstract class AbstractChatHandler { // This file should handle charging the user for the action before returning control back charge(event, cache.getProcessedChat(event.getPlayer())); + + cache.clearProcessedChat(event.getPlayer()); } boolean isAborted(final AsyncPlayerChatEvent event) { @@ -260,6 +262,7 @@ public abstract class AbstractChatHandler { } protected interface ChatListener extends Listener { + @SuppressWarnings("unused") void onPlayerChat(AsyncPlayerChatEvent event); } diff --git a/EssentialsChat/src/main/java/com/earth2me/essentials/chat/processing/ChatProcessingCache.java b/EssentialsChat/src/main/java/com/earth2me/essentials/chat/processing/ChatProcessingCache.java index f50d9f29d..4d27446bb 100644 --- a/EssentialsChat/src/main/java/com/earth2me/essentials/chat/processing/ChatProcessingCache.java +++ b/EssentialsChat/src/main/java/com/earth2me/essentials/chat/processing/ChatProcessingCache.java @@ -20,26 +20,40 @@ public class ChatProcessingCache { .expireAfterWrite(5, TimeUnit.MINUTES) .build(); - public IntermediateChat getIntermediateChat(Player player) { + public IntermediateChat getIntermediateChat(final Player player) { return intermediateChats.get(player); } - public void setIntermediateChat(Player player, IntermediateChat intermediateChat) { + public void setIntermediateChat(final Player player, final IntermediateChat intermediateChat) { intermediateChats.put(player, intermediateChat); } - public IntermediateChat clearIntermediateChat(Player player) { + public IntermediateChat clearIntermediateChat(final Player player) { return intermediateChats.remove(player); } - public ProcessedChat getProcessedChat(Player player) { + public ProcessedChat getProcessedChat(final Player player) { return processedChats.getIfPresent(player); } - public void setProcessedChat(Player player, ProcessedChat chat) { + public void setProcessedChat(final Player player, final ProcessedChat chat) { processedChats.put(player, chat); } + public ProcessedChat clearProcessedChat(final Player player) { + final ProcessedChat chat = processedChats.getIfPresent(player); + processedChats.invalidate(player); + return chat; + } + + public Chat getIntermediateOrElseProcessedChat(final Player player) { + final IntermediateChat chat = getIntermediateChat(player); + if (chat != null) { + return chat; + } + return getProcessedChat(player); + } + public static abstract class Chat { private final User user; private final String type; @@ -51,11 +65,11 @@ public class ChatProcessingCache { this.originalMessage = originalMessage; } - User getUser() { + public User getUser() { return user; } - String getType() { + public String getType() { return type; } @@ -63,32 +77,39 @@ public class ChatProcessingCache { return originalMessage; } - final String getLongType() { + public final String getLongType() { return type.length() == 0 ? "chat" : "chat-" + type; } } public static class ProcessedChat extends Chat { private final String message; + private final String format; private final Trade charge; public ProcessedChat(final IEssentials ess, final IntermediateChat sourceChat) { super(sourceChat.getUser(), sourceChat.getType(), sourceChat.getOriginalMessage()); + this.message = sourceChat.messageResult; + this.format = sourceChat.formatResult; this.charge = new Trade(getLongType(), ess); - this.message = sourceChat.modifiedMessage; } public String getMessage() { return message; } + public String getFormat() { + return format; + } + public Trade getCharge() { return charge; } } public static class IntermediateChat extends Chat { - private String modifiedMessage; + private String messageResult; + private String formatResult; private long radius; public IntermediateChat(final User user, final String type, final String originalMessage) { @@ -100,15 +121,24 @@ public class ChatProcessingCache { } void setRadius(final long radius) { + // TODO: use or remove this.radius = radius; } - public String getModifiedMessage() { - return modifiedMessage; + public String getMessageResult() { + return messageResult; } - public void setModifiedMessage(String modifiedMessage) { - this.modifiedMessage = modifiedMessage; + public void setMessageResult(String messageResult) { + this.messageResult = messageResult; + } + + public String getFormatResult() { + return formatResult; + } + + public void setFormatResult(String formatResult) { + this.formatResult = formatResult; } } diff --git a/EssentialsChat/src/main/java/com/earth2me/essentials/chat/processing/LegacyChatHandler.java b/EssentialsChat/src/main/java/com/earth2me/essentials/chat/processing/LegacyChatHandler.java index 8a2207e42..b10cf9ca2 100644 --- a/EssentialsChat/src/main/java/com/earth2me/essentials/chat/processing/LegacyChatHandler.java +++ b/EssentialsChat/src/main/java/com/earth2me/essentials/chat/processing/LegacyChatHandler.java @@ -1,5 +1,46 @@ package com.earth2me.essentials.chat.processing; -public class LegacyChatHandler { - // TODO +import com.earth2me.essentials.Essentials; +import com.earth2me.essentials.chat.EssentialsChat; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.player.AsyncPlayerChatEvent; +import org.bukkit.plugin.PluginManager; + +public class LegacyChatHandler extends AbstractChatHandler { + public LegacyChatHandler(Essentials ess, EssentialsChat essChat) { + super(ess, essChat); + } + + public void registerListeners() { + final PluginManager pm = essChat.getServer().getPluginManager(); + pm.registerEvents(new ChatLowest(), essChat); + pm.registerEvents(new ChatNormal(), essChat); + pm.registerEvents(new ChatHighest(), essChat); + } + + private class ChatLowest implements ChatListener { + @Override + @EventHandler(priority = EventPriority.LOWEST) + public void onPlayerChat(AsyncPlayerChatEvent event) { + handleChatFormat(event); + } + } + + private class ChatNormal implements ChatListener { + @Override + @EventHandler(priority = EventPriority.NORMAL) + public void onPlayerChat(AsyncPlayerChatEvent event) { + handleChatRecipients(event); + } + } + + private class ChatHighest implements ChatListener { + @Override + @EventHandler(priority = EventPriority.HIGHEST) + public void onPlayerChat(AsyncPlayerChatEvent event) { + handleChatPostFormat(event); + handleChatSubmit(event); + } + } } diff --git a/EssentialsChat/src/main/java/com/earth2me/essentials/chat/processing/SignedChatHandler.java b/EssentialsChat/src/main/java/com/earth2me/essentials/chat/processing/SignedChatHandler.java index 9d1534834..b4f205f99 100644 --- a/EssentialsChat/src/main/java/com/earth2me/essentials/chat/processing/SignedChatHandler.java +++ b/EssentialsChat/src/main/java/com/earth2me/essentials/chat/processing/SignedChatHandler.java @@ -1,6 +1,7 @@ package com.earth2me.essentials.chat.processing; import com.earth2me.essentials.Essentials; +import com.earth2me.essentials.I18n; import com.earth2me.essentials.chat.EssentialsChat; import com.earth2me.essentials.utils.VersionUtil; import org.bukkit.event.EventHandler; @@ -16,35 +17,104 @@ public class SignedChatHandler extends AbstractChatHandler { super(ess, essChat); } - boolean tryRegisterListeners() { + public boolean tryRegisterListeners() { + if (VersionUtil.getServerBukkitVersion().isLowerThan(VersionUtil.v1_19_1_R01)) { + return false; + } + try { final Class previewClass = Class.forName("org.bukkit.event.player.AsyncPlayerChatPreviewEvent"); - if (VersionUtil.getServerBukkitVersion().isLowerThan(VersionUtil.v1_19_1_R01) || !AsyncPlayerChatEvent.class.isAssignableFrom(previewClass)) { + if (!AsyncPlayerChatEvent.class.isAssignableFrom(previewClass)) { + essChat.getLogger().severe(I18n.tl("essChatNoSecureMsg", essChat.getDescription().getVersion())); return false; } } catch (ClassNotFoundException e) { + essChat.getLogger().severe(I18n.tl("essChatNoSecureMsg", essChat.getDescription().getVersion())); return false; } final PluginManager pm = essChat.getServer().getPluginManager(); - pm.registerEvents(new Lowest(), essChat); - // TODO Normal - // TODO Highest (or Monitor?) + pm.registerEvents(new PreviewLowest(), essChat); + pm.registerEvents(new PreviewHighest(), essChat); + pm.registerEvents(new ChatLowest(), essChat); + pm.registerEvents(new ChatNormal(), essChat); + pm.registerEvents(new ChatHighest(), essChat); return true; } + private void handleChatApplyPreview(AsyncPlayerChatEvent event) { + final ChatProcessingCache.ProcessedChat chat = cache.getProcessedChat(event.getPlayer()); + if (chat == null) { + handleChatFormat(event); + handleChatPostFormat(event); + } else { + event.setFormat(chat.getFormat()); + event.setMessage(chat.getMessage()); + } + } + + private void handleChatConfirmPreview(AsyncPlayerChatEvent event) { + if (!ess.getSettings().isDebug()) return; + + final ChatProcessingCache.ProcessedChat chat = cache.getProcessedChat(event.getPlayer()); + if (chat == null) { + // Can't confirm preview for some reason + essChat.getLogger().info("Processed chat missing for " + event.getPlayer()); + } else { + if (!event.getFormat().equals(chat.getFormat())) { + // Chat format modified by another plugin + essChat.getLogger().info("Chat format has been modified for " + event.getPlayer()); + essChat.getLogger().info("Expected '" + chat.getFormat() + "', got '" + event.getFormat()); + } + if (!event.getMessage().equals(chat.getMessage())) { + // Chat message modified by another plugin + essChat.getLogger().info("Chat message has been modified for " + event.getPlayer()); + essChat.getLogger().info("Expected '" + chat.getMessage() + "', got '" + event.getMessage()); + } + } + } + private interface PreviewListener extends Listener { void onPlayerChatPreview(AsyncPlayerChatPreviewEvent event); } - private class Lowest implements PreviewListener { + private class PreviewLowest implements PreviewListener { @EventHandler(priority = EventPriority.LOWEST) public void onPlayerChatPreview(AsyncPlayerChatPreviewEvent event) { - // TODO + handleChatFormat(event); } } - // TODO preview on Normal, Highest - // TODO chat on ???? priority, how do we do this without exploding all over other plugins? + private class PreviewHighest implements PreviewListener { + @EventHandler(priority = EventPriority.HIGHEST) + public void onPlayerChatPreview(AsyncPlayerChatPreviewEvent event) { + handleChatPostFormat(event); + } + } + + private class ChatLowest implements ChatListener { + @Override + @EventHandler(priority = EventPriority.LOWEST) + public void onPlayerChat(AsyncPlayerChatEvent event) { + handleChatApplyPreview(event); + } + } + + private class ChatNormal implements ChatListener { + @Override + @EventHandler(priority = EventPriority.NORMAL) + public void onPlayerChat(AsyncPlayerChatEvent event) { + handleChatRecipients(event); + } + } + + private class ChatHighest implements ChatListener { + @Override + @EventHandler(priority = EventPriority.HIGHEST) + public void onPlayerChat(AsyncPlayerChatEvent event) { + handleChatConfirmPreview(event); + handleChatSubmit(event); + } + } }