diff --git a/dependency-reduced-pom.xml b/dependency-reduced-pom.xml index 2c39594..8b08567 100644 --- a/dependency-reduced-pom.xml +++ b/dependency-reduced-pom.xml @@ -92,6 +92,9 @@ + + + diff --git a/pom.xml b/pom.xml index 5d2fc40..7fd3be4 100644 --- a/pom.xml +++ b/pom.xml @@ -430,6 +430,9 @@ + + + diff --git a/src/main/java/com/cnaude/purpleirc/CommandHandlers.java b/src/main/java/com/cnaude/purpleirc/CommandHandlers.java index 0e7e37b..aa4cc9b 100644 --- a/src/main/java/com/cnaude/purpleirc/CommandHandlers.java +++ b/src/main/java/com/cnaude/purpleirc/CommandHandlers.java @@ -56,6 +56,8 @@ public class CommandHandlers implements CommandExecutor { commands.put("join", new Join(plugin)); commands.put("kick", new Kick(plugin)); commands.put("leave", new Leave(plugin)); + commands.put("link", new Link(plugin)); + commands.put("linkaccept", new LinkAccept(plugin)); commands.put("list", new List(plugin)); commands.put("listbots", new ListBots(plugin)); commands.put("listops", new ListOps(plugin)); @@ -83,6 +85,8 @@ public class CommandHandlers implements CommandExecutor { commands.put("send", new Send(plugin)); commands.put("sendraw", new SendRaw(plugin)); commands.put("server", new Server(plugin)); + commands.put("slist", new SList(plugin)); + commands.put("smsg", new SMsg(plugin)); commands.put("topic", new Topic(plugin)); commands.put("unmute", new UnMute(plugin)); commands.put("updatecheck", new UpdateCheck(plugin)); diff --git a/src/main/java/com/cnaude/purpleirc/Commands/Link.java b/src/main/java/com/cnaude/purpleirc/Commands/Link.java new file mode 100644 index 0000000..e5e921d --- /dev/null +++ b/src/main/java/com/cnaude/purpleirc/Commands/Link.java @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2014 cnaude + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.cnaude.purpleirc.Commands; + +import com.cnaude.purpleirc.PurpleBot; +import com.cnaude.purpleirc.PurpleIRC; +import java.math.BigInteger; +import java.security.SecureRandom; +import org.apache.commons.codec.binary.Base64; +import org.bukkit.ChatColor; +import org.bukkit.command.CommandSender; + +/** + * + * @author cnaude + */ +public class Link implements IRCCommandInterface { + + private final PurpleIRC plugin; + private final String usage = "[bot1] [bot2] ([secret])"; + private final String desc = "Link bot1 with bot2. Optionally provide secret code."; + private final String name = "link"; + private final String fullUsage = ChatColor.WHITE + "Usage: " + ChatColor.GOLD + "/irc " + name + " " + usage; + + /** + * + * @param plugin + */ + public Link(PurpleIRC plugin) { + this.plugin = plugin; + } + + /** + * + * @param sender + * @param args + */ + @Override + public void dispatch(CommandSender sender, String[] args) { + if (args.length >= 3) { + String bot1 = plugin.botify(args[1]); + String bot2 = args[2]; + if (plugin.ircBots.containsKey(bot1)) { + PurpleBot ircBot = plugin.ircBots.get(bot1); + if (!ircBot.botLinkingEnabled) { + sender.sendMessage(ChatColor.RED + "Bot linking is not enabled!"); + return; + } + + String code = generateCode(args, 130); + String clearText = String.format("LINK_REQUEST:%s", code); + + ircBot.asyncCTCPMessage(bot2, plugin.encodeLinkMsg(PurpleIRC.LINK_CMD, clearText)); + ircBot.setBotLink(bot2, code); + + sender.sendMessage(ChatColor.LIGHT_PURPLE + "Link request sent to " + ChatColor.WHITE + bot2); + } else { + sender.sendMessage(plugin.invalidBotName.replace("%BOT%", bot1)); + } + } else { + sender.sendMessage(fullUsage); + } + } + + private String generateCode(String args[], int size) { + if (args.length == 4) { + return args[3]; + } else { + return new BigInteger(size, new SecureRandom()).toString(size); + } + } + + @Override + public String name() { + return name; + } + + @Override + public String desc() { + return desc; + } + + @Override + public String usage() { + return usage; + } +} diff --git a/src/main/java/com/cnaude/purpleirc/Commands/LinkAccept.java b/src/main/java/com/cnaude/purpleirc/Commands/LinkAccept.java new file mode 100644 index 0000000..8d7ed14 --- /dev/null +++ b/src/main/java/com/cnaude/purpleirc/Commands/LinkAccept.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2014 cnaude + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.cnaude.purpleirc.Commands; + +import com.cnaude.purpleirc.PurpleBot; +import com.cnaude.purpleirc.PurpleIRC; +import org.bukkit.ChatColor; +import org.bukkit.command.CommandSender; + +/** + * + * @author cnaude + */ +public class LinkAccept implements IRCCommandInterface { + + private final PurpleIRC plugin; + private final String usage = "[bot1] [bot2]"; + private final String desc = "Accept link request from bot2."; + private final String name = "linkaccept"; + private final String fullUsage = ChatColor.WHITE + "Usage: " + ChatColor.GOLD + "/irc " + name + " " + usage; + + /** + * + * @param plugin + */ + public LinkAccept(PurpleIRC plugin) { + this.plugin = plugin; + } + + /** + * + * @param sender + * @param args + */ + @Override + public void dispatch(CommandSender sender, String[] args) { + if (args.length >= 3) { + String bot1 = plugin.botify(args[1]); + String bot2 = args[2]; + if (plugin.ircBots.containsKey(bot1)) { + PurpleBot ircBot = plugin.ircBots.get(bot1); + if (!ircBot.botLinkingEnabled) { + sender.sendMessage(ChatColor.RED + "Bot linking is not enabled!"); + return; + } + if (ircBot.linkRequests.containsKey(bot2)) { + ircBot.setBotLink(bot2, ircBot.linkRequests.get(bot2)); + ircBot.linkRequests.remove(bot2); + sender.sendMessage(ChatColor.LIGHT_PURPLE + "Now linked to " + ChatColor.WHITE + bot2); + } else { + sender.sendMessage(ChatColor.RED + "No link requests from " + + ChatColor.WHITE + bot2 + ChatColor.RED + " found. Ask " + + ChatColor.WHITE + bot2 + ChatColor.RED + " to send a request."); + } + } else { + sender.sendMessage(plugin.invalidBotName.replace("%BOT%", bot1)); + } + } else { + sender.sendMessage(fullUsage); + } + } + + @Override + public String name() { + return name; + } + + @Override + public String desc() { + return desc; + } + + @Override + public String usage() { + return usage; + } +} diff --git a/src/main/java/com/cnaude/purpleirc/Commands/Msg.java b/src/main/java/com/cnaude/purpleirc/Commands/Msg.java index d3c6ad4..cdcca17 100644 --- a/src/main/java/com/cnaude/purpleirc/Commands/Msg.java +++ b/src/main/java/com/cnaude/purpleirc/Commands/Msg.java @@ -56,8 +56,8 @@ public class Msg implements IRCCommandInterface { int msgIdx = 2; String nick; java.util.List myBots = new ArrayList<>(); - if (plugin.ircBots.containsKey(args[1])) { - myBots.add(plugin.ircBots.get(args[1])); + if (plugin.ircBots.containsKey(plugin.botify(args[1]))) { + myBots.add(plugin.ircBots.get(plugin.botify(args[1]))); msgIdx = 3; nick = args[2]; } else { diff --git a/src/main/java/com/cnaude/purpleirc/Commands/SList.java b/src/main/java/com/cnaude/purpleirc/Commands/SList.java new file mode 100644 index 0000000..e04b480 --- /dev/null +++ b/src/main/java/com/cnaude/purpleirc/Commands/SList.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2014 cnaude + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.cnaude.purpleirc.Commands; + +import com.cnaude.purpleirc.PurpleBot; +import com.cnaude.purpleirc.PurpleIRC; +import java.text.Collator; +import java.util.ArrayList; +import java.util.Collections; +import org.bukkit.ChatColor; +import org.bukkit.command.CommandSender; + +/** + * + * @author cnaude + */ +public class SList implements IRCCommandInterface { + + private final PurpleIRC plugin; + private final String usage = ""; + private final String desc = "List remote players"; + private final String name = "slist"; + private final String fullUsage = ChatColor.WHITE + "Usage: " + ChatColor.GOLD + "/irc " + name + " " + usage; + + /** + * + * @param plugin + */ + public SList(PurpleIRC plugin) { + this.plugin = plugin; + } + + /** + * + * @param sender + * @param args + */ + @Override + public void dispatch(CommandSender sender, String[] args) { + + for (PurpleBot ircBot : plugin.ircBots.values()) { + if (ircBot.botLinkingEnabled) { + for (String remoteBot : ircBot.remotePlayers.keySet()) { + sender.sendMessage(ChatColor.DARK_PURPLE + "-----[ " + ChatColor.WHITE + "Remote Players" + + ChatColor.DARK_PURPLE + " - " + ChatColor.WHITE + remoteBot + ChatColor.DARK_PURPLE + " ]-----"); + java.util.List remotePlayersSorted = new ArrayList<>(ircBot.remotePlayers.get(remoteBot)); + Collections.sort(remotePlayersSorted, Collator.getInstance()); + for (String playerName : remotePlayersSorted) { + sender.sendMessage(" " + ChatColor.WHITE + playerName); + } + } + } + } + + } + + @Override + public String name() { + return name; + } + + @Override + public String desc() { + return desc; + } + + @Override + public String usage() { + return usage; + } +} diff --git a/src/main/java/com/cnaude/purpleirc/Commands/SMsg.java b/src/main/java/com/cnaude/purpleirc/Commands/SMsg.java new file mode 100644 index 0000000..a806b25 --- /dev/null +++ b/src/main/java/com/cnaude/purpleirc/Commands/SMsg.java @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2014 cnaude + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.cnaude.purpleirc.Commands; + +import com.cnaude.purpleirc.PurpleBot; +import com.cnaude.purpleirc.PurpleIRC; +import com.cnaude.purpleirc.TemplateName; +import java.util.ArrayList; +import org.bukkit.ChatColor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +/** + * + * @author cnaude + */ +public class SMsg implements IRCCommandInterface { + + private final PurpleIRC plugin; + private final String usage = "([bot]) [(server:)player] [message]"; + private final String desc = "Send a message to a player on another server."; + private final String name = "smsg"; + private final String fullUsage = ChatColor.WHITE + "Usage: " + ChatColor.GOLD + "/irc " + name + " " + usage; + + /** + * + * @param plugin + */ + public SMsg(PurpleIRC plugin) { + this.plugin = plugin; + } + + /** + * + * @param sender + * @param args + */ + @Override + public void dispatch(CommandSender sender, String[] args) { + if (args.length >= 3) { + plugin.logDebug("Dispatching smsg command..."); + int msgIdx = 2; + String target; + java.util.List myBots = new ArrayList<>(); + if (plugin.ircBots.containsKey(plugin.botify(args[1]))) { + myBots.add(plugin.ircBots.get(plugin.botify(args[1]))); + msgIdx = 3; + target = args[2]; + } else { + myBots.addAll(plugin.ircBots.values()); + target = args[1]; + } + + if (msgIdx == 3 && args.length <= 3) { + sender.sendMessage(fullUsage); + return; + } + + for (PurpleBot ircBot : myBots) { + String remoteBot = ""; + String remotePlayer = ""; + if (target.contains(":")) { + remoteBot = target.split(":", 2)[0]; + remotePlayer = target.split(":", 2)[1]; + } else { + for (String s : ircBot.remotePlayers.keySet()) { + plugin.logDebug("RB: " + s); + for (String rp : ircBot.remotePlayers.get(s)) { + plugin.logDebug("RP: " + rp); + if (target.equalsIgnoreCase(rp)) { + remotePlayer = target; + remoteBot = s; + break; + } + } + } + } + + if (remotePlayer.isEmpty()) { + sender.sendMessage(ChatColor.RED + "Remote player " + + ChatColor.WHITE + target + ChatColor.RED + " not found!"); + return; + } + + if (ircBot.botLinkingEnabled) { + String msg = ""; + final String template = plugin.getMsgTemplate(ircBot.botNick, "", TemplateName.GAME_PCHAT_RESPONSE); + for (int i = msgIdx; i < args.length; i++) { + msg = msg + " " + args[i]; + } + if (sender instanceof Player) { + ircBot.msgRemotePlayer((Player) sender, remoteBot, remotePlayer, msg.substring(1)); + } else { + ircBot.msgRemotePlayer(sender, remoteBot, remotePlayer, msg.substring(1)); + } + if (!template.isEmpty()) { + sender.sendMessage(plugin.tokenizer.msgChatResponseTokenizer(target, msg.substring(1), template)); + } + } + } + + } else { + sender.sendMessage(fullUsage); + } + } + + @Override + public String name() { + return name; + } + + @Override + public String desc() { + return desc; + } + + @Override + public String usage() { + return usage; + } +} diff --git a/src/main/java/com/cnaude/purpleirc/Commands/Test.java b/src/main/java/com/cnaude/purpleirc/Commands/Test.java index ecc54fb..6536141 100644 --- a/src/main/java/com/cnaude/purpleirc/Commands/Test.java +++ b/src/main/java/com/cnaude/purpleirc/Commands/Test.java @@ -82,7 +82,7 @@ public class Test implements IRCCommandInterface { } } else { sender.sendMessage(ChatColor.LIGHT_PURPLE + "Testing " + playername); - sender.sendMessage("displayName : " + plugin.getDisplayName(name)); + sender.sendMessage("displayName : " + plugin.getDisplayName(playername)); sender.sendMessage("getGroupPrefix : " + plugin.getGroupPrefix(plugin.defaultPlayerWorld, playername)); sender.sendMessage("getGroupSuffix : " + plugin.getGroupSuffix(plugin.defaultPlayerWorld, playername)); sender.sendMessage("getPlayerPrefix : " + plugin.getPlayerPrefix(plugin.defaultPlayerWorld, playername)); diff --git a/src/main/java/com/cnaude/purpleirc/GameListeners/GamePlayerJoinListener.java b/src/main/java/com/cnaude/purpleirc/GameListeners/GamePlayerJoinListener.java index 3523b3d..a6e7884 100644 --- a/src/main/java/com/cnaude/purpleirc/GameListeners/GamePlayerJoinListener.java +++ b/src/main/java/com/cnaude/purpleirc/GameListeners/GamePlayerJoinListener.java @@ -60,6 +60,7 @@ public class GamePlayerJoinListener implements Listener { if (plugin.netPackets != null) { plugin.netPackets.updateTabList(event.getPlayer()); } + ircBot.addRemotePlayer(event.getPlayer().getName()); } plugin.updateDisplayNameCache(event.getPlayer()); plugin.updateUuidCache(event.getPlayer()); diff --git a/src/main/java/com/cnaude/purpleirc/GameListeners/GamePlayerQuitListener.java b/src/main/java/com/cnaude/purpleirc/GameListeners/GamePlayerQuitListener.java index 3724fed..5dbded1 100644 --- a/src/main/java/com/cnaude/purpleirc/GameListeners/GamePlayerQuitListener.java +++ b/src/main/java/com/cnaude/purpleirc/GameListeners/GamePlayerQuitListener.java @@ -58,6 +58,7 @@ public class GamePlayerQuitListener implements Listener { if (plugin.netPackets != null) { plugin.netPackets.updateTabList(event.getPlayer()); } + ircBot.removeRemotePlayer(event.getPlayer().getName()); } } } diff --git a/src/main/java/com/cnaude/purpleirc/IRCListeners/NoticeListener.java b/src/main/java/com/cnaude/purpleirc/IRCListeners/NoticeListener.java index 1519b23..b7c17a0 100644 --- a/src/main/java/com/cnaude/purpleirc/IRCListeners/NoticeListener.java +++ b/src/main/java/com/cnaude/purpleirc/IRCListeners/NoticeListener.java @@ -18,6 +18,8 @@ package com.cnaude.purpleirc.IRCListeners; import com.cnaude.purpleirc.PurpleBot; import com.cnaude.purpleirc.PurpleIRC; +import java.util.ArrayList; +import org.apache.commons.codec.binary.Base64; import org.pircbotx.Channel; import org.pircbotx.User; import org.pircbotx.hooks.ListenerAdapter; @@ -49,9 +51,83 @@ public class NoticeListener extends ListenerAdapter { @Override public void onNotice(NoticeEvent event) { Channel channel = event.getChannel(); - String message = event.getMessage(); + String message = event.getMessage().trim(); String notice = event.getNotice(); User user = event.getUser(); + String nick = user.getNick(); + + if (message.startsWith(PurpleIRC.LINK_CMD) && ircBot.botLinkingEnabled) { + String encodedText = message.replace(PurpleIRC.LINK_CMD, ""); + String decodedText = new String(Base64.decodeBase64(encodedText.getBytes())); + String splitMsg[] = decodedText.split(":"); + + plugin.logDebug("REMOTE LINK COMMAND: " + encodedText + "(" + decodedText + ")"); + + if (splitMsg.length >= 2) { + String command = splitMsg[0]; + String code = splitMsg[1]; + + if (command.equals("LINK_REQUEST")) { + ircBot.linkRequests.put(user.getNick(), code); + plugin.logInfo("PurpleIRC bot link request from " + user.getNick()); + plugin.logInfo("To accept: /irc linkaccept " + + ircBot.getFileName().replace(".yml", "") + " " + user.getNick()); + return; + } + + plugin.logDebug("Are we linked to " + user.getNick() + "?"); + if (ircBot.botLinks.containsKey(nick)) { + plugin.logDebug("Yes we are linked. Is thee code correct?"); + if (ircBot.botLinks.get(nick).equals(code)) { + plugin.logDebug("Yes the code is correct! Command: " + command); + + if (command.equals("PRIVATE_MSG") && splitMsg.length >= 5) { + String from = splitMsg[2]; + String target = splitMsg[3]; + String sMessage = decodedText.split(":", 5)[4]; + + plugin.logDebug(PurpleIRC.LINK_CMD + + " [CODE:" + code + "]" + + " [FROM:" + from + "]" + + " [TO:" + target + "]" + + " [MSG: " + sMessage + "]"); + ircBot.playerCrossChat(user, from, target, sMessage); + } else if (command.equals("PLAYER_JOIN") && splitMsg.length == 3) { + String player = splitMsg[2]; + + plugin.logDebug(PurpleIRC.LINK_CMD + + " [CODE:" + code + "]" + + " [PLAYER:" + player + "]"); + if (!ircBot.remotePlayers.containsKey(nick)) { + plugin.logDebug("Initializing remote player list for " + nick); + ircBot.remotePlayers.put(nick, new ArrayList()); + } + if (!ircBot.remotePlayers.get(nick).contains(player)) { + plugin.logDebug("Adding " + player + " to remote player list for " + nick); + ircBot.remotePlayers.get(nick).add(player); + } + + } else if (command.equals("PLAYER_QUIT") && splitMsg.length == 3) { + String player = splitMsg[2]; + + plugin.logDebug(PurpleIRC.LINK_CMD + + " [CODE:" + code + "]" + + " [PLAYER:" + player + "]"); + if (ircBot.remotePlayers.containsKey(nick)) { + if (ircBot.remotePlayers.get(nick).contains(player)) { + ircBot.remotePlayers.get(nick).remove(player); + } + } + } + } else { + plugin.logDebug("Invalid code from " + nick + "!"); + } + } else { + plugin.logDebug("We are not linked to " + nick + "!"); + } + } + return; + } plugin.logInfo("-" + user.getNick() + "-" + message); if (channel != null) { diff --git a/src/main/java/com/cnaude/purpleirc/PurpleBot.java b/src/main/java/com/cnaude/purpleirc/PurpleBot.java index b84fb6e..cd5e4fc 100644 --- a/src/main/java/com/cnaude/purpleirc/PurpleBot.java +++ b/src/main/java/com/cnaude/purpleirc/PurpleBot.java @@ -179,6 +179,10 @@ public final class PurpleBot { public String sslInfo = ""; public List actionCommands; public List ciphers; + public boolean botLinkingEnabled; + public CaseInsensitiveMap botLinks; + public CaseInsensitiveMap linkRequests; + public CaseInsensitiveMap> remotePlayers; /** * @@ -236,6 +240,9 @@ public final class PurpleBot { this.whoisSenders = new ArrayList<>(); this.actionCommands = new ArrayList<>(); this.ciphers = new LinkedList<>(); + this.botLinks = new CaseInsensitiveMap<>(); + this.linkRequests = new CaseInsensitiveMap<>(); + this.remotePlayers = new CaseInsensitiveMap<>(); config = new YamlConfiguration(); goodBot = loadConfig(); if (goodBot) { @@ -713,6 +720,17 @@ public final class PurpleBot { channelCmdNotifyMode = config.getString("command-notify.mode", "msg"); plugin.logDebug(" channelCmdNotifyMode => " + channelCmdNotifyMode); + botLinkingEnabled = config.getBoolean("bot-linking-enabled", false); + plugin.logDebug(" BotLinkingEnabled => " + botLinkingEnabled); + if (config.contains("bot-links") && botLinkingEnabled) { + for (String t : config.getConfigurationSection("bot-links").getKeys(false)) { + if (!t.startsWith("MemorySection")) { + botLinks.put(t, config.getString("bot-links." + t, "")); + plugin.logDebug("Bot-Link: " + t + " => " + botLinks.get(t)); + } + } + } + for (String s : config.getStringList("custom-prefixes")) { String pair[] = s.split(" ", 2); if (pair.length > 0) { @@ -1732,6 +1750,17 @@ public final class PurpleBot { return channel; } + /** + * + * @param bot2 + * @param code + */ + public void setBotLink(String bot2, String code) { + plugin.logInfo("Saving bot-link: " + bot2); + botLinks.put(bot2, code); + saveConfig("bot-links", botLinks); + } + /** * * @param sender @@ -2641,6 +2670,32 @@ public final class PurpleBot { } } + /** + * Send received private chat to a player + * + * @param user + * @param from + * @param pName + * @param msg + */ + public void playerCrossChat(User user, String from, String pName, String msg) { + if (true) { + Player player = plugin.getServer().getPlayer(pName); + if (player != null) { + if (player.isOnline()) { + plugin.logDebug("Yup, " + pName + " is a valid player..."); + String template = plugin.getMsgTemplate(botNick, "", TemplateName.CROSS_CHAT); + String m = template.replace("%MESSAGE%", msg).replace("%SERVER%", user.getNick()); + player.sendMessage(plugin.colorConverter.ircColorsToGame(m)); + } else { + //no such player online + } + } else { + //asyncIRCMessage(from, "Player not found (possibly offline): " + pName); + } + } + } + // Broadcast action messages from IRC /** * @@ -2961,6 +3016,72 @@ public final class PurpleBot { asyncIRCMessage(nick, msg); } + /** + * Send a private message to a remote linked bot. + * + * @param sender + * @param remoteBot + * @param remotePlayer + * @param message + */ + public void msgRemotePlayer(Player sender, String remoteBot, String remotePlayer, String message) { + String msg = plugin.tokenizer.gameChatToIRCTokenizer(sender, + plugin.getMsgTemplate(botNick, "", TemplateName.GAME_PCHAT), message); + if (botLinks.containsKey(remoteBot)) { + String code = botLinks.get(remoteBot); + String from = sender.getName(); + String clearText = "PRIVATE_MSG:" + code + ":" + from + ":" + remotePlayer + ":" + msg; + asyncCTCPMessage(remoteBot, plugin.encodeLinkMsg(PurpleIRC.LINK_CMD, clearText)); + } else { + sender.sendMessage(ChatColor.RED + "Not linked to " + ChatColor.WHITE + remoteBot); + } + } + + /** + * Send a private message to a remote linked bot. + * + * @param player + */ + public void addRemotePlayer(String player) { + if (botLinkingEnabled) { + for (String remoteBot : botLinks.keySet()) { + String code = botLinks.get(remoteBot); + String clearText = "PLAYER_JOIN:" + code + ":" + player; + asyncCTCPMessage(remoteBot, plugin.encodeLinkMsg(PurpleIRC.LINK_CMD, clearText)); + } + } + } + + /** + * Send a private message to a remote linked bot. + * + * @param player + */ + public void removeRemotePlayer(String player) { + if (botLinkingEnabled) { + for (String remoteBot : botLinks.keySet()) { + String code = botLinks.get(remoteBot); + String clearText = "PLAYER_QUIT:" + code + ":" + player; + asyncCTCPMessage(remoteBot, plugin.encodeLinkMsg(PurpleIRC.LINK_CMD, clearText)); + } + } + } + + /** + * Send a private message to a remote linked bot. + * + * @param remoteBot + * @param remotePlayer + * @param message + */ + public void replyToRemotePlayer(String remotePlayer, String remoteBot, String message) { + if (botLinks.containsKey(remoteBot)) { + String code = botLinks.get(remoteBot); + String clearText = "PRIVATE_AUTO_REPLY:" + code + ":" + botNick + ":" + remotePlayer + ":" + message; + asyncCTCPMessage(remoteBot, plugin.encodeLinkMsg(PurpleIRC.LINK_CMD, clearText)); + } + } + /** * * @param nick @@ -2972,6 +3093,26 @@ public final class PurpleBot { asyncIRCMessage(nick, msg); } + /** + * + * @param sender + * @param remoteBot + * @param remotePlayer + * @param message + */ + public void msgRemotePlayer(CommandSender sender, String remoteBot, String remotePlayer, String message) { + String msg = plugin.tokenizer.gameChatToIRCTokenizer(sender.getName(), + plugin.getMsgTemplate(botNick, "", TemplateName.CONSOLE_CHAT), message); + if (botLinks.containsKey(remoteBot)) { + String code = botLinks.get(remoteBot); + String from = sender.getName(); + String clearText = "PRIVATE_MSG:" + code + ":" + from + ":" + remotePlayer + ":" + msg; + asyncCTCPMessage(remoteBot, plugin.encodeLinkMsg(PurpleIRC.LINK_CMD, clearText)); + } else { + sender.sendMessage(ChatColor.RED + "Not linked to " + ChatColor.WHITE + remoteBot); + } + } + /** * * @param player diff --git a/src/main/java/com/cnaude/purpleirc/PurpleIRC.java b/src/main/java/com/cnaude/purpleirc/PurpleIRC.java index 9be67d9..25d2ea0 100644 --- a/src/main/java/com/cnaude/purpleirc/PurpleIRC.java +++ b/src/main/java/com/cnaude/purpleirc/PurpleIRC.java @@ -83,6 +83,7 @@ import java.util.TreeMap; import java.util.UUID; import java.util.logging.Level; import java.util.logging.Logger; +import org.apache.commons.codec.binary.Base64; import org.bukkit.ChatColor; import org.bukkit.OfflinePlayer; import org.bukkit.command.CommandSender; @@ -215,7 +216,8 @@ public class PurpleIRC extends JavaPlugin { final String PL_HEROCHAT = "Herochat"; List hookList = new ArrayList<>(); public static final String PURPLETAG = "UHVycGxlSVJDCg=="; - public static final String TOWNYTAG = "VG93bnlDaGF0Cg=="; + public static final String TOWNYTAG = "VG93bnlDaGF0Cg=="; + public static final String LINK_CMD = "PurpleIRC-Link:"; public PurpleIRC() { this.MAINCONFIG = "MAIN-CONFIG"; @@ -1577,4 +1579,15 @@ public class PurpleIRC extends JavaPlugin { } } + /** + * + * @param cmd + * @param msg + * @return + */ + public String encodeLinkMsg(String cmd, String msg) { + String encodedText = new String(Base64.encodeBase64(msg.getBytes())); + return String.format("%s:%s", cmd, encodedText); + } + } diff --git a/src/main/java/com/cnaude/purpleirc/TemplateName.java b/src/main/java/com/cnaude/purpleirc/TemplateName.java index 39edde1..a316550 100644 --- a/src/main/java/com/cnaude/purpleirc/TemplateName.java +++ b/src/main/java/com/cnaude/purpleirc/TemplateName.java @@ -139,5 +139,7 @@ public class TemplateName { public final static String GAME_FLOOD_WARNING = "game-flood-warning"; public final static String IRC_FLOOD_WARNING = "irc-flood-warning"; + + public final static String CROSS_CHAT = "cross-chat"; } diff --git a/src/main/resources/SampleBot.yml b/src/main/resources/SampleBot.yml index aa83333..2ec8a0e 100644 --- a/src/main/resources/SampleBot.yml +++ b/src/main/resources/SampleBot.yml @@ -97,6 +97,11 @@ replace-first-occurrences: action-commands: - /me - /eme +# Bot linking +bot-linking-enabled: false +# Map of remote linked bots and codes. Use /irc link and /irc linkaccept +bot-links: +# - remotebot: 249505593790847552435733176657146971496 # channels - List the channels your bot will join here channels: # Channel name must be surrounded by sing quotes to be YAML compliant. diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 949e644..0fedd55 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -80,6 +80,8 @@ channel-check-interval: 100 message-format: # Message templates for game to IRC messages console-chat: '[&dServer&r] %MESSAGE%' + # Cross server chatting via linked bots + cross-chat: '[&4%SERVER%&r] %MESSAGE%' game-achievement: '[&2%WORLD%&r] %NAME% has just earned the achievement [%MESSAGE%]' game-mode: '[&2%WORLD%&r] %NAME% has changed game mode: [%MESSAGE%]' game-action: '[&2%WORLD%&r]***%NAME% %MESSAGE%'