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;
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;
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;
PrefixHandler prefixHandler = new PrefixHandler();
List<Handler> handlers = asList(
+ new MessageHandler(eventBus, this, prefixHandler),
+ new CtcpHandler(eventBus, this),
new MotdHandler(eventBus, this),
new ChannelNotJoinedHandler(eventBus, this),
new ConnectionEstablishHandler(eventBus, this),
}
}
- /* 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()) {
//
/**
- * 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> inetAddress = parseInetAddress(messageWords[3]);
- Optional<Integer> 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<Integer> 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.
*
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<InetAddress> 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 {
--- /dev/null
+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 <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+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<String> 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> inetAddress = parseInetAddress(messageWords[3]);
+ Optional<Integer> 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<Integer> 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<InetAddress> 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();
+ }
+ }
+
+}
--- /dev/null
+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 <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+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<String> 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));
+ }
+
+}