From fdebd77c3b0096f0db76d1d075e55fef350e7304 Mon Sep 17 00:00:00 2001 From: =?utf8?q?David=20=E2=80=98Bombe=E2=80=99=20Roden?= Date: Thu, 16 Oct 2014 22:53:35 +0200 Subject: [PATCH] Use dedicated handlers for normal messages and for CTCP messages. --- .../java/net/pterodactylus/irc/Connection.java | 100 +------------------ .../pterodactylus/irc/connection/CtcpHandler.java | 107 +++++++++++++++++++++ .../irc/connection/MessageHandler.java | 85 ++++++++++++++++ 3 files changed, 197 insertions(+), 95 deletions(-) create mode 100644 src/main/java/net/pterodactylus/irc/connection/CtcpHandler.java create mode 100644 src/main/java/net/pterodactylus/irc/connection/MessageHandler.java diff --git a/src/main/java/net/pterodactylus/irc/Connection.java b/src/main/java/net/pterodactylus/irc/Connection.java index 931acc0..6bb747a 100644 --- a/src/main/java/net/pterodactylus/irc/Connection.java +++ b/src/main/java/net/pterodactylus/irc/Connection.java @@ -29,9 +29,7 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.UnsupportedEncodingException; -import java.net.InetAddress; import java.net.Socket; -import java.net.UnknownHostException; import java.util.ArrayList; import java.util.List; import java.util.Set; @@ -42,27 +40,23 @@ import javax.net.SocketFactory; import net.pterodactylus.irc.connection.ChannelNotJoinedHandler; import net.pterodactylus.irc.connection.ConnectionEstablishHandler; +import net.pterodactylus.irc.connection.CtcpHandler; import net.pterodactylus.irc.connection.Handler; +import net.pterodactylus.irc.connection.MessageHandler; import net.pterodactylus.irc.connection.MotdHandler; import net.pterodactylus.irc.connection.PrefixHandler; import net.pterodactylus.irc.event.ChannelJoined; import net.pterodactylus.irc.event.ChannelLeft; -import net.pterodactylus.irc.event.ChannelMessageReceived; import net.pterodactylus.irc.event.ChannelNicknames; -import net.pterodactylus.irc.event.ChannelNoticeReceived; import net.pterodactylus.irc.event.ChannelTopic; import net.pterodactylus.irc.event.ClientQuit; import net.pterodactylus.irc.event.ConnectionClosed; import net.pterodactylus.irc.event.ConnectionEstablished; import net.pterodactylus.irc.event.ConnectionFailed; -import net.pterodactylus.irc.event.DccAcceptReceived; -import net.pterodactylus.irc.event.DccSendReceived; import net.pterodactylus.irc.event.KickedFromChannel; import net.pterodactylus.irc.event.NicknameChanged; import net.pterodactylus.irc.event.NicknameInUseReceived; import net.pterodactylus.irc.event.NoNicknameGivenReceived; -import net.pterodactylus.irc.event.PrivateMessageReceived; -import net.pterodactylus.irc.event.PrivateNoticeReceived; import net.pterodactylus.irc.event.ReplyReceived; import net.pterodactylus.irc.event.UnknownReplyReceived; import net.pterodactylus.irc.util.RandomNickname; @@ -74,8 +68,6 @@ import com.google.common.collect.Sets; import com.google.common.eventbus.EventBus; import com.google.common.eventbus.Subscribe; import com.google.common.io.Closeables; -import com.google.common.primitives.Ints; -import com.google.common.primitives.Longs; import com.google.common.util.concurrent.AbstractExecutionThreadService; import com.google.common.util.concurrent.Service; import org.apache.log4j.Logger; @@ -376,6 +368,8 @@ public class Connection extends AbstractExecutionThreadService implements Servic PrefixHandler prefixHandler = new PrefixHandler(); List handlers = asList( + new MessageHandler(eventBus, this, prefixHandler), + new CtcpHandler(eventBus, this), new MotdHandler(eventBus, this), new ChannelNotJoinedHandler(eventBus, this), new ConnectionEstablishHandler(eventBus, this), @@ -396,33 +390,8 @@ public class Connection extends AbstractExecutionThreadService implements Servic } } - /* most common events. */ - if (command.equalsIgnoreCase("PRIVMSG")) { - String recipient = parameters.get(0); - String message = parameters.get(1); - if (message.startsWith("\u0001") && message.endsWith("\u0001")) { - /* CTCP! */ - handleCtcp(reply.source().get(), message); - } else if (!prefixHandler.isChannel(recipient)) { - eventBus.post(new PrivateMessageReceived(this, reply.source().get(), message)); - } else { - eventBus.post(new ChannelMessageReceived(this, reply.source().get(), recipient, message)); - } - - } else if (command.equalsIgnoreCase("NOTICE")) { - String recipient = parameters.get(0); - String message = parameters.get(1); - if (message.startsWith("\u0001") && message.endsWith("\u0001")) { - /* CTCP! */ - handleCtcp(reply.source().get(), message); - } else if (!prefixHandler.isChannel(recipient)) { - eventBus.post(new PrivateNoticeReceived(this, reply.source().get(), message)); - } else { - eventBus.post(new ChannelNoticeReceived(this, reply.source().get(), recipient, message)); - } - /* 43x replies are for nick change errors. */ - } else if (command.equals("431")) { + if (command.equals("431")) { eventBus.post(new NoNicknameGivenReceived(this, reply)); } else if (command.equals("433")) { if (!established.get()) { @@ -503,39 +472,6 @@ public class Connection extends AbstractExecutionThreadService implements Servic // /** - * Handles a CTCP message. - * - * @param client - * The client sending the message - * @param message - * The message - */ - private void handleCtcp(Source client, String message) { - String[] messageWords = message.substring(1, message.length() - 1).split(" +"); - String ctcpCommand = messageWords[0]; - if (ctcpCommand.equalsIgnoreCase("DCC")) { - if (messageWords[1].equalsIgnoreCase("SEND")) { - Optional inetAddress = parseInetAddress(messageWords[3]); - Optional port = Optional.fromNullable(Ints.tryParse(messageWords[4])); - long fileSize = Optional.fromNullable(Longs.tryParse(messageWords[5])).or(-1L); - if (inetAddress.isPresent() && port.isPresent()) { - eventBus.post(new DccSendReceived(this, client, messageWords[2], inetAddress.get(), port.get(), fileSize)); - } else { - logger.warn(String.format("Received malformed DCC SEND: “%s”", message)); - } - } else if (messageWords[1].equalsIgnoreCase("ACCEPT")) { - Optional port = Optional.fromNullable(Ints.tryParse(messageWords[3])); - long position = (messageWords.length > 4) ? Optional.fromNullable(Longs.tryParse(messageWords[4])).or(-1L) : -1; - if (port.isPresent()) { - eventBus.post(new DccAcceptReceived(this, client, messageWords[2], port.get(), position)); - } else { - logger.warn(String.format("Received malformed DCC ACCEPT: “%s”", message)); - } - } - } - } - - /** * Returns an item from the list, or {@link Optional#absent()} if the list is * shorter than required for the given index. * @@ -555,32 +491,6 @@ public class Connection extends AbstractExecutionThreadService implements Servic return Optional.absent(); } - /** - * Parses the given {@code ip} and returns an {@link InetAddress} from it. - * - * @param ip - * The IP to parse - * @return The parsed inet address, or {@link Optional#absent()} if no inet - * address could be parsed - */ - private Optional parseInetAddress(String ip) { - Long ipNumber = Longs.tryParse(ip); - if (ipNumber == null) { - return Optional.absent(); - } - - StringBuilder hostname = new StringBuilder(15); - hostname.append((ipNumber >>> 24) & 0xff).append('.'); - hostname.append((ipNumber >>> 16) & 0xff).append('.'); - hostname.append((ipNumber >>> 8) & 0xff).append('.'); - hostname.append(ipNumber & 0xff); - try { - return Optional.of(InetAddress.getByName(hostname.toString())); - } catch (UnknownHostException uhe1) { - return Optional.absent(); - } - } - /** Handles input and output for the connection. */ private class ConnectionHandler implements Closeable { diff --git a/src/main/java/net/pterodactylus/irc/connection/CtcpHandler.java b/src/main/java/net/pterodactylus/irc/connection/CtcpHandler.java new file mode 100644 index 0000000..ff9757e --- /dev/null +++ b/src/main/java/net/pterodactylus/irc/connection/CtcpHandler.java @@ -0,0 +1,107 @@ +package net.pterodactylus.irc.connection; + +import static com.google.common.base.Optional.absent; +import static com.google.common.base.Optional.fromNullable; +import static com.google.common.base.Optional.of; +import static java.lang.String.format; +import static java.net.InetAddress.getByName; +import static org.apache.log4j.Logger.getLogger; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.List; + +import net.pterodactylus.irc.Connection; +import net.pterodactylus.irc.Reply; +import net.pterodactylus.irc.Source; +import net.pterodactylus.irc.event.DccAcceptReceived; +import net.pterodactylus.irc.event.DccSendReceived; + +import com.google.common.base.Optional; +import com.google.common.eventbus.EventBus; +import com.google.common.primitives.Ints; +import com.google.common.primitives.Longs; +import org.apache.log4j.Logger; + +/** + * Handles all CTCP messages relevant to DCC transfers. + * + * @author David ‘Bombe’ Roden + */ +public class CtcpHandler implements Handler { + + private static final Logger logger = getLogger(CtcpHandler.class); + private final EventBus eventBus; + private final Connection connection; + + public CtcpHandler(EventBus eventBus, Connection connection) { + this.eventBus = eventBus; + this.connection = connection; + } + + @Override + public boolean willHandle(Reply reply) { + return (commandIs(reply, "PRIVMSG") || commandIs(reply, "NOTICE")) + && messageIsCtcp(reply.parameters().get(1)); + } + + private boolean commandIs(Reply reply, String command) { + return reply.command().equalsIgnoreCase(command); + } + + private boolean messageIsCtcp(String message) { + return message.startsWith("\u0001") && message.endsWith("\u0001"); + } + + @Override + public void handleReply(Reply reply) { + List parameters = reply.parameters(); + String message = parameters.get(1); + Source source = reply.source().get(); + handleCtcp(source, message); + } + + private void handleCtcp(Source client, String message) { + String[] messageWords = message.substring(1, message.length() - 1).split(" +"); + String ctcpCommand = messageWords[0]; + if (ctcpCommand.equalsIgnoreCase("DCC")) { + if (messageWords[1].equalsIgnoreCase("SEND")) { + Optional inetAddress = parseInetAddress(messageWords[3]); + Optional port = fromNullable(Ints.tryParse(messageWords[4])); + long fileSize = fromNullable(Longs.tryParse(messageWords[5])).or(-1L); + if (inetAddress.isPresent() && port.isPresent()) { + eventBus.post(new DccSendReceived(connection, client, messageWords[2], inetAddress.get(), port.get(), fileSize)); + } else { + logger.warn(format("Received malformed DCC SEND: “%s”", message)); + } + } else if (messageWords[1].equalsIgnoreCase("ACCEPT")) { + Optional port = fromNullable(Ints.tryParse(messageWords[3])); + long position = (messageWords.length > 4) ? fromNullable(Longs.tryParse(messageWords[4])).or(-1L) : -1; + if (port.isPresent()) { + eventBus.post(new DccAcceptReceived(connection, client, messageWords[2], port.get(), position)); + } else { + logger.warn(format("Received malformed DCC ACCEPT: “%s”", message)); + } + } + } + } + + private Optional parseInetAddress(String ip) { + Long ipNumber = Longs.tryParse(ip); + if (ipNumber == null) { + return absent(); + } + + StringBuilder hostname = new StringBuilder(15); + hostname.append((ipNumber >>> 24) & 0xff).append('.'); + hostname.append((ipNumber >>> 16) & 0xff).append('.'); + hostname.append((ipNumber >>> 8) & 0xff).append('.'); + hostname.append(ipNumber & 0xff); + try { + return of(getByName(hostname.toString())); + } catch (UnknownHostException uhe1) { + return absent(); + } + } + +} diff --git a/src/main/java/net/pterodactylus/irc/connection/MessageHandler.java b/src/main/java/net/pterodactylus/irc/connection/MessageHandler.java new file mode 100644 index 0000000..36d1938 --- /dev/null +++ b/src/main/java/net/pterodactylus/irc/connection/MessageHandler.java @@ -0,0 +1,85 @@ +package net.pterodactylus.irc.connection; + +import java.util.List; + +import net.pterodactylus.irc.Connection; +import net.pterodactylus.irc.Reply; +import net.pterodactylus.irc.Source; +import net.pterodactylus.irc.event.ChannelMessageReceived; +import net.pterodactylus.irc.event.ChannelNoticeReceived; +import net.pterodactylus.irc.event.PrivateMessageReceived; +import net.pterodactylus.irc.event.PrivateNoticeReceived; + +import com.google.common.eventbus.EventBus; + +/** + * Handles {@code PRIVMSG}s and {@code NOTICE}s that are not CTCP messages. + * + * @author David ‘Bombe’ Roden + */ +public class MessageHandler implements Handler { + + private final EventBus eventBus; + private final Connection connection; + private final PrefixHandler prefixHandler; + + public MessageHandler(EventBus eventBus, Connection connection, + PrefixHandler prefixHandler) { + this.eventBus = eventBus; + this.connection = connection; + this.prefixHandler = prefixHandler; + } + + @Override + public boolean willHandle(Reply reply) { + return (commandIs(reply, "PRIVMSG") || commandIs(reply, "NOTICE")) + && !messageIsCtcp(reply.parameters().get(1)); + } + + private boolean commandIs(Reply reply, String command) { + return reply.command().equalsIgnoreCase(command); + } + + private boolean messageIsCtcp(String message) { + return message.startsWith("\u0001") && message.endsWith("\u0001"); + } + + @Override + public void handleReply(Reply reply) { + boolean isNotice = commandIs(reply, "NOTICE"); + List parameters = reply.parameters(); + String recipient = parameters.get(0); + String message = parameters.get(1); + Source source = reply.source().get(); + if (!prefixHandler.isChannel(recipient)) { + if (isNotice) { + firePrivateNoticeEvent(source, message); + } else { + firePrivateMessageEvent(source, message); + } + } else { + if (isNotice) { + fireChannelNoticeEvent(source, recipient, message); + } else { + fireChannelMessageEvent(source, recipient, message); + } + } + } + + private void firePrivateNoticeEvent(Source source, String message) { + eventBus.post(new PrivateNoticeReceived(connection, source, message)); + } + + private void firePrivateMessageEvent(Source source, String message) { + eventBus.post(new PrivateMessageReceived(connection, source, message)); + } + + private void fireChannelNoticeEvent(Source source, String channel, String message) { + eventBus.post(new ChannelNoticeReceived(connection, source, channel, message)); + } + + private void fireChannelMessageEvent(Source source, String channel, String message) { + eventBus.post(new ChannelMessageReceived(connection, source, channel, message)); + } + +} -- 2.7.4