/* * Project: xdccBee * Copyright (C) 2009 snert@snert-lab.de, * * 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 <http://www.gnu.org/licenses/>. */ package de.snertlab.xdccBee.irc; import java.io.File; import java.io.IOException; import java.net.InetAddress; import java.net.UnknownHostException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.HashMap; import java.util.List; import java.util.StringTokenizer; import org.schwering.irc.lib.IRCConnection; import org.schwering.irc.lib.IRCEventListener; import org.schwering.irc.lib.IRCModeParser; import org.schwering.irc.lib.IRCUser; import de.snertlab.xdccBee.irc.listener.LogMessage; import de.snertlab.xdccBee.irc.listener.NotifyManagerConnectedState; import de.snertlab.xdccBee.irc.listener.NotifyManagerDccBotLogging; import de.snertlab.xdccBee.irc.listener.NotifyManagerDccDownload; import de.snertlab.xdccBee.irc.listener.NotifyManagerDccPacket; /** * @author snert * */ public class DccBot implements IRCEventListener { private static final String DCC_SEND_LEADING = "DCC SEND "; public List<String> listChannelsJoined; private IrcServer ircServer; private String nickname; private String downloadDirFilename; private HashMap<String, DccFileTransfer> mapAwaitingDccFileTransferResume; private IRCConnection ircconnection; public DccBot(IrcServer ircServer, String botName, String botVersion, String downloadDirFilename) { // TODO: botName and botVersion??? this.listChannelsJoined = new ArrayList<String>(); this.ircServer = ircServer; this.mapAwaitingDccFileTransferResume = new HashMap<String, DccFileTransfer>(); this.downloadDirFilename = downloadDirFilename; } public void setNickname(String nickname) { this.nickname = nickname; } public void connect() throws IOException { if (ircconnection != null) ircconnection = null; ircconnection = new IRCConnection(ircServer.getHostname(), new int[] { Integer.parseInt(ircServer.getPort()) }, null, ircServer.getNickname(), ircServer.getNickname(), ircServer.getNickname()); ircconnection.setEncoding("ISO-8859-1"); ircconnection.setPong(true); ircconnection.setColors(false); ircconnection.addIRCEventListener(this); ircconnection.connect(); } public void log(String message) { log(new LogMessage( "[" + getLogTime() + "]" + " " + message, LogMessage.LOG_COLOR_DCCBOT_MESSAGE)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } private void log(LogMessage message) { NotifyManagerDccBotLogging.getNotifyManager() .notify(ircServer, message); } protected void onConnect() { ircServer.setConnected(true); List<IrcChannel> listIrcChannels = ircServer.getListChannels(); for (IrcChannel ircChannel : listIrcChannels) { if (ircChannel.isAutoconnect()) { ircconnection.doJoin(ircChannel.getChannelName()); // TODO: // Nicht // ganz // sauber, // aber // ircChannel.connect() // kann // nicht // aufgerufen // werden // da IRC Server threadBotConnect noch laeuft } } NotifyManagerConnectedState.getNotifyManager().notify(ircServer); } // TODO: kick oder ban abfangen?? public boolean isChannelJoined(String channel) { // TODO: Was passiert wenn es den Channel nicht gibt?? if (listChannelsJoined.contains(channel.toUpperCase())) { return true; } return false; } private String getLogTime() { Calendar cal = Calendar.getInstance(); SimpleDateFormat sdf = new SimpleDateFormat("HH:mm"); //$NON-NLS-1$ return sdf.format(cal.getTime()); } public void xdccSend(DccPacket dccPacket) { DccDownloadQueue downloadQueue = DccDownloadQueue.getInstance(); DccDownload dccDownload = new DccDownload(dccPacket, downloadDirFilename); if (downloadQueue.getDccDownload(dccDownload.getKey()) != null) { ircconnection.doPrivmsg(dccPacket.getSender(), "xdcc send #" + dccPacket.getPacketNr()); dccDownload = downloadQueue.getDccDownload(dccDownload.getKey()); dccDownload.setState(DccDownload.STATE_DOWNLOAD_WAITING); } else { downloadQueue.addToQueue(dccDownload); ircconnection.doPrivmsg(dccPacket.getSender(), "xdcc send #" + dccPacket.getPacketNr()); NotifyManagerDccDownload.getNotifyManager().notifyNewDccDownload( dccDownload); } } public IrcServer getIrcServer() { return ircServer; } public void removeChannelFromJoinedChannelList(String channelName) { listChannelsJoined.remove(channelName.toUpperCase()); } @Override public void onRegistered() { log("connected"); onConnect(); } @Override public void onDisconnected() { log("disconnect"); ircServer.disconnect(); NotifyManagerConnectedState.getNotifyManager().notify(ircServer); } @Override public void onError(String msg) { log(msg); } @Override public void onError(int num, String msg) { log(num + " " + msg); } @Override public void onInvite(String chan, IRCUser user, String passiveNick) { log("onInvite: channel:" + chan + "nick: " + user.getNick() + "passiveNick:" + passiveNick); } @Override public void onJoin(String chan, IRCUser user) { log("join " + chan + " user: " + user); if (nickname.equals(user.getNick())) { listChannelsJoined.add(chan.toUpperCase()); NotifyManagerConnectedState.getNotifyManager().notify( ircServer.getChannelByName(chan)); } } @Override public void onKick(String chan, IRCUser user, String passiveNick, String msg) { log("onKick" + user.getNick() + " " + msg); } @Override public void onMode(String chan, IRCUser user, IRCModeParser modeParser) { // nothing } @Override public void onMode(IRCUser user, String passiveNick, String mode) { log(mode); } @Override public void onNick(IRCUser user, String newNick) { log(newNick); } @Override public void onNotice(String target, IRCUser user, String msg) { log(msg); } @Override public void onPart(String chan, IRCUser user, String msg) { log(msg); if (nickname.equals(user.getNick())) { removeChannelFromJoinedChannelList(chan); NotifyManagerConnectedState.getNotifyManager().notify( ircServer.getChannelByName(chan)); } } @Override public void onPing(String ping) { log(ping); ircconnection.doPong(ping); } @Override public void onPrivmsg(String target, IRCUser user, String msg) { String nick = user.getNick(); log(nick + msg); // TODO: Wenn sich ein bot deconnected dann dies in Tabelle anzeigen => // onQuit if (DccMessageParser.isDccMessage(msg)) { DccPacket dccPacket = DccMessageParser.buildDccPacket( user.getNick(), msg); dccPacket.setDccBot(this); IrcChannel ircChannel = ircServer.getChannelByName(target); dccPacket.setIrcChannel(ircChannel); if (!ircServer.containsPacket(dccPacket)) { ircServer.addDccPacket(dccPacket); ircChannel.addDccPacket(dccPacket); log(new LogMessage(dccPacket.getName(), LogMessage.LOG_COLOR_DCC_MESSAGE)); NotifyManagerDccPacket.getNotifyManager().notifyNewPackage( dccPacket); } } else if (validDccSendMessage(nick, msg)) { DccFileTransfer dccFileTransfer = parseDccFileTransfer(nick, msg); if (dccFileTransfer.isResume() && !mapAwaitingDccFileTransferResume.containsKey(nick)) { mapAwaitingDccFileTransferResume.put(nick, dccFileTransfer); File f = new File(downloadDirFilename + dccFileTransfer.getFilename()); ircconnection.doPrivmsg(nick, "DCC RESUME file.ext " + dccFileTransfer.getPort() + " " + f.length()); return; } // FIXME: NullPointerException if xdcc send was not instantiated by // xdccBee DccDownload dccDownload = DccDownloadQueue.getInstance() .getDccDownload(dccFileTransfer); if (dccDownload == null) { return; } dccDownload.setDccFileTransfer(dccFileTransfer); dccFileTransfer.start(dccDownload.getDownloadDirFilename()); dccDownload.start(); } else { log(new LogMessage( "KEINE DCC MESSAGE: " + msg, LogMessage.LOG_COLOR_NO_DCC_MESSAGE)); //$NON-NLS-1$ } } @Override public void onQuit(IRCUser user, String msg) { log("Quit " + user.getNick() + msg); } @Override public void onReply(int num, String value, String msg) { log(value + " " + msg); } @Override public void onTopic(String chan, IRCUser user, String topic) { log(user.getNick() + " " + topic); } @Override public void unknown(String prefix, String command, String middle, String trailing) { log("unknown"); } private DccFileTransfer parseDccFileTransfer(String sender, String msg) { try { String tmpfile; StringTokenizer st = new StringTokenizer(msg); st.nextToken(); st.nextToken(); tmpfile = st.nextToken(); if (tmpfile.charAt(0) == '\"') { do { tmpfile += " " + st.nextToken(); } while (tmpfile.charAt(tmpfile.length() - 1) != '\"'); tmpfile = tmpfile.substring(1, tmpfile.length() - 1); } String tmphost = st.nextToken(); if (tmphost.charAt(0) == '\"') { tmphost = tmphost.substring(1); } if (tmphost.charAt(tmphost.length() - 1) == '\"') { tmphost = tmphost.substring(0, tmphost.length() - 1); } String xhost = getInetAddress(Long.parseLong(tmphost)) .getHostAddress(); int xport = Integer.parseInt(st.nextToken()); long xsize = Long.parseLong(st.nextToken()); boolean resume = false; File fTmpFile = new File(downloadDirFilename + tmpfile); if (fTmpFile.exists() && fTmpFile.length() != 0) { resume = true; } DccFileTransfer dccFileTransfer = new DccFileTransfer(xhost, xport, xsize, sender, tmpfile, resume); return dccFileTransfer; } catch (Exception exc) { throw new RuntimeException(exc); } } private boolean validDccSendMessage(String sender, String msg) { if (msg.length() <= DCC_SEND_LEADING.length()) { return false; } if (!msg.substring(0, DCC_SEND_LEADING.length()).equalsIgnoreCase( DCC_SEND_LEADING)) { return false; } return true; } private static InetAddress getInetAddress(long address) throws UnknownHostException { byte[] addr = new byte[4]; addr[0] = (byte) ((address >>> 24) & 0xFF); addr[1] = (byte) ((address >>> 16) & 0xFF); addr[2] = (byte) ((address >>> 8) & 0xFF); addr[3] = (byte) (address & 0xFF); return InetAddress.getByAddress(addr); } public void doQuit() { ircconnection.doQuit(); } public void close() { ircconnection.close(); } public void doJoin(String channelName) { ircconnection.doJoin(channelName); } public void doPart(String channelName) { ircconnection.doPart(channelName); } }