Use dedicated handlers for normal messages and for CTCP messages.
[xudocci.git] / src / main / java / net / pterodactylus / irc / connection / CtcpHandler.java
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 (file)
index 0000000..ff9757e
--- /dev/null
@@ -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 <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();
+               }
+       }
+
+}