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%'